From a581df39d1bdbb3584abb661dc74e09b018f6322 Mon Sep 17 00:00:00 2001 From: Hyperblast Date: Wed, 12 Feb 2025 07:30:52 +0500 Subject: [PATCH 01/12] enable multi-threaded compilation --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 00089a9..e05b595 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,7 @@ option(FOO_SYSTEM_WTL "Use system WTL library" OFF) option(FOO_SAMPLE "Build foo_sample component" OFF) set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake;${CMAKE_MODULE_PATH}") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4302 /wd4838 /wd4996 /d2notypeopt") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /wd4302 /wd4838 /wd4996 /d2notypeopt") if(FOO_STATIC_STDLIB) foreach(FLAGS CMAKE_CXX_FLAGS_DEBUG From 2e76e0274ff9fade1a47c69c1875dd9c3c577b9f Mon Sep 17 00:00:00 2001 From: Hyperblast Date: Wed, 12 Feb 2025 07:54:57 +0500 Subject: [PATCH 02/12] switch to gh actions --- .github/workflows/build.yml | 48 +++++++++++++++++++++++++++++++++++++ README.md | 2 +- appveyor.yml | 19 --------------- build.proj | 28 ---------------------- 4 files changed, 49 insertions(+), 48 deletions(-) create mode 100644 .github/workflows/build.yml delete mode 100644 appveyor.yml delete mode 100644 build.proj diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..6f32a79 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,48 @@ +name: build + +on: + + push: + branches: + - master + + pull_request: + branches: + - master + +jobs: + + build: + + runs-on: windows-2022 + + defaults: + run: + shell: cmd + + strategy: + matrix: + arch: + - Win32 + - x64 + + steps: + - name: Set git to use LF + run: | + git config --global core.autocrlf false + git config --global core.eol lf + + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup MSVC + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: ${{ matrix.arch }} + + - name: Build + run: | + mkdir build + cd build + cmake -A ${{ matrix.arch }} -DFOO_SAMPLE=ON .. + msbuild -v:m -p:Configuration=Release -p:Platform=${{ matrix.arch }} foosdk.sln diff --git a/README.md b/README.md index d2da26e..16c3e76 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # foosdk Foobar2000 SDK with CMake-based build system and few improvements. -[![Build Status](https://ci.appveyor.com/api/projects/status/github/hyperblast/foosdk?branch=master&svg=true)](https://ci.appveyor.com/project/hyperblast/foosdk) +[![Build Status](https://github.com/hyperblast/foosdk/actions/workflows/build.yml/badge.svg)](https://github.com/hyperblast/foosdk/actions/workflows/build.yml) ### Features - CMake-based build system diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 9fb2a4f..0000000 --- a/appveyor.yml +++ /dev/null @@ -1,19 +0,0 @@ -image: Visual Studio 2022 - -branches: - only: - - master - -build: - project: build.proj - -configuration: Release - -platform: -- Win32 -- x64 - -environment: - BuildFlags: -DFOO_SAMPLE=ON - -test_script: "" diff --git a/build.proj b/build.proj deleted file mode 100644 index f6978f5..0000000 --- a/build.proj +++ /dev/null @@ -1,28 +0,0 @@ - - - - Debug - Win32 - $(MSBuildProjectDirectory)\build - - - - - - - - - - - - - - - - - - From 01067f37ff8c7eda53e7f8f96a07ba05502dedd0 Mon Sep 17 00:00:00 2001 From: Hyperblast Date: Wed, 12 Feb 2025 07:22:20 +0500 Subject: [PATCH 03/12] update to SDK-2023-01-18 --- cmake/FileLists.cmake | 4 + sdk/foobar2000/SDK/advconfig.h | 3 +- sdk/foobar2000/SDK/advconfig_impl.h | 1 + sdk/foobar2000/SDK/app_close_blocker.cpp | 4 + sdk/foobar2000/SDK/audio_chunk.cpp | 51 ++++---- sdk/foobar2000/SDK/audio_chunk.h | 12 +- .../SDK/audio_chunk_channel_config.cpp | 32 ++++- sdk/foobar2000/SDK/callback_merit.h | 24 ++++ sdk/foobar2000/SDK/contextmenu.h | 29 +++++ sdk/foobar2000/SDK/core_api.h | 9 +- sdk/foobar2000/SDK/file_info.cpp | 89 +++++++------- sdk/foobar2000/SDK/file_info.h | 24 ++-- sdk/foobar2000/SDK/file_info_impl.cpp | 21 ++-- sdk/foobar2000/SDK/file_info_impl.h | 5 +- sdk/foobar2000/SDK/filesystem.cpp | 4 + sdk/foobar2000/SDK/foobar2000-versions.h | 2 +- sdk/foobar2000/SDK/foobar2000_SDK.vcxproj | 1 + .../SDK/foobar2000_SDK.vcxproj.filters | 3 + sdk/foobar2000/SDK/guids.cpp | 12 ++ sdk/foobar2000/SDK/initquit.h | 38 ++++++ sdk/foobar2000/SDK/library_callbacks.h | 3 +- sdk/foobar2000/SDK/library_index.h | 1 + sdk/foobar2000/SDK/library_manager.h | 10 ++ sdk/foobar2000/SDK/metadb_callbacks.h | 20 +++- sdk/foobar2000/SDK/metadb_handle.h | 3 + sdk/foobar2000/SDK/play_callback.h | 9 ++ sdk/foobar2000/SDK/playback_stream_capture.h | 40 ++++++- sdk/foobar2000/SDK/playlist.h | 10 +- sdk/foobar2000/SDK/replaygain_info.cpp | 5 +- sdk/foobar2000/SDK/search_tools.h | 35 ++++++ sdk/foobar2000/SDK/tag_processor.cpp | 8 +- sdk/foobar2000/SDK/tag_processor.h | 1 + sdk/foobar2000/SDK/threadsLite.h | 1 + sdk/foobar2000/SDK/utility.cpp | 44 +++++++ sdk/foobar2000/helpers/ThreadUtils.h | 6 +- sdk/foobar2000/helpers/callback_merit.h | 31 +++++ sdk/foobar2000/helpers/fb2kWorkerTool.h | 12 +- sdk/foobar2000/helpers/file_win32_wrapper.cpp | 52 ++++++-- sdk/foobar2000/helpers/file_win32_wrapper.h | 81 +++++++------ .../helpers/foobar2000_sdk_helpers.vcxproj | 3 + .../foobar2000_sdk_helpers.vcxproj.filters | 9 ++ sdk/foobar2000/helpers/metadb_handle_set.h | 42 ++++--- .../helpers/packet_decoder_aac_common.cpp | 43 +++++++ .../helpers/packet_decoder_aac_common.h | 6 + sdk/foobar2000/helpers/readWriteLock.h | 76 ++++++++++++ .../helpers/window_placement_helper.cpp | 14 ++- .../helpers/window_placement_helper.h | 36 +++--- sdk/foobar2000/shared/shared-ARM64.lib | Bin 36368 -> 36368 bytes sdk/foobar2000/shared/shared-ARM64EC.lib | Bin 40094 -> 40094 bytes sdk/foobar2000/shared/shared-Win32.lib | Bin 38516 -> 38516 bytes sdk/foobar2000/shared/shared-x64.lib | Bin 36368 -> 36368 bytes sdk/foobar2000/shared/shared.h | 2 + sdk/libPPUI/CListAccessible.cpp | 4 +- sdk/libPPUI/CListControl.cpp | 38 +++--- sdk/libPPUI/CListControl.h | 7 +- sdk/libPPUI/CListControlOwnerData.h | 3 +- sdk/libPPUI/libPPUI-license.txt | 2 +- sdk/pfc/SmartStrStr-twoCharMappings.h | 31 +++-- sdk/pfc/SmartStrStr.cpp | 112 ++++++++++++++++-- sdk/pfc/SmartStrStr.h | 24 +++- sdk/pfc/audio_sample.cpp | 65 ---------- sdk/pfc/audio_sample.h | 6 - sdk/pfc/charDownConvert.cpp | 37 +++--- sdk/pfc/charDownConvert.h | 15 +-- sdk/pfc/pfc-license.txt | 2 +- sdk/pfc/string_base.cpp | 9 ++ sdk/pfc/string_base.h | 6 +- sdk/pfc/synchro_win.h | 5 +- sdk/sdk-license.txt | 4 +- sdk/sdk-readme.html | 2 +- 70 files changed, 986 insertions(+), 357 deletions(-) create mode 100644 sdk/foobar2000/SDK/callback_merit.h create mode 100644 sdk/foobar2000/helpers/callback_merit.h create mode 100644 sdk/foobar2000/helpers/readWriteLock.h diff --git a/cmake/FileLists.cmake b/cmake/FileLists.cmake index c30465e..7454c3b 100644 --- a/cmake/FileLists.cmake +++ b/cmake/FileLists.cmake @@ -237,6 +237,7 @@ set( sdk/foobar2000/SDK/audioEncoder.h sdk/foobar2000/SDK/audio_postprocessor.h sdk/foobar2000/SDK/autoplaylist.h + sdk/foobar2000/SDK/callback_merit.h sdk/foobar2000/SDK/cfg_var.h sdk/foobar2000/SDK/cfg_var_legacy.h sdk/foobar2000/SDK/chapterizer.h @@ -418,6 +419,7 @@ set( sdk/foobar2000/helpers/audio_render_float.h sdk/foobar2000/helpers/AutoComplete.h sdk/foobar2000/helpers/BumpableElem.h + sdk/foobar2000/helpers/callback_merit.h sdk/foobar2000/helpers/CDialogResizeHelper.h sdk/foobar2000/helpers/cfg_dsp_chain_config.h sdk/foobar2000/helpers/cfg_obj.h @@ -431,6 +433,7 @@ set( sdk/foobar2000/helpers/DarkMode.h sdk/foobar2000/helpers/dsp_dialog.h sdk/foobar2000/helpers/duration_counter.h + sdk/foobar2000/helpers/fb2kWorkerTool.h sdk/foobar2000/helpers/fb2k_threads.h sdk/foobar2000/helpers/fb2k_wfx.h sdk/foobar2000/helpers/fileReadAhead.h @@ -479,6 +482,7 @@ set( sdk/foobar2000/helpers/ProfileCache.h sdk/foobar2000/helpers/readers.h sdk/foobar2000/helpers/reader_pretend_nonseekable.h + sdk/foobar2000/helpers/readWriteLock.h sdk/foobar2000/helpers/rethrow.h sdk/foobar2000/helpers/seekabilizer.h sdk/foobar2000/helpers/StdAfx.h diff --git a/sdk/foobar2000/SDK/advconfig.h b/sdk/foobar2000/SDK/advconfig.h index 12da216..ba36c0d 100644 --- a/sdk/foobar2000/SDK/advconfig.h +++ b/sdk/foobar2000/SDK/advconfig.h @@ -24,9 +24,10 @@ class NOVTABLE advconfig_entry : public service_base { 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, guid_branch_converter; + // \since 2.0 - static const GUID guid_branch_vis; + static const GUID guid_branch_vis, guid_branch_general; FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(advconfig_entry); }; diff --git a/sdk/foobar2000/SDK/advconfig_impl.h b/sdk/foobar2000/SDK/advconfig_impl.h index 8079f81..e3df22a 100644 --- a/sdk/foobar2000/SDK/advconfig_impl.h +++ b/sdk/foobar2000/SDK/advconfig_impl.h @@ -138,6 +138,7 @@ class advconfig_string_factory : public service_factory_single_t(p_name, fb2k::advconfig_autoName(p_guid), p_guid, p_parent, p_priority, p_initialstate, p_prefFlags) {} void get(pfc::string_base& out) { get_static_instance().get_state(out); } + pfc::string8 get() { pfc::string8 temp; get(temp); return temp; } void set(const char* in) { get_static_instance().set_state(in); } }; diff --git a/sdk/foobar2000/SDK/app_close_blocker.cpp b/sdk/foobar2000/SDK/app_close_blocker.cpp index 03c5bd3..a380a94 100644 --- a/sdk/foobar2000/SDK/app_close_blocker.cpp +++ b/sdk/foobar2000/SDK/app_close_blocker.cpp @@ -34,3 +34,7 @@ void fb2k::splitTask( pfc::thread::arg_t const & arg, std::function f) (void)taskref; // retain until here } ); } + +abort_callback& fb2k::mainAborter() { + return async_task_manager::get()->get_aborter(); +} \ No newline at end of file diff --git a/sdk/foobar2000/SDK/audio_chunk.cpp b/sdk/foobar2000/SDK/audio_chunk.cpp index d40bca2..fe48839 100644 --- a/sdk/foobar2000/SDK/audio_chunk.cpp +++ b/sdk/foobar2000/SDK/audio_chunk.cpp @@ -2,17 +2,25 @@ #include "mem_block_container.h" #include "audio_chunk.h" -void audio_chunk::set_data(const audio_sample * src,t_size samples,unsigned nch,unsigned srate,unsigned channel_config) -{ - t_size size = samples * nch; +void audio_chunk::set_data(const audio_sample* src, size_t samples, spec_t const & spec) { + t_size size = samples * spec.chanCount; set_data_size(size); if (src) - pfc::memcpy_t(get_data(),src,size); + pfc::memcpy_t(get_data(), src, size); else - pfc::memset_t(get_data(),(audio_sample)0,size); + pfc::memset_t(get_data(), (audio_sample)0, size); set_sample_count(samples); - set_channels(nch,channel_config); - set_srate(srate); + set_spec(spec); +} + +void audio_chunk::set_data(const audio_sample* src, size_t samples, unsigned nch, unsigned srate, unsigned channel_config) +{ + set_data(src, samples, makeSpec(srate, nch, channel_config)); +} + +void audio_chunk::set_data(const audio_sample* src, size_t samples, unsigned nch, unsigned srate) { + + set_data(src, samples, makeSpec(srate, nch)); } inline bool check_exclusive(unsigned val, unsigned mask) @@ -280,25 +288,27 @@ static void process_float_multi_swap(audio_sample * p_out,const t_float * p_in,c } } -void audio_chunk::set_data_32(const float* src, t_size samples, unsigned nch, unsigned srate) { +void audio_chunk::set_data_32(const float* src, size_t samples, spec_t const& spec) { #if audio_sample_size == 32 - set_data(src, samples, nch, srate); + set_data(src, samples, spec); #else - t_size size = samples * nch; + t_size size = samples * spec.chanCount; set_data_size(size); if (src) audio_math::convert(src, get_data(), size); else pfc::memset_t(get_data(), (audio_sample)0, size); set_sample_count(samples); - set_channels(nch); - set_srate(srate); + set_spec(spec); #endif } +void audio_chunk::set_data_32(const float* src, size_t samples, unsigned nch, unsigned srate) { + set_data_32(src, samples, makeSpec(srate, nch) ); +} void audio_chunk::set_data_floatingpoint_ex(const void * ptr,t_size size,unsigned srate,unsigned nch,unsigned bps,unsigned flags,unsigned p_channel_config) { - PFC_ASSERT(bps==32 || bps==64 || bps == 16 || bps == 24); + PFC_ASSERT(bps==32 || bps==64); PFC_ASSERT( check_exclusive(flags,FLAG_LITTLE_ENDIAN|FLAG_BIG_ENDIAN) ); PFC_ASSERT( ! (flags & (FLAG_SIGNED|FLAG_UNSIGNED) ) ); @@ -321,20 +331,6 @@ void audio_chunk::set_data_floatingpoint_ex(const void * ptr,t_size size,unsigne process_float_multi_swap(out,reinterpret_cast(ptr),count); else process_float_multi(out,reinterpret_cast(ptr),count); - } else if (bps == 16) { - const uint16_t * in = reinterpret_cast(ptr); - if (use_swap) { - for(size_t walk = 0; walk < count; ++walk) out[walk] = audio_math::decodeFloat16(pfc::byteswap_t(in[walk])); - } else { - for(size_t walk = 0; walk < count; ++walk) out[walk] = audio_math::decodeFloat16(in[walk]); - } - } else if (bps == 24) { - const uint8_t * in = reinterpret_cast(ptr); - if (use_swap) { - for(size_t walk = 0; walk < count; ++walk) out[walk] = audio_math::decodeFloat24ptrbs(&in[walk*3]); - } else { - for(size_t walk = 0; walk < count; ++walk) out[walk] = audio_math::decodeFloat24ptr(&in[walk*3]); - } } else pfc::throw_exception_with_message< exception_io_data >("invalid bit depth"); set_sample_count(count/nch); @@ -604,6 +600,7 @@ audio_chunk::spec_t audio_chunk::makeSpec(uint32_t rate, uint32_t channels) { } audio_chunk::spec_t audio_chunk::makeSpec(uint32_t rate, uint32_t channels, uint32_t mask) { + PFC_ASSERT(mask == 0 || pfc::countBits32(mask) == channels); spec_t spec = {}; spec.sampleRate = rate; spec.chanCount = channels; spec.chanMask = mask; return spec; diff --git a/sdk/foobar2000/SDK/audio_chunk.h b/sdk/foobar2000/SDK/audio_chunk.h index cded076..0cfab4f 100644 --- a/sdk/foobar2000/SDK/audio_chunk.h +++ b/sdk/foobar2000/SDK/audio_chunk.h @@ -12,6 +12,7 @@ PFC_DECLARE_EXCEPTION(exception_unexpected_audio_format_change, exception_io_dat //! Interface to container of a chunk of audio data. See audio_chunk_impl for an implementation. class NOVTABLE audio_chunk { public: + struct spec_t; // forward decl enum { sample_rate_min = 1000, sample_rate_max = 20000000 @@ -42,6 +43,7 @@ class NOVTABLE audio_chunk { channel_config_mono = channel_front_center, channel_config_stereo = channel_front_left | channel_front_right, + channel_config_2point1 = channel_front_left | channel_front_right | channel_lfe, channel_config_3point0 = channel_front_left | channel_front_right | channel_front_center, channel_config_4point0 = channel_front_left | channel_front_right | channel_back_left | channel_back_right, channel_config_4point1 = channel_front_left | channel_front_right | channel_back_left | channel_back_right | channel_lfe, @@ -78,6 +80,7 @@ class NOVTABLE audio_chunk { static unsigned g_find_channel_idx(unsigned p_flag); static void g_formatChannelMaskDesc(unsigned flags, pfc::string_base & out); static pfc::string8 g_formatChannelMaskDesc(unsigned flags); + static const char* g_channelMaskName(unsigned flags); @@ -169,10 +172,9 @@ class NOVTABLE audio_chunk { } //! Helper, sets chunk data to contents of specified buffer, with specified number of channels / sample rate / channel map. - void set_data(const audio_sample * src,t_size samples,unsigned nch,unsigned srate,unsigned channel_config); - - //! Helper, sets chunk data to contents of specified buffer, with specified number of channels / sample rate, using default channel map for specified channel count. - inline void set_data(const audio_sample * src,t_size samples,unsigned nch,unsigned srate) {set_data(src,samples,nch,srate,g_guess_channel_config(nch));} + void set_data(const audio_sample * src,size_t samples,unsigned nch,unsigned srate,unsigned channel_config); + void set_data(const audio_sample* src, size_t samples, spec_t const& spec); + void set_data(const audio_sample* src, t_size samples, unsigned nch, unsigned srate); void set_data_int16(const int16_t * src,t_size samples,unsigned nch,unsigned srate,unsigned channel_config); @@ -200,8 +202,10 @@ class NOVTABLE audio_chunk { void set_data_fixedpoint_ms(const void * ptr, size_t bytes, unsigned sampleRate, unsigned channels, unsigned bps, unsigned channelConfig); void set_data_floatingpoint_ex(const void * ptr,t_size bytes,unsigned p_sample_rate,unsigned p_channels,unsigned p_bits_per_sample,unsigned p_flags,unsigned p_channel_config);//signed/unsigned flags dont apply + static bool is_supported_floatingpoint(unsigned bps) { return bps == 32 || bps == 64; } void set_data_32(const float* src, t_size samples, unsigned nch, unsigned srate); + void set_data_32(const float* src, t_size samples, spec_t const & spec ); //! Appends silent samples at the end of the chunk. \n //! The chunk may be empty prior to this call, its sample rate & channel count will be set to the specified values then. \n diff --git a/sdk/foobar2000/SDK/audio_chunk_channel_config.cpp b/sdk/foobar2000/SDK/audio_chunk_channel_config.cpp index 4c2f399..9cf83e2 100644 --- a/sdk/foobar2000/SDK/audio_chunk_channel_config.cpp +++ b/sdk/foobar2000/SDK/audio_chunk_channel_config.cpp @@ -80,7 +80,7 @@ unsigned audio_chunk::g_channel_config_from_wfx(uint32_t p_wfx) } -static const unsigned g_audio_channel_config_table[] = +static constexpr unsigned g_audio_channel_config_table[] = { 0, audio_chunk::channel_config_mono, @@ -218,4 +218,34 @@ void audio_chunk::g_formatChannelMaskDesc(unsigned flags, pfc::string_base & out flags >>= 1; ++idx; } +} + +namespace { + struct maskDesc_t { + const char* name; + unsigned mask; + }; + static constexpr maskDesc_t maskDesc[] = { + {"mono", audio_chunk::channel_config_mono}, + {"stereo", audio_chunk::channel_config_stereo}, + {"stereo (rear)", audio_chunk::channel_back_left | audio_chunk::channel_back_right}, + {"stereo (side)", audio_chunk::channel_side_left | audio_chunk::channel_side_right}, + {"2.1", audio_chunk::channel_config_2point1}, + {"3.0", audio_chunk::channel_config_3point0}, + {"4.0", audio_chunk::channel_config_4point0}, + {"4.1", audio_chunk::channel_config_4point1}, + {"5.0", audio_chunk::channel_config_5point0}, + {"5.1", audio_chunk::channel_config_5point1}, + {"5.1 (side)", audio_chunk::channel_config_5point1_side}, + {"6.1", audio_chunk::channel_config_5point1 | audio_chunk::channel_back_center}, + {"6.1 (side)", audio_chunk::channel_config_5point1_side | audio_chunk::channel_back_center}, + {"7.1", audio_chunk::channel_config_7point1}, + }; +} + +const char* audio_chunk::g_channelMaskName(unsigned flags) { + for (auto& walk : maskDesc) { + if (flags == walk.mask) return walk.name; + } + return nullptr; } \ No newline at end of file diff --git a/sdk/foobar2000/SDK/callback_merit.h b/sdk/foobar2000/SDK/callback_merit.h new file mode 100644 index 0000000..ee65142 --- /dev/null +++ b/sdk/foobar2000/SDK/callback_merit.h @@ -0,0 +1,24 @@ +#pragma once + +namespace fb2k { + // callback_merit_t controls in what order callbacks are executed. \n + // In specific corner cases, you want your callback executed before other callbacks of the same kind. + typedef double callback_merit_t; + + // Note REVERSE sort. HIGHER merit called first. + static constexpr callback_merit_t callback_merit_default = 0; + static constexpr callback_merit_t callback_merit_indexer = 1000; // indexer: does nothing else than updating internal state, called early before UI updates, in case UI updates might rely on indexed data. + static constexpr callback_merit_t callback_merit_serializer = 2000; // serializer: does nothing else than saving new state, called early. + + //! Special class that can be optionally implemented by 'static' callbacks, such as library_callback, to control callback merit. \n + //! See also: callback_merit_t \n + //! Some callback classes support get_callback_merit() natively, such as metadb_io_callback_v2. \n + //! With callbacks registered dynamically, other means of controlling merit are provided. + class callback_with_merit : public service_base { + FB2K_MAKE_SERVICE_INTERFACE(callback_with_merit, service_base); + public: + virtual callback_merit_t get_callback_merit() = 0; + }; + + callback_merit_t callback_merit_of(service_ptr obj); +} \ No newline at end of file diff --git a/sdk/foobar2000/SDK/contextmenu.h b/sdk/foobar2000/SDK/contextmenu.h index 563da75..fef570c 100644 --- a/sdk/foobar2000/SDK/contextmenu.h +++ b/sdk/foobar2000/SDK/contextmenu.h @@ -1,5 +1,6 @@ #pragma once #include "metadb_handle.h" +#include //! Reserved for future use. typedef void * t_glyph; @@ -340,3 +341,31 @@ class contextmenu_group_popup_factory : public service_factory_single_t(guid, parent, name, sortPriority) {} }; + + + +class contextmenu_item_lambda : public contextmenu_item_simple { +public: + typedef std::function func_t; + contextmenu_item_lambda(func_t f, const char* n, const GUID& g, const GUID& pg, const char* d = nullptr, double sp = 0) : m_func(f), m_name(n), m_guid(g), m_parentGuid(pg), m_desc(d), m_sortPriority(sp) {} + + unsigned get_num_items() override { return 1; } + void get_item_name(unsigned p_index, pfc::string_base& p_out) override { p_out = m_name; } + void context_command(unsigned p_index, metadb_handle_list_cref p_data, const GUID& p_caller) override { m_func(p_data); } + GUID get_item_guid(unsigned p_index) override { return m_guid; } + bool get_item_description(unsigned p_index, pfc::string_base& p_out) override { + if (m_desc == nullptr) return false; + p_out = m_desc; + return true; + } + double get_sort_priority() override { return 0; } + GUID get_parent() override { return m_parentGuid; } +private: + const std::function m_func; + const char* const m_name; + const GUID m_guid, m_parentGuid; + const char* const m_desc; + const double m_sortPriority; +}; + +#define FB2K_DECLARE_CONTEXT_MENU_ITEM(func, name, guid, parent, desc, sort) FB2K_SERVICE_FACTORY_PARAMS(contextmenu_item_lambda, func, name, guid, parent, desc, sort) diff --git a/sdk/foobar2000/SDK/core_api.h b/sdk/foobar2000/SDK/core_api.h index afb42ff..071bd8f 100644 --- a/sdk/foobar2000/SDK/core_api.h +++ b/sdk/foobar2000/SDK/core_api.h @@ -39,10 +39,13 @@ namespace core_api { bool is_quiet_mode_enabled(); }; +#define FB2K_SUPPORT_LOW_MEM_MODE (SIZE_MAX <= UINT32_MAX) + namespace fb2k { -#ifdef _WIN32 - inline bool isDebugModeActive() { return !! PFC_DEBUG ;} -#else bool isDebugModeActive(); +#if FB2K_SUPPORT_LOW_MEM_MODE + bool isLowMemModeActive(); +#else + inline constexpr bool isLowMemModeActive() { return false; } #endif } diff --git a/sdk/foobar2000/SDK/file_info.cpp b/sdk/foobar2000/SDK/file_info.cpp index 11179f0..595e6b0 100644 --- a/sdk/foobar2000/SDK/file_info.cpp +++ b/sdk/foobar2000/SDK/file_info.cpp @@ -11,28 +11,25 @@ static constexpr char info_WAVEFORMATEXTENSIBLE_CHANNEL_MASK[] = "WAVEFORMATEXTENSIBLE_CHANNEL_MASK"; -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(); for(n=0;n= max) return 0; return meta_enum_value(index,p_index); } const char * file_info::info_get_ex(const char * p_name,t_size p_name_length) const { - t_size index = info_find_ex(p_name,p_name_length); - if (index == pfc_infinite) return 0; + auto index = info_find_ex(p_name,p_name_length); + if (index == SIZE_MAX) return 0; return info_enum_value(index); } @@ -311,19 +308,19 @@ void file_info::reset_replaygain() void file_info::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) { t_size n, m = p_source.meta_enum_value_count(p_index); - t_size new_index = pfc_infinite; + t_size new_index = SIZE_MAX; for(n=0;nmeta_add( tempName, tempValue ); + if (metaIndex == SIZE_MAX) metaIndex = this->meta_add( tempName, tempValue ); else this->meta_add_value( metaIndex, tempValue ); } } @@ -801,11 +798,11 @@ void file_info::from_mem( const void * memPtr, size_t memSize ) { for(;;) { const char * metaName = _readString( walk, remaining ); if (*metaName == 0) break; - size_t metaIndex = pfc_infinite; + size_t metaIndex = SIZE_MAX; for(;;) { const char * metaValue = _readString( walk, remaining ); if (*metaValue == 0) break; - if (metaIndex == pfc_infinite) metaIndex = this->meta_add( metaName, metaValue ); + if (metaIndex == SIZE_MAX) metaIndex = this->meta_add( metaName, metaValue ); else this->meta_add_value( metaIndex, metaName ); } } @@ -870,4 +867,16 @@ bool file_info::unicode_normalize_C() { } } return changed; +} + +void file_info::meta_enumerate(meta_enumerate_t cb) const { + const size_t nMeta = this->meta_get_count(); + for (size_t metaWalk = 0; metaWalk < nMeta; ++metaWalk) { + const char* name = this->meta_enum_name(metaWalk); + const size_t nValue = this->meta_enum_value_count(metaWalk); + for (size_t valueWalk = 0; valueWalk < nValue; ++valueWalk) { + const char* value = this->meta_enum_value(metaWalk, valueWalk); + cb(name, value); + } + } } \ No newline at end of file diff --git a/sdk/foobar2000/SDK/file_info.h b/sdk/foobar2000/SDK/file_info.h index 67a08a9..19903d9 100644 --- a/sdk/foobar2000/SDK/file_info.h +++ b/sdk/foobar2000/SDK/file_info.h @@ -1,16 +1,18 @@ #pragma once #include "audio_chunk.h" +#include //! Structure containing ReplayGain scan results from some playable object, also providing various helper methods to manipulate those results. struct replaygain_info { - float m_album_gain,m_track_gain; - float m_album_peak,m_track_peak; + static constexpr float peak_invalid = -1, gain_invalid = -1000; + + float m_album_gain = gain_invalid, m_track_gain = gain_invalid; + float m_album_peak = peak_invalid, m_track_peak = peak_invalid; enum {text_buffer_size = 16 }; typedef char t_text_buffer[text_buffer_size]; - static const float peak_invalid, gain_invalid; 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]); @@ -156,6 +158,8 @@ class NOVTABLE file_info { bool meta_format(const char * p_name,pfc::string_base & p_out, const char * separator = ", ") const; void meta_format_entry(t_size index, pfc::string_base & p_out, const char * separator = ", ") const;//same as meta_format but takes index instead of meta name. + typedef std::function meta_enumerate_t; + void meta_enumerate(meta_enumerate_t) const; bool info_exists_ex(const char * p_name,t_size p_name_length) const; void info_remove_index(t_size p_index); @@ -163,15 +167,15 @@ class NOVTABLE file_info { 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 t_size meta_find(const char* p_name) const { PFC_ASSERT(p_name != nullptr); return meta_find_ex(p_name, SIZE_MAX); } + inline bool meta_exists(const char* p_name) const { PFC_ASSERT(p_name != nullptr); return meta_exists_ex(p_name, SIZE_MAX); } + inline void meta_remove_field(const char* p_name) { PFC_ASSERT(p_name != nullptr); meta_remove_field_ex(p_name, SIZE_MAX); } + inline t_size meta_set(const char* p_name, const char* p_value) { PFC_ASSERT(p_name != nullptr && p_value != nullptr); 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 const char* meta_get(const char* p_name, t_size p_index) const { PFC_ASSERT(p_name != nullptr); return meta_get_ex(p_name, SIZE_MAX, p_index); } + inline t_size meta_get_count_by_name(const char* p_name) const { PFC_ASSERT(p_name != nullptr); return meta_get_count_by_name_ex(p_name, SIZE_MAX); } + inline t_size meta_add(const char* p_name, const char* p_value) { PFC_ASSERT(p_name != nullptr && p_value != nullptr); 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);} diff --git a/sdk/foobar2000/SDK/file_info_impl.cpp b/sdk/foobar2000/SDK/file_info_impl.cpp index 430803e..2ebbffd 100644 --- a/sdk/foobar2000/SDK/file_info_impl.cpp +++ b/sdk/foobar2000/SDK/file_info_impl.cpp @@ -91,12 +91,12 @@ void file_info_impl::info_remove_mask(const bit_array & p_mask) } -file_info_impl::file_info_impl(const file_info & p_source) : m_length(0) +file_info_impl::file_info_impl(const file_info & p_source) { copy(p_source); } -file_info_impl::file_info_impl(const file_info_impl & p_source) : m_length(0) +file_info_impl::file_info_impl(const file_info_impl & p_source) { copy(p_source); } @@ -107,10 +107,7 @@ const file_info_impl & file_info_impl::operator=(const file_info_impl & p_source return *this; } -file_info_impl::file_info_impl() : m_length(0) -{ - m_replaygain.reset(); -} +file_info_impl::file_info_impl() {} double file_info_impl::get_length() const { @@ -156,11 +153,19 @@ void file_info_impl_utils::info_storage::remove_mask(const bit_array & p_mask) { } +size_t file_info_impl_utils::meta_storage::add_blank(const char* name) { + meta_entry e; + e.m_name = name; + const auto ret = m_data.size(); + m_data.add_item(std::move(e)); + return ret; +} t_size file_info_impl_utils::meta_storage::add_entry(const char * p_name,t_size p_name_length,const char * p_value,t_size p_value_length) { - meta_entry temp(p_name,p_name_length,p_value,p_value_length); - return pfc::append_swap_t(m_data,temp); + const auto ret = m_data.size(); + m_data.add_item(meta_entry(p_name, p_name_length, p_value, p_value_length)); + return ret; } void file_info_impl_utils::meta_storage::insert_value(t_size p_index,t_size p_value_index,const char * p_value,t_size p_value_length) diff --git a/sdk/foobar2000/SDK/file_info_impl.h b/sdk/foobar2000/SDK/file_info_impl.h index ed6fad6..0f10f24 100644 --- a/sdk/foobar2000/SDK/file_info_impl.h +++ b/sdk/foobar2000/SDK/file_info_impl.h @@ -71,6 +71,7 @@ namespace file_info_impl_utils { class meta_storage { public: + size_t add_blank(const char* name); t_size add_entry(const char * p_name,t_size p_name_length,const char * p_value,t_size p_value_length); void insert_value(t_size p_index,t_size p_value_index,const char * p_value,t_size p_value_length); void modify_value(t_size p_index,t_size p_value_index,const char * p_value,t_size p_value_length); @@ -131,14 +132,12 @@ class file_info_impl : public file_info protected: t_size meta_set_nocheck_ex(const char * p_name,t_size p_name_length,const char * p_value,t_size p_value_length); t_size info_set_nocheck_ex(const char * p_name,t_size p_name_length,const char * p_value,t_size p_value_length); -private: - file_info_impl_utils::meta_storage m_meta; file_info_impl_utils::info_storage m_info; - double m_length; + double m_length = 0; replaygain_info m_replaygain; }; diff --git a/sdk/foobar2000/SDK/filesystem.cpp b/sdk/foobar2000/SDK/filesystem.cpp index 9736cdc..6ccdd11 100644 --- a/sdk/foobar2000/SDK/filesystem.cpp +++ b/sdk/foobar2000/SDK/filesystem.cpp @@ -965,6 +965,10 @@ PFC_NORETURN void foobar2000_io::exception_io_from_win32(DWORD p_code) { case ERROR_INVALID_FUNCTION: // Happens when trying to link files on FAT32 etc throw exception_io_unsupported_feature(); +#if 0 + case ERROR_BAD_LENGTH: + FB2K_BugCheckEx("ERROR_BAD_LENGTH"); +#endif default: throw exception_io_win32_ex(p_code); } diff --git a/sdk/foobar2000/SDK/foobar2000-versions.h b/sdk/foobar2000/SDK/foobar2000-versions.h index 2e0bca5..e3c007d 100644 --- a/sdk/foobar2000/SDK/foobar2000-versions.h +++ b/sdk/foobar2000/SDK/foobar2000-versions.h @@ -19,4 +19,4 @@ // Use this to determine what foobar2000 SDK version is in use, undefined for releases older than 2018 -#define FOOBAR2000_SDK_VERSION 20221116 \ No newline at end of file +#define FOOBAR2000_SDK_VERSION 20230118 \ No newline at end of file diff --git a/sdk/foobar2000/SDK/foobar2000_SDK.vcxproj b/sdk/foobar2000/SDK/foobar2000_SDK.vcxproj index 3f8a9d1..3a00c5c 100644 --- a/sdk/foobar2000/SDK/foobar2000_SDK.vcxproj +++ b/sdk/foobar2000/SDK/foobar2000_SDK.vcxproj @@ -354,6 +354,7 @@ + diff --git a/sdk/foobar2000/SDK/foobar2000_SDK.vcxproj.filters b/sdk/foobar2000/SDK/foobar2000_SDK.vcxproj.filters index 73c200e..4121b97 100644 --- a/sdk/foobar2000/SDK/foobar2000_SDK.vcxproj.filters +++ b/sdk/foobar2000/SDK/foobar2000_SDK.vcxproj.filters @@ -401,6 +401,9 @@ Header Files + + Header Files + diff --git a/sdk/foobar2000/SDK/guids.cpp b/sdk/foobar2000/SDK/guids.cpp index 37e5ba7..6fa27b2 100644 --- a/sdk/foobar2000/SDK/guids.cpp +++ b/sdk/foobar2000/SDK/guids.cpp @@ -1112,6 +1112,7 @@ 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_vis = { 0xea1017c6, 0x298, 0x446c, { 0xb6, 0xc7, 0xbd, 0xf9, 0x1e, 0xd8, 0x12, 0xee } }; +FOOGUIDDECL const GUID advconfig_entry::guid_branch_general = { 0x534dc6e3, 0x29a2, 0x42f4, { 0xab, 0x49, 0x5a, 0x2, 0x71, 0x9b, 0x1d, 0xa } }; 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 } }; FOOGUIDDECL const GUID advconfig_entry::guid_branch_converter = { 0x96ea6eae, 0xe848, 0x44d9, { 0x99, 0xd6, 0x4d, 0xa6, 0xeb, 0x39, 0x81, 0x8f } }; @@ -1316,6 +1317,7 @@ FOOGUIDDECL const GUID component_installation_validator::class_guid = { 0x639283 #endif FOOGUIDDECL const GUID playback_stream_capture::class_guid = { 0x9423439e, 0x8cd5, 0x45d7, { 0xaa, 0x6d, 0x4b, 0x98, 0xc, 0x22, 0x93, 0x3e } }; +FOOGUIDDECL const GUID playback_stream_capture_v2::class_guid = { 0x801e6865, 0x6040, 0x42a6, { 0x8c, 0x43, 0x57, 0x91, 0x8a, 0xdc, 0xee, 0xb7 } }; 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 } }; @@ -1331,6 +1333,7 @@ FOOGUIDDECL const GUID metadb_index_transaction::class_guid = { 0xe4b7e77e, 0xbe FOOGUIDDECL const GUID init_stage_callback::class_guid = { 0xaf51c159, 0x6326, 0x4da5, { 0x90, 0xb0, 0xf1, 0x1f, 0x99, 0x64, 0xcc, 0x2e } }; FOOGUIDDECL const GUID metadb_io_edit_callback::class_guid = { 0x2388a50f, 0x33d, 0x4b7c, { 0x91, 0xf2, 0x51, 0x53, 0x69, 0x43, 0xe9, 0xed } }; +FOOGUIDDECL const GUID metadb_io_edit_callback_v2::class_guid = { 0x8a4ac70, 0xaf77, 0x4a73, { 0xa6, 0xe9, 0xd5, 0xbc, 0x6, 0x9e, 0x6, 0x15 } }; FOOGUIDDECL const GUID progress_meter_instance::class_guid = { 0x13915b24, 0xefef, 0x42b5, { 0xae, 0x1d, 0x55, 0x24, 0x5e, 0x22, 0x22, 0xc5 } }; FOOGUIDDECL const GUID progress_meter::class_guid = { 0x5e98da34, 0xa9c7, 0x4925, { 0xb0, 0xec, 0x90, 0x9d, 0xe0, 0x16, 0xfa, 0x68 } }; @@ -1494,3 +1497,12 @@ FOOGUIDDECL const GUID contextmenu_manager_v2::class_guid = { 0x8e56ee90, 0x37fb FOOGUIDDECL const GUID fb2k::console_manager::class_guid = { 0x39c3406b, 0xe2f, 0x43f3, { 0x87, 0xf2, 0xa6, 0xa3, 0x79, 0x2a, 0x98, 0x8 } }; FOOGUIDDECL const GUID fb2k::toolbarDropDown::class_guid = { 0x59aabce2, 0xce9f, 0x428b, { 0x8f, 0x10, 0xe, 0x24, 0xf3, 0xb6, 0xc7, 0x6d } }; + +FOOGUIDDECL const GUID search_index_manager::class_guid = { 0x281b998c, 0xb379, 0x4533, { 0x95, 0xe0, 0x90, 0xa2, 0x89, 0x30, 0x2a, 0x4a } }; +FOOGUIDDECL const GUID search_index::class_guid = { 0x581f032e, 0x8e4c, 0x4a46, { 0xbb, 0xa4, 0xef, 0xc, 0xc6, 0x5c, 0x98, 0xfa } }; + + +FOOGUIDDECL const GUID fb2k::callback_with_merit::class_guid = { 0x27c64500, 0x5481, 0x477a, { 0x9b, 0x22, 0x5d, 0x4c, 0x4d, 0xa6, 0x2, 0x88 } }; +FOOGUIDDECL const GUID playlist_manager_v6::class_guid = { 0x8fd46228, 0x9ba3, 0x4bb1, { 0xa0, 0x9c, 0xe8, 0x5b, 0x9e, 0x45, 0x8a, 0x58 } }; +FOOGUIDDECL const GUID library_manager_v6::class_guid = { 0x92eea180, 0x93d0, 0x44ef, { 0xbc, 0x43, 0xb6, 0x88, 0xae, 0x41, 0xb7, 0xad } }; +FOOGUIDDECL const GUID play_callback_manager_v2::class_guid = { 0x7e59a4e6, 0x810d, 0x433b, { 0xb6, 0x9, 0x12, 0xf4, 0xde, 0x7f, 0x7f, 0x47 } }; diff --git a/sdk/foobar2000/SDK/initquit.h b/sdk/foobar2000/SDK/initquit.h index bc34b1f..411f63a 100644 --- a/sdk/foobar2000/SDK/initquit.h +++ b/sdk/foobar2000/SDK/initquit.h @@ -38,3 +38,41 @@ class NOVTABLE init_stage_callback : public service_base { static void dispatch(t_uint32 stage) {FB2K_FOR_EACH_SERVICE(init_stage_callback, on_init_stage(stage));} }; + +//! Helper for FB2K_RUN_ON_INIT_QUIT() +class initquit_lambda : public initquit { +public: + initquit_lambda(std::function i, std::function q) : m_init(i), m_quit(q) {} + void on_init() override { if (m_init) m_init(); } + void on_quit() override { if (m_quit) m_quit(); } +private: + const std::function m_init, m_quit; +}; + +//! Helper macros to skip implementing initquit.\n +//! Usage: \n +//! void myfunc() { ... } \n +//! FB2K_RUN_ON_INIT(myFunc); +#define FB2K_RUN_ON_INIT_QUIT(funcInit, funcQuit) FB2K_SERVICE_FACTORY_PARAMS(initquit_lambda, funcInit, funcQuit) +#define FB2K_RUN_ON_INIT(func) FB2K_RUN_ON_INIT_QUIT(func, nullptr) +#define FB2K_RUN_ON_QUIT(func) FB2K_RUN_ON_INIT_QUIT(nullptr, func) + +//! Helper for FB2K_ON_INIT_STAGE +class init_stage_callback_lambda : public init_stage_callback { +public: + init_stage_callback_lambda(std::function f, uint32_t stage) : m_func(f), m_stage(stage) {} + + void on_init_stage(t_uint32 stage) override { + PFC_ASSERT(m_func != nullptr); + if (stage == m_stage) m_func(); + } + + const std::function m_func; + const uint32_t m_stage; +}; + +//! Helper macro to skip implementing init_stage_callback.\n +//! Usage: \n +//! void myfunc() {...} \n +//! FB2K_ON_INIT_STAGE(myfunc, init_stages::after_ui_init); +#define FB2K_ON_INIT_STAGE(func, stage) FB2K_SERVICE_FACTORY_PARAMS(init_stage_callback_lambda, func, stage) diff --git a/sdk/foobar2000/SDK/library_callbacks.h b/sdk/foobar2000/SDK/library_callbacks.h index a36c32b..da455b3 100644 --- a/sdk/foobar2000/SDK/library_callbacks.h +++ b/sdk/foobar2000/SDK/library_callbacks.h @@ -1,6 +1,7 @@ #pragma once #include "library_manager.h" #include "metadb_callbacks.h" +#include "callback_merit.h" //! Callback service receiving notifications about Media Library content changes. Methods called only from main thread.\n //! Use library_callback_factory_t template to register. @@ -30,7 +31,6 @@ class NOVTABLE library_callback_v2 : public library_callback { FB2K_MAKE_SERVICE_INTERFACE(library_callback_v2, library_callback); }; - template class library_callback_factory_t : public service_factory_single_t {}; @@ -88,6 +88,7 @@ class library_callback_v2_dynamic_impl_base : public library_callback_v2_dynamic void on_items_added(metadb_handle_list_cref) override {} void on_items_removed(metadb_handle_list_cref) override {} void on_items_modified_v2(metadb_handle_list_cref, metadb_io_callback_v2_data&) override {} + void on_library_initialized() override {} PFC_CLASS_NOT_COPYABLE_EX(library_callback_v2_dynamic_impl_base); }; diff --git a/sdk/foobar2000/SDK/library_index.h b/sdk/foobar2000/SDK/library_index.h index 52067e9..db415a9 100644 --- a/sdk/foobar2000/SDK/library_index.h +++ b/sdk/foobar2000/SDK/library_index.h @@ -20,5 +20,6 @@ class NOVTABLE library_index : public service_base { }; //! @returns list of metadb_handles. Safe to use arr->as_list_of() to get a pfc::list_base_const_t + //! @param flags Optional; set flag_sort to sort output. virtual fb2k::arrayRef search(search_filter::ptr pattern, uint32_t flags, abort_callback& abort) = 0; }; \ No newline at end of file diff --git a/sdk/foobar2000/SDK/library_manager.h b/sdk/foobar2000/SDK/library_manager.h index ba8b93c..94b3b4b 100644 --- a/sdk/foobar2000/SDK/library_manager.h +++ b/sdk/foobar2000/SDK/library_manager.h @@ -1,4 +1,5 @@ #pragma once +#include "callback_merit.h" class library_callback_dynamic; class library_callback_v2_dynamic; @@ -115,6 +116,15 @@ class NOVTABLE library_manager_v5 : public library_manager_v4 { //! Extensible status query method. Returns 0 for unrecognized commands. virtual size_t library_status(const GUID& arg, size_t arg1, void* arg2, size_t arg2bytes) = 0; + + bool is_current_callback_from_hook() { return library_status(status_current_callback_from_hook, 0, nullptr, 0) != 0; } +}; + +//! \since 2.0 beta 18 +class NOVTABLE library_manager_v6 : public library_manager_v5 { + FB2K_MAKE_SERVICE_COREAPI_EXTENSION(library_manager_v6, library_manager_v5); +public: + virtual void set_callback_merit(library_callback_v2_dynamic*, fb2k::callback_merit_t) = 0; }; //! Implement this service to appear on "library viewers" list in Media Library preferences page.\n diff --git a/sdk/foobar2000/SDK/metadb_callbacks.h b/sdk/foobar2000/SDK/metadb_callbacks.h index d14024c..e7bc412 100644 --- a/sdk/foobar2000/SDK/metadb_callbacks.h +++ b/sdk/foobar2000/SDK/metadb_callbacks.h @@ -1,4 +1,5 @@ #pragma once +#include "callback_merit.h" //! Callback service receiving notifications about metadb contents changes. class NOVTABLE metadb_io_callback : public service_base { @@ -42,6 +43,15 @@ class NOVTABLE metadb_io_edit_callback : public service_base { virtual void on_edited(metadb_handle_list_cref items, t_infosref before, t_infosref after) = 0; }; +//! \since 2.0 +class NOVTABLE metadb_io_edit_callback_v2 : public metadb_io_edit_callback { + FB2K_MAKE_SERVICE_INTERFACE(metadb_io_edit_callback_v2, metadb_io_edit_callback) +public: + //! With original on_edited(), the implementation could not tell what the info in metadb was before, 'before' parameter being actual infos freshly read from the file prior to writing. \n + //! on_edited_v2() clarifies this, additional argument passes old metadb state to deal with cases where it was different than file contents. + virtual void on_edited_v2(metadb_handle_list_cref items, t_infosref before, t_infosref after, t_infosref beforeInMetadb) = 0; +}; + //! \since 2.0 //! Parameter for on_changed_sorted_v2() class NOVTABLE metadb_io_callback_v2_data { @@ -55,16 +65,16 @@ class NOVTABLE metadb_io_callback_v2 : public metadb_io_callback { FB2K_MAKE_SERVICE_INTERFACE(metadb_io_callback_v2, metadb_io_callback); public: virtual void on_changed_sorted_v2(metadb_handle_list_cref itemsSorted, metadb_io_callback_v2_data & data, bool bFromHook) = 0; - //! Reserved for future use. - virtual double get_callback_merit() { return 0; } + //! Controls callback merit, see: fb2k::callback_merit_t + virtual fb2k::callback_merit_t get_callback_merit() { return fb2k::callback_merit_default; } }; - +//! \since 2.0 class NOVTABLE metadb_io_callback_v2_dynamic { public: virtual void on_changed_sorted_v2(metadb_handle_list_cref itemsSorted, metadb_io_callback_v2_data & data, bool bFromHook) = 0; - //! Reserved for future use. - virtual double get_callback_merit() { return 0; } + //! Controls callback merit, see: fb2k::callback_merit_t + virtual fb2k::callback_merit_t get_callback_merit() { return fb2k::callback_merit_default; } bool try_register_callback(); void try_unregister_callback(); void register_callback(); void unregister_callback(); diff --git a/sdk/foobar2000/SDK/metadb_handle.h b/sdk/foobar2000/SDK/metadb_handle.h index 45f35d8..ecd0b03 100644 --- a/sdk/foobar2000/SDK/metadb_handle.h +++ b/sdk/foobar2000/SDK/metadb_handle.h @@ -185,6 +185,9 @@ class metadb_handle_v2 : public metadb_handle { virtual void formatTitle_v2(const rec_t& rec, titleformat_hook* p_hook, pfc::string_base& p_out, const service_ptr_t& p_script, titleformat_text_filter* p_filter) = 0; }; +typedef pfc::list_base_t* metadb_handle_list_ptr; +typedef pfc::list_base_const_t const * metadb_handle_list_cptr; + typedef pfc::list_base_t & metadb_handle_list_ref; typedef pfc::list_base_const_t const & metadb_handle_list_cref; diff --git a/sdk/foobar2000/SDK/play_callback.h b/sdk/foobar2000/SDK/play_callback.h index 920bd7b..8f60bbf 100644 --- a/sdk/foobar2000/SDK/play_callback.h +++ b/sdk/foobar2000/SDK/play_callback.h @@ -1,4 +1,6 @@ #pragma once +#include "callback_merit.h" + /*! Class receiving notifications about playback events. Note that all methods are called only from app's main thread. Use play_callback_manager to register your dynamically created instances. Statically registered version is available too - see play_callback_static. @@ -65,6 +67,13 @@ class NOVTABLE play_callback_manager : public service_base { virtual void unregister_callback(play_callback * p_callback) = 0; }; +//! \since 2.0 +class NOVTABLE play_callback_manager_v2 : public play_callback_manager { + FB2K_MAKE_SERVICE_COREAPI_EXTENSION(play_callback_manager_v2, play_callback_manager); +public: + virtual void set_callback_merit(play_callback*, fb2k::callback_merit_t) = 0; +}; + //! Implementation helper. class play_callback_impl_base : public play_callback { public: diff --git a/sdk/foobar2000/SDK/playback_stream_capture.h b/sdk/foobar2000/SDK/playback_stream_capture.h index 4550811..bb147e4 100644 --- a/sdk/foobar2000/SDK/playback_stream_capture.h +++ b/sdk/foobar2000/SDK/playback_stream_capture.h @@ -6,7 +6,8 @@ class NOVTABLE playback_stream_capture_callback { public: //! Delivers a real-time chunk of audio data. \n //! Audio is roughly synchronized with what can currently be heard. This API is provided for utility purposes such as streaming; if you want to implement a visualisation, use the visualisation_manager API instead. \n - //! Called only from the main thread. + //! Contrary to visualisation methods, this guarantees that all played audio data is coming thru. \n + //! Called only from the main thread. \n virtual void on_chunk(const audio_chunk &) = 0; protected: playback_stream_capture_callback() {} @@ -18,8 +19,45 @@ class NOVTABLE playback_stream_capture_callback { class NOVTABLE playback_stream_capture : public service_base { FB2K_MAKE_SERVICE_COREAPI(playback_stream_capture) public: + //! Register a playback_stream_capture_callback. \n //! Possible to call only from the main thread. virtual void add_callback(playback_stream_capture_callback * ) = 0; + //! Un-register a playback_stream_capture_callback. \n //! Possible to call only from the main thread. virtual void remove_callback(playback_stream_capture_callback * ) = 0; }; + +//! \since 2.0. +//! Implemented by core. +class NOVTABLE playback_stream_capture_v2 : public playback_stream_capture { + FB2K_MAKE_SERVICE_COREAPI_EXTENSION(playback_stream_capture_v2, playback_stream_capture); +public: + //! @param requestInterval Interval, in seconds, in which the callback expects to be called. \n + //! Set to -1 to use defaults. \n + //! Note that if many callbacks are registered, they all get called at once; one callback requesting lower interval lowers the interval for all. + virtual void add_callback_v2(playback_stream_capture_callback* cb, double requestInterval = -1) = 0; +}; + +class playback_stream_capture_callback_impl : public playback_stream_capture_callback { +public: + void on_chunk(const audio_chunk&) override {} + + playback_stream_capture_callback_impl(double interval = -1) { + PFC_ASSERT(core_api::is_main_thread()); +#if FOOBAR2020 + playback_stream_capture_v2::get()->add_callback_v2(this, interval); +#else + auto api = playback_stream_capture::get(); + playback_stream_capture_v2::ptr v2; + if (v2 &= api) v2->add_callback_v2(this, interval); + else api->add_callback(this); +#endif + } + ~playback_stream_capture_callback_impl() { + PFC_ASSERT(core_api::is_main_thread()); + playback_stream_capture::get()->remove_callback(this); + } + + playback_stream_capture_callback_impl(const playback_stream_capture_callback_impl&) = delete; + void operator=(const playback_stream_capture_callback_impl&) = delete; +}; diff --git a/sdk/foobar2000/SDK/playlist.h b/sdk/foobar2000/SDK/playlist.h index b3fb186..341ecdb 100644 --- a/sdk/foobar2000/SDK/playlist.h +++ b/sdk/foobar2000/SDK/playlist.h @@ -3,6 +3,7 @@ #include "titleformat.h" #include "playback_control.h" #include +#include "callback_merit.h" //! This interface allows filtering of playlist modification operations.\n //! Implemented by components "locking" playlists; use playlist_manager::playlist_lock_install() etc to takeover specific playlist with your instance of playlist_lock. @@ -538,7 +539,6 @@ class NOVTABLE playlist_manager_v4 : public playlist_manager_v3 { }; //! \since 2.0 -//! Internal, do not use class NOVTABLE playlist_manager_v5 : public playlist_manager_v4 { FB2K_MAKE_SERVICE_COREAPI_EXTENSION(playlist_manager_v5, playlist_manager_v4) public: @@ -546,6 +546,14 @@ class NOVTABLE playlist_manager_v5 : public playlist_manager_v4 { virtual size_t find_playlist_by_guid(const GUID&) = 0; }; +//! \since 2.0 beta 8 +class NOVTABLE playlist_manager_v6 : public playlist_manager_v5 { + FB2K_MAKE_SERVICE_COREAPI_EXTENSION(playlist_manager_v6, playlist_manager_v5); +public: + virtual void set_callback_merit(class playlist_callback*, fb2k::callback_merit_t) = 0; + virtual void set_callback_merit(class playlist_callback_single*, fb2k::callback_merit_t) = 0; + +}; class NOVTABLE playlist_callback { public: diff --git a/sdk/foobar2000/SDK/replaygain_info.cpp b/sdk/foobar2000/SDK/replaygain_info.cpp index eeda9cb..0d2f62c 100644 --- a/sdk/foobar2000/SDK/replaygain_info.cpp +++ b/sdk/foobar2000/SDK/replaygain_info.cpp @@ -51,10 +51,7 @@ bool replaygain_info::g_format_peak(float p_value,char p_buffer[text_buffer_size void replaygain_info::reset() { - m_album_gain = gain_invalid; - m_track_gain = gain_invalid; - m_album_peak = peak_invalid; - m_track_peak = peak_invalid; + *this = replaygain_info(); } #define meta_album_gain "replaygain_album_gain" diff --git a/sdk/foobar2000/SDK/search_tools.h b/sdk/foobar2000/SDK/search_tools.h index 6e2e740..05be2c6 100644 --- a/sdk/foobar2000/SDK/search_tools.h +++ b/sdk/foobar2000/SDK/search_tools.h @@ -97,3 +97,38 @@ class search_filter_manager_v3 : public search_filter_manager_v2 { //! This method INVALIDATES passed objects. Do not try to use them afterwards. virtual search_filter_v4::ptr combine(pfc::list_base_const_t const & arg, combine_t how, completion_notify::ptr changeNotify, t_uint32 flags) = 0; }; + +//! \since 2.0 +class search_index : public service_base { + FB2K_MAKE_SERVICE_INTERFACE(search_index, service_base) +public: + enum { + flag_sort = 1 << 0, + }; + + //! Searches Tracks in this index for tracks matching criteria. + //! @returns list of metadb_handles. Safe to use arr->as_list_of() to get a pfc::list_base_const_t + //! @param subset Optional: pass subset of tracks in this index to search - whole index is searched if nullptr is passed. + //! @param flags Optional: set flag_sort to sort output + virtual fb2k::arrayRef search(search_filter::ptr pattern, metadb_handle_list_cptr subset, uint32_t flags, abort_callback& abort) = 0; + //! Performs hit test on a group of tracks that are a subset of tracks in this index. + virtual void test(search_filter::ptr pattern, metadb_handle_list_cref items, bool* out, abort_callback& abort) = 0; + + + virtual void add_tracks(metadb_handle_list_cref, metadb_io_callback_v2_data* dataIfAvail) = 0; + virtual void remove_tracks(metadb_handle_list_cref) = 0; +}; + +//! \since 2.0 +class search_index_manager : public service_base { + FB2K_MAKE_SERVICE_COREAPI(search_index_manager); +public: + virtual search_index::ptr create_index(metadb_handle_list_cref items, metadb_io_callback_v2_data* dataIfAvail) = 0; + + //! Create a search index referencing a playlist. \n + //! Specify null GUID to follow active playlist (typical playlist search). + virtual search_index::ptr create_playlist_index(const GUID& playlistID = pfc::guid_null) = 0; + + //! Returns a shared object indexing user's media library. + virtual search_index::ptr get_library_index() = 0; +}; \ No newline at end of file diff --git a/sdk/foobar2000/SDK/tag_processor.cpp b/sdk/foobar2000/SDK/tag_processor.cpp index 4e08483..fd780e3 100644 --- a/sdk/foobar2000/SDK/tag_processor.cpp +++ b/sdk/foobar2000/SDK/tag_processor.cpp @@ -166,6 +166,12 @@ void tag_processor::skip_id3v2(const service_ptr_t & p_file,t_filesize & p tag_processor_id3v2::g_skip(p_file,p_size_skipped,p_abort); } +t_filesize tag_processor::skip_id3v2(file::ptr const & f, abort_callback & a) { + t_filesize ret = 0; + skip_id3v2(f, ret, a); + return ret; +} + bool tag_processor::is_id3v1_sufficient(const file_info & p_info) { return tag_processor_trailing::get()->is_id3v1_sufficient(p_info); @@ -174,4 +180,4 @@ bool tag_processor::is_id3v1_sufficient(const file_info & p_info) void tag_processor::truncate_to_id3v1(file_info & p_info) { tag_processor_trailing::get()->truncate_to_id3v1(p_info); -} \ No newline at end of file +} diff --git a/sdk/foobar2000/SDK/tag_processor.h b/sdk/foobar2000/SDK/tag_processor.h index d90a348..58b0409 100644 --- a/sdk/foobar2000/SDK/tag_processor.h +++ b/sdk/foobar2000/SDK/tag_processor.h @@ -98,6 +98,7 @@ namespace tag_processor { void read_id3v2_trailing(const service_ptr_t & p_file,file_info & p_info,abort_callback & p_abort); void skip_id3v2(const service_ptr_t & p_file,t_filesize & p_size_skipped,abort_callback & p_abort); + t_filesize skip_id3v2(file::ptr const & f, abort_callback & a); bool is_id3v1_sufficient(const file_info & p_info); void truncate_to_id3v1(file_info & p_info); diff --git a/sdk/foobar2000/SDK/threadsLite.h b/sdk/foobar2000/SDK/threadsLite.h index 963a5d1..6c8255b 100644 --- a/sdk/foobar2000/SDK/threadsLite.h +++ b/sdk/foobar2000/SDK/threadsLite.h @@ -3,6 +3,7 @@ namespace fb2k { //! pfc::splitThread() + async_task_manager::acquire void splitTask(std::function); void splitTask(pfc::thread::arg_t const&, std::function); + abort_callback& mainAborter(); } diff --git a/sdk/foobar2000/SDK/utility.cpp b/sdk/foobar2000/SDK/utility.cpp index 9562186..2cb0ba3 100644 --- a/sdk/foobar2000/SDK/utility.cpp +++ b/sdk/foobar2000/SDK/utility.cpp @@ -293,3 +293,47 @@ void search_filter_v2::test_multi_here(metadb_handle_list& ref, abort_callback& this->test_multi_ex(ref, mask.get_ptr(), abort); ref.filter_mask(mask.get_ptr()); } + + + +// core_api.h + +namespace fb2k { + bool isDebugModeActive() { +#if PFC_DEBUG + return true; +#else + auto api = fb2k::configStore::tryGet(); + if (api.is_empty()) return false; + return api->getConfigBool("core.debugMode"); +#endif + } + + static bool _isLowMemModeActive() { + auto api = fb2k::configStore::tryGet(); + if (api.is_empty()) return false; + return api->getConfigBool("core.lowMemMode"); + } + +#if FB2K_SUPPORT_LOW_MEM_MODE + bool isLowMemModeActive() { + static bool cached = _isLowMemModeActive(); + return cached; + } +#endif +} + +// callback_merit.h +namespace fb2k { + callback_merit_t callback_merit_of(service_ptr obj) { + { + callback_with_merit::ptr q; + if (q &= obj) return q->get_callback_merit(); + } + { + metadb_io_callback_v2::ptr q; + if (q &= obj) return q->get_callback_merit(); + } + return callback_merit_default; + } +} diff --git a/sdk/foobar2000/helpers/ThreadUtils.h b/sdk/foobar2000/helpers/ThreadUtils.h index eedad77..bb7ea9d 100644 --- a/sdk/foobar2000/helpers/ThreadUtils.h +++ b/sdk/foobar2000/helpers/ThreadUtils.h @@ -19,10 +19,10 @@ namespace ThreadUtils { // Do not use, broken version of MultiWaitAbortable_MsgLoop2 retained for compatibility (returns 1 based index) t_size MultiWaitAbortable_MsgLoop(const HANDLE* ev, t_size evCount, abort_callback& abort); - void SleepAbortable_MsgLoop(abort_callback & abort, DWORD timeout /*must not be INFINITE*/); - bool WaitAbortable_MsgLoop(HANDLE ev, abort_callback & abort, DWORD timeout /*must not be INFINITE*/); + void SleepAbortable_MsgLoop(abort_callback & abort, DWORD timeoutMS); + bool WaitAbortable_MsgLoop(HANDLE ev, abort_callback & abort, DWORD timeoutMS); - DWORD MultiWait_MsgLoop(const HANDLE* ev, DWORD evCount, DWORD timeout); + DWORD MultiWait_MsgLoop(const HANDLE* ev, DWORD evCount, DWORD timeoutMS); DWORD MultiWait_MsgLoop(const HANDLE* ev, DWORD evCount); // Drop-in replacement for pfc::event::g_wait_for() diff --git a/sdk/foobar2000/helpers/callback_merit.h b/sdk/foobar2000/helpers/callback_merit.h new file mode 100644 index 0000000..a0a9685 --- /dev/null +++ b/sdk/foobar2000/helpers/callback_merit.h @@ -0,0 +1,31 @@ +#pragma once +#include +#include +#include + +namespace fb2k { + // Call global callbacks in correct order + // INTENDED FOR CORE USE ONLY + // Not aware of dynamically registered callbacks, if there are such for the same event type + // Usage: for_each_callback_by_merit< metadb_io_edit_callback > ( [] ( metadb_io_edit_callback::ptr ) { ...} ); + template + void for_each_callback_by_merit(std::function)> f) { + struct rec_t { + class_t* obj; // non-autoptr INTENDED, avoid destruction order bugs on shutdown + fb2k::callback_merit_t merit; + }; + auto generator = [] { + std::vector ret; ret.reserve(64); + for (auto ptr : class_t::enumerate()) { + rec_t r; + r.merit = fb2k::callback_merit_of(ptr); + r.obj = ptr.detach(); + ret.push_back( std::move(r) ); + } + std::sort(ret.begin(), ret.end(), [](rec_t const& e1, rec_t const& e2) { return e1.merit > e2.merit; }); + return ret; + }; + static std::vector cache = generator(); + for (auto& walk : cache) f(walk.obj); + } +} diff --git a/sdk/foobar2000/helpers/fb2kWorkerTool.h b/sdk/foobar2000/helpers/fb2kWorkerTool.h index c7ae288..486b669 100644 --- a/sdk/foobar2000/helpers/fb2kWorkerTool.h +++ b/sdk/foobar2000/helpers/fb2kWorkerTool.h @@ -12,7 +12,7 @@ namespace fb2k { }; void operator+=(work_t && work) { - m_workQueue.push_back(std::move(work)); + m_workQueue.push_back( std::make_shared< work_t> ( std::move(work) ) ); kickWork(); } void flush() { @@ -30,7 +30,7 @@ namespace fb2k { } void kickWork() { PFC_ASSERT( core_api::is_main_thread() ); - if (!m_working && m_workQueue.size() > 0) { + if (!m_working && !m_workQueue.empty()) { m_working = true; auto iter = m_workQueue.begin(); auto work = std::move(*iter); m_workQueue.erase(iter); @@ -38,11 +38,13 @@ namespace fb2k { auto a = m_abort; fb2k::inCpuWorkerThread( [ work, pThis, a] { try { - if ( work.work ) work.work(); + // release lambdas early, synchronously from same context as they're executed + { auto f = std::move(work->work); if (f) f(); } a->check(); fb2k::inMainThread( [work, pThis, a] { if ( ! a->is_set() ) { - work.done(); + // release lambdas early, synchronously from same context as they're executed + { auto f = std::move(work->done); if (f) f(); } pThis->workDone(); } }); @@ -61,7 +63,7 @@ namespace fb2k { std::shared_ptr m_abort = std::make_shared(); bool m_working = false; - std::list m_workQueue; + std::list< std::shared_ptr > m_workQueue; }; } diff --git a/sdk/foobar2000/helpers/file_win32_wrapper.cpp b/sdk/foobar2000/helpers/file_win32_wrapper.cpp index 9f65ea9..4a7a640 100644 --- a/sdk/foobar2000/helpers/file_win32_wrapper.cpp +++ b/sdk/foobar2000/helpers/file_win32_wrapper.cpp @@ -6,16 +6,9 @@ namespace file_win32_helpers { t_filesize get_size(HANDLE p_handle) { - union { - t_uint64 val64; - t_uint32 val32[2]; - } u; - - u.val64 = 0; - SetLastError(NO_ERROR); - u.val32[0] = GetFileSize(p_handle,reinterpret_cast(&u.val32[1])); - if (GetLastError()!=NO_ERROR) exception_io_from_win32(GetLastError()); - return u.val64; + LARGE_INTEGER v = {}; + WIN32_IO_OP(GetFileSizeEx(p_handle, &v)); + return make_uint64(v); } void seek(HANDLE p_handle,t_sfilesize p_position,file::t_seek_mode p_mode) { union { @@ -225,6 +218,45 @@ namespace file_win32_helpers { return 0; } + t_filestats2 stats2_from_handle(HANDLE h, const wchar_t * fallbackPath, uint32_t flags, abort_callback& a) { + a.check(); + // Sadly GetFileInformationByHandle() is UNRELIABLE with certain net shares + BY_HANDLE_FILE_INFORMATION info = {}; + if (GetFileInformationByHandle(h, &info)) { + return file_win32_helpers::translate_stats2(info); + } + + a.check(); + t_filestats2 ret; + + // ALWAYS get size, fail if bad handle + ret.m_size = get_size(h); + + if (flags & (stats2_timestamp | stats2_timestampCreate)) { + static_assert(sizeof(t_filetimestamp) == sizeof(FILETIME), "struct sanity"); + FILETIME ftCreate = {}, ftWrite = {}; + if (GetFileTime(h, &ftCreate, nullptr, &ftWrite)) { + ret.m_timestamp = make_uint64(ftWrite); ret.m_timestampCreate = make_uint64(ftCreate); + } + } + if (flags & stats2_flags) { + // No other way to get this from handle? + if (fallbackPath != nullptr && *fallbackPath != 0) { + DWORD attr = GetFileAttributes(fallbackPath); + if (attr != INVALID_FILE_ATTRIBUTES) { + attribs_from_win32(ret, attr); + } + } + } + return ret; + } + void attribs_from_win32(t_filestats2& out, DWORD in) { + out.set_readonly((in & FILE_ATTRIBUTE_READONLY) != 0); + out.set_folder((in & FILE_ATTRIBUTE_DIRECTORY) != 0); + out.set_hidden((in & FILE_ATTRIBUTE_HIDDEN) != 0); + out.set_system((in & FILE_ATTRIBUTE_SYSTEM) != 0); + out.set_remote(false); + } } #endif // _WIN32 diff --git a/sdk/foobar2000/helpers/file_win32_wrapper.h b/sdk/foobar2000/helpers/file_win32_wrapper.h index 27067ca..b199ea5 100644 --- a/sdk/foobar2000/helpers/file_win32_wrapper.h +++ b/sdk/foobar2000/helpers/file_win32_wrapper.h @@ -1,6 +1,7 @@ #pragma once #include +#include #ifdef _WIN32 namespace file_win32_helpers { @@ -17,12 +18,15 @@ namespace file_win32_helpers { size_t lowLevelIO(HANDLE hFile, const GUID & guid, size_t arg1, void * arg2, size_t arg2size, bool canWrite, abort_callback & abort); - static t_uint64 make_uint64(t_uint32 p_low, t_uint32 p_high) { + static uint64_t make_uint64(t_uint32 p_low, t_uint32 p_high) { return ((t_uint64)p_low) + ((t_uint64)p_high << 32); } - - static t_uint64 make_uint64(FILETIME const& ft) { - return make_uint64(ft.dwLowDateTime, ft.dwHighDateTime); + static uint64_t make_uint64(LARGE_INTEGER const& i) { + return reinterpret_cast(i); + } + static uint64_t make_uint64(FILETIME const& ft) { + return reinterpret_cast(ft); +// return make_uint64(ft.dwLowDateTime, ft.dwHighDateTime); } template @@ -33,44 +37,47 @@ namespace file_win32_helpers { return ret; } + void attribs_from_win32(t_filestats2& out, DWORD in); template static t_filestats2 translate_stats2(const t_info& p_info) { t_filestats2 ret; ret.m_size = make_uint64(p_info.nFileSizeLow, p_info.nFileSizeHigh); ret.m_timestamp = make_uint64(p_info.ftLastWriteTime); ret.m_timestampCreate = make_uint64(p_info.ftCreationTime); - ret.set_readonly((p_info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) != 0); - ret.set_folder((p_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0); - ret.set_hidden((p_info.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0); - ret.set_system((p_info.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) != 0); - ret.set_remote(false); + attribs_from_win32(ret, p_info.dwFileAttributes); return ret; } + + t_filestats2 stats2_from_handle(HANDLE, const wchar_t * fallbackPath, uint32_t flags, abort_callback &a); }; template class file_win32_wrapper_t : public service_multi_inherit { + typedef file_win32_wrapper_t self_t; public: - file_win32_wrapper_t(HANDLE p_handle) : m_handle(p_handle), m_position(0) - { - } + file_win32_wrapper_t(HANDLE handle, pfc::wstringLite && path) : m_handle(handle), m_path(std::move(path)) {} static file::ptr g_CreateFile(const char * p_path,DWORD p_access,DWORD p_sharemode,LPSECURITY_ATTRIBUTES p_security_attributes,DWORD p_createmode,DWORD p_flags,HANDLE p_template) { + auto pathW = pfc::wideFromUTF8(p_path); SetLastError(NO_ERROR); - HANDLE handle = uCreateFile(p_path,p_access,p_sharemode,p_security_attributes,p_createmode,p_flags,p_template); + HANDLE handle = CreateFile(pathW,p_access,p_sharemode,p_security_attributes,p_createmode,p_flags,p_template); if (handle == INVALID_HANDLE_VALUE) { const DWORD code = GetLastError(); if (p_access & GENERIC_WRITE) win32_file_write_failure(code, p_path); else exception_io_from_win32(code); } try { - return g_create_from_handle(handle); + return g_create_from_handle(handle, std::move(pathW)); } catch(...) {CloseHandle(handle); throw;} } - static service_ptr_t g_create_from_handle(HANDLE p_handle) { - return new service_impl_t >(p_handle); + static service_ptr_t g_create_from_handle(HANDLE handle, pfc::wstringLite && path) { + return new service_impl_t(handle, std::move(path)); + } + static service_ptr_t g_create_from_handle(HANDLE handle) { + pfc::wstringLite blank; + g_create_from_handle(handle, std::move(blank)); } @@ -175,18 +182,15 @@ class file_win32_wrapper_t : public service_multi_inherit class file_win32_wrapper_overlapped_t : public service_multi_inherit< file_v2, file_lowLevelIO > { + typedef file_win32_wrapper_overlapped_t self_t; public: - file_win32_wrapper_overlapped_t(HANDLE file) : m_handle(file), m_position() { + file_win32_wrapper_overlapped_t(HANDLE file, pfc::wstringLite && path) : m_handle(file), m_path(std::move(path)) { WIN32_OP( (m_event = CreateEvent(NULL, TRUE, FALSE, NULL)) != NULL ); } ~file_win32_wrapper_overlapped_t() {CloseHandle(m_event); CloseHandle(m_handle);} @@ -257,40 +263,42 @@ class file_win32_wrapper_overlapped_t : public service_multi_inherit< file_v2, f t_filestats2 get_stats2(uint32_t f, abort_callback& a) { a.check(); if (p_writeable) FlushFileBuffers(m_handle); - SetLastError(0); - BY_HANDLE_FILE_INFORMATION info = {}; - if (!GetFileInformationByHandle(m_handle, &info)) exception_io_from_win32(GetLastError()); - return file_win32_helpers::translate_stats2(info); + return file_win32_helpers::stats2_from_handle(m_handle, m_path, f, a); } t_filetimestamp get_timestamp(abort_callback & p_abort) { p_abort.check_e(); if (p_writeable) FlushFileBuffers(m_handle); SetLastError(ERROR_SUCCESS); - t_filetimestamp temp; - if (!GetFileTime(m_handle,0,0,(FILETIME*)&temp)) exception_io_from_win32(GetLastError()); - return temp; + FILETIME temp; + if (!GetFileTime(m_handle,0,0,&temp)) exception_io_from_win32(GetLastError()); + return file_win32_helpers::make_uint64(temp); } bool is_remote() {return false;} static file::ptr g_CreateFile(const char * p_path,DWORD p_access,DWORD p_sharemode,LPSECURITY_ATTRIBUTES p_security_attributes,DWORD p_createmode,DWORD p_flags,HANDLE p_template) { + auto pathW = pfc::wideFromUTF8(p_path); p_flags |= FILE_FLAG_OVERLAPPED; SetLastError(NO_ERROR); - HANDLE handle = uCreateFile(p_path,p_access,p_sharemode,p_security_attributes,p_createmode,p_flags,p_template); + HANDLE handle = CreateFile(pathW,p_access,p_sharemode,p_security_attributes,p_createmode,p_flags,p_template); if (handle == INVALID_HANDLE_VALUE) { const DWORD code = GetLastError(); if (p_access & GENERIC_WRITE) win32_file_write_failure(code, p_path); else exception_io_from_win32(code); } try { - return g_create_from_handle(handle); + return g_create_from_handle(handle, std::move(pathW)); } catch(...) {CloseHandle(handle); throw;} } + static file::ptr g_create_from_handle(HANDLE p_handle, pfc::wstringLite && path) { + return new service_impl_t(p_handle, std::move(path)); + } static file::ptr g_create_from_handle(HANDLE p_handle) { - return new service_impl_t >(p_handle); + pfc::wstringLite blank; + return g_create_from_handle(p_handle, std::move(blank)); } size_t lowLevelIO(const GUID & guid, size_t arg1, void * arg2, size_t arg2size, abort_callback & abort) override { @@ -299,7 +307,8 @@ class file_win32_wrapper_overlapped_t : public service_multi_inherit< file_v2, f protected: HANDLE m_event, m_handle; - t_filesize m_position; + t_filesize m_position = 0; + pfc::wstringLite m_path; }; #endif // _WIN32 diff --git a/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj b/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj index 8068941..b4fcb48 100644 --- a/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj +++ b/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj @@ -506,6 +506,7 @@ + @@ -519,6 +520,7 @@ + @@ -567,6 +569,7 @@ + diff --git a/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj.filters b/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj.filters index d2efd9a..101e27f 100644 --- a/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj.filters +++ b/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj.filters @@ -403,5 +403,14 @@ Header Files + + Header Files + + + Header Files + + + Header Files + \ No newline at end of file diff --git a/sdk/foobar2000/helpers/metadb_handle_set.h b/sdk/foobar2000/helpers/metadb_handle_set.h index 8cf1993..e59c242 100644 --- a/sdk/foobar2000/helpers/metadb_handle_set.h +++ b/sdk/foobar2000/helpers/metadb_handle_set.h @@ -21,10 +21,8 @@ class metadb_handle_set { if (rv) p->service_release(); return rv; } - - size_t get_count() const { - return m_content.size(); - } + size_t size() const {return m_content.size();} + size_t get_count() const {return m_content.size(); } template bool contains(ptr_t const & item) const { return m_content.count(&*item) != 0; @@ -44,28 +42,40 @@ class metadb_handle_set { bool added = m_content.insert(p).second; if (!added) p->service_release(); } - void remove_all() { - for (auto iter = m_content.begin(); iter != m_content.end(); ++iter) { - metadb_handle * p = (*iter); - p->service_release(); - } + void clear() { + for (auto p : m_content) p->service_release(); m_content.clear(); } + void remove_all() { clear();} template void enumerate(callback_t & cb) const { - for (auto iter = m_content.begin(); iter != m_content.end(); ++iter) { - cb(*iter); - } + for (auto iter : m_content) cb(iter); } typedef std::set impl_t; typedef impl_t::const_iterator const_iterator; const_iterator begin() const { return m_content.begin(); } const_iterator end() const { return m_content.end(); } -private: - std::set m_content; + metadb_handle_list to_list() const { + metadb_handle_list ret; ret.prealloc(m_content.size()); + for (auto h : m_content) { + ret.add_item(h); + } + return ret; + } + metadb_handle_set(const metadb_handle_set& src) { _copy(src); } + void operator=(const metadb_handle_set& src) { _copy(src); } + metadb_handle_set(metadb_handle_set&& src) noexcept { _move(src); } + void operator=(metadb_handle_set&& src) noexcept { _move(src); } private: - metadb_handle_set(const metadb_handle_set &) = delete; - void operator=(const metadb_handle_set&) = delete; + void _copy(const metadb_handle_set& src) { + m_content = src.m_content; + for (auto h : m_content) h->service_add_ref(); + } + void _move(metadb_handle_set& src) { + m_content = std::move(src.m_content); src.m_content.clear(); + } + + impl_t m_content; }; diff --git a/sdk/foobar2000/helpers/packet_decoder_aac_common.cpp b/sdk/foobar2000/helpers/packet_decoder_aac_common.cpp index bb4ac28..1b1b9fc 100644 --- a/sdk/foobar2000/helpers/packet_decoder_aac_common.cpp +++ b/sdk/foobar2000/helpers/packet_decoder_aac_common.cpp @@ -267,3 +267,46 @@ const char * packet_decoder_aac_common::objectTypeStr( unsigned ot ) { const char * packet_decoder_aac_common::audioSpecificConfig_t::objectTypeStr() const { return packet_decoder_aac_common::objectTypeStr( this->m_objectType ); } + +pfc::array_t packet_decoder_aac_common::buildASC(audioSpecificConfig_t const& arg) { + pfc::array_t ret; ret.resize(5); memset(ret.get_ptr(), 0, ret.get_size()); + unsigned pos = 0; + auto write = [&](unsigned v, unsigned bits) { + bitreader_helper::write_int(ret.get_ptr(), pos, bits, v); + pos += bits; + }; + + if (arg.m_objectType < 32) { + write(arg.m_objectType, 5); + } else { + write(31, 5); + write(arg.m_objectType - 32, 6); + } + + { + bool stdRate = false; + for (unsigned i = 0; i < std::size(aac_sample_rates); ++i) { + if (arg.m_sampleRate == aac_sample_rates[i]) { + write(i, 4); + stdRate = true; break; + } + } + if (!stdRate) { + write(arg.m_sampleRate, 24); + } + + write(arg.m_channels, 4); + } + + ret.set_size((pos + 7) / 8); + return ret; +} + +pfc::array_t packet_decoder_aac_common::buildSafeASC(unsigned rate) { + if (rate == 0) rate = 44100; + audioSpecificConfig_t info = {}; + info.m_sampleRate = rate; + info.m_objectType = 1; // 1 = main, 2 = LC + info.m_channels = 2; // stereo + return buildASC(info); +} \ No newline at end of file diff --git a/sdk/foobar2000/helpers/packet_decoder_aac_common.h b/sdk/foobar2000/helpers/packet_decoder_aac_common.h index b074dbc..c8d1371 100644 --- a/sdk/foobar2000/helpers/packet_decoder_aac_common.h +++ b/sdk/foobar2000/helpers/packet_decoder_aac_common.h @@ -37,4 +37,10 @@ class packet_decoder_aac_common : public packet_decoder { static audioSpecificConfig_t parseASC(const void *, size_t); static unsigned get_ASC_object_type(const void *, size_t); + + static pfc::array_t buildASC(audioSpecificConfig_t const&); + + // If no sane ASC was provided by container, make something up to initialize decoder and attempt decoding. + static pfc::array_t buildSafeASC(unsigned rate = 0); + }; diff --git a/sdk/foobar2000/helpers/readWriteLock.h b/sdk/foobar2000/helpers/readWriteLock.h new file mode 100644 index 0000000..909cc85 --- /dev/null +++ b/sdk/foobar2000/helpers/readWriteLock.h @@ -0,0 +1,76 @@ +#pragma once + + +namespace fb2k { + // fb2k::readWriteLock: abortable readWriteLock, allowing multiple concurrent readers while not writing, or one writer while not reading. + class readWriteLock { + pfc::mutex m_guard; + size_t m_readers = 0, m_writers = 0; + typedef std::shared_ptr < pfc::event> eventRef_t; + eventRef_t m_currentEvent; + public: + + void shutdown() { + for (;;) { + eventRef_t waitFor; + { + PFC_INSYNC(m_guard); + if (m_readers == 0 && m_writers == 0) return; + PFC_ASSERT(m_currentEvent); + waitFor = m_currentEvent; + } + waitFor->wait_for(-1); + } + } + + service_ptr beginRead(abort_callback& a) { + for (;;) { + a.check(); + eventRef_t waitFor; + { + PFC_INSYNC(m_guard); + if (m_writers == 0) { + if (!m_currentEvent) m_currentEvent = std::make_shared(); + ++m_readers; + return fb2k::callOnRelease([this] { + PFC_INSYNC(m_guard); + PFC_ASSERT(m_currentEvent); + PFC_ASSERT(m_readers > 0 && m_writers == 0); + if (--m_readers == 0) { + m_currentEvent->set_state(true); m_currentEvent = nullptr; + } + }); + } + PFC_ASSERT(m_currentEvent); + waitFor = m_currentEvent; + } + a.waitForEvent(*waitFor); + } + } + service_ptr beginWrite(abort_callback& a) { + for (;;) { + a.check(); + eventRef_t waitFor; + { + PFC_INSYNC(m_guard); + if (m_readers == 0 && m_writers == 0) { + m_currentEvent = std::make_shared(); + ++m_writers; + return fb2k::callOnRelease([this] { + PFC_INSYNC(m_guard); + PFC_ASSERT(m_currentEvent); + PFC_ASSERT(m_readers == 0 && m_writers > 0); + if (--m_writers == 0) { + m_currentEvent->set_state(true); m_currentEvent = nullptr; + } + }); + } + PFC_ASSERT(m_currentEvent); + waitFor = m_currentEvent; + } + a.waitForEvent(*waitFor); + } + } + + }; +} diff --git a/sdk/foobar2000/helpers/window_placement_helper.cpp b/sdk/foobar2000/helpers/window_placement_helper.cpp index 4559020..d9bfe4e 100644 --- a/sdk/foobar2000/helpers/window_placement_helper.cpp +++ b/sdk/foobar2000/helpers/window_placement_helper.cpp @@ -41,7 +41,7 @@ static bool test_rect(const RECT * rc) { } -bool cfg_window_placement_common::read_from_window(HWND window) +bool cfg_window_placement::read_from_window(HWND window) { WINDOWPLACEMENT wp = {}; if (g_is_enabled()) { @@ -68,7 +68,7 @@ bool cfg_window_placement_common::read_from_window(HWND window) return wp.length == sizeof(wp); } -bool cfg_window_placement_common::apply_to_window(HWND window, bool allowHidden) { +bool cfg_window_placement::apply_to_window(HWND window, bool allowHidden) { bool ret = false; if (g_is_enabled()) { @@ -117,8 +117,7 @@ static BOOL SetWindowSize(HWND p_wnd,unsigned p_x,unsigned p_y) return FALSE; } -bool cfg_window_size::on_window_creation(HWND p_wnd) -{ +bool cfg_window_size::apply_to_window(HWND p_wnd) { bool ret = false; if (g_is_enabled()) @@ -127,11 +126,14 @@ bool cfg_window_size::on_window_creation(HWND p_wnd) if (v.cx > 0 && v.cy > 0) { if (SetWindowSize(p_wnd, v.cx, v.cy)) ret = true; } - - } + } return ret; } +bool cfg_window_size::on_window_creation(HWND p_wnd) +{ + return apply_to_window(p_wnd); +} void cfg_window_size::on_window_destruction(HWND p_wnd) { diff --git a/sdk/foobar2000/helpers/window_placement_helper.h b/sdk/foobar2000/helpers/window_placement_helper.h index 6f8dd2b..1e2a13f 100644 --- a/sdk/foobar2000/helpers/window_placement_helper.h +++ b/sdk/foobar2000/helpers/window_placement_helper.h @@ -4,36 +4,40 @@ #include "../SDK/cfg_var.h" -class cfg_window_placement_common : public cfg_struct_t { +//! Window position management helpers +//! Usage: create a static instance, like with any cfg_var; access it on creation/reposition/destruction of your window. +class cfg_window_placement : public cfg_struct_t { public: - cfg_window_placement_common(const GUID& guid) : cfg_struct_t(guid) {} + cfg_window_placement(const GUID& guid) : cfg_struct_t(guid) {} + //! Read and save position data from HWND. bool read_from_window(HWND window); + //! Apply saved position data to HWND. bool apply_to_window(HWND window, bool allowHidden); -}; -class cfg_window_placement : public cfg_window_placement_common -{ -public: + // OLD methods tracking only destroy/create. + // Use of read_from_window() / apply_to_window() instead is preferred, so changes can be saved immediately. bool on_window_creation(HWND window, bool allowHidden = false);//returns true if window position has been changed, false if not void on_window_creation_silent(HWND window); void on_window_destruction(HWND window); - cfg_window_placement(const GUID& guid) : cfg_window_placement_common(guid) {} -}; - -class cfg_window_placement_v2 : public cfg_window_placement_common { -public: - cfg_window_placement_v2(const GUID& guid) : cfg_window_placement_common(guid) {} - // All already in cfg_window_placement_common }; +// At one point there was a separate cfg_window_placement_v2 without legacy methods +typedef cfg_window_placement cfg_window_placement_v2; - +//! Window size tracker \n +//! Usage: create a static instance, like with any cfg_var; access it on creation/reposition/destruction of your window. class cfg_window_size : public cfg_struct_t { public: + cfg_window_size(const GUID& id) : cfg_struct_t(id) {} + //! Read and save size data from HWND. + bool read_from_window(HWND window); + //! Apply saved size data to HWND. + bool apply_to_window(HWND); + + // OLD methods tracking only destroy/create. + // Use of read_from_window() / apply_to_window() instead is preferred, so changes can be saved immediately. bool on_window_creation(HWND window);//returns true if window position has been changed, false if not void on_window_destruction(HWND window); - bool read_from_window(HWND window); - cfg_window_size(const GUID& id) : cfg_struct_t(id) {} }; #endif // FOOBAR2000_DESKTOP_WINDOWS diff --git a/sdk/foobar2000/shared/shared-ARM64.lib b/sdk/foobar2000/shared/shared-ARM64.lib index 754a40aadf69842441d619f103c4702354989142..c95dd58528ea93ed541e191538988e0a95f54a45 100644 GIT binary patch delta 106 zcmbO*hiSqbrVUlDEcT~F&rhy%UCW}xaIj{wzFQ;{kc#t=n!LpA534kH%e5VoZ+pm3 mKH{DVQ=vY2ohJuGRRzob6H~8DzU2Yeu8feB+I-2=&IJJa$14y3 delta 106 zcmbO*hiSqbrVUlDEDdv>{+wLrx|T(ep|5(fzFQ;{kc#t=n!LpA4{KpR_pu$5Z+pm3 mKH{DVQ=vY2ohJuGRRv4O#`Uiz-|~QKS4K!mZNB7b=K=sUa4Qu6 diff --git a/sdk/foobar2000/shared/shared-ARM64EC.lib b/sdk/foobar2000/shared/shared-ARM64EC.lib index 77043dcbf36cb5641223b3bf35eaf028a1061275..b464ad489bc21f9e843ac8fbc1f275d19ee01353 100644 GIT binary patch delta 250 zcmbQYlWE>grVZ!ZIN!KrUgctBVBnbi*F$=;pO^GxUiTsvC5D4FlN&wNC$DlhVmer} z`JTHNBdc%QuTMKB>wC#hmheo4DbWW?Prm0aHTjHZ9E)qr}^K%RI zGE<<6)Vve8+&%|AGhtw0I52zi1n(-YU0H>9b%5M{=FK8LubjBe3>_Z?0r`du0+Z(p zsZG}JFXVYK-Rp-JP|SrvfMN1^DY3~4{T!1|^%rn&x%c651Vm!8udw9gxCt%1^Z2jd dj01|902SL$W|Wbh+%L>O*=HixX61?1+yK(|Srh;O delta 250 zcmbQYlWE>grVZ!ZI9=@D+~Q(nVBnbi*F$=;pO^GxUiTsvMTWlW$&H@slUKPLG4)k% zzUMB+$a>m4>gSHh`d;#rB|KAMO7wx!lkd4pO+Mop$8tf^`}1TyueC5qWiE&0{M-V) z%oM01HSYwjnX44unlOOC@ z81Mf#UJx;c$>*iSCM)!FOg`0Lz|DTx_)Y{=v9GY?1rVV;NoClodKHy?xVBnY>>nA;Voxk+tT%RHqC5D4FlOOu2Pv-J9Vmer} z+0Ivtk@dtpi}O1s_xsCFuJB8RDbWW?Pqy=wnylj=$I|$|`RwFA|FtklX)cH4{M-V) N%oK>C&2<6aTmhsPFuec( delta 124 zcmeyehUv>1rVV;NoR_qUuX8anFmOzc^^=~w&R=?Ru1^t*B12#GsrVZ+pm3 mKH{DVQ=vY2ohJuGRRxQ+<;+`?Z+XDAD(ptOrigin.y - clientHeight / 2, 0); - yMax = yBase + clientHeight * 2; - baseItem = pfc::min_t(this->IndexFromPointAbs(yBase), count - 1); - } else { - auto itemHeight = GetItemHeight(); - size_t extraItems = (size_t)(clientHeight / itemHeight); + + if (!m_greedyGroupLayout) { + if (indexLo == SIZE_MAX) { + yBase = pfc::max_t(ptOrigin.y - clientHeight / 2, 0); + yMax = yBase + clientHeight * 2; + baseItem = pfc::min_t(this->IndexFromPointAbs(yBase), count - 1); + } else { + auto itemHeight = GetItemHeight(); + size_t extraItems = (size_t)(clientHeight / itemHeight); #if PrepLayoutCache_Debug - PFC_DEBUGLOG << "PrepLayoutCache: clientHeight=" << clientHeight << " itemHeight=" << itemHeight << " extraItems=" << extraItems; + PFC_DEBUGLOG << "PrepLayoutCache: clientHeight=" << clientHeight << " itemHeight=" << itemHeight << " extraItems=" << extraItems; #endif - if (indexLo < extraItems) baseItem = 0; - else baseItem = indexLo - extraItems; + if (indexLo < extraItems) baseItem = 0; + else baseItem = indexLo - extraItems; - if (indexHi == SIZE_MAX) { - endItem = baseItem + extraItems; - } else { - endItem = indexHi + extraItems; - } - if (endItem > count) endItem = count; + if (indexHi == SIZE_MAX) { + endItem = baseItem + extraItems; + } else { + endItem = indexHi + extraItems; + } + if (endItem > count) endItem = count; #if PrepLayoutCache_Debug - PFC_DEBUGLOG << "PrepLayoutCache: baseItem=" << baseItem << " endItem=" << endItem; + PFC_DEBUGLOG << "PrepLayoutCache: baseItem=" << baseItem << " endItem=" << endItem; #endif + } } + size_t item = baseItem; { const auto group = this->GetItemGroup(baseItem); diff --git a/sdk/libPPUI/CListControl.h b/sdk/libPPUI/CListControl.h index 7bffbef..878f119 100644 --- a/sdk/libPPUI/CListControl.h +++ b/sdk/libPPUI/CListControl.h @@ -325,12 +325,17 @@ class CListControlImpl : public CWindowImpl m_varItemHeights; std::set m_groupHeaders; - + size_t FindGroupBaseCached(size_t itemFor) const; size_t FindGroupBase(size_t itemFor) const; size_t FindGroupBase(size_t itemFor, groupID_t group) const; protected: + // Grouped layout mode toggle + // Default mode is greedy, probes whole list layout in advance (no glitches when scrolling) + // In special conditions when probing is expensive, greedy mode should be turned off + bool m_greedyGroupLayout = true; + pfc::map_t m_themeCache; CTheme & themeFor( const char * what ); CTheme & theme() { return themeFor("LISTVIEW");} diff --git a/sdk/libPPUI/CListControlOwnerData.h b/sdk/libPPUI/CListControlOwnerData.h index 8f9f9d1..04488ad 100644 --- a/sdk/libPPUI/CListControlOwnerData.h +++ b/sdk/libPPUI/CListControlOwnerData.h @@ -29,7 +29,8 @@ class IListControlOwnerDataSource { lineCount = 1; return listGetSubItemText( ctx, item, subItem); } virtual void listSetEditField(ctx_t ctx, size_t item, size_t subItem, const char * val) {} - virtual uint32_t listGetEditFlags(ctx_t ctx, size_t item, size_t subItem) {return 0;} + // Returns InPlaceEdit::KFlag* + virtual uint32_t listGetEditFlags(ctx_t ctx, size_t item, size_t subItem) {return 0;} typedef InPlaceEdit::CTableEditHelperV2::autoComplete_t autoComplete_t; typedef InPlaceEdit::CTableEditHelperV2::combo_t combo_t; virtual autoComplete_t listGetAutoComplete(ctx_t, size_t item, size_t subItem) {return autoComplete_t();} diff --git a/sdk/libPPUI/libPPUI-license.txt b/sdk/libPPUI/libPPUI-license.txt index 3f05fcc..0ab480d 100644 --- a/sdk/libPPUI/libPPUI-license.txt +++ b/sdk/libPPUI/libPPUI-license.txt @@ -1,4 +1,4 @@ -Copyright (C) 2002-2022 Peter Pawlowski +Copyright (C) 2002-2023 Peter Pawlowski This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/sdk/pfc/SmartStrStr-twoCharMappings.h b/sdk/pfc/SmartStrStr-twoCharMappings.h index 042d43b..a950636 100644 --- a/sdk/pfc/SmartStrStr-twoCharMappings.h +++ b/sdk/pfc/SmartStrStr-twoCharMappings.h @@ -5,21 +5,38 @@ static constexpr struct { const char* to; } twoCharMappings[] = { {0x00C6, "AE"}, + {0x00E6, "ae"}, + {0x00DF, "ss"}, + +#if 0 + // umlauts + // the problem with these is that changing them to two-letter represenatations prevents search by non-umlaut vowel from working. + {0x00C4, "AE"}, + {0x00E4, "ae"}, + {0x00D6, "OE"}, + {0x00F6, "oe"}, + {0x00DC, "UE"}, + {0x00FC, "ue"}, +#endif + +#if 0 + // Incomplete list, hence disabled. Nobody uses these. {0x01E2, "AE"}, {0x01FC, "AE"}, - {0x00E6, "ae"}, {0x01E3, "ae"}, {0x01FD, "ae"}, {0x0152, "OE"}, {0x0153, "oe"}, {0x0276, "oe"}, + {0x01C3, "dz"}, {0x01C4, "DZ"}, - {0x01F1, "DZ"}, + {0x01C5, "Dz"}, {0x01C6, "dz"}, + {0x01F1, "DZ"}, + {0x01F2, "Dz"}, {0x01F3, "dz"}, {0x02A3, "dz"}, {0x02A5, "dz"}, - {0x00DF, "ss"}, {0x01C7, "LJ"}, {0x01C8, "Lj"}, {0x01C9, "lj"}, @@ -28,13 +45,5 @@ static constexpr struct { {0x01CC, "nj"}, {0x0132, "IJ"}, {0x0133, "ij"}, - -#if 0 // umlauts - {0x00C4, "AE"}, - {0x00E4, "ae"}, - {0x00D6, "OE"}, - {0x00F6, "oe"}, - {0x00DC, "UE"}, - {0x00FC, "ue"}, #endif }; diff --git a/sdk/pfc/SmartStrStr.cpp b/sdk/pfc/SmartStrStr.cpp index b5b0bbd..ee5cf31 100644 --- a/sdk/pfc/SmartStrStr.cpp +++ b/sdk/pfc/SmartStrStr.cpp @@ -7,6 +7,50 @@ #include "SmartStrStr-table.h" #include "SmartStrStr-twoCharMappings.h" +bool SmartStrStr::isWordChar(unsigned c) { + // FIX ME map Unicode ranges somehow + return c >= 128 || pfc::char_is_ascii_alphanumeric((char)c); +} + +bool SmartStrStr::isWordChar(const char* ptr) { + unsigned c; + size_t d = pfc::utf8_decode_char(ptr, c); + if (d == 0) return false; // bad UTF-8 + return isWordChar(c); +} + +bool SmartStrStr::isValidWord(const char* ptr) { + if (*ptr == 0) return false; + do { + unsigned c; + size_t d = pfc::utf8_decode_char(ptr, c); + if (d == 0) return false; // bad UTF-8 + if (!isWordChar(c)) return false; + ptr += d; + } while (*ptr != 0); + return true; +} + +void SmartStrStr::findWords(const char* str, std::function cb) { + size_t base = 0, walk = 0; + for (;; ) { + unsigned c = 0; + size_t d = pfc::utf8_decode_char(str + walk, c); + if (d == 0) break; + + if (!SmartStrStr::isWordChar(c)) { + if (walk > base) { + cb(pfc::string_part(str + base, walk - base)); + } + base = walk + d; + } + walk += d; + } + if (walk > base) { + cb(pfc::string_part(str + base, walk - base)); + } +} + SmartStrStr::SmartStrStr() { std::map > substitutions, substitutionsReverse; std::map downconvert; @@ -179,6 +223,32 @@ const char16_t * SmartStrStr::strStrEnd16(const char16_t * pString, const char16 } } +static bool wordBeginsHere(const char* base, size_t offset) { + if (offset == 0) return true; + for (size_t len = 1; len <= offset && len <= 6; --len) { + unsigned c; + if (pfc::utf8_decode_char(base + offset - len, c) == len) { + return !SmartStrStr::isWordChar(c); + } + } + return false; +} + +const char* SmartStrStr::strStrEndWord(const char* pString, const char* pSubString, size_t* outFoundAt) const { + size_t walk = 0; + for (;;) { + size_t foundAt = 0; + auto end = strStrEnd(pString + walk, pSubString, &foundAt); + if (end == nullptr) return nullptr; + foundAt += walk; + if (!isWordChar(end) && wordBeginsHere(pString, foundAt)) { + if (outFoundAt) *outFoundAt = foundAt; + return end; + } + walk = end - pString; + } +} + bool SmartStrStr::matchOneChar(uint32_t cInput, uint32_t cData) const { if (cInput == cData) return true; auto v = m_substitutions.query_ptr(cData); @@ -191,13 +261,17 @@ pfc::string8 SmartStrStr::transformStr(const char* str) const { } void SmartStrStr::transformStrHere(pfc::string8& out, const char* in) const { - out.prealloc(strlen(in)); + transformStrHere(out, in, strlen(in)); +} + +void SmartStrStr::transformStrHere(pfc::string8& out, const char* in, size_t inLen) const { + out.prealloc(inLen); out.clear(); - for (;; ) { + for (size_t walk = 0; walk < inLen; ) { unsigned c; - size_t d = pfc::utf8_decode_char(in, c); - if (d == 0) break; - in += d; + size_t d = pfc::utf8_decode_char(in + walk, c); + if (d == 0 || walk+d>inLen) break; + walk += d; const char* alt = m_twoCharMappings.query(c); if (alt != nullptr) { out << alt; continue; @@ -357,10 +431,24 @@ void SmartStrFilter::init(const char* ptr, size_t len) { bool SmartStrFilter::test_disregardCounts(const char* src) const { if (m_items.size() == 0) return false; - auto& dc = SmartStrStr::global(); + for (auto& walk : m_items) { + if (!dc->strStrEnd(src, walk.first.c_str())) return false; + } + return true; +} + +bool SmartStrFilter::testWords(const char* src) const { + if (m_items.size() == 0) return false; for (auto& walk : m_items) { - if (!dc.strStrEnd(src, walk.first.c_str())) return false; + const t_size count = walk.second; + const std::string& str = walk.first; + const char* strWalk = src; + for (t_size walk = 0; walk < count; ++walk) { + const char* next = dc->strStrEndWord(strWalk, str.c_str()); + if (next == nullptr) return false; + strWalk = next; + } } return true; } @@ -369,14 +457,18 @@ bool SmartStrFilter::test(const char* src) const { if (m_items.size() == 0) return false; - auto& dc = SmartStrStr::global(); - + // Use the faster routine first, it can't be used to count occurances but nobody really knows about this feature + for (auto& walk : m_items) { + if (!dc->testSubstring(src, walk.first.c_str())) return false; + } + // Have any items where specific number of occurances is wanted? for (auto & walk : m_items) { const t_size count = walk.second; + if (count == 1) continue; const std::string& str = walk.first; const char* strWalk = src; for (t_size walk = 0; walk < count; ++walk) { - const char* next = dc.strStrEnd(strWalk, str.c_str()); + const char* next = dc->strStrEnd(strWalk, str.c_str()); if (next == nullptr) return false; strWalk = next; } diff --git a/sdk/pfc/SmartStrStr.h b/sdk/pfc/SmartStrStr.h index 6a1fc19..073a572 100644 --- a/sdk/pfc/SmartStrStr.h +++ b/sdk/pfc/SmartStrStr.h @@ -9,8 +9,6 @@ //! Implementation of string matching for search purposes, such as media library search or typefind in list views. \n //! Inspired by Unicode asymetic search, but not strictly implementing the Unicode asymetric search specifications. \n -//! Bootstraps its character mapping data from various Win32 API methods, requires no externally provided character mapping data. \n -//! Windows-only code. \n //! \n //! Keeping a global instance of it is recommended, due to one time init overhead. \n //! Thread safety: safe to call concurrently once constructed. @@ -19,10 +17,17 @@ class SmartStrStr { public: SmartStrStr(); + static bool isWordChar(unsigned c); + static bool isWordChar(const char* ptr); + static bool isValidWord(const char*); + static void findWords(const char*, std::function); + //! Returns ptr to the end of the string if positive (for continuing search), nullptr if negative. const char * strStrEnd(const char * pString, const char * pSubString, size_t * outFoundAt = nullptr) const; const char16_t * strStrEnd16(const char16_t * pString, const char16_t * pSubString, size_t * outFoundAt = nullptr) const; + const char* strStrEndWord(const char* pString, const char* pSubString, size_t* outFoundAt = nullptr) const; + bool testSubstring( const char * str, const char * sub ) const; bool testSubstring16( const char16_t * str, const char16_t * sub ) const; #ifdef _WIN32 @@ -46,6 +51,7 @@ class SmartStrStr { pfc::string8 transformStr(const char * str) const; void transformStrHere(pfc::string8& out, const char* in) const; + void transformStrHere(pfc::string8& out, const char* in, size_t inLen) const; private: bool testSubString_prefix(const char* str, const char* sub, const char * prefix, size_t prefixLen) const; bool testSubString_prefix(const char* str, const char* sub, uint32_t c) const; @@ -67,11 +73,11 @@ class SmartStrStr { class SmartStrFilter { - typedef std::map t_stringlist; - t_stringlist m_items; - public: + typedef std::map t_stringlist; SmartStrFilter() { } + SmartStrFilter(t_stringlist const& arg) : m_items(arg) {} + SmartStrFilter(t_stringlist&& arg) : m_items(std::move(arg)) {} SmartStrFilter(const char* p) { init(p, strlen(p)); } SmartStrFilter(const char* p, size_t l) { init(p, l); } @@ -79,5 +85,13 @@ class SmartStrFilter { void init(const char* ptr, size_t len); bool test(const char* src) const; + bool testWords(const char* src) const; bool test_disregardCounts(const char* src) const; + + const t_stringlist& items() const { return m_items; } + operator bool() const { return !m_items.empty(); } + bool empty() const { return m_items.empty(); } +private: + t_stringlist m_items; + SmartStrStr * dc = &SmartStrStr::global(); }; diff --git a/sdk/pfc/audio_sample.cpp b/sdk/pfc/audio_sample.cpp index 36172e1..3808e7f 100644 --- a/sdk/pfc/audio_sample.cpp +++ b/sdk/pfc/audio_sample.cpp @@ -4,71 +4,6 @@ #include "byte_order.h" namespace pfc { - float audio_math::decodeFloat24ptr(const void * sourcePtr) { - PFC_STATIC_ASSERT(pfc::byte_order_is_little_endian); - union { - uint8_t bytes[4]; - float v; - } u; - const uint8_t * s = reinterpret_cast(sourcePtr); - u.bytes[0] = 0; - u.bytes[1] = s[0]; - u.bytes[2] = s[1]; - u.bytes[3] = s[2]; - return u.v; - } - float audio_math::decodeFloat24ptrbs(const void * sourcePtr) { - PFC_STATIC_ASSERT(pfc::byte_order_is_little_endian); - union { - uint8_t bytes[4]; - float v; - } u; - const uint8_t * s = reinterpret_cast(sourcePtr); - u.bytes[0] = 0; - u.bytes[1] = s[2]; - u.bytes[2] = s[1]; - u.bytes[3] = s[0]; - return u.v; - } - - float audio_math::decodeFloat16(uint16_t source) { - const unsigned fractionBits = 10; - const unsigned widthBits = 16; - typedef uint16_t source_t; - - /* typedef uint64_t out_t; typedef double retval_t; - enum { - outExponent = 11, - outFraction = 52, - outExponentShift = (1 << (outExponent-1))-1 - };*/ - - typedef uint32_t out_t; typedef float retval_t; - enum { - outExponent = 8, - outFraction = 23, - outExponentShift = (1 << (outExponent-1))-1 - }; - - const unsigned exponentBits = widthBits - fractionBits - 1; - // 1 bit sign | exponent | fraction - source_t fraction = source & (((source_t)1 << fractionBits)-1); - source >>= fractionBits; - int exponent = (int)( source & (((source_t)1 << exponentBits)-1) ) - (int)((1 << (exponentBits-1))-1); - source >>= exponentBits; - - if (outExponent + outExponentShift <= 0) return 0; - - out_t output = (out_t)( source&1 ); - output <<= outExponent; - output |= (unsigned) (exponent + outExponentShift) & ( (1<> -shift); - else output |= (out_t) (fraction << shift); - return *(retval_t*)&output / pfc::audio_math::float16scale; - } - unsigned audio_math::bitrate_kbps(uint64_t fileSize, double duration) { if (fileSize > 0 && duration > 0) return (unsigned)floor((double)fileSize * 8 / (duration * 1000) + 0.5); return 0; diff --git a/sdk/pfc/audio_sample.h b/sdk/pfc/audio_sample.h index 5f4a5ae..3014b16 100644 --- a/sdk/pfc/audio_sample.h +++ b/sdk/pfc/audio_sample.h @@ -61,12 +61,6 @@ namespace pfc { static inline double gain_to_scale(double p_gain) { return pow(10.0, p_gain / 20.0); } static inline double scale_to_gain(double scale) { return 20.0*log10(scale); } - static constexpr float float16scale = 65536.f; - - static float decodeFloat24ptr(const void * sourcePtr); - static float decodeFloat24ptrbs(const void * sourcePtr); - static float decodeFloat16(uint16_t source); - static unsigned bitrate_kbps( uint64_t fileSize, double duration ); }; // class audio_math diff --git a/sdk/pfc/charDownConvert.cpp b/sdk/pfc/charDownConvert.cpp index a49f18d..3ca39ab 100644 --- a/sdk/pfc/charDownConvert.cpp +++ b/sdk/pfc/charDownConvert.cpp @@ -81,44 +81,49 @@ namespace pfc { size_t CharDownConvert::numMappings() { return std::size(g_mappings); } CharDownConvert::CharDownConvert() { + std::map charConvertMap; + for (auto& l : g_mappings) { - m_charConvertMap[(uint32_t)l.from] = (uint32_t)l.to; + charConvertMap[(uint32_t)l.from] = (uint32_t)l.to; + } + for (auto& line : twoCharMappings) { + charConvertMap[line.from] = line.to; } - g_charConvertMapInit_AddBullshitExceptions(); + + m_charConvertMap.initialize(std::move(charConvertMap)); } void CharDownConvert::TransformCharCachedAppend(t_uint32 c, pfc::string_base& out) { - auto subst = m_charConvertMap.find(c); - if (subst != m_charConvertMap.end()) { - out << subst->second.ptr(); + auto subst = m_charConvertMap.query_ptr(c); + if (subst != nullptr) { + out << subst->ptr(); } else { out.add_char(c); } } + void CharDownConvert::TransformStringHere(pfc::string_base& out, const char* src, size_t len) { + out.reset(); this->TransformStringAppend(out, src, len); + } - void CharDownConvert::TransformStringAppend(pfc::string_base& out, const char* src) { - for (;;) { - char c = *src; + void CharDownConvert::TransformStringAppend(pfc::string_base& out, const char* src, size_t len) { + size_t walk = 0; + while(walk < len) { + char c = src[walk]; if (c > 0) { out.add_byte(pfc::ascii_tolower_lookup(c)); - ++src; + ++walk; } else if (c == 0) { break; } else { unsigned c; t_size d; - d = pfc::utf8_decode_char(src, c); + d = pfc::utf8_decode_char(src + walk, c, len - walk); if (d == 0) break; TransformCharCachedAppend(c, out); - src += d; + walk += d; } } } - void CharDownConvert::g_charConvertMapInit_AddBullshitExceptions() { - for (auto& line : twoCharMappings) { - m_charConvertMap[line.from] = line.to; - } - } CharDownConvert& CharDownConvert::instance() { static CharDownConvert obj; return obj; } diff --git a/sdk/pfc/charDownConvert.h b/sdk/pfc/charDownConvert.h index 1cf825d..536acda 100644 --- a/sdk/pfc/charDownConvert.h +++ b/sdk/pfc/charDownConvert.h @@ -1,10 +1,8 @@ #pragma once #include "string_base.h" -#include - -// This converts to ASCII *and* lowercases for matching -// Legacy feature, do not use in new code +#include "fixed_map.h" +// This converts to ASCII *and* lowercases for simplified search matching namespace pfc { class CharStorage { public: @@ -35,7 +33,8 @@ namespace pfc { CharDownConvert(); void TransformCharCachedAppend(t_uint32 c, pfc::string_base& out); - void TransformStringAppend(pfc::string_base& out, const char* src); + void TransformStringAppend(pfc::string_base& out, const char* src, size_t len = SIZE_MAX); + void TransformStringHere(pfc::string_base& out, const char* src, size_t len = SIZE_MAX); string8 TransformString(const char* src) { pfc::string8 ret; TransformStringAppend(ret, src); return ret; } void TransformString(pfc::string_base& out, const char* src) { out.reset(); TransformStringAppend(out, src); @@ -50,10 +49,6 @@ namespace pfc { static size_t numMappings(); private: - - void g_charConvertMapInit_AddBullshitExceptions(); - private: - std::map m_charConvertMap; + fixed_map m_charConvertMap; }; } - diff --git a/sdk/pfc/pfc-license.txt b/sdk/pfc/pfc-license.txt index 3f05fcc..0ab480d 100644 --- a/sdk/pfc/pfc-license.txt +++ b/sdk/pfc/pfc-license.txt @@ -1,4 +1,4 @@ -Copyright (C) 2002-2022 Peter Pawlowski +Copyright (C) 2002-2023 Peter Pawlowski This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/sdk/pfc/string_base.cpp b/sdk/pfc/string_base.cpp index 15005b1..bca94a4 100644 --- a/sdk/pfc/string_base.cpp +++ b/sdk/pfc/string_base.cpp @@ -902,6 +902,15 @@ string8 format_time_ex(double p_seconds,unsigned p_extra) { return ret; } +void stringToUpperHere(string_base& p_out, const char* p_source, t_size p_sourceLen) { + p_out.clear(); + stringToUpperAppend(p_out, p_source, p_sourceLen); +} +void stringToLowerHere(string_base& p_out, const char* p_source, t_size p_sourceLen) { + p_out.clear(); + stringToLowerAppend(p_out, p_source, p_sourceLen); +} + void stringToUpperAppend(string_base & out, const char * src, t_size len) { while(len && *src) { unsigned c; t_size d; diff --git a/sdk/pfc/string_base.h b/sdk/pfc/string_base.h index df3148e..a2ae836 100644 --- a/sdk/pfc/string_base.h +++ b/sdk/pfc/string_base.h @@ -310,8 +310,10 @@ namespace pfc { namespace pfc { - void stringToUpperAppend(string_base & p_out, const char * p_source, t_size p_sourceLen); - void stringToLowerAppend(string_base & p_out, const char * p_source, t_size p_sourceLen); + void stringToUpperAppend(string_base & p_out, const char * p_source, t_size p_sourceLen = SIZE_MAX); + void stringToLowerAppend(string_base & p_out, const char * p_source, t_size p_sourceLen = SIZE_MAX); + void stringToUpperHere(string_base& p_out, const char* p_source, t_size p_sourceLen = SIZE_MAX); + void stringToLowerHere(string_base& p_out, const char* p_source, t_size p_sourceLen = SIZE_MAX); t_uint32 charLower(t_uint32 param); t_uint32 charUpper(t_uint32 param); char ascii_tolower_lookup(char c); diff --git a/sdk/pfc/synchro_win.h b/sdk/pfc/synchro_win.h index c52a193..70e44c8 100644 --- a/sdk/pfc/synchro_win.h +++ b/sdk/pfc/synchro_win.h @@ -43,8 +43,7 @@ namespace pfc { // Warning, non-recursion proof class readWriteLock { public: - readWriteLock() : theLock() { - } + readWriteLock() {} void enterRead() { AcquireSRWLockShared( & theLock ); @@ -63,7 +62,7 @@ class readWriteLock { readWriteLock(const readWriteLock&) = delete; void operator=(const readWriteLock&) = delete; - SRWLOCK theLock; + SRWLOCK theLock = SRWLOCK_INIT; }; typedef ::_critical_section_base mutexBase_t; diff --git a/sdk/sdk-license.txt b/sdk/sdk-license.txt index eac453f..0824e77 100644 --- a/sdk/sdk-license.txt +++ b/sdk/sdk-license.txt @@ -1,5 +1,5 @@ -foobar2000 1.6 SDK -Copyright (c) 2001-2021, Peter Pawlowski +foobar2000 2.0 SDK +Copyright (c) 2001-2023, Peter Pawlowski All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/sdk/sdk-readme.html b/sdk/sdk-readme.html index 69b897c..6652f30 100644 --- a/sdk/sdk-readme.html +++ b/sdk/sdk-readme.html @@ -8,7 +8,7 @@

-foobar2000 SDK, version 2022-11-16 +foobar2000 SDK, version 2023-01-18

Documentation:
From 09dcdc5ddf9a8fb945e7e674d1e56cdd12efac87 Mon Sep 17 00:00:00 2001 From: Hyperblast Date: Wed, 12 Feb 2025 08:15:59 +0500 Subject: [PATCH 04/12] update to SDK-2023-02-22 --- cmake/FileLists.cmake | 1 + sdk/foobar2000/SDK/audio_chunk.h | 29 ++--- .../SDK/audio_chunk_channel_config.cpp | 45 +++----- sdk/foobar2000/SDK/configStore.h | 6 +- sdk/foobar2000/SDK/filesystem.cpp | 3 +- sdk/foobar2000/SDK/foobar2000-versions.h | 2 +- sdk/foobar2000/SDK/menu.h | 15 +-- sdk/foobar2000/SDK/playlist_loader.cpp | 99 ++++++++++-------- sdk/foobar2000/helpers/cfg_objList.h | 7 +- sdk/foobar2000/helpers/text_file_loader_v2.h | 2 +- .../helpers/window_placement_helper.cpp | 2 +- sdk/foobar2000/shared/shared-ARM64.lib | Bin 36368 -> 36368 bytes sdk/foobar2000/shared/shared-ARM64EC.lib | Bin 40094 -> 40094 bytes sdk/foobar2000/shared/shared-Win32.lib | Bin 38516 -> 38516 bytes sdk/foobar2000/shared/shared-x64.lib | Bin 36368 -> 36368 bytes sdk/libPPUI/Controls.cpp | 2 + sdk/libPPUI/Controls.h | 6 +- sdk/libPPUI/DarkMode-CHyperLink.h | 35 +++++++ sdk/libPPUI/DarkMode.cpp | 20 ++-- sdk/libPPUI/libPPUI.vcxproj | 1 + sdk/libPPUI/libPPUI.vcxproj.filters | 3 + sdk/libPPUI/windowLifetime.h | 20 ++++ sdk/pfc/nix-objects.cpp | 3 +- sdk/pfc/nix-objects.h | 2 +- sdk/pfc/primitives.h | 15 +-- sdk/pfc/win-objects.h | 2 +- sdk/sdk-readme.html | 4 +- 27 files changed, 199 insertions(+), 125 deletions(-) create mode 100644 sdk/libPPUI/DarkMode-CHyperLink.h diff --git a/cmake/FileLists.cmake b/cmake/FileLists.cmake index 7454c3b..dc2c71c 100644 --- a/cmake/FileLists.cmake +++ b/cmake/FileLists.cmake @@ -572,6 +572,7 @@ set( sdk/libPPUI/CPropVariant.h sdk/libPPUI/CWindowCreateAndDelete.h sdk/libPPUI/CDialogResizeHelper.h + sdk/libPPUI/DarkMode-CHyperLink.h sdk/libPPUI/DarkMode.h sdk/libPPUI/DarkModeEx.h sdk/libPPUI/gdi-types-portable.h diff --git a/sdk/foobar2000/SDK/audio_chunk.h b/sdk/foobar2000/SDK/audio_chunk.h index 0cfab4f..bc8b7dd 100644 --- a/sdk/foobar2000/SDK/audio_chunk.h +++ b/sdk/foobar2000/SDK/audio_chunk.h @@ -41,19 +41,22 @@ class NOVTABLE audio_chunk { channel_top_back_center = 1<<16, channel_top_back_right = 1<<17, + channels_back_left_right = channel_back_left | channel_back_right, + channels_side_left_right = channel_side_left | channel_side_right, + channel_config_mono = channel_front_center, channel_config_stereo = channel_front_left | channel_front_right, - channel_config_2point1 = channel_front_left | channel_front_right | channel_lfe, - channel_config_3point0 = channel_front_left | channel_front_right | channel_front_center, - channel_config_4point0 = channel_front_left | channel_front_right | channel_back_left | channel_back_right, - channel_config_4point1 = channel_front_left | channel_front_right | channel_back_left | channel_back_right | channel_lfe, - channel_config_5point0 = channel_front_left | channel_front_right | channel_front_center | channel_back_left | channel_back_right, - channel_config_5point1 = channel_front_left | channel_front_right | channel_front_center | channel_lfe | channel_back_left | channel_back_right, - 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, + channel_config_2point1 = channel_config_stereo | channel_lfe, + channel_config_3point0 = channel_config_stereo | channel_front_center, + channel_config_4point0 = channel_config_stereo | channels_back_left_right, + channel_config_4point0_side = channel_config_stereo | channels_side_left_right, + channel_config_4point1 = channel_config_4point0 | channel_lfe, + channel_config_5point0 = channel_config_4point0 | channel_front_center, + channel_config_6point0 = channel_config_4point0 | channels_side_left_right, + channel_config_5point1 = channel_config_4point0 | channel_front_center | channel_lfe, + channel_config_5point1_side = channel_config_4point0_side | channel_front_center | channel_lfe, + channel_config_7point1 = channel_config_5point1 | channels_side_left_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, }; @@ -64,14 +67,14 @@ class NOVTABLE audio_chunk { static unsigned g_guess_channel_config_xiph(unsigned count); //! Helper function; translates audio_chunk channel map to WAVEFORMATEXTENSIBLE channel map. - static uint32_t g_channel_config_to_wfx(unsigned p_config); + static constexpr uint32_t g_channel_config_to_wfx(unsigned p_config) { return p_config;} //! Helper function; translates WAVEFORMATEXTENSIBLE channel map to audio_chunk channel map. - static unsigned g_channel_config_from_wfx(uint32_t p_wfx); + static constexpr unsigned g_channel_config_from_wfx(uint32_t p_wfx) { return p_wfx;} //! Extracts flag describing Nth channel from specified map. Usable to figure what specific channel in a stream means. static unsigned g_extract_channel_flag(unsigned p_config,unsigned p_index); //! Counts channels specified by channel map. - static unsigned g_count_channels(unsigned p_config); + static constexpr unsigned g_count_channels(unsigned p_config) { return pfc::countBits32(p_config); } //! Calculates index of a channel specified by p_flag in a stream where channel map is described by p_config. static unsigned g_channel_index_from_flag(unsigned p_config,unsigned p_flag); diff --git a/sdk/foobar2000/SDK/audio_chunk_channel_config.cpp b/sdk/foobar2000/SDK/audio_chunk_channel_config.cpp index 9cf83e2..85a92cd 100644 --- a/sdk/foobar2000/SDK/audio_chunk_channel_config.cpp +++ b/sdk/foobar2000/SDK/audio_chunk_channel_config.cpp @@ -50,34 +50,6 @@ static struct {DWORD m_wfx; unsigned m_native; } const g_translation_table[] = #endif #endif -// foobar2000 channel flags are 1:1 identical to Windows WFX ones. -uint32_t audio_chunk::g_channel_config_to_wfx(unsigned p_config) -{ - return p_config; -#if 0 - DWORD ret = 0; - unsigned n; - for(n=0;n( PFC_string_formatter() << "Unknown I/O error (#" << code << ")"); diff --git a/sdk/foobar2000/SDK/foobar2000-versions.h b/sdk/foobar2000/SDK/foobar2000-versions.h index e3c007d..3daeeed 100644 --- a/sdk/foobar2000/SDK/foobar2000-versions.h +++ b/sdk/foobar2000/SDK/foobar2000-versions.h @@ -19,4 +19,4 @@ // Use this to determine what foobar2000 SDK version is in use, undefined for releases older than 2018 -#define FOOBAR2000_SDK_VERSION 20230118 \ No newline at end of file +#define FOOBAR2000_SDK_VERSION 20230222 \ No newline at end of file diff --git a/sdk/foobar2000/SDK/menu.h b/sdk/foobar2000/SDK/menu.h index d9fa494..66a33c7 100644 --- a/sdk/foobar2000/SDK/menu.h +++ b/sdk/foobar2000/SDK/menu.h @@ -143,19 +143,22 @@ class mainmenu_group_popup_impl : public mainmenu_group_popup { GUID m_guid,m_parent; t_uint32 m_priority; pfc::string8 m_name; }; -typedef service_factory_single_t __mainmenu_group_factory; -typedef service_factory_single_t __mainmenu_group_popup_factory; +typedef service_factory_single_t _mainmenu_group_factory; +typedef service_factory_single_t _mainmenu_group_popup_factory; -class mainmenu_group_factory : public __mainmenu_group_factory { +class mainmenu_group_factory : public _mainmenu_group_factory { public: - mainmenu_group_factory(const GUID & p_guid,const GUID & p_parent,t_uint32 p_priority) : __mainmenu_group_factory(p_guid,p_parent,p_priority) {} + mainmenu_group_factory(const GUID & p_guid,const GUID & p_parent,t_uint32 p_priority) : _mainmenu_group_factory(p_guid,p_parent,p_priority) {} }; -class mainmenu_group_popup_factory : public __mainmenu_group_popup_factory { +class mainmenu_group_popup_factory : public _mainmenu_group_popup_factory { public: - mainmenu_group_popup_factory(const GUID & p_guid,const GUID & p_parent,t_uint32 p_priority,const char * p_name) : __mainmenu_group_popup_factory(p_guid,p_parent,p_priority,p_name) {} + mainmenu_group_popup_factory(const GUID & p_guid,const GUID & p_parent,t_uint32 p_priority,const char * p_name) : _mainmenu_group_popup_factory(p_guid,p_parent,p_priority,p_name) {} }; +#define FB2K_DECLARE_MAINMENU_GROUP( guid, parent, priority, name ) FB2K_SERVICE_FACTORY_PARAMS(mainmenu_group_impl, guid, parent, priority, name ); +#define FB2K_DECLARE_MAINMENU_GROUP_POPUP( guid, parent, priority, name ) FB2K_SERVICE_FACTORY_PARAMS(mainmenu_group_popup_impl, guid, parent, priority, name ); + template class mainmenu_commands_factory_t : public service_factory_single_t {}; diff --git a/sdk/foobar2000/SDK/playlist_loader.cpp b/sdk/foobar2000/SDK/playlist_loader.cpp index 6dab850..26c92bc 100644 --- a/sdk/foobar2000/SDK/playlist_loader.cpp +++ b/sdk/foobar2000/SDK/playlist_loader.cpp @@ -5,8 +5,10 @@ #include "file_info_impl.h" #include "input.h" #include "advconfig.h" +#include +#include +#include -#if FOOBAR2000_TARGET_VERSION >= 76 static void process_path_internal(const char * p_path,const service_ptr_t & p_reader,playlist_loader_callback::ptr callback, abort_callback & abort,playlist_loader_callback::t_entry_type type,const t_filestats & p_stats); namespace { @@ -216,61 +218,71 @@ namespace { return false; } - // SPECIAL HACK - // filesystem service does not present file hidden attrib but we want to weed files/folders out - // so check separately on all native paths (inefficient but meh) class directory_callback_myimpl : public directory_callback { public: - directory_callback_myimpl() : m_addHidden(queryAddHidden()) {} + void main(const char* folder, abort_callback& abort) { + visit(folder); + + abort.check(); + const uint32_t flags = listMode::filesAndFolders | (queryAddHidden() ? listMode::hidden : 0); + + auto workHere = [&] (folder_t const & f) { + filesystem_v2::ptr v2; + if (v2 &= f.m_fs) { + v2->list_directory_ex(f.m_folder.c_str(), *this, flags, abort); + } else { + f.m_fs->list_directory(f.m_folder.c_str(), *this, abort); + } + }; + + workHere( folder_t { folder, filesystem::get(folder) } ); + + for (;; ) { + abort.check(); + auto iter = m_foldersPending.begin(); + if ( iter == m_foldersPending.end() ) break; + auto f = std::move(*iter); m_foldersPending.erase(iter); + + try { + workHere( f ); + } catch (exception_io const & e) { + FB2K_console_formatter() << "Error walking directory (" << e << "): " << f.m_folder.c_str(); + } + } + } bool on_entry(filesystem * owner,abort_callback & p_abort,const char * url,bool is_subdirectory,const t_filestats & p_stats) { p_abort.check(); + if (!visit(url)) return true; filesystem_v2::ptr v2; v2 &= owner; if ( is_subdirectory ) { - try { - if (v2.is_valid()) { - v2->list_directory_ex(url, *this, flags(), p_abort); - } else { - owner->list_directory(url, *this, p_abort); - } - } catch (exception_io const & e) { - FB2K_console_formatter() << "Error walking directory (" << e << "): " << url; - } + m_foldersPending.emplace_back( folder_t { url, owner } ); } else { - // In fb2k 1.4 the default filesystem is v2 and performs hidden file checks -#if FOOBAR2000_TARGET_VERSION < 79 - if ( ! m_addHidden && v2.is_empty() ) { - const char * n = url; - if (_extract_native_path_ptr(n)) { - DWORD att = uGetFileAttributes(n); - if (att == ~0 || (att & FILE_ATTRIBUTE_HIDDEN) != 0) return true; - } - } -#endif - auto i = m_entries.insert_last(); - i->m_path = url; - i->m_stats = p_stats; + m_entries.emplace_back( entry_t { url, p_stats } ); } return true; } - uint32_t flags() const { - uint32_t flags = listMode::filesAndFolders; - if (m_addHidden) flags |= listMode::hidden; - return flags; - } - - const bool m_addHidden; struct entry_t { - pfc::string8 m_path; + std::string m_path; t_filestats m_stats; }; - pfc::chain_list_v2_t m_entries; + std::list m_entries; + bool visit(const char* path) { + return m_visited.insert( path ).second; + } + std::unordered_set m_visited; + + struct folder_t { + std::string m_folder; + filesystem::ptr m_fs; + }; + std::list m_foldersPending; }; } @@ -288,19 +300,16 @@ static void process_path_internal(const char * p_path,const service_ptr_t if (p_reader.is_empty() && type != playlist_loader_callback::entry_directory_enumerated) { try { directory_callback_myimpl results; - auto fs = filesystem::get(p_path); - filesystem_v2::ptr v2; - if ( v2 &= fs ) v2->list_directory_ex(p_path, results, results.flags(), abort ); - else fs->list_directory(p_path, results, abort); - for( auto i = results.m_entries.first(); i.is_valid(); ++i ) { + results.main( p_path, abort ); + for( auto & i : results.m_entries ) { try { - process_path_internal(i->m_path, 0, callback, abort, playlist_loader_callback::entry_directory_enumerated, i->m_stats); + process_path_internal(i.m_path.c_str(), 0, callback, abort, playlist_loader_callback::entry_directory_enumerated, i.m_stats); } catch (exception_aborted) { throw; } catch (std::exception const& e) { - FB2K_console_formatter() << "Error walking path (" << e << "): " << file_path_display(i->m_path); + FB2K_console_formatter() << "Error walking path (" << e << "): " << file_path_display(i.m_path.c_str()); } catch (...) { - FB2K_console_formatter() << "Error walking path (bad exception): " << file_path_display(i->m_path); + FB2K_console_formatter() << "Error walking path (bad exception): " << file_path_display(i.m_path.c_str()); } } return; // successfully enumerated directory - go no further @@ -458,5 +467,3 @@ bool playlist_loader::g_process_path_ex(const char * filename,playlist_loader_ca g_process_path(filename,callback,abort,type); return false; } - -#endif \ No newline at end of file diff --git a/sdk/foobar2000/helpers/cfg_objList.h b/sdk/foobar2000/helpers/cfg_objList.h index 293bd9a..e2b5a24 100644 --- a/sdk/foobar2000/helpers/cfg_objList.h +++ b/sdk/foobar2000/helpers/cfg_objList.h @@ -23,17 +23,20 @@ namespace cfg_var_modern { if (gone > 0) save(); return gone; } + //! Returns number of items removed. template size_t remove_if(pred_t&& p) { init(); PFC_INSYNC_WRITE(m_listGuard); - size_t gone = pfc::remove_if_t(m_list, std::forward(p)); + const auto nBefore = m_list.size(); + const size_t nAfter = pfc::remove_if_t(m_list, std::forward(p)); + const auto gone = nAfter - nBefore; if (gone > 0) save(); return gone; } bool remove_item(obj_t const& v) { return remove_if([&v](const obj_t& arg) { return v == arg; }) != 0; } - size_t size() { init(); return m_list.size(); } + size_t size() { init(); PFC_INSYNC_READ(m_listGuard);return m_list.size(); } size_t get_count() { return size(); } size_t get_size() { return size(); } diff --git a/sdk/foobar2000/helpers/text_file_loader_v2.h b/sdk/foobar2000/helpers/text_file_loader_v2.h index a4ecb68..fe2e861 100644 --- a/sdk/foobar2000/helpers/text_file_loader_v2.h +++ b/sdk/foobar2000/helpers/text_file_loader_v2.h @@ -8,7 +8,7 @@ class text_file_loader_v2 { void load(file::ptr f, abort_callback & abort); - std::vector< const char * > m_lines; + std::vector< char * > m_lines; pfc::string8 m_data; }; \ No newline at end of file diff --git a/sdk/foobar2000/helpers/window_placement_helper.cpp b/sdk/foobar2000/helpers/window_placement_helper.cpp index d9bfe4e..42f42ae 100644 --- a/sdk/foobar2000/helpers/window_placement_helper.cpp +++ b/sdk/foobar2000/helpers/window_placement_helper.cpp @@ -63,7 +63,7 @@ bool cfg_window_placement::read_from_window(HWND window) }*/ } - set(wp); + try { set(wp); } catch(...) {} // this tends to be called often / we really couldn't care less about this failing return wp.length == sizeof(wp); } diff --git a/sdk/foobar2000/shared/shared-ARM64.lib b/sdk/foobar2000/shared/shared-ARM64.lib index c95dd58528ea93ed541e191538988e0a95f54a45..d9ca039b2bf095aeb7c3a2fd4c98757b93846e26 100644 GIT binary patch delta 94 zcmbO*hiSqbrVUlDESqBTE>Es=UC(%IvYuNMkc{<^p1j2E5370Wo(DT7-}aE7e8fE+ iEUPhjohJuaMJ0>XtjfcaZ+SqpslX+qH(&C!a{&OFBPcWg delta 94 zcmbO*hiSqbrVUlDEcT~F&rhy%UC(%MvYuNMkc{<^p1j2E534kH%e5VoZ+pm3KH{DZ imerWN&XWVIqLO9*iK$m6-|~QHQ-MoJZ@%Pd=K=s-TqnE$ diff --git a/sdk/foobar2000/shared/shared-ARM64EC.lib b/sdk/foobar2000/shared/shared-ARM64EC.lib index b464ad489bc21f9e843ac8fbc1f275d19ee01353..989114839d671b527b055f68f3806bc3d0adaf84 100644 GIT binary patch delta 125 zcmbQYlWE>grVZ!ZIR7!Nea*$lz`!y2uZQ$xKQHOYyzV88$0j#;YD`|`ZUkg)^pu|b z!~G9yMUcVC9h3FFgrVZ!ZIN!KrUgctBVBnbi*F$=;pO^GxUiT8lgOeLPH72ieHv+OYdP-0J z;r@r!x9!)b9h3FF5!bCTcDSj0@14G{e*K@ RR^eS81_p-y&B8w20RWZ3GNb?i diff --git a/sdk/foobar2000/shared/shared-Win32.lib b/sdk/foobar2000/shared/shared-Win32.lib index d1a8991744963ae04bfbd6c9503cece8202bc1bb..d1a4b5f0e1e98b2dea4938e45a0031f1fd243150 100644 GIT binary patch delta 111 zcmeyehUv>1rVV;NoV9uupSc(r7&s=!`bke-=Px}u*QbQ>*yIO(8k4zvjesmcpjd?O zAJ)>nows&O?)R6UT;Z1vR$%~^tz_wIue&k1&wo8wP=?bXIX|~RFEa(Kb#q<7H&+0a Cu`N6R delta 111 zcmeyehUv>1rVV;NoClodKHy?xVBnY>>nA;Voxk+tT%QuggOeZlX-wwwH3G5(fnpK9 ze^^hx}NdaWIeYiAQ|f+J$Z@SAJ$EG-CpmQeA`2Q@)7rR iu&l=9b)Fnx6_qTZf!)6*-|~QHQ-MoJZ@%Pd=K=uWbtyjp delta 94 zcmbO*hiSqbrVUlDEa@)srVZ+pm3KH{DZ imerWN&XWVIqLRhha^|hcw>%))RNxZQn=g6Vxc~rE-zMz< diff --git a/sdk/libPPUI/Controls.cpp b/sdk/libPPUI/Controls.cpp index 68ce658..4e967ec 100644 --- a/sdk/libPPUI/Controls.cpp +++ b/sdk/libPPUI/Controls.cpp @@ -11,6 +11,7 @@ void CSeparator::OnPaint(CDCHandle dc) { PaintUtils::PaintSeparatorControl(*this); } +#if 0 // BROKEN WITH DARK MODE, DO NOT USE CStaticMainInstruction::CStaticMainInstruction() { SetThemePart(TEXT_MAININSTRUCTION); } @@ -48,3 +49,4 @@ void CStaticThemed::OnPaint(CDCHandle) { PFC_ASSERT(SUCCEEDED(retval)); } } +#endif \ No newline at end of file diff --git a/sdk/libPPUI/Controls.h b/sdk/libPPUI/Controls.h index 374c488..b1ecf03 100644 --- a/sdk/libPPUI/Controls.h +++ b/sdk/libPPUI/Controls.h @@ -46,7 +46,9 @@ class CTextControl : public CWindowRegisteredT { CFontHandle m_font; }; - +// CStaticThemed BROKEN WITH DARK MODE, DO NOT USE +// CStaticMainInstruction = use 1.5x scaled font for non subclassed static instead +#if 0 // Static control subclass with override for theme part used for rendering class CStaticThemed : public CWindowImpl { public: @@ -78,7 +80,7 @@ class CStaticMainInstruction : public CStaticThemed { public: CStaticMainInstruction(); }; - +#endif class CSeparator : public CTextControl { diff --git a/sdk/libPPUI/DarkMode-CHyperLink.h b/sdk/libPPUI/DarkMode-CHyperLink.h new file mode 100644 index 0000000..534a0b0 --- /dev/null +++ b/sdk/libPPUI/DarkMode-CHyperLink.h @@ -0,0 +1,35 @@ +#pragma once +#include +#include "DarkMode.h" + +namespace DarkMode { + template class CHyperLinkImpl : public ::CHyperLinkImpl { + public: + BEGIN_MSG_MAP_EX(CDarkHyperLinkImpl) + MESSAGE_HANDLER_EX(DarkMode::msgSetDarkMode(), OnSetDarkMode) + CHAIN_MSG_MAP(::CHyperLinkImpl) + END_MSG_MAP() + private: + LRESULT OnSetDarkMode(UINT, WPARAM wp, LPARAM) { + const bool bDark = (wp != 0); + if ( m_clrLinkBackup == CLR_INVALID ) m_clrLinkBackup = this->m_clrLink; + + if (bDark != m_isDark) { + m_isDark = bDark; + m_clrLink = bDark ? DarkMode::GetSysColor(COLOR_HOTLIGHT) : m_clrLinkBackup; + Invalidate(); + } + + return 1; + } + COLORREF m_clrLinkBackup = CLR_INVALID; + bool m_isDark = false; + }; + + + class CHyperLink : public CHyperLinkImpl { + public: + DECLARE_WND_CLASS(_T("WTL_DarkHyperLink")) + }; + +} diff --git a/sdk/libPPUI/DarkMode.cpp b/sdk/libPPUI/DarkMode.cpp index 962c98d..5f97d19 100644 --- a/sdk/libPPUI/DarkMode.cpp +++ b/sdk/libPPUI/DarkMode.cpp @@ -965,7 +965,8 @@ namespace DarkMode { const DWORD uiState = (DWORD)SendMessage(WM_QUERYUISTATE); - const bool bPressed = (ctrlState & BST_CHECKED) != 0; + const bool bChecked = (ctrlState & BST_CHECKED) != 0; + const bool bMixed = (ctrlState & BST_INDETERMINATE) != 0; const bool bHot = (ctrlState & BST_HOT) != 0; const bool bFocus = (ctrlState & BST_FOCUS) != 0 && (uiState & UISF_HIDEFOCUS) == 0; @@ -977,11 +978,17 @@ namespace DarkMode { if (theme != NULL && IsThemePartDefined(theme, part, 0)) { int state = 0; if (bDisabled) { - state = bPressed ? CBS_CHECKEDDISABLED : CBS_UNCHECKEDDISABLED; + if ( bChecked ) state = CBS_CHECKEDDISABLED; + else if ( bMixed ) state = CBS_MIXEDDISABLED; + else state = CBS_UNCHECKEDDISABLED; } else if (bHot) { - state = bPressed ? CBS_CHECKEDHOT : CBS_UNCHECKEDHOT; + if ( bChecked ) state = CBS_CHECKEDHOT; + else if ( bMixed ) state = CBS_MIXEDHOT; + else state = CBS_UNCHECKEDNORMAL; } else { - state = bPressed ? CBS_CHECKEDNORMAL : CBS_UNCHECKEDNORMAL; + if ( bChecked ) state = CBS_CHECKEDNORMAL; + else if ( bMixed ) state = CBS_MIXEDNORMAL; + else state = CBS_UNCHECKEDNORMAL; } CSize size; @@ -1001,7 +1008,8 @@ namespace DarkMode { if (theme != NULL) CloseThemeData(theme); if (!bDrawn) { int stateEx = bRadio ? DFCS_BUTTONRADIO : DFCS_BUTTONCHECK; - if (bPressed) stateEx |= DFCS_CHECKED; + if (bChecked) stateEx |= DFCS_CHECKED; + // FIX ME bMixed ? if (bDisabled) stateEx |= DFCS_INACTIVE; else if (bHot) stateEx |= DFCS_HOT; @@ -1490,7 +1498,7 @@ namespace DarkMode { CButton btn(wnd); auto style = btn.GetButtonStyle(); auto type = style & BS_TYPEMASK; - if ((type == BS_CHECKBOX || type == BS_AUTOCHECKBOX || type == BS_RADIOBUTTON || type == BS_AUTORADIOBUTTON) && (style & BS_PUSHLIKE) == 0) { + if ((type == BS_CHECKBOX || type == BS_AUTOCHECKBOX || type == BS_RADIOBUTTON || type == BS_AUTORADIOBUTTON || type == BS_3STATE || type == BS_AUTO3STATE) && (style & BS_PUSHLIKE) == 0) { // MS checkbox implementation is terminally retarded and won't draw text in correct color // Subclass it and draw our own content // Other button types seem OK diff --git a/sdk/libPPUI/libPPUI.vcxproj b/sdk/libPPUI/libPPUI.vcxproj index 4aedc64..e49f3ac 100644 --- a/sdk/libPPUI/libPPUI.vcxproj +++ b/sdk/libPPUI/libPPUI.vcxproj @@ -352,6 +352,7 @@ + diff --git a/sdk/libPPUI/libPPUI.vcxproj.filters b/sdk/libPPUI/libPPUI.vcxproj.filters index eba3ed5..5b67d43 100644 --- a/sdk/libPPUI/libPPUI.vcxproj.filters +++ b/sdk/libPPUI/libPPUI.vcxproj.filters @@ -194,6 +194,9 @@ Header Files + + Header Files + diff --git a/sdk/libPPUI/windowLifetime.h b/sdk/libPPUI/windowLifetime.h index 6a7e9bc..f1f7ca8 100644 --- a/sdk/libPPUI/windowLifetime.h +++ b/sdk/libPPUI/windowLifetime.h @@ -19,4 +19,24 @@ namespace PP { WIN32_OP_D(ret->SubclassWindow(wnd)); return ret; } + + //! Creates a new window object, of ctrl_t typem with automatic lifetime management, + //! and replaces an existing control in a dialog. + template + ctrl_t * replaceDialogCtrl(CWindow wndDialog, UINT replaceControlID) { + CWindow wndReplace = wndDialog.GetDlgItem(replaceControlID); + ATLASSERT(wndReplace != NULL); + CRect rc; + CWindow wndPrev = wndDialog.GetNextDlgTabItem(wndReplace, TRUE); + WIN32_OP_D(wndReplace.GetWindowRect(&rc)); + WIN32_OP_D(wndDialog.ScreenToClient(rc)); + CString text; + wndReplace.GetWindowText(text); + WIN32_OP_D(wndReplace.DestroyWindow()); + auto ctrl = newWindowObj(); + WIN32_OP_D(ctrl->Create(wndDialog, &rc, text, 0, 0, replaceControlID)); + if (wndPrev != NULL) ctrl->SetWindowPos(wndPrev, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); + ctrl->SetFont(wndDialog.GetFont()); + return ctrl; + } } \ No newline at end of file diff --git a/sdk/pfc/nix-objects.cpp b/sdk/pfc/nix-objects.cpp index b3012a0..e35ed1c 100644 --- a/sdk/pfc/nix-objects.cpp +++ b/sdk/pfc/nix-objects.cpp @@ -187,10 +187,11 @@ namespace pfc { return sel.Select( timeOutSeconds ) > 0; } - nix_event::nix_event() { + nix_event::nix_event(bool state) { createPipe( m_fd ); setNonBlocking( m_fd[0] ); setNonBlocking( m_fd[1] ); + if ( state ) set_state(true); } nix_event::~nix_event() { close( m_fd[0] ); diff --git a/sdk/pfc/nix-objects.h b/sdk/pfc/nix-objects.h index d7bc8e6..c795a64 100644 --- a/sdk/pfc/nix-objects.h +++ b/sdk/pfc/nix-objects.h @@ -77,7 +77,7 @@ namespace pfc { class nix_event { public: - nix_event(); + nix_event(bool state = false); ~nix_event(); void set_state( bool state ); diff --git a/sdk/pfc/primitives.h b/sdk/pfc/primitives.h index 71a13f9..dc9f675 100644 --- a/sdk/pfc/primitives.h +++ b/sdk/pfc/primitives.h @@ -723,20 +723,22 @@ namespace pfc { t_int32 rint32(double p_val); t_int64 rint64(double p_val); - - + //! Returns amount of items left. template inline size_t remove_if_t( array_t & arr, pred_t pred ) { const size_t inCount = arr.size(); size_t walk = 0; - - for( walk = 0; walk < inCount; ++ walk ) { + for (;; ) { + if ( walk == inCount ) return inCount; if ( pred(arr[walk]) ) break; + ++ walk; } size_t total = walk; + ++ walk; // already know that at walk is pred() positive + for( ; walk < inCount; ++ walk ) { if ( !pred(arr[walk] ) ) { move_t(arr[total++], arr[walk]); @@ -747,8 +749,9 @@ namespace pfc { return total; } + //! Returns amount of items left. template - inline t_size remove_mask_t(t_array & p_array,const bit_array & p_mask)//returns amount of items left + inline t_size remove_mask_t(t_array & p_array,const bit_array & p_mask) { t_size n,count = p_array.size(), total = 0; @@ -882,7 +885,7 @@ namespace pfc { template incrementScope autoIncrement(obj_t& v) { return incrementScope(v); } - inline unsigned countBits32(uint32_t i) { + constexpr inline unsigned countBits32(uint32_t i) { const uint32_t mask = 0x11111111; uint32_t acc = i & mask; acc += (i >> 1) & mask; diff --git a/sdk/pfc/win-objects.h b/sdk/pfc/win-objects.h index 3ca3aa5..7a98e91 100644 --- a/sdk/pfc/win-objects.h +++ b/sdk/pfc/win-objects.h @@ -168,7 +168,7 @@ namespace pfc { class event : public win32_event { public: - event() { create(true, false); } + event(bool initial = false) { create(true, initial); } HANDLE get_handle() const { return win32_event::get(); } }; diff --git a/sdk/sdk-readme.html b/sdk/sdk-readme.html index 6652f30..8ff0f82 100644 --- a/sdk/sdk-readme.html +++ b/sdk/sdk-readme.html @@ -8,11 +8,11 @@

-foobar2000 SDK, version 2023-01-18 +foobar2000 SDK, version 2023-02-22

Documentation:
-SDK release notes
+SDK release notes
foobar2000 Development Overview

From b749f7f1587aee3ff468f4fb62ced384b563fcc1 Mon Sep 17 00:00:00 2001 From: Hyperblast Date: Wed, 12 Feb 2025 08:21:01 +0500 Subject: [PATCH 05/12] update to SDK-2023-04-18 --- cmake/FileLists.cmake | 3 + sdk/foobar2000/SDK/abort_callback.h | 32 +-- sdk/foobar2000/SDK/advconfig.cpp | 4 - sdk/foobar2000/SDK/advconfig.h | 21 +- sdk/foobar2000/SDK/advconfig_impl.h | 2 + sdk/foobar2000/SDK/advconfig_impl_legacy.h | 125 ++++++----- sdk/foobar2000/SDK/album_art.cpp | 6 + sdk/foobar2000/SDK/album_art.h | 2 + sdk/foobar2000/SDK/app_close_blocker.cpp | 30 ++- sdk/foobar2000/SDK/app_close_blocker.h | 41 ++-- sdk/foobar2000/SDK/archive.h | 9 +- sdk/foobar2000/SDK/audio_postprocessor.h | 1 - sdk/foobar2000/SDK/cfg_var.cpp | 10 +- sdk/foobar2000/SDK/cfg_var_legacy.cpp | 100 ++++++++- sdk/foobar2000/SDK/cfg_var_legacy.h | 93 ++++++-- sdk/foobar2000/SDK/commandline.h | 18 +- sdk/foobar2000/SDK/configStore.h | 8 +- sdk/foobar2000/SDK/dsp.h | 2 +- sdk/foobar2000/SDK/file_info.cpp | 23 +- sdk/foobar2000/SDK/file_info.h | 6 + sdk/foobar2000/SDK/filesystem.cpp | 24 +++ sdk/foobar2000/SDK/filesystem.h | 1 + sdk/foobar2000/SDK/foobar2000-versions.h | 12 +- sdk/foobar2000/SDK/foobar2000_SDK.vcxproj | 1 + .../SDK/foobar2000_SDK.vcxproj.filters | 3 + sdk/foobar2000/SDK/guids.cpp | 11 +- sdk/foobar2000/SDK/main_thread_callback.cpp | 16 ++ sdk/foobar2000/SDK/main_thread_callback.h | 136 ++---------- sdk/foobar2000/SDK/message_loop.h | 51 ++--- sdk/foobar2000/SDK/metadb.cpp | 30 +++ sdk/foobar2000/SDK/metadb.h | 52 ++++- sdk/foobar2000/SDK/metadb_callbacks.h | 24 ++- sdk/foobar2000/SDK/noInfo.h | 1 + sdk/foobar2000/SDK/playlistColumnProvider.h | 10 + sdk/foobar2000/SDK/playlist_loader.cpp | 23 +- sdk/foobar2000/SDK/popup_message.cpp | 2 + sdk/foobar2000/SDK/popup_message.h | 15 +- sdk/foobar2000/SDK/powerManager.h | 9 +- sdk/foobar2000/SDK/threaded_process.cpp | 2 + sdk/foobar2000/SDK/threaded_process.h | 6 +- sdk/foobar2000/SDK/threadsLite.h | 10 +- sdk/foobar2000/SDK/ui_element.cpp | 5 + sdk/foobar2000/SDK/ui_element.h | 25 ++- sdk/foobar2000/SDK/utility.cpp | 42 ++++ sdk/foobar2000/foo_sample/foo_sample.vcxproj | 12 +- .../foo_sample/foo_sample.vcxproj.filters | 1 + sdk/foobar2000/foo_sample/main.cpp | 3 + sdk/foobar2000/foo_sample/packages.config | 4 + sdk/foobar2000/foo_sample/preferences.cpp | 50 ++++- sdk/foobar2000/helpers/CallForwarder.h | 3 +- sdk/foobar2000/helpers/DarkMode.h | 5 + .../helpers/WindowPositionUtils.cpp | 91 +++++++- sdk/foobar2000/helpers/WindowPositionUtils.h | 201 +++--------------- .../helpers/callInMainThreadHelper.h | 127 +++++++++++ .../helpers/foobar2000_sdk_helpers.vcxproj | 11 + .../foobar2000_sdk_helpers.vcxproj.filters | 6 + sdk/foobar2000/helpers/packages.config | 4 + sdk/foobar2000/helpers/readWriteLock.h | 3 +- .../helpers/window_placement_helper.cpp | 42 ++-- .../helpers/window_placement_helper.h | 2 + sdk/foobar2000/shared/shared-ARM64.lib | Bin 36368 -> 36632 bytes sdk/foobar2000/shared/shared-ARM64EC.lib | Bin 40094 -> 40388 bytes sdk/foobar2000/shared/shared-Win32.lib | Bin 38516 -> 38796 bytes sdk/foobar2000/shared/shared-x64.lib | Bin 36368 -> 36632 bytes sdk/foobar2000/shared/shared.h | 1 + sdk/libPPUI/CListControl.cpp | 6 +- sdk/libPPUI/CListControlWithSelection.cpp | 6 +- sdk/libPPUI/DarkMode.cpp | 186 ++++++++++++++-- sdk/libPPUI/DarkMode.h | 3 + sdk/libPPUI/EditBoxFix.cpp | 19 ++ sdk/libPPUI/EditBoxFixes.h | 7 + sdk/libPPUI/PaintUtils.cpp | 3 + sdk/libPPUI/libPPUI.vcxproj | 12 ++ sdk/libPPUI/libPPUI.vcxproj.filters | 9 + sdk/libPPUI/packages.config | 4 + sdk/libPPUI/windowLifetime.h | 2 + sdk/libPPUI/wtl-pp.h | 97 ++------- sdk/pfc/audio_math.cpp | 16 +- sdk/pfc/cpuid.cpp | 12 +- sdk/pfc/cpuid.h | 14 +- sdk/pfc/debug.h | 6 + sdk/pfc/pathUtils.cpp | 18 +- sdk/pfc/string_base.cpp | 23 ++ sdk/pfc/string_base.h | 3 + sdk/pfc/win-objects.cpp | 37 ++++ sdk/pfc/win-objects.h | 3 + sdk/sdk-readme.html | 4 +- 87 files changed, 1416 insertions(+), 687 deletions(-) create mode 100644 sdk/foobar2000/foo_sample/packages.config create mode 100644 sdk/foobar2000/helpers/callInMainThreadHelper.h create mode 100644 sdk/foobar2000/helpers/packages.config create mode 100644 sdk/libPPUI/EditBoxFix.cpp create mode 100644 sdk/libPPUI/EditBoxFixes.h create mode 100644 sdk/libPPUI/packages.config diff --git a/cmake/FileLists.cmake b/cmake/FileLists.cmake index dc2c71c..a0a82ef 100644 --- a/cmake/FileLists.cmake +++ b/cmake/FileLists.cmake @@ -420,6 +420,7 @@ set( sdk/foobar2000/helpers/AutoComplete.h sdk/foobar2000/helpers/BumpableElem.h sdk/foobar2000/helpers/callback_merit.h + sdk/foobar2000/helpers/callInMainThreadHelper.h sdk/foobar2000/helpers/CDialogResizeHelper.h sdk/foobar2000/helpers/cfg_dsp_chain_config.h sdk/foobar2000/helpers/cfg_obj.h @@ -522,6 +523,7 @@ set( sdk/libPPUI/CDialogResizeHelper.cpp sdk/libPPUI/CPowerRequest.cpp sdk/libPPUI/DarkMode.cpp + sdk/libPPUI/EditBoxFix.cpp sdk/libPPUI/gdiplus_helpers.cpp sdk/libPPUI/GDIUtils.cpp sdk/libPPUI/IDataObjectUtils.cpp @@ -575,6 +577,7 @@ set( sdk/libPPUI/DarkMode-CHyperLink.h sdk/libPPUI/DarkMode.h sdk/libPPUI/DarkModeEx.h + sdk/libPPUI/EditBoxFixes.h sdk/libPPUI/gdi-types-portable.h sdk/libPPUI/gdiplus-helpers-webp.h sdk/libPPUI/gdiplus_helpers.h diff --git a/sdk/foobar2000/SDK/abort_callback.h b/sdk/foobar2000/SDK/abort_callback.h index 37ba34f..cfc772d 100644 --- a/sdk/foobar2000/SDK/abort_callback.h +++ b/sdk/foobar2000/SDK/abort_callback.h @@ -50,6 +50,9 @@ class NOVTABLE abort_callback 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); + + abort_callback( const abort_callback & ) = delete; + void operator=( const abort_callback & ) = delete; protected: abort_callback() {} ~abort_callback() {} @@ -57,49 +60,49 @@ class NOVTABLE abort_callback -//! Implementation of abort_callback interface. +//! Standard implementation of abort_callback interface. class abort_callback_impl : public abort_callback { public: - abort_callback_impl() : m_aborting(false) {} + abort_callback_impl() {} inline void abort() {set_state(true);} inline void set() {set_state(true);} inline void reset() {set_state(false);} void set_state(bool p_state) {m_aborting = p_state; m_event.set_state(p_state);} - bool is_aborting() const {return m_aborting;} + bool is_aborting() const override {return m_aborting;} - abort_callback_event get_abort_event() const {return m_event.get_handle();} + abort_callback_event get_abort_event() const override {return m_event.get_handle();} private: abort_callback_impl(const abort_callback_impl &) = delete; const abort_callback_impl & operator=(const abort_callback_impl&) = delete; - volatile bool m_aborting; + volatile bool m_aborting = false; pfc::event m_event; }; - +//! Alternate abort_callback implementation, supply your own event handle to signal abort. \n +//! Slightly less efficient (is_aborting() polls the event instead of reading a bool variable). class abort_callback_usehandle : public abort_callback { public: abort_callback_usehandle( abort_callback_event handle ) : m_handle(handle) {} - bool is_aborting() const; - abort_callback_event get_abort_event() const { return m_handle; } + bool is_aborting() const override; + abort_callback_event get_abort_event() const override { return m_handle; } private: const abort_callback_event m_handle; }; //! Dummy abort_callback that never gets aborted. \n -//! Slightly more efficient than the regular one especially when you need to regularly create temporary instances of it. +//! Note that there's no need to create instances of it, use shared fb2k::noAbort object instead. class abort_callback_dummy : public abort_callback { public: - abort_callback_dummy() : m_event(GetInfiniteWaitEvent()) {} - bool is_aborting() const { return false; } + bool is_aborting() const override { return false; } - abort_callback_event get_abort_event() const { return m_event;} + abort_callback_event get_abort_event() const override { return m_event;} private: - const abort_callback_event m_event; + const abort_callback_event m_event = GetInfiniteWaitEvent(); }; } @@ -117,6 +120,7 @@ using namespace foobar2000_io; namespace fb2k { - // A shared abort_callback_dummy instance + //! A shared abort_callback_dummy instance. \n + //! Use when some function requires an abort_callback& and you don't have one: somefunc(fb2k::noAbort); extern abort_callback_dummy noAbort; } diff --git a/sdk/foobar2000/SDK/advconfig.cpp b/sdk/foobar2000/SDK/advconfig.cpp index 81509c6..1034d22 100644 --- a/sdk/foobar2000/SDK/advconfig.cpp +++ b/sdk/foobar2000/SDK/advconfig.cpp @@ -76,10 +76,6 @@ void advconfig_entry_checkbox_impl::set_data_raw(stream_reader* p_stream, t_size } #endif -pfc::string8 fb2k::advconfig_autoName(const GUID& id) { - return pfc::format("advconfig.unnamed.", pfc::print_guid(id)); -} - void advconfig_entry_string_impl::reset() { fb2k::configStore::get()->deleteConfigString(m_varName); } diff --git a/sdk/foobar2000/SDK/advconfig.h b/sdk/foobar2000/SDK/advconfig.h index ba36c0d..616db76 100644 --- a/sdk/foobar2000/SDK/advconfig.h +++ b/sdk/foobar2000/SDK/advconfig.h @@ -32,14 +32,14 @@ class NOVTABLE advconfig_entry : public service_base { FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(advconfig_entry); }; -//! Creates a new branch in Advanced Preferences. \n +//! Declares a new branch in Advanced Preferences. \n //! Implementation: see advconfig_branch_impl / advconfig_branch_factory. class NOVTABLE advconfig_branch : public advconfig_entry { public: FB2K_MAKE_SERVICE_INTERFACE(advconfig_branch,advconfig_entry); }; -//! Creates a checkbox/radiocheckbox entry in Advanced Preferences. \n +//! Declares a checkbox/radiocheckbox entry in Advanced Preferences. \n //! The difference between checkboxes and radiocheckboxes is different icon (obviously) and that checking a radiocheckbox unchecks all other radiocheckboxes in the same branch. \n //! Implementation: see advconfig_entry_checkbox_impl / advconfig_checkbox_factory_t. class NOVTABLE advconfig_entry_checkbox : public advconfig_entry { @@ -53,6 +53,7 @@ class NOVTABLE advconfig_entry_checkbox : public advconfig_entry { FB2K_MAKE_SERVICE_INTERFACE(advconfig_entry_checkbox,advconfig_entry); }; +//! Extension to advconfig_entry_checkbox, adds default state and preferences flags. class NOVTABLE advconfig_entry_checkbox_v2 : public advconfig_entry_checkbox { FB2K_MAKE_SERVICE_INTERFACE(advconfig_entry_checkbox_v2, advconfig_entry_checkbox) public: @@ -60,7 +61,7 @@ class NOVTABLE advconfig_entry_checkbox_v2 : public advconfig_entry_checkbox { virtual t_uint32 get_preferences_flags() {return 0;} //signals whether changing this setting should trigger playback restart or app restart; see: preferences_state::* constants }; -//! Creates a string/integer editbox entry in Advanced Preferences.\n +//! Declares a string/integer editbox entry in Advanced Preferences.\n //! Implementation: see advconfig_entry_string_impl / advconfig_string_factory. class NOVTABLE advconfig_entry_string : public advconfig_entry { public: @@ -78,6 +79,7 @@ class NOVTABLE advconfig_entry_string : public advconfig_entry { FB2K_MAKE_SERVICE_INTERFACE(advconfig_entry_string,advconfig_entry); }; +//! Extension to advconfig_entry_string, adds default state, validation and preferences flags. class NOVTABLE advconfig_entry_string_v2 : public advconfig_entry_string { FB2K_MAKE_SERVICE_INTERFACE(advconfig_entry_string_v2, advconfig_entry_string) public: @@ -85,16 +87,3 @@ class NOVTABLE advconfig_entry_string_v2 : public advconfig_entry_string { virtual void validate(pfc::string_base & val) {} virtual t_uint32 get_preferences_flags() {return 0;} //signals whether changing this setting should trigger playback restart or app restart; see: preferences_state::* constants }; - - -//! Not currently used, reserved for future use. -class NOVTABLE advconfig_entry_enum : public advconfig_entry { -public: - virtual t_size get_value_count() = 0; - virtual void enum_value(pfc::string_base & p_out,t_size p_index) = 0; - virtual t_size get_state() = 0; - virtual void set_state(t_size p_value) = 0; - - FB2K_MAKE_SERVICE_INTERFACE(advconfig_entry_enum,advconfig_entry); -}; - diff --git a/sdk/foobar2000/SDK/advconfig_impl.h b/sdk/foobar2000/SDK/advconfig_impl.h index e3df22a..fa456a4 100644 --- a/sdk/foobar2000/SDK/advconfig_impl.h +++ b/sdk/foobar2000/SDK/advconfig_impl.h @@ -1,5 +1,7 @@ #pragma once +// advconfig_impl.h : mainline (foobar2000 v2.0) implementation of advconfig objects + #include "advconfig.h" //! Standard implementation of advconfig_branch. \n diff --git a/sdk/foobar2000/SDK/advconfig_impl_legacy.h b/sdk/foobar2000/SDK/advconfig_impl_legacy.h index b20e2c0..ce136e4 100644 --- a/sdk/foobar2000/SDK/advconfig_impl_legacy.h +++ b/sdk/foobar2000/SDK/advconfig_impl_legacy.h @@ -1,8 +1,22 @@ #pragma once +// advconfig_impl_legacy.h : legacy (foobar2000 v1.x compatible) implementation of advconfig objects + #include "cfg_var_legacy.h" using namespace cfg_var_legacy; +namespace fb2k { + pfc::string8 advconfig_autoName(const GUID&); +} + +#if FOOBAR2000_SUPPORT_CFG_VAR_DOWNGRADE +#define ADVCONFIG_DOWNGRADE { this->get_static_instance().downgrade_set_name(configStoreName); } +#define ADVCONFIG_DOWNGRADE_AUTO { this->get_static_instance().downgrade_set_name( fb2k::advconfig_autoName(p_guid) ); } +#else +#define ADVCONFIG_DOWNGRADE {(void)configStoreName;} +#define ADVCONFIG_DOWNGRADE_AUTO +#endif + //! Standard implementation of advconfig_entry_checkbox. \n class advconfig_entry_checkbox_impl : public advconfig_entry_checkbox_v2 { public: @@ -22,6 +36,9 @@ class advconfig_entry_checkbox_impl : public advconfig_entry_checkbox_v2 { bool get_state_() const { return m_state; } bool get_default_state_() const { return m_initialstate; } +#if FOOBAR2000_SUPPORT_CFG_VAR_DOWNGRADE + void downgrade_set_name(const char * arg) { m_state.downgrade_set_name(arg); } +#endif private: const pfc::string8 m_name; const bool m_initialstate; @@ -53,14 +70,26 @@ class advconfig_checkbox_factory_common : public service_factory_single_t class advconfig_checkbox_factory_t : public advconfig_checkbox_factory_common { public: advconfig_checkbox_factory_t(const char* p_name, const GUID& p_guid, const GUID& p_parent, double p_priority, bool p_initialstate) - : advconfig_checkbox_factory_common(p_name, p_guid, p_parent, p_priority, p_initialstate, p_is_radio, prefFlags) {} -}; - - -//! Standard advconfig_entry_string implementation. Use advconfig_string_factory to register your own string entries in Advanced Preferences instead of using this class directly. -class advconfig_entry_string_impl : public advconfig_entry_string_v2 { -public: - advconfig_entry_string_impl(const char* p_name, const GUID& p_guid, const GUID& p_parent, double p_priority, const char* p_initialstate, t_uint32 p_prefFlags) - : m_name(p_name), m_parent(p_parent), m_priority(p_priority), m_initialstate(p_initialstate), m_state(p_guid, p_initialstate), m_prefFlags(p_prefFlags) {} - void get_name(pfc::string_base& p_out) { p_out = m_name; } - GUID get_guid() { return m_state.get_guid(); } - GUID get_parent() { return m_parent; } - void reset() { core_api::ensure_main_thread(); m_state = m_initialstate; } - double get_sort_priority() { return m_priority; } - void get_state(pfc::string_base& p_out) { core_api::ensure_main_thread(); p_out = m_state; } - void set_state(const char* p_string, t_size p_length = ~0) { core_api::ensure_main_thread(); m_state.set_string(p_string, p_length); } - t_uint32 get_flags() { return 0; } - void get_default_state(pfc::string_base& out) { out = m_initialstate; } - t_uint32 get_preferences_flags() { return m_prefFlags; } -private: - const pfc::string8 m_initialstate, m_name; - cfg_string m_state; - const double m_priority; - const GUID m_parent; - const t_uint32 m_prefFlags; -}; - -//! Service factory helper around standard advconfig_entry_string implementation. Use this class to register your own string entries in Advanced Preferences. \n -//! Usage: static advconfig_string_factory mystring(name, itemID, branchID, priority, initialValue); -class advconfig_string_factory : public service_factory_single_t { -public: - advconfig_string_factory(const char* p_name, const GUID& p_guid, const GUID& p_parent, double p_priority, const char* p_initialstate, t_uint32 p_prefFlags = 0) - : service_factory_single_t(p_name, p_guid, p_parent, p_priority, p_initialstate, p_prefFlags) {} - - void get(pfc::string_base& out) { get_static_instance().get_state(out); } - void set(const char* in) { get_static_instance().set_state(in); } + : advconfig_checkbox_factory_common(p_name, p_guid, p_parent, p_priority, p_initialstate, p_is_radio, prefFlags) { + ADVCONFIG_DOWNGRADE_AUTO; + } + advconfig_checkbox_factory_t(const char* p_name, const char * configStoreName, const GUID& p_guid, const GUID& p_parent, double p_priority, bool p_initialstate) + : advconfig_checkbox_factory_common(p_name, p_guid, p_parent, p_priority, p_initialstate, p_is_radio, prefFlags) { + ADVCONFIG_DOWNGRADE; + } }; - //! Special advconfig_entry_string implementation - implements integer entries. Use advconfig_integer_factory to register your own integer entries in Advanced Preferences instead of using this class directly. template class advconfig_entry_integer_impl_ : public advconfig_entry_string_v2 { @@ -132,9 +131,12 @@ class advconfig_entry_integer_impl_ : public advconfig_entry_string_v2 { format(out, m_initval); } void validate(pfc::string_base& val) { - format(val, pfc::clip_t(myATOI(val, ~0), m_min, m_max)); + format(val, pfc::clip_t(myATOI(val, SIZE_MAX), m_min, m_max)); } t_uint32 get_preferences_flags() { return m_prefFlags; } +#if FOOBAR2000_SUPPORT_CFG_VAR_DOWNGRADE + void downgrade_set_name(const char * arg) { m_state.downgrade_set_name(arg); } +#endif private: static void format(pfc::string_base& out, int_t v) { if (is_signed()) out = pfc::format_int(v).get_ptr(); @@ -164,7 +166,14 @@ class advconfig_integer_factory_ : public service_factory_single_t >(p_name, p_guid, p_parent, p_priority, p_initialstate, p_min, p_max, p_prefFlags) {} + : service_factory_single_t >(p_name, p_guid, p_parent, p_priority, p_initialstate, p_min, p_max, p_prefFlags) { + ADVCONFIG_DOWNGRADE_AUTO; + } + + advconfig_integer_factory_(const char* p_name, const char * configStoreName, 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 >(p_name, p_guid, p_parent, p_priority, p_initialstate, p_min, p_max, p_prefFlags) { + ADVCONFIG_DOWNGRADE; + } 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); } @@ -177,10 +186,10 @@ typedef advconfig_integer_factory_ advconfig_integer_factory; typedef advconfig_integer_factory_ advconfig_signed_integer_factory; -//! Special version if advconfig_entry_string_impl that allows the value to be retrieved from worker threads. -class advconfig_entry_string_impl_MT : public advconfig_entry_string_v2 { +//! Standard advconfig_entry_string implementation +class advconfig_entry_string_impl : public advconfig_entry_string_v2 { public: - advconfig_entry_string_impl_MT(const char* p_name, const GUID& p_guid, const GUID& p_parent, double p_priority, const char* p_initialstate, t_uint32 p_prefFlags) + advconfig_entry_string_impl(const char* p_name, const GUID& p_guid, const GUID& p_parent, double p_priority, const char* p_initialstate, t_uint32 p_prefFlags) : m_name(p_name), m_parent(p_parent), m_priority(p_priority), m_initialstate(p_initialstate), m_state(p_guid, p_initialstate), m_prefFlags(p_prefFlags) {} void get_name(pfc::string_base& p_out) { p_out = m_name; } GUID get_guid() { return m_state.get_guid(); } @@ -194,13 +203,16 @@ class advconfig_entry_string_impl_MT : public advconfig_entry_string_v2 { inReadSync(m_sync); p_out = m_state; } - void set_state(const char* p_string, t_size p_length = ~0) { + void set_state(const char* p_string, t_size p_length = SIZE_MAX) { inWriteSync(m_sync); m_state.set_string(p_string, p_length); } t_uint32 get_flags() { return 0; } void get_default_state(pfc::string_base& out) { out = m_initialstate; } t_uint32 get_preferences_flags() { return m_prefFlags; } +#if FOOBAR2000_SUPPORT_CFG_VAR_DOWNGRADE + void downgrade_set_name(const char * arg) { m_state.downgrade_set_name(arg); } +#endif private: const pfc::string8 m_initialstate, m_name; cfg_string m_state; @@ -210,17 +222,26 @@ class advconfig_entry_string_impl_MT : public advconfig_entry_string_v2 { const t_uint32 m_prefFlags; }; -//! Special version if advconfig_string_factory that allows the value to be retrieved from worker threads. -class advconfig_string_factory_MT : public service_factory_single_t { +//! Service factory helper around standard advconfig_entry_string implementation. Use this class to register your own string entries in Advanced Preferences. \n +//! Usage: static advconfig_string_factory mystring(name, itemID, branchID, priority, initialValue); +class advconfig_string_factory : public service_factory_single_t { public: - advconfig_string_factory_MT(const char* p_name, const GUID& p_guid, const GUID& p_parent, double p_priority, const char* p_initialstate, t_uint32 p_prefFlags = 0) - : service_factory_single_t(p_name, p_guid, p_parent, p_priority, p_initialstate, p_prefFlags) {} + advconfig_string_factory(const char* p_name, const GUID& p_guid, const GUID& p_parent, double p_priority, const char* p_initialstate, t_uint32 p_prefFlags = 0) + : service_factory_single_t(p_name, p_guid, p_parent, p_priority, p_initialstate, p_prefFlags) { + ADVCONFIG_DOWNGRADE_AUTO; + } + advconfig_string_factory(const char* p_name, const char * configStoreName, const GUID& p_guid, const GUID& p_parent, double p_priority, const char* p_initialstate, t_uint32 p_prefFlags = 0) + : service_factory_single_t(p_name, p_guid, p_parent, p_priority, p_initialstate, p_prefFlags) { + ADVCONFIG_DOWNGRADE; + } void get(pfc::string_base& out) { get_static_instance().get_state(out); } void set(const char* in) { get_static_instance().set_state(in); } }; - +// No more separate _MT versions, readWriteLock overhead is irrelevant +typedef advconfig_entry_string_impl advconfig_entry_string_impl_MT; +typedef advconfig_string_factory advconfig_string_factory_MT; /* @@ -235,3 +256,7 @@ class advconfig_string_factory_MT : public service_factory_single_t f) abort_callback& fb2k::mainAborter() { return async_task_manager::get()->get_aborter(); -} \ No newline at end of file +} + +app_close_blocking_task_impl::app_close_blocking_task_impl(const char * name) : m_name(name) { + PFC_ASSERT( core_api::is_main_thread() ); + app_close_blocking_task_manager::get()->register_task(this); +} + +app_close_blocking_task_impl::~app_close_blocking_task_impl() { + PFC_ASSERT( core_api::is_main_thread() ); + app_close_blocking_task_manager::get()->unregister_task(this); +} + +void app_close_blocking_task_impl::query_task_name(pfc::string_base & out) { + out = m_name; +} + +void app_close_blocking_task_impl_dynamic::toggle_blocking(bool state) { + PFC_ASSERT( core_api::is_main_thread() ); + if (state != m_taskActive) { + auto api = app_close_blocking_task_manager::get(); + if (state) api->register_task(this); + else api->unregister_task(this); + m_taskActive = state; + } +} + +void app_close_blocking_task_impl_dynamic::query_task_name(pfc::string_base& out) { + out = m_name; +} diff --git a/sdk/foobar2000/SDK/app_close_blocker.h b/sdk/foobar2000/SDK/app_close_blocker.h index 9c96122..aed5bfd 100644 --- a/sdk/foobar2000/SDK/app_close_blocker.h +++ b/sdk/foobar2000/SDK/app_close_blocker.h @@ -19,6 +19,9 @@ class NOVTABLE app_close_blocker : public service_base //! Implementation: it's recommended that you derive from app_close_blocking_task_impl class instead of deriving from app_close_blocking_task directly, it manages registration/unregistration behind-the-scenes. class NOVTABLE app_close_blocking_task { public: + //! Retrieves user-friendly name of the task to be shown to the user, should the user try to close foobar2000 while the task is active. \n + //! Implementation note: this will NOT be called from register_task() or unregister_task(), only in response to user attempting to close foobar2000. \n + //! Common helper implementations of app_close_blocking_task register from base class constructor while intended query_task_name() override is not yet in place. virtual void query_task_name(pfc::string_base & out) = 0; protected: @@ -28,42 +31,46 @@ class NOVTABLE app_close_blocking_task { PFC_CLASS_NOT_COPYABLE_EX(app_close_blocking_task); }; -//! Entrypoint class for registering app_close_blocking_task instances. Introduced in 0.9.5.1. \n -//! Usage: static_api_ptr_t(). May fail if user runs pre-0.9.5.1. It's recommended that you use app_close_blocking_task_impl class instead of calling app_close_blocking_task_manager directly. +//! Entrypoint class for registering app_close_blocking_task instances. \n +//! You can use app_close_blocking_task_impl to call this automatically with your object. class NOVTABLE app_close_blocking_task_manager : public service_base { FB2K_MAKE_SERVICE_COREAPI(app_close_blocking_task_manager); public: + //! Registers a task object. \n + //! Main thread only. virtual void register_task(app_close_blocking_task * task) = 0; + //! Unregisters a task object. \n + //! Main thread only. virtual void unregister_task(app_close_blocking_task * task) = 0; }; //! Helper; implements standard functionality required by app_close_blocking_task implementations - registers/unregisters the task on construction/destruction. class app_close_blocking_task_impl : public app_close_blocking_task { public: - app_close_blocking_task_impl() { app_close_blocking_task_manager::get()->register_task(this);} - ~app_close_blocking_task_impl() { app_close_blocking_task_manager::get()->unregister_task(this);} + app_close_blocking_task_impl(const char * name = ""); + ~app_close_blocking_task_impl(); - void query_task_name(pfc::string_base & out) { out = ""; } + //! Override me, or provide name to constructor + void query_task_name(pfc::string_base & out) override; + + app_close_blocking_task_impl( const app_close_blocking_task_impl & ) = delete; + void operator=(const app_close_blocking_task_impl & ) = delete; +private: + const char * const m_name; }; class app_close_blocking_task_impl_dynamic : public app_close_blocking_task { public: - app_close_blocking_task_impl_dynamic() : m_taskActive() {} + app_close_blocking_task_impl_dynamic(const char * name = "") : m_name(name) {} ~app_close_blocking_task_impl_dynamic() { toggle_blocking(false); } - void query_task_name(pfc::string_base & out) { out = ""; } + //! Override me, or provide name to constructor + void query_task_name(pfc::string_base & out) override; -protected: - void toggle_blocking(bool state) { - if (state != m_taskActive) { - auto api = app_close_blocking_task_manager::get(); - if (state) api->register_task(this); - else api->unregister_task(this); - m_taskActive = state; - } - } + void toggle_blocking(bool state); private: - bool m_taskActive; + bool m_taskActive = false; + const char * const m_name; }; diff --git a/sdk/foobar2000/SDK/archive.h b/sdk/foobar2000/SDK/archive.h index 7d88ec0..a9a6b4f 100644 --- a/sdk/foobar2000/SDK/archive.h +++ b/sdk/foobar2000/SDK/archive.h @@ -5,6 +5,10 @@ namespace foobar2000_io { class archive; + //! Callback passed to archive listing methods. \n + //! For backwards compatibility, this inherits with abort_callback as well. \n + //! When implementiong, you must override abort_callback methods redirecting them to your abort_callback. \n + //! It is recommended to use lambda-based archive_list helper instead of implementing this interface. 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 & p_reader) = 0; @@ -17,10 +21,11 @@ namespace foobar2000_io { typedef std::function list_func_t; //! Lists archive contents. \n - //! May be called with any path, not only path accepted by is_our_archive. + //! May be called with any path, not only path accepted by is_our_archive. \n + //! It is strongly recommended to use the lambda_based archive_list() helper instead of calling this directly. virtual void archive_list(const char * p_path,const service_ptr_t & p_reader,archive_callback & p_callback,bool p_want_readers) = 0; - //! Helper implemented on top of the other archive_list, uses lambda instead of callback. + //! Helper implemented on top of the other archive_list, uses lambda instead of callback, avoids having to implement archive_callback. void archive_list(const char * path, file::ptr, list_func_t, bool wantReaders, abort_callback&); //! Optional method to weed out unsupported formats prior to calling archive_list. \n diff --git a/sdk/foobar2000/SDK/audio_postprocessor.h b/sdk/foobar2000/SDK/audio_postprocessor.h index d70f6b3..31af5df 100644 --- a/sdk/foobar2000/SDK/audio_postprocessor.h +++ b/sdk/foobar2000/SDK/audio_postprocessor.h @@ -4,7 +4,6 @@ #include "mem_block_container.h" //! This class handles conversion of audio data (audio_chunk) to various linear PCM types, with optional dithering. - class NOVTABLE audio_postprocessor : public service_base { public: diff --git a/sdk/foobar2000/SDK/cfg_var.cpp b/sdk/foobar2000/SDK/cfg_var.cpp index 633aa0d..8b0dd2c 100644 --- a/sdk/foobar2000/SDK/cfg_var.cpp +++ b/sdk/foobar2000/SDK/cfg_var.cpp @@ -2,6 +2,14 @@ #include "cfg_var.h" #include "configStore.h" +namespace fb2k { + pfc::string8 formatCfgVarName(const GUID& guid) { + return pfc::format("cfg_var.", pfc::print_guid(guid)); + } + pfc::string8 advconfig_autoName(const GUID& id) { + return pfc::format("advconfig.unnamed.", pfc::print_guid(id)); + } +} namespace cfg_var_modern { #ifdef FOOBAR2000_HAVE_CFG_VAR_LEGACY @@ -88,7 +96,7 @@ namespace cfg_var_modern { pfc::string8 cfg_var_common::formatVarName(const GUID& guid) { - return pfc::format("cfg_var.", pfc::print_guid(guid)); + return fb2k::formatCfgVarName( guid ); } pfc::string8 cfg_var_common::formatName() const { diff --git a/sdk/foobar2000/SDK/cfg_var_legacy.cpp b/sdk/foobar2000/SDK/cfg_var_legacy.cpp index 58fbce6..c96f167 100644 --- a/sdk/foobar2000/SDK/cfg_var_legacy.cpp +++ b/sdk/foobar2000/SDK/cfg_var_legacy.cpp @@ -1,9 +1,18 @@ #include "foobar2000-sdk-pch.h" #include "cfg_var_legacy.h" +#if FOOBAR2000_SUPPORT_CFG_VAR_DOWNGRADE +#include "configStore.h" +#include +#endif + #ifdef FOOBAR2000_HAVE_CFG_VAR_LEGACY +#if FOOBAR2000_SUPPORT_CFG_VAR_DOWNGRADE +namespace fb2k { + pfc::string8 formatCfgVarName(const GUID&); +} +#endif // FOOBAR2000_SUPPORT_CFG_VAR_DOWNGRADE namespace cfg_var_legacy { - cfg_var_reader* cfg_var_reader::g_list = NULL; cfg_var_writer* cfg_var_writer::g_list = NULL; @@ -22,11 +31,11 @@ namespace cfg_var_legacy { guid = pfc::byteswap_if_be_t(guid); p_stream->read_lendian_t(size, p_abort); - cfg_var_reader* var; - if (vars.query(guid, var)) { + auto iter = vars.find(guid); + if ( iter.is_valid() ) { stream_reader_limited_ref wrapper(p_stream, size); try { - var->set_data_raw(&wrapper, size, p_abort); + iter->m_value->set_data_raw(&wrapper, size, p_abort); } catch (exception_io_data) {} wrapper.flush_remaining(p_abort); } else { @@ -34,7 +43,19 @@ namespace cfg_var_legacy { } } } - +#if FOOBAR2000_SUPPORT_CFG_VAR_DOWNGRADE + static std::once_flag downgrade_once; + void cfg_var_reader::downgrade_main() { + std::call_once(downgrade_once, [] { + auto api = fb2k::configStore::tryGet(); + if (api.is_valid()) { + for (cfg_var_reader* walk = g_list; walk != NULL; walk = walk->m_next) { + walk->downgrade_check(api); + } + } + }); + } +#endif void cfg_var_writer::config_write_file(stream_writer* p_stream, abort_callback& p_abort) { cfg_var_writer* ptr; pfc::array_t temp; @@ -63,5 +84,74 @@ namespace cfg_var_legacy { set_string(temp); } + +#if FOOBAR2000_SUPPORT_CFG_VAR_DOWNGRADE + int64_t downgrade_this(fb2k::configStore::ptr api, const char * name, int64_t current) { + int64_t v = api->getConfigInt(name, INT64_MAX); + if (v == INT64_MAX) { + v = api->getConfigInt(name, INT64_MIN); + if ( v == INT64_MIN ) return current; + } + api->deleteConfigInt(name); + return v; + } + uint64_t downgrade_this(fb2k::configStore::ptr api, const char * name, uint64_t current) { + return (uint64_t) downgrade_this(api, name, (int64_t) current); + } + int32_t downgrade_this(fb2k::configStore::ptr api, const char * name, int32_t current) { + return (int32_t) downgrade_this(api, name, (int64_t) current); + } + uint32_t downgrade_this(fb2k::configStore::ptr api, const char * name, uint32_t current) { + return (uint32_t) downgrade_this(api, name, (int64_t) current); + } + bool downgrade_this(fb2k::configStore::ptr api, const char * name, bool current) { + return downgrade_this(api, name, (int64_t)(current?1:0)) != 0; + } + double downgrade_this(fb2k::configStore::ptr api, const char * name, double current) { + double v = api->getConfigFloat(name, -1); + if (v == -1) { + v = api->getConfigFloat(name, 0); + if ( v == 0 ) return current; + } + api->deleteConfigFloat(name); + return v; + } + GUID downgrade_this(fb2k::configStore::ptr api, const char * name, GUID current) { + auto blob = api->getConfigBlob( name ); + if (blob.is_valid() && blob->size() == sizeof(GUID)) { + GUID ret; + memcpy(&ret, blob->get_ptr(), sizeof(ret)); + api->deleteConfigBlob( name ); + return ret; + } + return current; + } + + void cfg_string::downgrade_check(fb2k::configStore::ptr api) { + const auto name = this->downgrade_name(); + auto v = api->getConfigString(name, nullptr); + if (v.is_valid()) { + this->set(v->c_str()); + api->deleteConfigString(name); + } + } + void cfg_string_mt::downgrade_check(fb2k::configStore::ptr api) { + const auto name = this->downgrade_name(); + auto v = api->getConfigString(name, nullptr); + if (v.is_valid()) { + this->set(v->c_str()); + api->deleteConfigString(name); + } + } + + pfc::string8 cfg_var_reader::downgrade_name() const { + if (m_downgrade_name.length() > 0) { + return m_downgrade_name; + } else { + return fb2k::formatCfgVarName(this->m_guid); + } + } +#endif + } #endif // FOOBAR2000_HAVE_CFG_VAR_LEGACY diff --git a/sdk/foobar2000/SDK/cfg_var_legacy.h b/sdk/foobar2000/SDK/cfg_var_legacy.h index f45c3dc..943c86e 100644 --- a/sdk/foobar2000/SDK/cfg_var_legacy.h +++ b/sdk/foobar2000/SDK/cfg_var_legacy.h @@ -4,6 +4,11 @@ #include #include "filesystem.h" // stream_reader, stream_writer +#if FOOBAR2000_SUPPORT_CFG_VAR_DOWNGRADE +#include "configStore.h" +#include "initquit.h" +#endif + namespace cfg_var_legacy { #define CFG_VAR_ASSERT_SAFEINIT PFC_ASSERT(!core_api::are_services_available());/*imperfect check for nonstatic instantiation*/ @@ -19,6 +24,22 @@ namespace cfg_var_legacy { //! @param p_sizehint Number of bytes contained in the stream; reading past p_sizehint bytes will fail (EOF). virtual void set_data_raw(stream_reader* p_stream, t_size p_sizehint, abort_callback& p_abort) = 0; +#if FOOBAR2000_SUPPORT_CFG_VAR_DOWNGRADE + private: + pfc::string8 m_downgrade_name; + public: + pfc::string8 downgrade_name() const; + void downgrade_set_name( const char * arg ) { m_downgrade_name = arg; } + + //! Implementation of config downgrade for this var, see FOOBAR2000_SUPPORT_CFG_VAR_DOWNGRADE for more info. \n + //! Most components should not use this. + virtual void downgrade_check(fb2k::configStore::ptr api) {} + //! Config downgrade main for your component, see FOOBAR2000_SUPPORT_CFG_VAR_DOWNGRADE for more info. \n + //! Put FOOBAR2000_IMPLEMENT_CFG_VAR_DOWNGRADE somewhere in your component to call on startup, or call from your code as early as possible after config read. \n + //! If you call it more than once, spurious calls will be ignored. + static void downgrade_main(); +#endif + //! For internal use only, do not call. static void config_read_file(stream_reader* p_stream, abort_callback& p_abort); @@ -62,6 +83,16 @@ namespace cfg_var_legacy { GUID get_guid() const { return cfg_var_reader::m_guid; } }; +#if FOOBAR2000_SUPPORT_CFG_VAR_DOWNGRADE + int64_t downgrade_this( fb2k::configStore::ptr api, const char*, int64_t current); + uint64_t downgrade_this( fb2k::configStore::ptr api, const char*, uint64_t current); + int32_t downgrade_this( fb2k::configStore::ptr api, const char*, int32_t current); + uint32_t downgrade_this( fb2k::configStore::ptr api, const char*, uint32_t current); + bool downgrade_this( fb2k::configStore::ptr api, const char*, bool current); + double downgrade_this( fb2k::configStore::ptr api, const char*, double current); + GUID downgrade_this( fb2k::configStore::ptr api, const char*, GUID current); +#endif + //! Generic integer config variable class. Template parameter can be used to specify integer type to use.\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). template @@ -69,13 +100,17 @@ namespace cfg_var_legacy { 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 get_data_raw(stream_writer* p_stream, abort_callback& p_abort) override { p_stream->write_lendian_t(m_val, p_abort); } + void set_data_raw(stream_reader* p_stream, t_size, abort_callback& p_abort) override { 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; } - +#if FOOBAR2000_SUPPORT_CFG_VAR_DOWNGRADE + void downgrade_check(fb2k::configStore::ptr api) override { + m_val = downgrade_this(api, this->downgrade_name(), m_val); + } +#endif public: //! @param p_guid GUID of the variable, used to identify variable implementations owning specific configuration file entries when reading the configuration file back. You must generate a new GUID every time you declare a new cfg_var. //! @param p_default Default value of the variable. @@ -91,54 +126,59 @@ namespace cfg_var_legacy { typedef cfg_int_t cfg_int; typedef cfg_int_t cfg_uint; - //! Since relevant byteswapping functions also understand GUIDs, this can be used to declare a cfg_guid. - typedef cfg_int_t cfg_guid; - typedef cfg_int_t cfg_bool; - typedef cfg_int_t cfg_float; - typedef cfg_int_t cfg_double; + typedef cfg_int_t cfg_guid; // ANNOYING OLD DESIGN. THIS DOESN'T BELONG HERE BUT CANNOT BE CHANGED WITHOUT BREAKING PEOPLE'S STUFF. BLARFGH. + typedef cfg_int_t cfg_bool; // See above. + typedef cfg_int_t cfg_float; // See above %$!@#$ + typedef cfg_int_t 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). class cfg_string : public cfg_var, public pfc::string8 { protected: - void get_data_raw(stream_writer* p_stream, abort_callback& p_abort); - void set_data_raw(stream_reader* p_stream, t_size p_sizehint, abort_callback& p_abort); + void get_data_raw(stream_writer* p_stream, abort_callback& p_abort) override; + void set_data_raw(stream_reader* p_stream, t_size p_sizehint, abort_callback& p_abort) override; +#if FOOBAR2000_SUPPORT_CFG_VAR_DOWNGRADE + void downgrade_check(fb2k::configStore::ptr) override; +#endif public: //! @param p_guid GUID of the variable, used to identify variable implementations owning specific configuration file entries when reading the configuration file back. You must generate a new GUID every time you declare a new cfg_var. //! @param p_defaultval Default/initial value of the variable. explicit inline cfg_string(const GUID& p_guid, const char* p_defaultval) : cfg_var(p_guid), pfc::string8(p_defaultval) {} - inline const cfg_string& operator=(const cfg_string& p_val) { set_string(p_val); return *this; } - inline const cfg_string& operator=(const char* p_val) { set_string(p_val); return *this; } + const cfg_string& operator=(const cfg_string& p_val) { set_string(p_val); return *this; } + const cfg_string& operator=(const char* p_val) { set_string(p_val); return *this; } + const cfg_string& operator=(pfc::string8 && p_val) { set(std::move(p_val)); return *this; } + inline operator const char* () const { return get_ptr(); } const pfc::string8& get() const { return *this; } + void set( const char * arg ) { this->set_string(arg); } + void set(pfc::string8&& arg) { pfc::string8 * pThis = this; *pThis = std::move(arg); } }; class cfg_string_mt : public cfg_var { protected: - void get_data_raw(stream_writer* p_stream, abort_callback& p_abort) { + void get_data_raw(stream_writer* p_stream, abort_callback& p_abort) override { pfc::string8 temp; 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, abort_callback& p_abort) override { pfc::string8_fastalloc temp; p_stream->read_string_raw(temp, p_abort); set(temp); } +#if FOOBAR2000_SUPPORT_CFG_VAR_DOWNGRADE + void downgrade_check(fb2k::configStore::ptr) override; +#endif public: cfg_string_mt(const GUID& id, const char* defVal) : cfg_var(id), m_val(defVal) {} - void get(pfc::string_base& out) const { - inReadSync(m_sync); - out = m_val; - } - void set(const char* val, t_size valLen = ~0) { - inWriteSync(m_sync); - m_val.set_string(val, valLen); - } + void get(pfc::string_base& out) const { inReadSync(m_sync); out = m_val; } + pfc::string8 get() const { inReadSync(m_sync); return m_val; } + void set(const char* val, t_size valLen = SIZE_MAX) { inWriteSync(m_sync); m_val.set_string(val, valLen); } + void set( pfc::string8 && val ) { inWriteSync(m_sync); m_val = std::move(val); } private: mutable pfc::readWriteLock m_sync; pfc::string8 m_val; @@ -315,7 +355,10 @@ namespace cfg_var_legacy { } } }; -} +#if FOOBAR2000_SUPPORT_CFG_VAR_DOWNGRADE +#define FOOBAR2000_IMPLEMENT_CFG_VAR_DOWNGRADE FB2K_RUN_ON_INIT(cfg_var_reader::downgrade_main) +#endif // FOOBAR2000_SUPPORT_CFG_VAR_DOWNGRADE +} // cfg_var_legacy #else namespace cfg_var_legacy { // Dummy class @@ -326,3 +369,7 @@ namespace cfg_var_legacy { }; } #endif + +#ifndef FOOBAR2000_IMPLEMENT_CFG_VAR_DOWNGRADE +#define FOOBAR2000_IMPLEMENT_CFG_VAR_DOWNGRADE +#endif \ No newline at end of file diff --git a/sdk/foobar2000/SDK/commandline.h b/sdk/foobar2000/SDK/commandline.h index 5e230d2..45e29bc 100644 --- a/sdk/foobar2000/SDK/commandline.h +++ b/sdk/foobar2000/SDK/commandline.h @@ -1,4 +1,6 @@ #pragma once + +//! Service for handling commandline arguments passed to foobar2000.exe class NOVTABLE commandline_handler : public service_base { public: @@ -16,16 +18,18 @@ class NOVTABLE commandline_handler : public service_base FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(commandline_handler); }; -class commandline_handler_metadb_handle : public commandline_handler//helper -{ +//! Helper automatically turning passed file locations into metadb_handle objects (audio track references) +class commandline_handler_metadb_handle : public commandline_handler { protected: - virtual void on_file(const char * url); - virtual bool want_directories() {return true;} + void on_file(const char * url) override final; + bool want_directories() override {return true;} public: - virtual result on_token(const char * token)=0; + //! Override me + virtual result on_token(const char * token) = 0; + //! Override me virtual void on_files_done() {}; - - virtual void on_file(const metadb_handle_ptr & ptr)=0; + //! Override me + virtual void on_file(const metadb_handle_ptr & ptr) = 0; }; /* diff --git a/sdk/foobar2000/SDK/configStore.h b/sdk/foobar2000/SDK/configStore.h index 8092b4d..6782938 100644 --- a/sdk/foobar2000/SDK/configStore.h +++ b/sdk/foobar2000/SDK/configStore.h @@ -22,11 +22,13 @@ typedef void * configStoreNotifyHandle_t; class configStore : public service_base { FB2K_MAKE_SERVICE_COREAPI( configStore ); public: - //! Obsolete since late 2.0 beta, returns null. Delay-write cache is always used, no need to specifically request transactions. \n - //! To specifically flush after changing a bunch of variables, use commitBlocking(). + //! Causes multiple writes to be chained together. \n + //! Use of this is no longer essential since late foobar2000 v2.0 betas, as delay-write cache is always used. \n + //! You can still use it to guarantee that multiple updates are written together, that is either all or none are saved, should the system or application crash. virtual fb2k::objRef acquireTransactionScope() = 0; - //! Synchronously flushes changes to disk. Doesn't return until changes have actually been written. + //! Synchronously flushes changes to disk. Doesn't return until changes have actually been written. \n + //! Use of this is strongly recommended against. virtual void commitBlocking() = 0; virtual int64_t getConfigInt( const char * name, int64_t defVal = 0 ) = 0; diff --git a/sdk/foobar2000/SDK/dsp.h b/sdk/foobar2000/SDK/dsp.h index 95d6e14..001b002 100644 --- a/sdk/foobar2000/SDK/dsp.h +++ b/sdk/foobar2000/SDK/dsp.h @@ -397,7 +397,7 @@ class NOVTABLE dsp_entry_v3 : public dsp_entry_v2 { #ifdef _WIN32 //! Shows configuration popup, asynchronous version - creates dialog then returns immediately. \n - //! Since not every DSP implements this, caller must be prepated to call legacy blocking show_config_popup methods instead. \n + //! Since not every DSP implements this, caller must be prepared to call legacy blocking show_config_popup methods instead. \n //! show_config_popup_v3() may throw pfc::exception_not_implemented() to signal host that this DSP doesn't support this method yet. \n //! Main thread only! \n //! @returns Object to retain by host, to be released to request the dialog to be closed. diff --git a/sdk/foobar2000/SDK/file_info.cpp b/sdk/foobar2000/SDK/file_info.cpp index 595e6b0..ee435fc 100644 --- a/sdk/foobar2000/SDK/file_info.cpp +++ b/sdk/foobar2000/SDK/file_info.cpp @@ -417,6 +417,20 @@ void file_info::info_calculate_bitrate(uint64_t p_filesize,double p_length) if ( b > 0 ) info_set_bitrate(b); } +void file_info::info_set_bitspersample(uint32_t val, bool isFloat) { + // Bits per sample semantics + // "bitspersample" is set to integer value of bits per sample + // "bitspersample_extra" is used for bps of 32 or 64, either "floating-point" or "fixed-point" + // bps other than 32 or 64 are implicitly fixed-point as floating-point for such makes no sense + + info_set_int("bitspersample", val); + if ( isFloat || val == 32 || val == 64 ) { + info_set("bitspersample_extra", isFloat ? "floating-point" : "fixed-point"); + } else { + info_remove("bitspersample_extra"); + } +} + bool file_info::is_encoding_float() const { auto bs = info_get_int("bitspersample"); auto extra = info_get("bitspersample_extra"); @@ -586,7 +600,10 @@ void file_info::to_console() const { FB2K_console_formatter1() << "File info dump:"; if (get_length() > 0) FB2K_console_formatter() << "Duration: " << pfc::format_time_ex(get_length(), 6); pfc::string_formatter temp; - for(t_size metaWalk = 0; metaWalk < meta_get_count(); ++metaWalk) { + const auto numMeta = meta_get_count(), numInfo = info_get_count(); + if (numMeta == 0) { + FB2K_console_formatter() << "Meta is blank"; + } else for(t_size metaWalk = 0; metaWalk < numMeta; ++metaWalk) { const char * name = meta_enum_name( metaWalk ); const auto valCount = meta_enum_value_count( metaWalk ); for ( size_t valWalk = 0; valWalk < valCount; ++valWalk ) { @@ -598,7 +615,9 @@ void file_info::to_console() const { FB2K_console_formatter() << "Meta: " << meta_enum_name(metaWalk) << " = " << temp; */ } - for(t_size infoWalk = 0; infoWalk < info_get_count(); ++infoWalk) { + if (numInfo == 0) { + FB2K_console_formatter() << "Info is blank"; + } else for(t_size infoWalk = 0; infoWalk < numInfo; ++infoWalk) { FB2K_console_formatter() << "Info: " << info_enum_name(infoWalk) << " = " << info_enum_value(infoWalk); } } diff --git a/sdk/foobar2000/SDK/file_info.h b/sdk/foobar2000/SDK/file_info.h index 19903d9..2a7037d 100644 --- a/sdk/foobar2000/SDK/file_info.h +++ b/sdk/foobar2000/SDK/file_info.h @@ -235,9 +235,15 @@ class NOVTABLE file_info { //! Returns channel mask value. 0 if not set, use default for the channel count then. uint32_t info_get_wfx_chanMask() const; + //! Is a lossy codec? bool is_encoding_lossy() const; + //! Is lossless/PCM that can't be sanely represented in this fb2k build due to audio_sample limitations? \n + //! Always returns false in 64-bit fb2k. bool is_encoding_overkill() const; + //! Floating-point PCM used? bool is_encoding_float() const; + //! Helper; sets bit depth of lossless/PCM format. + void info_set_bitspersample(uint32_t val, bool isFloat = false); //! Sets bitrate value using file size in bytes and duration. void info_calculate_bitrate(uint64_t p_filesize,double p_length); diff --git a/sdk/foobar2000/SDK/filesystem.cpp b/sdk/foobar2000/SDK/filesystem.cpp index a2e4e27..10005bb 100644 --- a/sdk/foobar2000/SDK/filesystem.cpp +++ b/sdk/foobar2000/SDK/filesystem.cpp @@ -1145,6 +1145,30 @@ bool foobar2000_io::extract_native_path_ex(const char * p_fspath, pfc::string_ba return true; } +static bool extract_native_path_fsv3(const char* in, pfc::string_base& out, abort_callback& a) { + if (foobar2000_io::extract_native_path(in, out)) return true; + filesystem_v3::ptr v3; + if (v3 &= filesystem::tryGet(in)) { + auto n = v3->getNativePath(in, a); + if ( n.is_valid() ) { + out = n->c_str(); return true; + } + } + return false; +} + +bool foobar2000_io::extract_native_path_archive_aware_ex(const char* in, pfc::string_base& out, abort_callback& a) { + if (extract_native_path_fsv3(in, out, a)) 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 extract_native_path_fsv3(arc, out, a); + } + } + return false; +} + 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)) { diff --git a/sdk/foobar2000/SDK/filesystem.h b/sdk/foobar2000/SDK/filesystem.h index d686387..93d48cd 100644 --- a/sdk/foobar2000/SDK/filesystem.h +++ b/sdk/foobar2000/SDK/filesystem.h @@ -418,6 +418,7 @@ namespace foobar2000_io 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 ); + bool extract_native_path_archive_aware_ex( const char * fspatch, pfc::string_base & out, abort_callback & a ); template pfc::string getPathDisplay(const T& source) { diff --git a/sdk/foobar2000/SDK/foobar2000-versions.h b/sdk/foobar2000/SDK/foobar2000-versions.h index 3daeeed..43f4e3e 100644 --- a/sdk/foobar2000/SDK/foobar2000-versions.h +++ b/sdk/foobar2000/SDK/foobar2000-versions.h @@ -10,7 +10,7 @@ #define FOOBAR2000_TARGET_VERSION_COMPATIBLE 72 #else // x64 & ARM64 targets -// Allow components made with new foobar2000 v1.6 SDK with x64 & ARM64 targets +// Allow components made with special foobar2000 v1.6 SDK with x64 & ARM64 targets #define FOOBAR2000_TARGET_VERSION_COMPATIBLE 80 #endif @@ -19,4 +19,12 @@ // Use this to determine what foobar2000 SDK version is in use, undefined for releases older than 2018 -#define FOOBAR2000_SDK_VERSION 20230222 \ No newline at end of file +#define FOOBAR2000_SDK_VERSION 20230418 + +// cfg_var downgrade support, experimental, intended for specific components only. +// Allows new style configStore data to be imported back to old foobar2000 friendly cfg_vars. +// Intended to retain config when reverting FOOBAR2000_TARGET_VERSION value of 81 or newer to 80. +// Takes effect with FOOBAR2000_TARGET_VERSION 80 only. +// Place FOOBAR2000_IMPLEMENT_CFG_VAR_DOWNGRADE somewhere in your code to declare init calls for cfg_var downgrade. Or, if you wish to call manually, call cfg_var_reader::downgrade_main() before accessing your cfg_vars. +// Spurious calls to cfg_var_reader::downgrade_main() will be ignored, only first one will take effect. +#define FOOBAR2000_SUPPORT_CFG_VAR_DOWNGRADE 0 \ No newline at end of file diff --git a/sdk/foobar2000/SDK/foobar2000_SDK.vcxproj b/sdk/foobar2000/SDK/foobar2000_SDK.vcxproj index 3a00c5c..fa8b8dc 100644 --- a/sdk/foobar2000/SDK/foobar2000_SDK.vcxproj +++ b/sdk/foobar2000/SDK/foobar2000_SDK.vcxproj @@ -346,6 +346,7 @@ + diff --git a/sdk/foobar2000/SDK/foobar2000_SDK.vcxproj.filters b/sdk/foobar2000/SDK/foobar2000_SDK.vcxproj.filters index 4121b97..aa813f5 100644 --- a/sdk/foobar2000/SDK/foobar2000_SDK.vcxproj.filters +++ b/sdk/foobar2000/SDK/foobar2000_SDK.vcxproj.filters @@ -404,6 +404,9 @@ Header Files + + Header Files + diff --git a/sdk/foobar2000/SDK/guids.cpp b/sdk/foobar2000/SDK/guids.cpp index 6fa27b2..5203bef 100644 --- a/sdk/foobar2000/SDK/guids.cpp +++ b/sdk/foobar2000/SDK/guids.cpp @@ -901,6 +901,10 @@ FOOGUIDDECL const GUID playback_queue_callback::class_guid = FOOGUIDDECL const GUID main_thread_callback_manager::class_guid = { 0x1131d64b, 0x4cb, 0x43ee, { 0x95, 0xeb, 0x24, 0xd1, 0x8b, 0x75, 0x32, 0x48 } }; +// {38986E70-A333-456D-8FEE-0AFBDFD4F919} +FOOGUIDDECL const GUID main_thread_callback_manager_v2::class_guid = +{ 0x38986e70, 0xa333, 0x456d, { 0x8f, 0xee, 0xa, 0xfb, 0xdf, 0xd4, 0xf9, 0x19 } }; + // {87D2C583-7AFB-4e58-B21E-FBD3E6E8F5E7} FOOGUIDDECL const GUID main_thread_callback::class_guid = { 0x87d2c583, 0x7afb, 0x4e58, { 0xb2, 0x1e, 0xfb, 0xd3, 0xe6, 0xe8, 0xf5, 0xe7 } }; @@ -1121,10 +1125,6 @@ FOOGUIDDECL const GUID advconfig_entry::guid_branch_converter = { 0x96ea6eae, 0x FOOGUIDDECL const GUID playback_control_v2::class_guid = { 0x1eb67bda, 0x1345, 0x49ae, { 0x8e, 0x89, 0x50, 0x5, 0xd9, 0x1, 0x62, 0x89 } }; - - -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 } }; FOOGUIDDECL const GUID info_lookup_handler_v2::class_guid = { 0x3c9728a5, 0x89e5, 0x4560, { 0xb6, 0x8b, 0x9b, 0x9b, 0x90, 0x1f, 0x0, 0x7b } }; @@ -1391,6 +1391,7 @@ FOOGUIDDECL const GUID ui_element_instance_callback_v3::class_guid = { 0x6d15c0c FOOGUIDDECL const GUID ui_element_popup_host_v2::class_guid = { 0x8caac11e, 0x52b6, 0x47f7,{ 0x97, 0xc9, 0x2c, 0x87, 0xdb, 0xdb, 0x2e, 0x5b } }; FOOGUIDDECL const GUID ui_config_manager::class_guid = { 0x199050a6, 0xd0fe, 0x47af, { 0x9b, 0xd7, 0xfc, 0x74, 0x59, 0x9e, 0x47, 0xbd } }; +FOOGUIDDECL const GUID ui_config_manager_v2::class_guid = { 0x2ed12611, 0xda05, 0x4ab9, { 0x87, 0x5b, 0xfb, 0x1b, 0x5c, 0x39, 0xcd, 0xc2 } }; FOOGUIDDECL const GUID ui_edit_context::class_guid = { 0xf9ba651b, 0x52dd, 0x466f,{ 0xaa, 0x77, 0xa9, 0x7a, 0x74, 0x98, 0x80, 0x7e } }; @@ -1506,3 +1507,5 @@ FOOGUIDDECL const GUID fb2k::callback_with_merit::class_guid = { 0x27c64500, 0x5 FOOGUIDDECL const GUID playlist_manager_v6::class_guid = { 0x8fd46228, 0x9ba3, 0x4bb1, { 0xa0, 0x9c, 0xe8, 0x5b, 0x9e, 0x45, 0x8a, 0x58 } }; FOOGUIDDECL const GUID library_manager_v6::class_guid = { 0x92eea180, 0x93d0, 0x44ef, { 0xbc, 0x43, 0xb6, 0x88, 0xae, 0x41, 0xb7, 0xad } }; FOOGUIDDECL const GUID play_callback_manager_v2::class_guid = { 0x7e59a4e6, 0x810d, 0x433b, { 0xb6, 0x9, 0x12, 0xf4, 0xde, 0x7f, 0x7f, 0x47 } }; +FOOGUIDDECL const GUID metadb_hint_list_v4::class_guid = { 0xe7908ec9, 0xa26a, 0x418e, { 0xac, 0x13, 0xb4, 0x17, 0x67, 0x8c, 0xa, 0x4 } }; +FOOGUIDDECL const GUID metadb_pre_update_callback::class_guid = { 0xc81865af, 0x1da2, 0x4361, { 0x92, 0x88, 0xac, 0xf7, 0x83, 0x89, 0xe1, 0x9c } }; diff --git a/sdk/foobar2000/SDK/main_thread_callback.cpp b/sdk/foobar2000/SDK/main_thread_callback.cpp index 77492f8..500ccb6 100644 --- a/sdk/foobar2000/SDK/main_thread_callback.cpp +++ b/sdk/foobar2000/SDK/main_thread_callback.cpp @@ -42,6 +42,11 @@ void fb2k::inMainThread2( std::function f ) { void fb2k::inMainThreadSynchronous(std::function f, abort_callback & abort) { abort.check(); + + if (core_api::is_main_thread()) { + f(); return; + } + auto evt = std::make_shared(); auto f2 = [f, evt] { f(); @@ -49,4 +54,15 @@ void fb2k::inMainThreadSynchronous(std::function f, abort_callback & ab }; inMainThread(f2); abort.waitForEvent(*evt); +} + +void fb2k::inMainThreadSynchronous2(std::function f) { + // Have new API? + auto api = main_thread_callback_manager_v2::tryGet(); + if (api.is_valid()) { + api->run_synchronously( fb2k::service_new(f) ); + return; + } + + inMainThreadSynchronous(f, fb2k::noAbort); } \ No newline at end of file diff --git a/sdk/foobar2000/SDK/main_thread_callback.h b/sdk/foobar2000/SDK/main_thread_callback.h index a7dd95c..a350e7c 100644 --- a/sdk/foobar2000/SDK/main_thread_callback.h +++ b/sdk/foobar2000/SDK/main_thread_callback.h @@ -28,12 +28,23 @@ There is no need to use this API directly - use fb2k::inMainThread() with a lamb */ class NOVTABLE main_thread_callback_manager : public service_base { public: - //! Queues a callback object. This can be called from any thread, implementation ensures multithread safety. Implementation will call p_callback->callback_run() once later. To get it called repeatedly, you would need to add your callback again. + //! Queues a callback object. This can be called from any thread, implementation ensures multithread safety. Implementation will call p_callback->callback_run() once later. To get it called repeatedly, you would need to add your callback again. \n + //! Queued callbacks will be called in the same order as they were queued (FIFO). virtual void add_callback(service_ptr_t p_callback) = 0; FB2K_MAKE_SERVICE_COREAPI(main_thread_callback_manager); }; +//! \since 2.0 +//! Additional method added to help recovering from method-called-in-wrong-thread scenarios. +class NOVTABLE main_thread_callback_manager_v2 : public main_thread_callback_manager { + FB2K_MAKE_SERVICE_COREAPI_EXTENSION(main_thread_callback_manager_v2, main_thread_callback_manager) +public: + //! Uses win32 SendMessage() to invoke your callback synchronously, blocks until done. \n + //! If multiple threads call this, order of callbacks is undefined. \n + //! Callbacks run_synchronously() callbacks take precedence over add_callback(). + virtual void run_synchronously( main_thread_callback::ptr ) = 0; +}; // ====================================================================================================== // Obsolete helpers - they still work, but it's easier to just use fb2k::inMainThread(). @@ -52,125 +63,4 @@ template static void mai main_thread_callback_add(new service_impl_t(p1, p2)); } -// Proxy class - friend this to allow callInMainThread to access your private methods -class callInMainThread { -public: - template - static void callThis(host_t * host, param_t & param) { - host->inMainThread(param); - } - template - static void callThis( host_t * host ) { - host->inMainThread(); - } -}; - -// Internal class, do not use. -template -class _callInMainThreadSvc_t : public main_thread_callback { -public: - _callInMainThreadSvc_t(service_t * host, param_t const & param) : m_host(host), m_param(param) {} - void callback_run() { - callInMainThread::callThis(m_host.get_ptr(), m_param); - } -private: - service_ptr_t m_host; - param_t m_param; -}; - - -// Main thread callback helper. You can use this to easily invoke inMainThread(someparam) on your class without writing any wrapper code. -// Requires myservice_t to be a fb2k service class with reference counting. -template -static void callInMainThreadSvc(myservice_t * host, param_t const & param) { - typedef _callInMainThreadSvc_t impl_t; - service_ptr_t obj = new service_impl_t(host, param); - main_thread_callback_manager::get()->add_callback( obj ); -} - - - - -//! Helper class to call methods of your class (host class) in main thread with convenience. \n -//! Deals with the otherwise ugly scenario of your class becoming invalid while a method is queued. \n -//! 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. -class callInMainThreadHelper { -public: - - typedef std::function< void () > func_t; - - typedef pfc::rcptr_t< bool > killswitch_t; - - class entryFunc : public main_thread_callback { - public: - entryFunc( func_t const & func, killswitch_t ks ) : m_ks(ks), m_func(func) {} - - void callback_run() { - if (!*m_ks) m_func(); - } - - private: - killswitch_t m_ks; - func_t m_func; - }; - - template - class entry : public main_thread_callback { - public: - entry( host_t * host, arg_t const & arg, killswitch_t ks ) : m_ks(ks), m_host(host), m_arg(arg) {} - void callback_run() { - if (!*m_ks) callInMainThread::callThis( m_host, m_arg ); - } - private: - killswitch_t m_ks; - host_t * m_host; - arg_t m_arg; - }; - template - class entryVoid : public main_thread_callback { - public: - entryVoid( host_t * host, killswitch_t ks ) : m_ks(ks), m_host(host) {} - void callback_run() { - if (!*m_ks) callInMainThread::callThis( m_host ); - } - private: - killswitch_t m_ks; - host_t * m_host; - }; - - void add(func_t f) { - add_( new service_impl_t< entryFunc > ( f, m_ks ) ); - } - - template - void add( host_t * host, arg_t const & arg) { - add_( new service_impl_t< entry >( host, arg, m_ks ) ); - } - template - void add( host_t * host ) { - add_( new service_impl_t< entryVoid >( host, m_ks ) ); - } - void add_( main_thread_callback::ptr cb ) { - main_thread_callback_add( cb ); - } - - callInMainThreadHelper() { - m_ks.new_t(); - * m_ks = false; - } - void shutdown() { - PFC_ASSERT( core_api::is_main_thread() ); - * m_ks = true; - } - ~callInMainThreadHelper() { - shutdown(); - } - -private: - killswitch_t m_ks; - -}; +// More legacy helper code moved to helpers/callInMainThreadHelper.h \ No newline at end of file diff --git a/sdk/foobar2000/SDK/message_loop.h b/sdk/foobar2000/SDK/message_loop.h index d6756fd..04048ab 100644 --- a/sdk/foobar2000/SDK/message_loop.h +++ b/sdk/foobar2000/SDK/message_loop.h @@ -1,17 +1,26 @@ #pragma once #ifdef _WIN32 -class NOVTABLE message_filter -{ +//! A message filter class. Allows you to filter incoming messages in main app loop. Use message_loop API to register/unregister, \n +//! or derive from message_filter_impl_base to have your class registered/deregistered automatically with lifetime. +//! //! Use with caution. Will not be executed during modal loops. +class NOVTABLE message_filter { public: + //! Notifies you about incoming message. \n + //! You can alter the message (not generally recommended), let others handle it (return false) \n + //! or signal that you've handled it (return true) to suppress further processing. virtual bool pretranslate_message(MSG * p_msg) = 0; }; +//! An idle handler class. Executed when main loop is about to enter idle state. \n +//! Use with caution. Will not be executed during modal loops. class NOVTABLE idle_handler { public: virtual bool on_idle() = 0; }; +//! Entrypoint API for registering message_filter and idle_handler objects. \n +//! Usage: message_loop::get()->add_message_filter(myfilter); class NOVTABLE message_loop : public service_base { public: @@ -33,35 +42,23 @@ class NOVTABLE message_loop_v2 : public message_loop { class message_filter_impl_base : public message_filter { public: - message_filter_impl_base() {message_loop::get()->add_message_filter(this);} - message_filter_impl_base(t_uint32 lowest, t_uint32 highest) { - message_loop_v2::get()->add_message_filter_ex(this, lowest, highest); - } - ~message_filter_impl_base() {message_loop::get()->remove_message_filter(this);} - bool pretranslate_message(MSG * p_msg) {return false;} + message_filter_impl_base(); + message_filter_impl_base(t_uint32 lowest, t_uint32 highest); + ~message_filter_impl_base(); + + bool pretranslate_message(MSG * p_msg) override {return false;} PFC_CLASS_NOT_COPYABLE(message_filter_impl_base,message_filter_impl_base); }; class message_filter_impl_accel : public message_filter_impl_base { protected: - bool pretranslate_message(MSG * p_msg) { - if (m_wnd != NULL) { - if (GetActiveWindow() == m_wnd) { - if (TranslateAccelerator(m_wnd,m_accel.get(),p_msg) != 0) { - return true; - } - } - } - return false; - } + bool pretranslate_message(MSG * p_msg) override; public: - message_filter_impl_accel(HINSTANCE p_instance,const TCHAR * p_accel) : m_wnd(NULL) { - m_accel.load(p_instance,p_accel); - } + message_filter_impl_accel(HINSTANCE p_instance,const TCHAR * p_accel); void set_wnd(HWND p_wnd) {m_wnd = p_wnd;} private: - HWND m_wnd; + HWND m_wnd = NULL; win32_accelerator m_accel; PFC_CLASS_NOT_COPYABLE(message_filter_impl_accel,message_filter_impl_accel); @@ -69,19 +66,13 @@ class message_filter_impl_accel : public message_filter_impl_base { class message_filter_remap_f1 : public message_filter_impl_base { public: - bool pretranslate_message(MSG * p_msg) { - if (IsOurMsg(p_msg) && m_wnd != NULL && GetActiveWindow() == m_wnd) { - ::PostMessage(m_wnd, WM_SYSCOMMAND, SC_CONTEXTHELP, -1); - return true; - } - return false; - } + bool pretranslate_message(MSG * p_msg) override; void set_wnd(HWND wnd) {m_wnd = wnd;} private: static bool IsOurMsg(const MSG * msg) { return msg->message == WM_KEYDOWN && msg->wParam == VK_F1; } - HWND m_wnd; + HWND m_wnd = NULL; }; class idle_handler_impl_base : public idle_handler { diff --git a/sdk/foobar2000/SDK/metadb.cpp b/sdk/foobar2000/SDK/metadb.cpp index bea4b5e..fce8cd4 100644 --- a/sdk/foobar2000/SDK/metadb.cpp +++ b/sdk/foobar2000/SDK/metadb.cpp @@ -80,6 +80,7 @@ void metadb_io_v2::update_info_async_simple(const pfc::list_base_const_ton_files_rechaptered(local); @@ -115,23 +117,34 @@ metadb_hint_list_v3::ptr metadb_hint_list_v3::create() { return ret; } +metadb_hint_list_v4::ptr metadb_hint_list_v4::create() { + metadb_hint_list_v4::ptr ret; + ret ^= metadb_hint_list::create(); + return ret; +} + void metadb_io_callback_dynamic::register_callback() { + PFC_ASSERT(core_api::is_main_thread()); metadb_io_v3::get()->register_callback(this); } void metadb_io_callback_dynamic::unregister_callback() { + PFC_ASSERT(core_api::is_main_thread()); metadb_io_v3::get()->unregister_callback(this); } void metadb_io_callback_v2_dynamic::register_callback() { + PFC_ASSERT(core_api::is_main_thread()); metadb_io_v5::get()->register_callback_v2(this); } void metadb_io_callback_v2_dynamic::unregister_callback() { + PFC_ASSERT(core_api::is_main_thread()); metadb_io_v5::get()->unregister_callback_v2(this); } bool metadb_io_callback_v2_dynamic::try_register_callback() { + PFC_ASSERT(core_api::is_main_thread()); auto api = metadb_io_v5::tryGet(); if (api.is_empty()) return false; api->register_callback_v2(this); @@ -139,6 +152,23 @@ bool metadb_io_callback_v2_dynamic::try_register_callback() { } void metadb_io_callback_v2_dynamic::try_unregister_callback() { + PFC_ASSERT(core_api::is_main_thread()); auto api = metadb_io_v5::tryGet(); if (api.is_valid()) api->unregister_callback_v2(this); } + +metadb_io_callback_dynamic_impl_base::metadb_io_callback_dynamic_impl_base() { + register_callback(); +} + +metadb_io_callback_dynamic_impl_base::~metadb_io_callback_dynamic_impl_base() { + unregister_callback(); +} + +metadb_io_callback_v2_dynamic_impl_base::metadb_io_callback_v2_dynamic_impl_base() { + register_callback(); +} + +metadb_io_callback_v2_dynamic_impl_base::~metadb_io_callback_v2_dynamic_impl_base() { + unregister_callback(); +} diff --git a/sdk/foobar2000/SDK/metadb.h b/sdk/foobar2000/SDK/metadb.h index 5d5f5d4..a0fd52c 100644 --- a/sdk/foobar2000/SDK/metadb.h +++ b/sdk/foobar2000/SDK/metadb.h @@ -141,6 +141,18 @@ class NOVTABLE metadb_hint_list_v3 : public metadb_hint_list_v2 { virtual void add_hint_forced_reader(const char * p_path,service_ptr_t const & p_reader,abort_callback & p_abort) = 0; }; +//! \since 2.0 +//! Allows dispatching of metadb_io_edit_callback from your code. +class NOVTABLE metadb_hint_list_v4 : public metadb_hint_list_v3 { + FB2K_MAKE_SERVICE_INTERFACE( metadb_hint_list_v4, metadb_hint_list_v3 ); +public: + static metadb_hint_list_v4::ptr create(); + + virtual void before_edit( const char * path, service_ptr_t reader, abort_callback & a ) = 0; + virtual void after_edit( const char * path, service_ptr_t reader, abort_callback & a ) = 0; + +}; + //! New in 0.9.3. Extends metadb_io functionality with nonblocking versions of tag read/write functions, and some other utility features. class NOVTABLE metadb_io_v2 : public metadb_io { @@ -168,23 +180,27 @@ class NOVTABLE metadb_io_v2 : public metadb_io { op_flag_detect_rechapter = 1 << 5, }; - //! Preloads information from the specified tracks. + //! Preloads information from the specified tracks. \n + //! Use from main thread only (starts a threaded_process to show a progress dialog). //! @param p_list List of items to process. //! @param p_op_flags Can be null, or one or more of op_flag_* enum values combined, altering behaviors of the operation. //! @param p_notify Called when the task is completed. Status code is one of t_load_info_state values. Can be null if caller doesn't care. virtual void load_info_async(metadb_handle_list_cref p_list,t_load_info_type p_type,fb2k::hwnd_t p_parent_window,t_uint32 p_op_flags,completion_notify_ptr p_notify) = 0; - //! Updates tags of the specified tracks. + //! Updates tags of the specified tracks. \n + //! Use from main thread only (starts a threaded_process to show a progress dialog). //! @param p_list List of items to process. //! @param p_op_flags Can be null, or one or more of op_flag_* enum values combined, altering behaviors of the operation. //! @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. //! @param p_filter Callback handling actual file_info alterations. Typically used to replace entire meta part of file_info, or to alter something else such as ReplayGain while leaving meta intact. virtual void update_info_async(metadb_handle_list_cref p_list,service_ptr_t p_filter,fb2k::hwnd_t p_parent_window,t_uint32 p_op_flags,completion_notify_ptr p_notify) = 0; - //! Rewrites tags of the specified tracks; similar to update_info_async() but using last known/cached file_info values rather than values passed by caller. + //! Rewrites tags of the specified tracks; similar to update_info_async() but using last known/cached file_info values rather than values passed by caller. \n + //! Use from main thread only (starts a threaded_process to show a progress dialog). //! @param p_list List of items to process. //! @param p_op_flags Can be null, or one or more of op_flag_* enum values combined, altering behaviors of the operation. //! @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 rewrite_info_async(metadb_handle_list_cref p_list,fb2k::hwnd_t p_parent_window,t_uint32 p_op_flags,completion_notify_ptr p_notify) = 0; - //! Strips all tags / metadata fields from the specified tracks. + //! Strips all tags / metadata fields from the specified tracks. \n + //! Use from main thread only (starts a threaded_process to show a progress dialog). //! @param p_list List of items to process. //! @param p_op_flags Can be null, or one or more of op_flag_* enum values combined, altering behaviors of the operation. //! @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. @@ -194,7 +210,8 @@ class NOVTABLE metadb_io_v2 : public metadb_io { //! 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. virtual metadb_hint_list::ptr create_hint_list() = 0; - //! Updates tags of the specified tracks. Helper; uses update_info_async internally. + //! Updates tags of the specified tracks. Helper; uses update_info_async internally. \n + //! Use from main thread only (starts a threaded_process to show a progress dialog). //! @param p_list List of items to process. //! @param p_op_flags Can be null, or one or more of op_flag_* enum values combined, altering behaviors of the operation. //! @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. @@ -202,10 +219,12 @@ class NOVTABLE metadb_io_v2 : public metadb_io { void update_info_async_simple(metadb_handle_list_cref p_list,const pfc::list_base_const_t & p_new_info, fb2k::hwnd_t p_parent_window,t_uint32 p_op_flags,completion_notify_ptr p_notify); //! Helper to be called after a file has been rechaptered. \n - //! Forcibly reloads info then tells playlist_manager to update all affected playlists. + //! Forcibly reloads info then tells playlist_manager to update all affected playlists. \n + //! Call from main thread only. 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. + //! Forcibly reloads info then tells playlist_manager to update all affected playlists. \n + //! Call from main thread only. void on_files_rechaptered( metadb_handle_list_cref newHandles ); FB2K_MAKE_SERVICE_COREAPI_EXTENSION(metadb_io_v2,metadb_io); @@ -215,7 +234,13 @@ class NOVTABLE metadb_io_v2 : public metadb_io { //! \since 0.9.5 class NOVTABLE metadb_io_v3 : public metadb_io_v2 { public: + //! Registers a callback object to receive notifications about metadb_io operations. \n + //! See: metadb_io_callback_dynamic \n + //! Call from main thread only. virtual void register_callback(metadb_io_callback_dynamic * p_callback) = 0; + //! Unregisters a callback object to receive notifications about metadb_io operations. \n + //! See: metadb_io_callback_dynamic \n + //! Call from main thread only. virtual void unregister_callback(metadb_io_callback_dynamic * p_callback) = 0; FB2K_MAKE_SERVICE_COREAPI_EXTENSION(metadb_io_v3,metadb_io_v2); @@ -230,15 +255,18 @@ class NOVTABLE metadb_io_v4 : public 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. + //! Useful for performing the operation with your own in-dialog progress display instead of the generic progress popup. \n + //! Main thread only. virtual service_ptr_t spawn_update_info( metadb_handle_list_cref items, service_ptr_t 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. + //! Useful for performing the operation with your own in-dialog progress display instead of the generic progress popup. \n + //! Main thread only. virtual service_ptr_t 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. + //! Useful for performing the operation with your own in-dialog progress display instead of the generic progress popup. \n + //! Main thread only. virtual service_ptr_t spawn_load_info( metadb_handle_list_cref items, t_load_info_type opType, uint32_t opFlags, completion_notify_ptr reply) = 0; }; @@ -246,7 +274,11 @@ class NOVTABLE metadb_io_v4 : public metadb_io_v3 { class NOVTABLE metadb_io_v5 : public metadb_io_v4 { FB2K_MAKE_SERVICE_COREAPI_EXTENSION(metadb_io_v5, metadb_io_v4); public: + //! Register a metadb_io_callback_v2_dynamic object to receive notifications about metadb_io events. \n + //! Main thread only. virtual void register_callback_v2(metadb_io_callback_v2_dynamic*) = 0; + //! Unregister a metadb_io_callback_v2_dynamic object. \n + //! Main thread only. virtual void unregister_callback_v2(metadb_io_callback_v2_dynamic*) = 0; }; diff --git a/sdk/foobar2000/SDK/metadb_callbacks.h b/sdk/foobar2000/SDK/metadb_callbacks.h index e7bc412..c184961 100644 --- a/sdk/foobar2000/SDK/metadb_callbacks.h +++ b/sdk/foobar2000/SDK/metadb_callbacks.h @@ -4,7 +4,8 @@ //! Callback service receiving notifications about metadb contents changes. class NOVTABLE metadb_io_callback : public service_base { public: - //! Called when metadb contents change. (Or, one of display hook component requests display update). + //! Called when metadb contents change. (Or, one of display hook component requests display update). \n + //! Main thread only. //! @param p_items_sorted List of items that have been updated. The list is always sorted by pointer value, to allow fast bsearch to test whether specific item has changed. //! @param p_fromhook Set to true when actual file contents haven't changed but one of metadb_display_field_provider implementations requested an update so output of metadb_handle::format_title() etc has changed. virtual void on_changed_sorted(metadb_handle_list_cref p_items_sorted, bool p_fromhook) = 0; @@ -15,6 +16,7 @@ class NOVTABLE metadb_io_callback : public service_base { //! Dynamically-registered version of metadb_io_callback. See metadb_io_callback for documentation, register instances using metadb_io_v3::register_callback(). It's recommended that you use the metadb_io_callback_dynamic_impl_base helper class to manage registration/unregistration. class NOVTABLE metadb_io_callback_dynamic { public: + //! See metadb_io_callback::on_changed_sorted() virtual void on_changed_sorted(metadb_handle_list_cref p_items_sorted, bool p_fromhook) = 0; void register_callback(); void unregister_callback(); @@ -26,8 +28,8 @@ class metadb_io_callback_dynamic_impl_base : public metadb_io_callback_dynamic { public: void on_changed_sorted(metadb_handle_list_cref p_items_sorted, bool p_fromhook) override {} - metadb_io_callback_dynamic_impl_base() { register_callback(); } - ~metadb_io_callback_dynamic_impl_base() { unregister_callback(); } + metadb_io_callback_dynamic_impl_base(); + ~metadb_io_callback_dynamic_impl_base(); PFC_CLASS_NOT_COPYABLE_EX(metadb_io_callback_dynamic_impl_base) }; @@ -61,6 +63,7 @@ class NOVTABLE metadb_io_callback_v2_data { }; //! \since 2.0 +//! Extended version of metadb_io_callback. class NOVTABLE metadb_io_callback_v2 : public metadb_io_callback { FB2K_MAKE_SERVICE_INTERFACE(metadb_io_callback_v2, metadb_io_callback); public: @@ -70,6 +73,17 @@ class NOVTABLE metadb_io_callback_v2 : public metadb_io_callback { }; //! \since 2.0 +//! NEW interface introduced in late 2.0. \n +//! Invoked *BEFORE* actual update, with incoming info. \n +//! Note that incoming info may be partial (either main info or browse info not set), in such cases the info will remain unchanged. +class NOVTABLE metadb_pre_update_callback : public service_base { + FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT( metadb_pre_update_callback ); +public: + virtual void will_update( metadb_handle_list_cref itemsSorted, metadb_io_callback_v2_data & data) = 0; +}; + +//! \since 2.0 +//! Extended version of metadb_io_callback_dynamic. class NOVTABLE metadb_io_callback_v2_dynamic { public: virtual void on_changed_sorted_v2(metadb_handle_list_cref itemsSorted, metadb_io_callback_v2_data & data, bool bFromHook) = 0; @@ -84,8 +98,8 @@ class metadb_io_callback_v2_dynamic_impl_base : public metadb_io_callback_v2_dyn public: void on_changed_sorted_v2(metadb_handle_list_cref itemsSorted, metadb_io_callback_v2_data & data, bool bFromHook) override {} - metadb_io_callback_v2_dynamic_impl_base() { register_callback(); } - ~metadb_io_callback_v2_dynamic_impl_base() { unregister_callback(); } + metadb_io_callback_v2_dynamic_impl_base(); + ~metadb_io_callback_v2_dynamic_impl_base(); PFC_CLASS_NOT_COPYABLE_EX(metadb_io_callback_v2_dynamic_impl_base) }; diff --git a/sdk/foobar2000/SDK/noInfo.h b/sdk/foobar2000/SDK/noInfo.h index a4846bf..3a75ce3 100644 --- a/sdk/foobar2000/SDK/noInfo.h +++ b/sdk/foobar2000/SDK/noInfo.h @@ -3,6 +3,7 @@ #include "file_info.h" namespace fb2k { + //! Helper: shared blank file_info object. See: file_info. class noInfo_t : public file_info { [[noreturn]] static void verboten() { FB2K_BugCheck(); } public: diff --git a/sdk/foobar2000/SDK/playlistColumnProvider.h b/sdk/foobar2000/SDK/playlistColumnProvider.h index bb26bc9..234c30e 100644 --- a/sdk/foobar2000/SDK/playlistColumnProvider.h +++ b/sdk/foobar2000/SDK/playlistColumnProvider.h @@ -1,18 +1,28 @@ #pragma once namespace fb2k { + //! Declares a column to be made available in Default UI playlist view, \n + //! without user having to manually enter title formatting patterns. class playlistColumnProvider : public service_base { FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(playlistColumnProvider); public: + //! Number of columns published by this object. virtual size_t numColumns() = 0; + //! Unique identifier of a column. virtual GUID columnID(size_t col) = 0; + //! Formatting pattern used for displaying a column. virtual fb2k::stringRef columnFormatSpec(size_t col) = 0; + //! Optional; sorting pattern used for this column. Return null to use display pattern for sorting. virtual fb2k::stringRef columnSortScript(size_t col) = 0; + //! Name of the column shown to the user. virtual fb2k::stringRef columnName(size_t col) = 0; + //! Display flags (alignment). \n + //! See flag_* constants. virtual unsigned columnFlags(size_t col) = 0; static constexpr unsigned flag_alignLeft = 0; static constexpr unsigned flag_alignRight = 1 << 0; static constexpr unsigned flag_alignCenter = 1 << 1; + static constexpr unsigned flag_alignMask = (flag_alignLeft|flag_alignRight|flag_alignCenter); }; } diff --git a/sdk/foobar2000/SDK/playlist_loader.cpp b/sdk/foobar2000/SDK/playlist_loader.cpp index 26c92bc..85e6836 100644 --- a/sdk/foobar2000/SDK/playlist_loader.cpp +++ b/sdk/foobar2000/SDK/playlist_loader.cpp @@ -11,23 +11,6 @@ static void process_path_internal(const char * p_path,const service_ptr_t & p_reader,playlist_loader_callback::ptr callback, abort_callback & abort,playlist_loader_callback::t_entry_type type,const t_filestats & p_stats); -namespace { - class archive_callback_impl : public archive_callback { - public: - archive_callback_impl(playlist_loader_callback::ptr p_callback, abort_callback & p_abort) : m_callback(p_callback), m_abort(p_abort) {} - bool on_entry(archive * owner,const char * p_path,const t_filestats & p_stats,const service_ptr_t & p_reader) - { - process_path_internal(p_path,p_reader,m_callback,m_abort,playlist_loader_callback::entry_directory_enumerated,p_stats); - return !m_abort.is_aborting(); - } - bool is_aborting() const {return m_abort.is_aborting();} - abort_callback_event get_abort_event() const {return m_abort.get_abort_event();} - private: - const playlist_loader_callback::ptr m_callback; - abort_callback & m_abort; - }; -} - bool playlist_loader::g_try_load_playlist(file::ptr fileHint,const char * p_path,playlist_loader_callback::ptr p_callback, abort_callback & p_abort) { // Determine if this file is a playlist or not (which usually means that it's a media file) pfc::string8 filepath; @@ -327,7 +310,6 @@ static void process_path_internal(const char * p_path,const service_ptr_t } { - archive_callback_impl archive_results(callback, abort); for (auto f : filesystem::enumerate()) { abort.check(); service_ptr_t arch; @@ -335,7 +317,10 @@ static void process_path_internal(const char * p_path,const service_ptr_t if (p_reader.is_valid()) p_reader->reopen(abort); try { - TRACK_CODE("archive::archive_list",arch->archive_list(p_path,p_reader,archive_results,true)); + archive::list_func_t archive_results = [callback, &abort](const char* p_path, const t_filestats& p_stats, file::ptr p_reader) { + process_path_internal(p_path,p_reader,callback,abort,playlist_loader_callback::entry_directory_enumerated,p_stats); + }; + TRACK_CODE("archive::archive_list",arch->archive_list(p_path,p_reader,archive_results,/*want readers*/true, abort)); return; } catch(exception_aborted) {throw;} catch(...) { diff --git a/sdk/foobar2000/SDK/popup_message.cpp b/sdk/foobar2000/SDK/popup_message.cpp index 3e4ec03..8682df8 100644 --- a/sdk/foobar2000/SDK/popup_message.cpp +++ b/sdk/foobar2000/SDK/popup_message.cpp @@ -135,6 +135,7 @@ int popup_message_v3::messageBoxReply(uint32_t status) { return -1; } void popup_message_v3::messageBoxAsync(fb2k::hwnd_t parent, const char* msg, const char* title, unsigned flags, std::function reply) { + PFC_ASSERT( core_api::is_main_thread() ); auto q = setupMessageBox(parent, msg, title, flags); if (reply) { q.reply = fb2k::makeCompletionNotify([reply](unsigned code) { @@ -144,6 +145,7 @@ void popup_message_v3::messageBoxAsync(fb2k::hwnd_t parent, const char* msg, con this->show_query(q); } int popup_message_v3::messageBox(fb2k::hwnd_t parent, const char* msg, const char* title, unsigned flags) { + PFC_ASSERT( core_api::is_main_thread() ); auto q = setupMessageBox(parent, msg, title, flags); uint32_t status = this->show_query_modal(q); return messageBoxReply(status); diff --git a/sdk/foobar2000/SDK/popup_message.h b/sdk/foobar2000/SDK/popup_message.h index 72e69cf..f6ca598 100644 --- a/sdk/foobar2000/SDK/popup_message.h +++ b/sdk/foobar2000/SDK/popup_message.h @@ -6,8 +6,8 @@ //! 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 +//! Thread safety: OK to call from worker threads (will delegate UI ops to main thread automatically). \n //! Note that all strings are UTF-8. - class NOVTABLE popup_message : public service_base { public: enum t_icon {icon_information, icon_error, icon_query}; @@ -46,6 +46,9 @@ class NOVTABLE popup_message : public service_base { #define EXCEPTION_TO_POPUP_MESSAGE(CODE,LABEL) try { CODE; } catch(std::exception const & e) {popup_message::g_complain(LABEL,e);} //! \since 1.1 +//! Extendsion to popup_message API. \n +//! Thread safety: OK to call from worker threads (will delegate UI ops to main thread automatically). \n +//! Note that all strings are UTF-8. class NOVTABLE popup_message_v2 : public service_base { FB2K_MAKE_SERVICE_COREAPI(popup_message_v2); public: @@ -58,6 +61,8 @@ class NOVTABLE popup_message_v2 : public service_base { }; namespace fb2k { + //! \since 2.0 + //! Not really implemented for Windows yet. class popup_toast : public service_base { FB2K_MAKE_SERVICE_COREAPI( popup_toast ); public: @@ -71,8 +76,10 @@ namespace fb2k { class toastFormatter : public pfc::string_formatter { public: - ~toastFormatter() { - if ( this->length() > 0 ) showToast( c_str() ); + ~toastFormatter() noexcept { + try { + if ( this->length() > 0 ) showToast( c_str() ); + } catch(...) {} } }; } @@ -81,6 +88,8 @@ namespace fb2k { //! \since 1.5 +//! MessageBox-like dialog, only non-blocking and with dark mode support under foobar2000 v2.0. \n +//! Call from main thread only (contrary to popup_message / popup_message_v2) !!! class NOVTABLE popup_message_v3 : public service_base { FB2K_MAKE_SERVICE_COREAPI(popup_message_v3); public: diff --git a/sdk/foobar2000/SDK/powerManager.h b/sdk/foobar2000/SDK/powerManager.h index 0d96e2a..9ba99a0 100644 --- a/sdk/foobar2000/SDK/powerManager.h +++ b/sdk/foobar2000/SDK/powerManager.h @@ -1,6 +1,7 @@ #pragma once namespace fb2k { + //! \since 2.0 class powerManager : public service_base { public: enum { @@ -10,11 +11,13 @@ namespace fb2k { flagDisplay = flagStrong }; - //! Blocks device sleep for the duration of returned object's lifetime. - //! By default we ask politely but can be still put to sleep by the OS. Specify flagStrong to force the device into awake state (possibly at cost of keeping the screen up). + //! Blocks device sleep for the duration of returned object's lifetime. \n + //! By default we ask politely but can be still put to sleep by the OS. Specify flagStrong to force the device into awake state (possibly at cost of keeping the screen up). \n + //! Thread safety: OK to call from any thread. virtual objRef makeTask(const char* name, unsigned flags) = 0; - //! Returns whether we're running on AC power (not on battery). + //! Returns whether we're running on AC power (not on battery). \n + //! Thread safety: OK to call from any thread. virtual bool haveACPower() = 0; objRef makeTaskWeak(const char* name) { return makeTask(name, 0); } diff --git a/sdk/foobar2000/SDK/threaded_process.cpp b/sdk/foobar2000/SDK/threaded_process.cpp index 16796f6..b8fc8ef 100644 --- a/sdk/foobar2000/SDK/threaded_process.cpp +++ b/sdk/foobar2000/SDK/threaded_process.cpp @@ -29,11 +29,13 @@ void threaded_process_status::set_progress_secondary_float(double p_state) bool threaded_process::g_run_modal(service_ptr_t p_callback,unsigned p_flags,fb2k::hwnd_t p_parent,const char * p_title,t_size p_title_len) { + PFC_ASSERT( core_api::is_main_thread() ); return threaded_process::get()->run_modal(p_callback,p_flags,p_parent,p_title,p_title_len); } bool threaded_process::g_run_modeless(service_ptr_t p_callback,unsigned p_flags,fb2k::hwnd_t p_parent,const char * p_title,t_size p_title_len) { + PFC_ASSERT( core_api::is_main_thread() ); return threaded_process::get()->run_modeless(p_callback,p_flags,p_parent,p_title,p_title_len); } diff --git a/sdk/foobar2000/SDK/threaded_process.h b/sdk/foobar2000/SDK/threaded_process.h index 3fd92cc..1618017 100644 --- a/sdk/foobar2000/SDK/threaded_process.h +++ b/sdk/foobar2000/SDK/threaded_process.h @@ -96,14 +96,16 @@ class NOVTABLE threaded_process : public service_base { }; //! Runs a synchronous threaded_process operation - the function does not return until the operation has completed, though the app UI is not frozen and the operation is abortable. \n - //! This API is obsolete and should not be used. Please use run_modeless() instead if possible. + //! This API is obsolete and should not be used. Please use run_modeless() instead if possible. \n + //! Call from main thread only. //! @param p_callback Interface to your threaded_process client. //! @param p_flags Flags describing requested dialog functionality. See threaded_process::flag_* constants. //! @param p_parent Parent window for the progress dialog - typically core_api::get_main_window(). //! @param p_title Initial title of the dialog. //! @returns True if the operation has completed normally, false if the user has aborted the operation. In case of a catastrophic failure such as dialog creation failure, exceptions will be thrown. virtual bool run_modal(service_ptr_t p_callback,unsigned p_flags,fb2k::hwnd_t p_parent,const char * p_title,t_size p_title_len = SIZE_MAX) = 0; - //! Runs an asynchronous threaded_process operation. + //! Runs an asynchronous threaded_process operation. \n + //! Call from main thread only. //! @param p_callback Interface to your threaded_process client. //! @param p_flags Flags describing requested dialog functionality. See threaded_process::flag_* constants. //! @param p_parent Parent window for the progress dialog - typically core_api::get_main_window(). diff --git a/sdk/foobar2000/SDK/threadsLite.h b/sdk/foobar2000/SDK/threadsLite.h index 6c8255b..28a7a1b 100644 --- a/sdk/foobar2000/SDK/threadsLite.h +++ b/sdk/foobar2000/SDK/threadsLite.h @@ -14,11 +14,17 @@ namespace fb2k { // ====================================================================================================== 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. + //! You can call this from any thread, including main thread - to execute some code outside the current call stack / global fb2k callbacks / etc. \n + //! Guaranteed FIFO order of execution. See also: main_thread_callback::add_callback(). void inMainThread(std::function f); //! Call f synchronously if called from main thread, queue call if called from another. void inMainThread2(std::function f); - //! Synchronous version. + //! Synchronous / abortable version. May exit *before* f() finishes, if abort becomes set. void inMainThreadSynchronous(std::function f, abort_callback& abort); + + //! Synchronous blocking version. \n + //! Uses new foobar2000 v2.0 methods if available, synchronizing to main thread via SendMessage(). \n + //! Introduced to help recovering from method-called-from-wrong-context scenarios. Does *not* guarentee FIFO execution order contrary to plain inMainThread(). + void inMainThreadSynchronous2(std::function f); } diff --git a/sdk/foobar2000/SDK/ui_element.cpp b/sdk/foobar2000/SDK/ui_element.cpp index e7ccbe1..51e9241 100644 --- a/sdk/foobar2000/SDK/ui_element.cpp +++ b/sdk/foobar2000/SDK/ui_element.cpp @@ -239,17 +239,20 @@ ui_element_replace_dialog_notify::ptr ui_element_replace_dialog_notify::create(s } bool ui_config_manager::is_dark_mode() { + PFC_ASSERT(core_api::is_main_thread()); t_ui_color clr = 0xFFFFFF; if (this->query_color(ui_color_darkmode, clr)) return clr == 0; return false; } bool ui_config_manager::g_is_dark_mode() { + PFC_ASSERT(core_api::is_main_thread()); auto api = tryGet(); if (api.is_valid()) return api->is_dark_mode(); else return false; } #ifdef _WIN32 t_ui_color ui_config_manager::getSysColor(int sysColorIndex) { + PFC_ASSERT(core_api::is_main_thread()); GUID guid = ui_color_from_sys_color_index(sysColorIndex); if (guid != pfc::guid_null) { t_ui_color ret = 0; @@ -260,11 +263,13 @@ t_ui_color ui_config_manager::getSysColor(int sysColorIndex) { #endif ui_config_callback_impl::ui_config_callback_impl() { + PFC_ASSERT(core_api::is_main_thread()); auto api = ui_config_manager::tryGet(); if (api.is_valid()) api->add_callback(this); } ui_config_callback_impl::~ui_config_callback_impl() { + PFC_ASSERT(core_api::is_main_thread()); auto api = ui_config_manager::tryGet(); if (api.is_valid()) api->remove_callback(this); } diff --git a/sdk/foobar2000/SDK/ui_element.h b/sdk/foobar2000/SDK/ui_element.h index 85921cd..49432d3 100644 --- a/sdk/foobar2000/SDK/ui_element.h +++ b/sdk/foobar2000/SDK/ui_element.h @@ -612,13 +612,19 @@ class NOVTABLE ui_config_callback { class NOVTABLE ui_config_manager : public service_base { FB2K_MAKE_SERVICE_COREAPI(ui_config_manager); public: + //! Registers a callback to receive notifications about colors/fonts change. \n + //! Main thread only! virtual void add_callback(ui_config_callback*) = 0; + //! Unregisters a callback to receive notifications about colors/fonts change. \n + //! Main thread only! virtual void remove_callback(ui_config_callback*) = 0; - //! Queries actual color to be used for the specified ui_color_* element. + //! Queries actual color to be used for the specified ui_color_* element. \n + //! Main thread only! \n //! @returns True if color is user-overridden, false if system-default color should be used. virtual bool query_color(const GUID& p_what, t_ui_color& p_out) = 0; //! Queries font to be used for the specified ui_font_* element. \n + //! Main thread only! \n //! The returned font handle is valid until the next font change callback cycle *completes*, that is, during a font change callback, both old and new handle are momentarily valid. virtual t_ui_font query_font(const GUID& p_what) = 0; @@ -629,13 +635,24 @@ class NOVTABLE ui_config_manager : public service_base { t_ui_color getSysColor(int sysColorIndex); #endif - //! Special method that's safe to call without checking if ui_config_manager exists, that is, it works on foobar2000 < 2.0. - //! Returns false if ui_conifg_manager doesn't exist and therefore dark mode isn't supported by this foobar2000 revision. + //! Special method that's safe to call without checking if ui_config_manager exists, that is, it works on foobar2000 < 2.0. \n + //! Returns false if ui_conifg_manager doesn't exist and therefore dark mode isn't supported by this foobar2000 revision. \n + //! Main thread only! static bool g_is_dark_mode(); }; //! \since 2.0 -//! Does nothing (fails to register quietly) if used in fb2k prior to 2.0 +class NOVTABLE ui_config_manager_v2 : public ui_config_manager { + FB2K_MAKE_SERVICE_COREAPI_EXTENSION(ui_config_manager_v2, ui_config_manager) +public: + //! Tells ui_config_manager about system theme having changed. \n + //! Intended for keeping track of live dark mode toggle when foo_ui_std is not the active UI. Do not use. + virtual void notify_system_theme_changed() = 0; +}; + +//! \since 2.0 +//! Does nothing (fails to register quietly) if used in fb2k prior to 2.0 \n +//! Use in main thread only! class ui_config_callback_impl : public ui_config_callback { public: ui_config_callback_impl(); diff --git a/sdk/foobar2000/SDK/utility.cpp b/sdk/foobar2000/SDK/utility.cpp index 2cb0ba3..8af69c8 100644 --- a/sdk/foobar2000/SDK/utility.cpp +++ b/sdk/foobar2000/SDK/utility.cpp @@ -132,6 +132,7 @@ namespace fb2k { namespace fb2k { void callLater(double timeAfter, std::function< void() > func) { + PFC_ASSERT( core_api::is_main_thread() ); auto releaseMe = std::make_shared(); *releaseMe = registerTimer(timeAfter, [=] { if (releaseMe->is_valid()) { @@ -141,6 +142,7 @@ namespace fb2k { }); } objRef registerTimer(double interval, std::function func) { + PFC_ASSERT( core_api::is_main_thread() ); return static_api_ptr_t()->addTimer(interval, makeCompletionNotify([func](unsigned) { func(); })); } } @@ -337,3 +339,43 @@ namespace fb2k { return callback_merit_default; } } + +#ifdef _WIN32 +#include "message_loop.h" +message_filter_impl_base::message_filter_impl_base() { + PFC_ASSERT( core_api::is_main_thread() ); + message_loop::get()->add_message_filter(this); +} +message_filter_impl_base::message_filter_impl_base(t_uint32 lowest, t_uint32 highest) { + PFC_ASSERT( core_api::is_main_thread() ); + message_loop_v2::get()->add_message_filter_ex(this, lowest, highest); +} +message_filter_impl_base::~message_filter_impl_base() { + PFC_ASSERT( core_api::is_main_thread() ); + message_loop::get()->remove_message_filter(this); +} + +bool message_filter_impl_accel::pretranslate_message(MSG * p_msg) { + if (m_wnd != NULL) { + if (GetActiveWindow() == m_wnd) { + if (TranslateAccelerator(m_wnd,m_accel.get(),p_msg) != 0) { + return true; + } + } + } + return false; +} + +message_filter_impl_accel::message_filter_impl_accel(HINSTANCE p_instance,const TCHAR * p_accel) { + m_accel.load(p_instance,p_accel); +} + +bool message_filter_remap_f1::pretranslate_message(MSG * p_msg) { + if (IsOurMsg(p_msg) && m_wnd != NULL && GetActiveWindow() == m_wnd) { + ::PostMessage(m_wnd, WM_SYSCOMMAND, SC_CONTEXTHELP, -1); + return true; + } + return false; +} + +#endif \ No newline at end of file diff --git a/sdk/foobar2000/foo_sample/foo_sample.vcxproj b/sdk/foobar2000/foo_sample/foo_sample.vcxproj index 7ac8e6d..2b1d488 100644 --- a/sdk/foobar2000/foo_sample/foo_sample.vcxproj +++ b/sdk/foobar2000/foo_sample/foo_sample.vcxproj @@ -191,7 +191,6 @@ true Windows - false ../shared/shared-$(Platform).lib @@ -214,7 +213,6 @@ true Windows - false ../shared/shared-$(Platform).lib @@ -299,7 +297,6 @@ Windows true true - false ../shared/shared-$(Platform).lib @@ -327,7 +324,6 @@ Windows true true - false ../shared/shared-$(Platform).lib @@ -373,6 +369,7 @@ + @@ -394,5 +391,12 @@ + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + \ No newline at end of file diff --git a/sdk/foobar2000/foo_sample/foo_sample.vcxproj.filters b/sdk/foobar2000/foo_sample/foo_sample.vcxproj.filters index c9aa418..e0dae3e 100644 --- a/sdk/foobar2000/foo_sample/foo_sample.vcxproj.filters +++ b/sdk/foobar2000/foo_sample/foo_sample.vcxproj.filters @@ -94,5 +94,6 @@ + \ No newline at end of file diff --git a/sdk/foobar2000/foo_sample/main.cpp b/sdk/foobar2000/foo_sample/main.cpp index 44a6e31..bd4c0ca 100644 --- a/sdk/foobar2000/foo_sample/main.cpp +++ b/sdk/foobar2000/foo_sample/main.cpp @@ -9,3 +9,6 @@ DECLARE_COMPONENT_VERSION("Sample Component","1.0","about message goes here"); // This will prevent users from renaming your component around (important for proper troubleshooter behaviors) or loading multiple instances of it. VALIDATE_COMPONENT_FILENAME("foo_sample.dll"); + +// Activate cfg_var downgrade functionality if enabled. Relevant only when cycling from newer FOOBAR2000_TARGET_VERSION to older. +FOOBAR2000_IMPLEMENT_CFG_VAR_DOWNGRADE; diff --git a/sdk/foobar2000/foo_sample/packages.config b/sdk/foobar2000/foo_sample/packages.config new file mode 100644 index 0000000..1c54a40 --- /dev/null +++ b/sdk/foobar2000/foo_sample/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/sdk/foobar2000/foo_sample/preferences.cpp b/sdk/foobar2000/foo_sample/preferences.cpp index 97d6852..cc45cd7 100644 --- a/sdk/foobar2000/foo_sample/preferences.cpp +++ b/sdk/foobar2000/foo_sample/preferences.cpp @@ -15,25 +15,53 @@ // These GUIDs identify the variables within our component's configuration file. -static const GUID guid_cfg_bogoSetting1 = { 0xbd5c777, 0x735c, 0x440d, { 0x8c, 0x71, 0x49, 0xb6, 0xac, 0xff, 0xce, 0xb8 } }; -static const GUID guid_cfg_bogoSetting2 = { 0x752f1186, 0x9f61, 0x4f91, { 0xb3, 0xee, 0x2f, 0x25, 0xb1, 0x24, 0x83, 0x5d } }; +static constexpr GUID guid_cfg_bogoSetting1 = { 0xbd5c777, 0x735c, 0x440d, { 0x8c, 0x71, 0x49, 0xb6, 0xac, 0xff, 0xce, 0xb8 } }; +static constexpr GUID guid_cfg_bogoSetting2 = { 0x752f1186, 0x9f61, 0x4f91, { 0xb3, 0xee, 0x2f, 0x25, 0xb1, 0x24, 0x83, 0x5d } }; // This GUID identifies our Advanced Preferences branch (replace with your own when reusing code). -static const GUID guid_advconfig_branch = { 0x28564ced, 0x4abf, 0x4f0c, { 0xa4, 0x43, 0x98, 0xda, 0x88, 0xe2, 0xcd, 0x39 } }; +static constexpr GUID guid_advconfig_branch = { 0x28564ced, 0x4abf, 0x4f0c, { 0xa4, 0x43, 0x98, 0xda, 0x88, 0xe2, 0xcd, 0x39 } }; // This GUID identifies our Advanced Preferences setting (replace with your own when reusing code) as well as this setting's storage within our component's configuration file. -static const GUID guid_cfg_bogoSetting3 = { 0xf7008963, 0xed60, 0x4084, { 0xa8, 0x5d, 0xd1, 0xcd, 0xc5, 0x51, 0x22, 0xca } }; +static constexpr GUID guid_cfg_bogoSetting3 = { 0xf7008963, 0xed60, 0x4084, { 0xa8, 0x5d, 0xd1, 0xcd, 0xc5, 0x51, 0x22, 0xca } }; +static constexpr GUID guid_cfg_bogoSetting4 = { 0x99e206f8, 0xd7be, 0x47e6, { 0xb5, 0xfe, 0xf4, 0x41, 0x5f, 0x6c, 0x16, 0xed } }; +static constexpr GUID guid_cfg_bogoSetting5 = { 0x7369ad25, 0x9e81, 0x4e2f, { 0x8b, 0xe7, 0x95, 0xcb, 0x81, 0x99, 0x9b, 0x1b } }; +static constexpr GUID guid_cfg_bogoRadio = { 0x4c18b9ab, 0xf823, 0x4d05, { 0xb6, 0x18, 0x14, 0xb9, 0x4c, 0xad, 0xa2, 0xaa } }; +static constexpr GUID guid_cfg_bogoRadio1 = { 0xdd0a3a95, 0x1546, 0x4f25, { 0xa6, 0x8c, 0x23, 0xcf, 0x3d, 0xa5, 0x8f, 0x59 } }; +static constexpr GUID guid_cfg_bogoRadio2 = { 0xc35e1689, 0xb96f, 0x4bf4, { 0x95, 0xfb, 0xb7, 0x8e, 0x83, 0xc5, 0x2c, 0x7d } }; +static constexpr GUID guid_cfg_bogoRadio3 = { 0x790fe179, 0x9908, 0x47e2, { 0x9f, 0xde, 0xce, 0xe1, 0x3f, 0x9a, 0xfc, 0x5b } }; + +// defaults +constexpr int default_cfg_bogo1 = 1337, + default_cfg_bogo2 = 666, + default_cfg_bogo3 = 42; + +static constexpr char default_cfg_bogo4[] = "foobar"; +static constexpr bool default_cfg_bogo5 = false; + +// Advanced preferences order +enum { + order_bogo3, + order_bogo4, + order_bogo5, + order_bogoRadio +}; enum { - default_cfg_bogoSetting1 = 1337, - default_cfg_bogoSetting2 = 666, - default_cfg_bogoSetting3 = 42, + order_bogoRadio1, + order_bogoRadio2, + order_bogoRadio3, }; -static cfg_uint cfg_bogoSetting1(guid_cfg_bogoSetting1, default_cfg_bogoSetting1), cfg_bogoSetting2(guid_cfg_bogoSetting2, default_cfg_bogoSetting2); +static cfg_uint cfg_bogoSetting1(guid_cfg_bogoSetting1, default_cfg_bogo1), cfg_bogoSetting2(guid_cfg_bogoSetting2, default_cfg_bogo2); static advconfig_branch_factory g_advconfigBranch("Sample Component", guid_advconfig_branch, advconfig_branch::guid_branch_tools, 0); -static advconfig_integer_factory cfg_bogoSetting3("Bogo setting 3", guid_cfg_bogoSetting3, guid_advconfig_branch, 0, default_cfg_bogoSetting3, 0 /*minimum value*/, 9999 /*maximum value*/); +static advconfig_integer_factory cfg_bogoSetting3("Bogo setting 3","foo_sample.bogo3", guid_cfg_bogoSetting3, guid_advconfig_branch, order_bogo3, default_cfg_bogo3, 0 /*minimum value*/, 9999 /*maximum value*/); +static advconfig_string_factory cfg_bogoSetting4("Bogo setting 4", "foo_sample.bogo4", guid_cfg_bogoSetting4, guid_advconfig_branch, order_bogo4, default_cfg_bogo4); +static advconfig_checkbox_factory cfg_bogoSetting5("Bogo setting 5", "foo_sample.bogo5", guid_cfg_bogoSetting5, guid_advconfig_branch, order_bogo5, default_cfg_bogo5); +static advconfig_branch_factory cfg_bogoRadioBranch("Bogo radio", guid_cfg_bogoRadio, guid_advconfig_branch, order_bogoRadio); +static advconfig_radio_factory cfg_bogoRadio1("Radio 1", "foo_sample.bogoRaidio.1", guid_cfg_bogoRadio1, guid_cfg_bogoRadio, order_bogoRadio1, true); +static advconfig_radio_factory cfg_bogoRadio2("Radio 2", "foo_sample.bogoRaidio.2", guid_cfg_bogoRadio2, guid_cfg_bogoRadio, order_bogoRadio2, false); +static advconfig_radio_factory cfg_bogoRadio3("Radio 3", "foo_sample.bogoRaidio.3", guid_cfg_bogoRadio3, guid_cfg_bogoRadio, order_bogoRadio3, false); class CMyPreferences : public CDialogImpl, public preferences_page_instance { public: @@ -93,8 +121,8 @@ t_uint32 CMyPreferences::get_state() { } void CMyPreferences::reset() { - SetDlgItemInt(IDC_BOGO1, default_cfg_bogoSetting1, FALSE); - SetDlgItemInt(IDC_BOGO2, default_cfg_bogoSetting2, FALSE); + SetDlgItemInt(IDC_BOGO1, default_cfg_bogo1, FALSE); + SetDlgItemInt(IDC_BOGO2, default_cfg_bogo2, FALSE); OnChanged(); } diff --git a/sdk/foobar2000/helpers/CallForwarder.h b/sdk/foobar2000/helpers/CallForwarder.h index d1ed43f..257458d 100644 --- a/sdk/foobar2000/helpers/CallForwarder.h +++ b/sdk/foobar2000/helpers/CallForwarder.h @@ -1,6 +1,5 @@ #pragma once -#include - +#include "callInMainThreadHelper.h" namespace CF { template class _inMainThread : public main_thread_callback { public: diff --git a/sdk/foobar2000/helpers/DarkMode.h b/sdk/foobar2000/helpers/DarkMode.h index 05a21f2..1c6a3e8 100644 --- a/sdk/foobar2000/helpers/DarkMode.h +++ b/sdk/foobar2000/helpers/DarkMode.h @@ -11,6 +11,11 @@ // Keeps track of dark mode preference changes at runtime // Does nothing if used in foobar2000 older than 2.0 +// IMPORTANT +// See also: SDK/coreDarkMode.h +// Using CCoreDarkMode lets you invoke foobar2000's instance of this code instead of static linking it, resulting in much smaller component binary. +// Using CDarkModeHooks directly is good mainly for debugging or troubleshooting. + namespace fb2k { bool isDarkMode(); diff --git a/sdk/foobar2000/helpers/WindowPositionUtils.cpp b/sdk/foobar2000/helpers/WindowPositionUtils.cpp index 5683ff8..c04171e 100644 --- a/sdk/foobar2000/helpers/WindowPositionUtils.cpp +++ b/sdk/foobar2000/helpers/WindowPositionUtils.cpp @@ -1,6 +1,7 @@ #include "StdAfx.h" #include "WindowPositionUtils.h" +#define FB2K_WPU_DEBUG 0 namespace { static BOOL GetParentWndRect(CWindow wndParent, CRect& rc) { if (!wndParent.IsIconic()) { @@ -49,8 +50,10 @@ namespace { bool cfgDialogPositionData::grabFrom(CWindow wnd) { CRect rc; - if (!GetClientRectAsSC(wnd, rc)) return false; - const CSize DPI = QueryScreenDPIEx(); + if (!GetClientRectAsSC(wnd, rc)) { + return false; + } + const CSize DPI = QueryScreenDPIEx(wnd); m_dpiX = DPI.cx; m_dpiY = DPI.cy; m_width = rc.Width(); m_height = rc.Height(); m_posX = m_posY = posInvalid; @@ -61,10 +64,23 @@ bool cfgDialogPositionData::grabFrom(CWindow wnd) { m_posX = rc.left - rcParent.left; m_posY = rc.top - rcParent.top; } + } else { + m_posX = rc.left; m_posY = rc.top; } return true; } +pfc::string8 cfgDialogPositionData::debug() const { + pfc::string_formatter ret; + if (m_width != sizeInvalid) ret << "W: " << m_width << "\n"; + if (m_height != sizeInvalid) ret << "H: " << m_height << "\n"; + if (m_posX != posInvalid) ret << "X: " << m_posX << "\n"; + if (m_posY != posInvalid) ret << "Y: " << m_posY << "\n"; + if (m_dpiX != dpiInvalid) ret << "DPI-X: " << m_dpiX << "\n"; + if (m_dpiY != dpiInvalid) ret << "DPI-Y: " << m_dpiY << "\n"; + return ret; +} + cfgDialogPositionData cfgDialogPositionData::reDPI( CSize screenDPI ) const { cfgDialogPositionData v = *this; if (screenDPI.cx == 0 || screenDPI.cy == 0) { @@ -96,7 +112,14 @@ bool cfgDialogPositionData::overrideDefaultSize(t_uint32 width, t_uint32 height) } bool cfgDialogPositionData::applyTo(CWindow wnd) const { - auto v = reDPI(QueryScreenDPIEx()); +#if FB2K_WPU_DEBUG + FB2K_console_formatter() << "cfgDialogPositionData::applyTo(0x" << pfc::format_window( wnd ) << ")"; + FB2K_console_formatter() << "data:\n" << this->debug(); +#endif + const auto v = reDPI(QueryScreenDPIEx(wnd)); +#if FB2K_WPU_DEBUG + FB2K_console_formatter() << "after reDPI:\n" << v.debug(); +#endif CWindow wndParent = wnd.GetParent(); UINT flags = SWP_NOACTIVATE | SWP_NOZORDER; CRect rc; @@ -117,6 +140,10 @@ bool cfgDialogPositionData::applyTo(CWindow wnd) const { rc.MoveToXY(center.x - rc.Width() / 2, center.y - rc.Height() / 2); } } + } else { + if (v.m_posX != v.posInvalid && v.m_posY != v.posInvalid ) { + rc.MoveToXY( v.m_posX, v.m_posY ); + } } if (!AdjustWindowRectHelper(wnd, rc)) return FALSE; @@ -135,12 +162,60 @@ bool cfgDialogPositionData::applyTo(CWindow wnd) const { return wnd.SetWindowPos(NULL, rc, flags); } -void cfgDialogPosition::AddWindow(CWindow wnd) { +void cfgDialogPosition::read_from_window(HWND wnd) { + cfgDialogPositionData data; + if (data.grabFrom(wnd)) this->set(data); +} + +bool cfgDialogPosition::apply_to_window(HWND wnd) { auto data = this->get(); - data.applyTo(wnd); + return data.applyTo(wnd); } -void cfgDialogPosition::RemoveWindow(CWindow wnd) { - cfgDialogPositionData data; - if (data.grabFrom(wnd)) this->set(data); +bool cfgWindowPositionData::grabFrom(CWindow wnd) { + WINDOWPLACEMENT wp = {sizeof(wp)}; + bool rv = !! wnd.GetWindowPlacement(&wp); + if (rv) { + if ( !wnd.IsWindowVisible() ) wp.showCmd = SW_HIDE; + this->m_wp = wp; + m_dpi = QueryScreenDPIEx(wnd); + PFC_ASSERT( m_dpi.cx > 0 && m_dpi.cy > 0 ); + } + return rv; +} + +static void reDPI(WINDOWPLACEMENT& wp, SIZE from, SIZE to) { + wp.rcNormalPosition.left = MulDiv(wp.rcNormalPosition.left, to.cx, from.cx); + wp.rcNormalPosition.right = MulDiv(wp.rcNormalPosition.right, to.cx, from.cx); + wp.rcNormalPosition.top = MulDiv(wp.rcNormalPosition.top, to.cy, from.cy); + wp.rcNormalPosition.bottom = MulDiv(wp.rcNormalPosition.bottom, to.cy, from.cy); +} + +bool applyWindowPlacement(HWND window, WINDOWPLACEMENT const& data, bool allowHidden); // window_placement_helper.cpp + +bool cfgWindowPositionData::applyTo(CWindow wnd, bool allowHidden) const { + WINDOWPLACEMENT wp = m_wp; + if ( wp.length == 0 ) return false; + auto dpi = QueryScreenDPIEx(wnd); + if (dpi.cx != m_dpi.cx || dpi.cy != m_dpi.cy) { + reDPI( wp, m_dpi, dpi ); + } + return applyWindowPlacement(wnd, wp, allowHidden); } + +void cfgWindowPosition::read_from_window(HWND wnd) { + // grabFrom might work partially, fail to obtain size due to window being hidden, use last values + cfgWindowPositionData data = get(); + if ( data.grabFrom( wnd ) ) set(data); +} + +bool cfgWindowPosition::apply_to_window(HWND wnd, bool allowHidden) { + auto data = get(); + return data.applyTo( wnd, allowHidden ); +} + +void cfgWindowPosition::windowCreated(HWND wnd, bool allowHidden) { + if (!apply_to_window(wnd, allowHidden)) { + ::ShowWindow( wnd, SW_SHOWDEFAULT ); + } +} \ No newline at end of file diff --git a/sdk/foobar2000/helpers/WindowPositionUtils.h b/sdk/foobar2000/helpers/WindowPositionUtils.h index 80fe227..78b0b10 100644 --- a/sdk/foobar2000/helpers/WindowPositionUtils.h +++ b/sdk/foobar2000/helpers/WindowPositionUtils.h @@ -102,21 +102,31 @@ class cfgDialogSizeTracker : public cfgWindowSizeTracker { }; struct cfgDialogPositionData { - enum { - posInvalid = 0x80000000, + static constexpr int32_t + posInvalid = 0x80000000; + static constexpr uint32_t sizeInvalid = 0xFFFFFFFF, - dpiInvalid = 0, - }; + dpiInvalid = 0; - uint32_t m_width = (uint32_t)sizeInvalid, m_height = (uint32_t)sizeInvalid; - int32_t m_posX = (int32_t)posInvalid, m_posY = (int32_t)posInvalid; - uint32_t m_dpiX = (uint32_t)dpiInvalid, m_dpiY = (uint32_t)dpiInvalid; + uint32_t m_width = sizeInvalid, m_height = sizeInvalid; + int32_t m_posX = posInvalid, m_posY = posInvalid; + uint32_t m_dpiX = dpiInvalid, m_dpiY = dpiInvalid; cfgDialogPositionData reDPI(CSize) const; bool grabFrom(CWindow wnd); bool applyTo(CWindow wnd) const; bool overrideDefaultSize(t_uint32 width, t_uint32 height); + + pfc::string8 debug() const; +}; + +struct cfgWindowPositionData { + WINDOWPLACEMENT m_wp = {}; + SIZE m_dpi = {}; + + bool grabFrom(CWindow wnd); + bool applyTo(CWindow wnd, bool allowHidden = false) const; }; FB2K_STREAM_READER_OVERLOAD(cfgDialogPositionData) { @@ -133,172 +143,29 @@ FB2K_STREAM_WRITER_OVERLOAD(cfgDialogPositionData) { return stream << value.m_width << value.m_height << value.m_posX << value.m_posY << value.m_dpiX << value.m_dpiY; } -#if 0 -class cfgDialogPositionData { +class cfgDialogPosition : public cfg_struct_t { public: - cfgDialogPositionData_ v; - cfgDialogPositionData() {} - - void OverrideDefaultSize(t_uint32 width, t_uint32 height) { - if (v.m_width == v.sizeInvalid && v.m_height == v.sizeInvalid) { - v.m_width = width; v.m_height = height; v.m_posX = v.m_posY = v.posInvalid; - v.m_dpiX = v.m_dpiY = 96; - } - } - - void AddWindow(CWindow wnd) { - TryFetchConfig(); - m_windows += wnd; - ApplyConfig(wnd); - } - void RemoveWindow(CWindow wnd) { - if (m_windows.contains(wnd)) { - StoreConfig(wnd); m_windows -= wnd; - } - } - void FetchConfig() {TryFetchConfig();} - -private: - BOOL ApplyConfig(CWindow wnd) { - ApplyDPI(); - CWindow wndParent = wnd.GetParent(); - UINT flags = SWP_NOACTIVATE | SWP_NOZORDER; - CRect rc; - if (!GetClientRectAsSC(wnd,rc)) return FALSE; - if (v.m_width != v.sizeInvalid && v.m_height != v.sizeInvalid && (wnd.GetWindowLong(GWL_STYLE) & WS_SIZEBOX) != 0) { - rc.right = rc.left + v.m_width; - rc.bottom = rc.top + v.m_height; - } else { - flags |= SWP_NOSIZE; - } - if (wndParent != NULL) { - CRect rcParent; - if (GetParentWndRect(wndParent, rcParent)) { - if (v.m_posX != v.posInvalid && v.m_posY != v.posInvalid) { - rc.MoveToXY( rcParent.TopLeft() + CPoint(v.m_posX, v.m_posY) ); - } else { - CPoint center = rcParent.CenterPoint(); - rc.MoveToXY( center.x - rc.Width() / 2, center.y - rc.Height() / 2); - } - } - } - if (!AdjustWindowRectHelper(wnd, rc)) return FALSE; - - DeOverlap(wnd, rc); - - { - CRect rcAdjust(0,0,1,1); - if (wndParent != NULL) { - CRect temp; - if (wndParent.GetWindowRect(temp)) rcAdjust = temp; - } - AdjustRectToScreenArea(rc, rcAdjust); - } - - - return wnd.SetWindowPos(NULL, rc, flags); - } - struct DeOverlapState { - CWindow m_thisWnd; - CPoint m_topLeft; - bool m_match; - }; - static BOOL CALLBACK MyEnumChildProc(HWND wnd, LPARAM param) { - DeOverlapState * state = reinterpret_cast(param); - if (wnd != state->m_thisWnd && IsWindowVisible(wnd) ) { - CRect rc; - if (GetWindowRect(wnd, rc)) { - if (rc.TopLeft() == state->m_topLeft) { - state->m_match = true; return FALSE; - } - } - } - return TRUE; - } - static bool DeOverlapTest(CWindow wnd, CPoint topLeft) { - DeOverlapState state = {}; - state.m_thisWnd = wnd; state.m_topLeft = topLeft; state.m_match = false; - EnumThreadWindows(GetCurrentThreadId(), MyEnumChildProc, reinterpret_cast(&state)); - return state.m_match; - } - static int DeOverlapDelta() { - return pfc::max_t(GetSystemMetrics(SM_CYCAPTION),1); - } - static void DeOverlap(CWindow wnd, CRect & rc) { - const int delta = DeOverlapDelta(); - for(;;) { - if (!DeOverlapTest(wnd, rc.TopLeft())) break; - rc.OffsetRect(delta,delta); - } - } - BOOL StoreConfig(CWindow wnd) { - CRect rc; - if (!GetClientRectAsSC(wnd, rc)) return FALSE; - const CSize DPI = QueryScreenDPIEx(); - v.m_dpiX = DPI.cx; v.m_dpiY = DPI.cy; - v.m_width = rc.Width(); v.m_height = rc.Height(); - v.m_posX = v.m_posY = v.posInvalid; - CWindow parent = wnd.GetParent(); - if (parent != NULL) { - CRect rcParent; - if (GetParentWndRect(parent, rcParent)) { - v.m_posX = rc.left - rcParent.left; - v.m_posY = rc.top - rcParent.top; - } - } - return TRUE; - } - void TryFetchConfig() { - for(auto walk = m_windows.cfirst(); walk.is_valid(); ++walk) { - if (StoreConfig(*walk)) break; - } - } - - void ApplyDPI() { - const CSize screenDPI = QueryScreenDPIEx(); - if (screenDPI.cx == 0 || screenDPI.cy == 0) { - PFC_ASSERT(!"Should not get here - something seriously wrong with the OS"); - return; - } - if (v.m_dpiX != v.dpiInvalid && v.m_dpiX != screenDPI.cx) { - if (v.m_width != v.sizeInvalid) v.m_width = MulDiv(v.m_width, screenDPI.cx, v.m_dpiX); - if (v.m_posX != v.posInvalid) v.m_posX = MulDiv(v.m_posX, screenDPI.cx, v.m_dpiX); - } - if (v.m_dpiY != v.dpiInvalid && v.m_dpiY != screenDPI.cy) { - if (v.m_height != v.sizeInvalid) v.m_height = MulDiv(v.m_height, screenDPI.cy, v.m_dpiY); - if (v.m_posY != v.posInvalid) v.m_posY = MulDiv(v.m_posY, screenDPI.cy, v.m_dpiY); - } - v.m_dpiX = screenDPI.cx; - v.m_dpiY = screenDPI.cy; - } - CSize GrabDPI() const { - CSize DPI(96,96); - if (v.m_dpiX != v.dpiInvalid) DPI.cx = v.m_dpiX; - if (v.m_dpiY != v.dpiInvalid) DPI.cy = v.m_dpiY; - return DPI; - } + cfgDialogPosition(const GUID& id) : cfg_struct_t(id) {} - static BOOL GetParentWndRect(CWindow wndParent, CRect & rc) { - if (!wndParent.IsIconic()) { - return wndParent.GetWindowRect(rc); - } - WINDOWPLACEMENT pl = {sizeof(pl)}; - if (!wndParent.GetWindowPlacement(&pl)) return FALSE; - rc = pl.rcNormalPosition; - return TRUE; - } + //! Read and save size data from HWND. + void read_from_window(HWND); + //! Apply saved size data to HWND. + bool apply_to_window(HWND); - pfc::avltree_t m_windows; -public: + void AddWindow(HWND wnd) { apply_to_window(wnd); } + void RemoveWindow(HWND wnd) { read_from_window(wnd); } }; -#endif -class cfgDialogPosition : public cfg_struct_t { +class cfgWindowPosition : public cfg_struct_t { public: - cfgDialogPosition(const GUID& id) : cfg_struct_t(id) {} - - void AddWindow(CWindow wnd); - void RemoveWindow(CWindow wnd); + cfgWindowPosition(const GUID & id) : cfg_struct_t(id) {} + + //! Read and save size data from HWND. + void read_from_window(HWND); + //! Apply saved size data to HWND. + bool apply_to_window(HWND, bool allowHidden = false); + //! New window created, show it with saved metrics. + void windowCreated(HWND, bool allowHidden = false); }; class cfgDialogPositionTracker { diff --git a/sdk/foobar2000/helpers/callInMainThreadHelper.h b/sdk/foobar2000/helpers/callInMainThreadHelper.h new file mode 100644 index 0000000..c1399a6 --- /dev/null +++ b/sdk/foobar2000/helpers/callInMainThreadHelper.h @@ -0,0 +1,127 @@ +#pragma once +#include + +// ====================================================================================================== +// Obsolete helpers - they still work, but it's easier to just use fb2k::inMainThread(). +// ====================================================================================================== + + +// Proxy class - friend this to allow callInMainThread to access your private methods +class callInMainThread { +public: + template + static void callThis(host_t * host, param_t & param) { + host->inMainThread(param); + } + template + static void callThis( host_t * host ) { + host->inMainThread(); + } +}; + +// Internal class, do not use. +template +class _callInMainThreadSvc_t : public main_thread_callback { +public: + _callInMainThreadSvc_t(service_t * host, param_t const & param) : m_host(host), m_param(param) {} + void callback_run() { + callInMainThread::callThis(m_host.get_ptr(), m_param); + } +private: + service_ptr_t m_host; + param_t m_param; +}; + + +// Main thread callback helper. You can use this to easily invoke inMainThread(someparam) on your class without writing any wrapper code. +// Requires myservice_t to be a fb2k service class with reference counting. +template +static void callInMainThreadSvc(myservice_t * host, param_t const & param) { + typedef _callInMainThreadSvc_t impl_t; + service_ptr_t obj = new service_impl_t(host, param); + main_thread_callback_manager::get()->add_callback( obj ); +} + +//! Helper class to call methods of your class (host class) in main thread with convenience. \n +//! Deals with the otherwise ugly scenario of your class becoming invalid while a method is queued. \n +//! 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. +class callInMainThreadHelper { +public: + + typedef std::function< void () > func_t; + + typedef pfc::rcptr_t< bool > killswitch_t; + + class entryFunc : public main_thread_callback { + public: + entryFunc( func_t const & func, killswitch_t ks ) : m_ks(ks), m_func(func) {} + + void callback_run() { + if (!*m_ks) m_func(); + } + + private: + killswitch_t m_ks; + func_t m_func; + }; + + template + class entry : public main_thread_callback { + public: + entry( host_t * host, arg_t const & arg, killswitch_t ks ) : m_ks(ks), m_host(host), m_arg(arg) {} + void callback_run() { + if (!*m_ks) callInMainThread::callThis( m_host, m_arg ); + } + private: + killswitch_t m_ks; + host_t * m_host; + arg_t m_arg; + }; + template + class entryVoid : public main_thread_callback { + public: + entryVoid( host_t * host, killswitch_t ks ) : m_ks(ks), m_host(host) {} + void callback_run() { + if (!*m_ks) callInMainThread::callThis( m_host ); + } + private: + killswitch_t m_ks; + host_t * m_host; + }; + + void add(func_t f) { + add_( new service_impl_t< entryFunc > ( f, m_ks ) ); + } + + template + void add( host_t * host, arg_t const & arg) { + add_( new service_impl_t< entry >( host, arg, m_ks ) ); + } + template + void add( host_t * host ) { + add_( new service_impl_t< entryVoid >( host, m_ks ) ); + } + void add_( main_thread_callback::ptr cb ) { + main_thread_callback_add( cb ); + } + + callInMainThreadHelper() { + m_ks.new_t(); + * m_ks = false; + } + void shutdown() { + PFC_ASSERT( core_api::is_main_thread() ); + * m_ks = true; + } + ~callInMainThreadHelper() { + shutdown(); + } + +private: + killswitch_t m_ks; + +}; diff --git a/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj b/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj index b4fcb48..1cceafa 100644 --- a/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj +++ b/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj @@ -507,6 +507,7 @@ + @@ -591,7 +592,17 @@ + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + \ No newline at end of file diff --git a/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj.filters b/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj.filters index 101e27f..1a2fc16 100644 --- a/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj.filters +++ b/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj.filters @@ -412,5 +412,11 @@ Header Files + + Header Files + + + + \ No newline at end of file diff --git a/sdk/foobar2000/helpers/packages.config b/sdk/foobar2000/helpers/packages.config new file mode 100644 index 0000000..1c54a40 --- /dev/null +++ b/sdk/foobar2000/helpers/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/sdk/foobar2000/helpers/readWriteLock.h b/sdk/foobar2000/helpers/readWriteLock.h index 909cc85..279fa39 100644 --- a/sdk/foobar2000/helpers/readWriteLock.h +++ b/sdk/foobar2000/helpers/readWriteLock.h @@ -2,7 +2,8 @@ namespace fb2k { - // fb2k::readWriteLock: abortable readWriteLock, allowing multiple concurrent readers while not writing, or one writer while not reading. + //! fb2k::readWriteLock: abortable readWriteLock, allowing multiple concurrent readers while not writing, or one writer while not reading. \n + //! Safe to release locks in different threads than obtained, contrary to system object such as SRW locks. class readWriteLock { pfc::mutex m_guard; size_t m_readers = 0, m_writers = 0; diff --git a/sdk/foobar2000/helpers/window_placement_helper.cpp b/sdk/foobar2000/helpers/window_placement_helper.cpp index 42f42ae..d905254 100644 --- a/sdk/foobar2000/helpers/window_placement_helper.cpp +++ b/sdk/foobar2000/helpers/window_placement_helper.cpp @@ -68,30 +68,36 @@ bool cfg_window_placement::read_from_window(HWND window) return wp.length == sizeof(wp); } -bool cfg_window_placement::apply_to_window(HWND window, bool allowHidden) { +bool applyWindowPlacement(HWND window, WINDOWPLACEMENT const& data, bool allowHidden) { bool ret = false; - if (g_is_enabled()) + if (data.length == sizeof(data) && test_rect(&data.rcNormalPosition)) { - auto data = get(); - if (data.length == sizeof(data) && test_rect(&data.rcNormalPosition)) - { - if (allowHidden || data.showCmd != SW_HIDE) { - if (data.showCmd == SW_HIDE && (data.flags & WPF_RESTORETOMAXIMIZED)) { - // Special case of hidden-from-maximized - auto fix = data; - fix.showCmd = SW_SHOWMINIMIZED; - if (SetWindowPlacement(window, &fix)) { - ShowWindow(window, SW_HIDE); - ret = true; - } - } else { - if (SetWindowPlacement(window, &data)) { - ret = true; - } + if (allowHidden || data.showCmd != SW_HIDE) { + if (data.showCmd == SW_HIDE && (data.flags & WPF_RESTORETOMAXIMIZED)) { + // Special case of hidden-from-maximized + auto fix = data; + fix.showCmd = SW_SHOWMINIMIZED; + if (SetWindowPlacement(window, &fix)) { + ShowWindow(window, SW_HIDE); + ret = true; + } + } else { + if (SetWindowPlacement(window, &data)) { + ret = true; } } } } + return ret; +} + +bool cfg_window_placement::apply_to_window(HWND window, bool allowHidden) { + bool ret = false; + if (g_is_enabled()) + { + auto data = get(); + ret = applyWindowPlacement(window, data, allowHidden); + } return ret; } diff --git a/sdk/foobar2000/helpers/window_placement_helper.h b/sdk/foobar2000/helpers/window_placement_helper.h index 1e2a13f..20f0369 100644 --- a/sdk/foobar2000/helpers/window_placement_helper.h +++ b/sdk/foobar2000/helpers/window_placement_helper.h @@ -1,5 +1,7 @@ #pragma once +// DEPRECATED, NOT DPI SAFE +// use cfgDialogPosition & cfgWindowSize2 instead #ifdef FOOBAR2000_DESKTOP_WINDOWS #include "../SDK/cfg_var.h" diff --git a/sdk/foobar2000/shared/shared-ARM64.lib b/sdk/foobar2000/shared/shared-ARM64.lib index d9ca039b2bf095aeb7c3a2fd4c98757b93846e26..25737391234bb74c95c987cf0546fca6ceec6a7f 100644 GIT binary patch delta 3402 zcmc)KdrXz*9S88Q6f7@LYvIVPAXpGDtJY4WsI;}B2wvbIc;qIWa1crjJj@itx1h@i*@@xJhW?;Ea^YXNIvJ` zx&NNu^S*EY5tpG6m;TlE=%~oh=|7_fFl#Na@dB{v9*__LY^hSVj{(w_2gYk-t{OW7XIlT)%&(LVsD<+7xd z6-pB4NQRrrP6IHF+1yEK(aH`6EOj1H?44XdDqsLo{#B(n4Ul?1S1K8~ls;R@he%ZmjY6~yHYyH`XKMWE?UXwM9IJj(!R@zaWNn{xVThfR7~ub zO13LK&CHa<=R~URREp~XsqZbtIRQvrRb-bxylcsss+b*sv}gB>i!8~^(@W(%u~fzD zlC0xO5lgAD>Fb9OpR3Oq7?CjQVAEAiti}9 zV*trGpqO%*5o$WG6wl!}vP3KOB}_dv8I&>`?BEYj?IufVi&9#7P^k=x@iFh;_?VlrLFyiwv79Akhbz?&nM%rX zSL(0uBvi+ZrS@jU#yL_)hEg@gE25S=N-Nu?RAy1y;Wo^l;SE< zZNR!D;AA2XxD^OuIl#7w6kvQ8FjxpY+RTp_jWlw+gAXZ_;!STi0P9nM* zaHNy{6juOT&F8nF7xH|{ z%@ICBzU|Bgo#$dveZVO$-pI+ey$pgU^ymVXmIChe%mB;iI`(mM53X@}AF$ZS@f>HY zVcoQ1iG*euc8&HsKI{JVkfFm3>$XC0yFlY9-ZjGvj{@~^3aA@lp-15$BT%^ zdOU516PwYE3gqJu9H>JUs*r|CY(o78j6!7MAPi_hGm6lU zCZs@*H;{-13?dM|@P{|%K?fh~z!o$z%|Td=HAuh_yop})pa2^%1p7t|qXaAP0=6Ot zMwpO|0USUE(h-T3h{GoA`rl>1j;H^x8CWue@0Nil#FQ3x;pkY_fbk zVv!h2a95*hT+0t%xg@T|e=|Mo-<^Rc-cR`bs##Iu2c

FVFwz)5Uz3YWWuY*AKWb zmA)#D+jTla^cS~v({J9_qjL>nUDnIuZkCT%X8NTY;q0vAQo=DWK*Tzdyh_u&?mx%I zdf8|U_7gvKBx$}s%ljmVjSb?dCbM?-#gNGm)*3}^lU1vYST*%5Yj*Kx_IcM&Tnc8* zA$Bxd{F=^v_`V-&O)}UNi>b_?EDYfbVB4zIc(H*b^ElGo_O$-Obc(WCQBEm-+j4sPdQ zN1(6xN4cjMDcYc2K>K+aUx&zSGi#4VJ3f^0b&7LsmO1bE{OGGd*1D$S6D3vgVs4gB z`%Aa=p^U;QM%&F=e)>QE9>7|+@a!_1S#(^@^zui?-~w z>mSH@eIlvTtYzK}`Gf4+FMi%>(Y#{k-wtK1Uo7deYQG$R?~gK!1L9DZMf=-<1;3Ud z4u~h6X01N_@^55NLX(*<*by1(n zT?fUvZnM_@aOrR5>^H>99+OtC8Qu+LZAiS?WA(i1J8@m^dPvUJ`7q-#BD+`TslEH? e!UDDrv;7O5pE%g7*QWk-`b#3>9-4m5=Q{J-hx5MY z@;v99T_>g-Mo&77hMRYX@AS9-%Xa}D3J0PifPMKu>^KmATS@T+r2WN8LIWTro?W$- zk@nwJ4%h%Y2S!TWspN$KQn|AdUt#6~6+qlQr9%hUtuRVfrQIKpQfHL*DYmJ2UTJ#= zkc><~>I_!0!vHBaVbujj%2`rs%;$g_DPAc~+ij|2; z<%^1WfmKmI&t0mTR9c$=soGg-nFd;>dH$swD5bY3EqnNa^b?AilS_>^lmfn!j$TrR zIL^+6ks2N-rmq2Mn7bqmTu}N=OicQm%={QgPzt{RB*RUmC=!qi`ARJ-mg>(bCENw6 za#i;fAT{(Wwd3qh%}h!v>|W);NWF6`On#KsDRtZ$yBbESV1-f@7m$u-Cl7ttU&OQoYC{Ad?HvpC4%cRB1W`*sV+QK`XKv9e03i_fGqCL^V@=yVsoK2Agi@0cxh@^KP>GrJ1^sCD*u zEZkf8ySmS=b^Xx>bLjU!kX!^2(M)|GFdhrsjt6`>Yw>=r#!GZI5!gz1*|r@39B5}M z5RwNtmvc+l|6UxR>i|~BO8)J@4Eszm&KCpkv~j!<2<`;JviUP>&IK;eQVwvghCi2- z#*SkLfp3$!INeGDPBW2s#uQ$XD->}En5L;T_U!|L=-d(hu2Zs&$q#YzdM2I;xN+{& zT&qV2;c>Ha$n3ca&jgz*TwHH$C@~C6~~Sa@{Z6L`<1ftCT@KU&)l86)WY4IVgV^k)RzS; zayL`lI6(-{(1qI;E?(W@9TY{SzC7N2eLG5>&m zcpkeDf#(p3P1uc}U<`iP3}5JQ9Q}9!d(eecG-3oz$Up;3s6+vZPzVEB(T84aL;yCR z1l`z+DkNhELa`4&#ac545Qjn3q7)N6#untD9*0ne1SDb@9e5o6FrpmQs6h|HP>e~G zAsYheu%Z(cI0g$+kc4p@KpRfL2cGc8qwv6bq#+*dXvSlB7U77+&v6nq4B-f(@Csgn z`DZwa?Fhks9EKkG$ivGRMHVvg40a+KG06RYu7Ar9ssCZ|QGDQRWRQN{>|A)MHX9Z7 zYX`@fT+?raF6J%A09Jay>25s-De_z|omRaO=8MV0iklWsDS;Vz2z1!8XppOFC>g1dvBw&L` z>`vBZo*9^z3t7eM-3C|hwVU4eXRC{;+>i1SPxmCb&Tcn+CztEyv+I7IVzMV$*Ya`j zd$M1TOfOZqn+kOw_Ih5HdGxAB7E`>ilz2G(!TQ?G%|hSnCH~l(s%@*U|6(IM^^52G z3N*`|@sH)&1LE~QgZ5&_nJ;|U8WijM3$zWN^gWR8hD3Y6!S&vsGydhvmW?@#zT_dk z>rc{jjlaJydkl+10|u?2ZTX7qF(P&hdJ5Z6q|jx1IBhfT`iH-`IN&2<22-^3+TUH5 zn=>k29W-iJa~J+86Mk8&9WrR`ORxQ1W_Db(4i&f_{P6tyPq8Jq-Xqa|!r7Lry;Xkq zGr13ALT@Y4jtBJGS3e=H+YH*<7n}YfM~{o=h6`NFZruNsKU=SGv_9HPygQtvov>L} q>pJXJ(Rd|kLa1;Rt%ie7TLB2NK< z>oUGD(Q#_icBcIh+B9i8sbd&x8>h9zN#hK`1Why0ST#0DI~h&a(b8$B?WA8ao;_>! zS!@6Idi>WubM}j`c@Mnq-J9x@6b31Ykm{83koj^fIoNX|*1a(N-jnNd90*H-#1wF* z!c-4D&<6uL$BNnyLi_Vjy&ryj06tM$!!gLqg6tyL(+ltSKPP|UN1^HnoIDIehu~#RCQRqdRl2TH zu^MiuWTnI6cKAgb{H6esRnG5IoXVDJcsE0XuZ3+Y)lxdM&x?d%|7CtV;%_gPnOovvmR~@P(==+T=aA&LfutBZPLnbR)$*|Hl zv`wpQRvK$GXcc^ahhh|eW3#qM8OYKE-dDSAyC$aCTurb@13PuSR}*U1L=u(y(o*<~ zO{=)5+5cSU>l4aKg)(tbosHxug(}I)(!1L4A!Wg;iJWfIIku z9;b+BsiuZj7EnwdWo+gESv0YSa(ZcGEg2kQ6)p}ELJ+|`OdyXCz3CGfe{d(8EmI=QedZn$Z({!&F2@q+{y%VEXD{4lGwx$A+-5VrvKL<;1MYjr z@xC$OzIPn&8w2j~5Ar@SFlYRO{Ava!h$k(m|AR@<-w0Y>ZLisuQc+Zyv$ob=U7KE6 zTwGF7+&{^GN0|I_u8;9gt9a%<(%%pjK3U$2GyMJ??OE(F{+FjOmv?*1Pm*Kg4XeKq z>G;#{eY{|j+)fUaRjHxkmsCA5f=e!GOnFj%m=x=M$<;rc6y#-@Q2ncOuS#_4V-lQF zI1Y){Wf@Kik@G3Gi66y{{!XG&e>A=r;S--JLc& z={&DE*`6O@w1(z>ZdGHItZ@bU{!86b<(f8WT$fzi0{OKo!1(Q!vCDcDp-?__75W8Q zs|J^-X2+ihsc(o7XM@e?n-=`(VzrjZ2Mvuz-$Cb!P zc{@tBwgt=Qt#)JMQ2wo0UCR)A+b+X0^JizxeJkWjo5Qle>#5tZa=AT3>e};-lb>2Y zHnUhI_Vyt8TYItb`VYEJn=!SJy>-Ub!%=@U=}42&y*0*(zBzYhtCk^!9ovnLx0YT= zR&9k`?&vXI&iZ1+tZtdqb=Di<4;X(iV_M~lPKTxc%10m0mg`+X(%F^cxAx7~PMa~~ z?~+sbOrT8OS73be`l$gk?k3r_ug>peLEN=Ps&N++)*UX>x;Gov4WHdGcg~Z>ZkO-5 zmbiEHwxz#1e>wi}jQ;2zUoYQfA@)mp$>|KUbB;j4mF!E@Re{&V6g`TEbCV+ZG}k7{5MskcdZV{(o}r0 zIw{x$a~nkBkm7CdW7#DYpH>HNm%*6*0u*T8vv7Tnfb>1M8&U**B^Ro6eRv(5lnNJi zL3yD_Y=hTZR9AMfT53H53)=B>=7>6IQbE}?U3-e4VuK3GKGAh zfP#qmIiHxxTtRL0lPgwZa$ld61R0cy2kJ8HuQkcVB zzQ;U%$U>4?!sATi2Q1};AIn=siBd>Od*a) zw$MNtRpgUM0-2-|&JnWxG*eAECpDJmc^V&U*+njSw6UKV#8S#OcCeE}ETD|jJVPOd z)znkRvvhEP0+w@}Wz=$vC?+zQ@k}6sRk+#5UZ%2`$H?LZ&d^E=TX~8Tq;rZ&V&)T1 z4#jN5!v?zO)X>)PeUey821RDn=s62#Gn-jj-_?3pYo^v{tw*%Nv?gi&hjON5bd=vd zXP>e2?cD#8$2eSsFa`$?F%~Blp(A)-ckUZZ#{VFr`4%SQe~{69&1AmGo%#R%AK<6? zEzEzz|8oAL%#7Sgflou{KNM27hMDF^{;0rO*NW)CwfNYvf$>Yqt-y)&#^4}_8OTd8 zd6_Qji{RJ(>y_llzeX!mWt{%fum%7l(P=19y`ZEg6aa zGk&s(J5Xk2^tOE-ujn?@b--r@+OOVNATPy)*VR~_zNEj{Kqbc1Ra^H43V)X%&u7Bx zcU#@1^FDr9p4W8LZwo69?)l(xd0R(nPhT2oVh(Px-gQM>vujtHj)OjD$-0bdi{x#@ zWrkgo&8!A**uD$z4cmCzN6rN$Ofa5uhk3JMeRyr?Pyc3TkFfQvG(lkzCgG6R>brmO zA2z35rsq(#l^Xy0U7J(6i8?%N-RLiR-^NQZ5sg0UgX%Z_K3m>;)74mMEv~H`viDMr z)#S4pvXA{fNnW05Y}#ur`{?YTy_avSBR;2V$+1CuZ>e~`HEyEmJ+dk6y^=Yh@dDGs4-~NC=#O8fU2^QqcPT+#&MifO=?Yoj1mY^C4WU&bV0+-e}E4TwDs814Y^!OGSsK#D)2B%B1K zq#?Idwv@o}QsQ~H2)2}xtmM25NS3=w+<*;;8=&P%GlNUdKXR*MD?w>;0aD6UrCHDM zRMe<61@Jx<9#-1I0V$JnO4)BJIYCT>vTYmqL6ukBve;75EG79gFou&R)0S>G54N=R zg0i_1kkT66M%dDJtJ@v6wC$YY`~;9}&H{d+T~0S&w$#JGV~lL6rdmmV3y`vQDw(X5 z)Yh-G^I0h))a?LU%ABsGb1rE|)EFCbZ(>XuS1egdl;UfE>yi!-JvgZ{*YG9vKF+<}1H%w4UjssHaVWoaQAenrXmU2!=b+eVctAMnd z!6er$H&)X{wv|db%P#HXbCTd9rLNOt<45-rw?k}cXRnf93yk@Ktu#@oV(FxsdrHv* zo)s$dRyr;MQZ18`s!l0;Qvhk_BE>ww1m#EPs8X_)6`<;1w?4LHJ*w80I?ig^Pd zne0kl9xFnvmy~iVS55_~O5;XAYTc|<+=mVPKp7K|>RAb?j(uZV*wT&xrMQ4+f@&rx zh0FLeqk{8FE`v#>$%=Iq6Q>SdOZFk9qKB@JpEFcL+NBI)pDg$J7Y+8CMRt(Dyf<<9=5Q-P)&d)#F}Zb#uS@O<|0$% zGNhLoE#@NYI!k70UUbop;`D@X-4}6dyax@FuKCzjEd9^>^Cj>n7y}%S1@0Jt;CLWv zD{zGE$pm01iLoe{-_Iuk5tN()yqp8vKfp!bRO6&CdF9&4C>nsgk}H-GI)Nbv(v}{Q9FQ}xeUySOSqbA z#atn`z^@Ys>je&x2m76T_*^N+@?6Ds0k7=g_Xc1_1u%i_@e;0%2X;TV-`B(g%yF}M zR<7ppx!u4m7ZatGHYQ)rkJ8yorV zXUBc6V3d1O{KmJv-0wR#qvQ6zR8CNs>% z)YC+cJIV##VCe@K!@}zHv!V{ha4^x$T)<-^ET@$d7`caGEZb`FMvzzF4-tq(Scm{< z5QHi4!q2c6FCiY!A{ZeE#g8x!@cunTbr!;^@@T1>N{4I9x8E6jKS zb*Mrr%8`sRY=Qv}p0N4w#|{+0f>Jc&DVXpg^05srY(@j>Q3xmYA^}G1Lo9003vcK# z8#CaES(u3=Jcn9T;&D8URfxs`{1hFqV<&!${jjY^A4;$UPap>A$Ur8xqZ?gF!B#B8 zQf$CakcR(R1#Fo1f2}~^etfSA4El#0pCSGkuATBdLSRc`E@DYVE7LNtEUL!t@4HT0$g^j;nGZ?W+KTh*?)v+_DM5ke%*b|%k z&5$Q}TSRQ~7NLgi9_L=W{k3oyj(u~}XHsN#abd|~bB-D`SZkcVLR>V?(stb1_gM(| ze@2{W_MGyqcX#A6aj+pyd#(Ta-)HlFrTE43>68C_BL2%jURA*Z!l{2;gtZuTuDf4; zw2+&H%>@#9s4 zOeABWr&ymKE~sZKQa+YNj@+ zCFL_ej%pKU9VTr^-|&UGylNLqJ9D*`EBTk@J-ayAY1007arnD3a))@#Y1U0Oum4Cc z+`-vD)q9FQr%|Knt$EL1WOjKAZC8RW>-ASZmf1Tw;><>G@i0AnEaJ@-rSJN&ze`;2 zGHEaM`=9mYRkw)l&ehyqGjw&X@E3aVo9+bNuhuOY4dp!-XNXxaUqlOo_Q13HQMuwC zaZu!IKm7GC|KP`~Ug7C7X-2Q#ddFA%#ibYfTnW102Mj-y@%QuT@EP7>T8}|zS~~43 tS(6vo=XlOb)b$uAzjnLfeL1dAmjANn9PzNnpbbfy`hg7dqS(|M_-_wYY@PrB delta 3304 zcmdtidr%a{9S88Q2GbmO*4J^siHbZFk!rM+Kr}*3(h4YdC?W{*5Dt!)JOt!@yc9T& zN5jtZXlF*i+wqwz>Pbt}I6>AtE9pz?{ zxH>1EE!Ce^Dp-1n1)9~vxKj5yrN@hXoBZHuq}(r+y!(KZZ&vaO*r)12r7jkb4ks#Q z^?>BKq|`Ghsm4cX_yCY{?Q;xl$@!26k{?CPNUCwpdCr!~7Ar@21gYY(Vm;3aQ1+CP za}AK%hL!ROK*}FgnlG^Q)V5uzO5kIs@w+n_p|kFHmfJ!@ zzy393`gjrp=wpFs6T`*!AgdN~3;@G1?UIzQ_Yy;XkkM*z_Gg&Y?&r1od2F9ycFi!B}#%=q7X9>J{ z3gJd~nZP5SEBzoaLD8u|P%<#q#UEdqE@qABTpu^3d$oXX8gM;>zXassrZ3w0UErAf zsVGb5YZzvbK?|^hDjED%39zjQSkno-b6cA}T_setnqGsbpatATfZo7Hi#qMtIU3MP7m2byFx7p5@4FdvAE z_ZTkbt@HE`!Wsl30RC8jwO9xP&fq&Zi#SAL9fGkQA!6$~Z`(JRhu5$LuVO2SdK7+V<+CmX*ke;1A?!18 zeb-Oj{4icCY`c@@kJt9b8O8MOnFZzVw|{(DtT(R`dXwe96V|#%W)>9|Z^+G36R(<5 z-JGrU6C&9Bb&%!%Gv`uV@GIhGmfquc4V%Zj_%*MB8`8?nrMZX8vJ=GX{gGl(`!em1 zcK-R=TK=~hZlXJCg@|r9>o%nY{5FtdHC!Q9`WnS(yIHgFXTSO7Dh}2PZ+nh*TllM= z`>|KYWe%N}c#@$N7wm6pPmUR<8Q42^=bYzMQ=V z@kvLf&ex*(mE68jZdDxUBdiXyX3{=#-Is$+;unq_&7+eww*uH}7MnWrb)WoEcT;ZM zA{RLQJjI8drbWO1OYP_W96ZLswDP^8#K%K~*j^JKmM_!1`)ur?%;>o2aOUWKGJWH| z%%xQ>zY$>&`Yy9(OX{v+<$-13Aks zV!ACFv83XzoYf(I-kqa+=JVbInUzC^jf?aYZ}gb7Tl41Kk~?=Y&_+)WVYO@%7pwGI zON8Np%)!a=QKMd1ED>U~M6b2a_FZ4htun>2Uc{?or@T$ec0Z_#evGX7VY#|h3@vdbvex=fmzA4mUF<~$&5 ju3XKPy6%`;e_r#O$j?H diff --git a/sdk/foobar2000/shared/shared-x64.lib b/sdk/foobar2000/shared/shared-x64.lib index 5c4b69facfebd854c6d4fa8ea93f0843ea8fae96..285e090b4f72f4f64b84f7ee35a3a576a62a6e0f 100644 GIT binary patch delta 3402 zcmc)KdrXz*9S88Q43rnBT0MfIRw}6II_g%WsHhYb0l6IHei6>`c+LTY!yQF|bKr12 zT(mrv0;T9uYHZ?2Gc#kdjUI{UWgAJ`lSS*jc0O8U>`C50!+OfRq%e zB%T4J_=8H~64oi9S4kNMq}^l6zCJ*Tdt#SA)SxsB1CoP_OZJ{;=CP#u_m$KrKxzn4 zta?DI-=A*B*GlMe2l{5w{wGS!wb}k?lF#xIXveKOiNL}}oYDO+)%~W!@z% zD$WLOOvN_E!AwXUUP}2IK&tap%KKRF z)-k1orPOjl*}sqhP}NGMb`X$EI%N;9%r1Z0&MAfN%m7s}HBz;kQo<8TWn5e;y`$`j z03<`NVze+L)ObNDoy~D%4p-{Rn0jhVS1N3QX9%h=>ShH<$tIYuuZBi zQY^eC$$VVN>*BLS#XQ8cTP&$1Oljspr3xs9r@Vi|Q*O!zsk8r?5SEk|r0jppR8p>| zQuhf@LWj7q)Y_!jI7e#BR%%9hMdZArG_zewWfrA0k3s$no_@(A!6UfJSWy*UYPA;H ztfo;G@wEVRG+?RWDS1HZT(xW5Bf8OsfK0;9aHhb(6% z0Fg<+nM58i9$3P%mu=%Iz}Rk}Zy)d^jvp}^Zs2$aA5tb|9=%@=M5O{DY}Z?XZLA;U z^@j4W6Ly~BYA(N;T%?R;bR{swyx!)3Aa3qTW&nC#53S{9Qw-u3?>#+(!BTi87fu6) z+SyOhMZo1kejB=hd%VJ{)eI(!{W+ z;*2-eg1!zS&6P;s+qpA65vD& zu#gL^tO5pW0UgJT>;cZT0qzW-kL_+e`7Vwf!BZ|SpZ@+% zUI_(p++zmm$!qME1CiK*W~AZ(4x<(s*pE`!um@(Cuorb`M;jI+5Q|WN7Hma1lJOJ#7%_;# z96MZyLno?Ghygfo2)U?1CaRHuB=qpQm*YiPP|R;fC0el#R=kCM$iY#h!-*!8;0PL# z0zKYDBI?lxfB0e{=3xPJn2$8P9{Di9 zh&=S-bz~z8p?C$+*n!>uyA0Sd=l`04)&2N>8Tf&?sRf??d{zGQ!sg}e{oT*v=JnN@ zaQ#Q)si;Xe_r6l+UD2@pXYPTxQZHVP&T?as7vnERqMvxo3A9d}6`#f|6B9ek-;7u# zMq@qIr~~e^oI_8=RLr;21OMIWfBN^aAFrDcCVpBze?{86hrbHuyHv}!;J<#rg|U2# zIAPc6PTi<{tebxGz8P&v7m>M}#AmtleWKQ#p9*5{OX-VbpU0udngQ#t^Y9j@6K3dG0UEF1#$Ckb;OIdS> zv?jCP?5K>t`?1z2gH16TD@+A?V^x9p-M(ZW=cMI}K=w7sjb?0ED59NuEiKmYNN(g5 z$DAf_FH7I00M?q}E{t1!MPPH1Pt$1CO}TlCoR+*nC(aZ{2uGLBd+OBZSLNVV4tDta zimxlZ#c;_s?N@Fc<1)TBk<((*mj9*vyo|41oNqDDE*jYUwLfbe)A5P2niw%RSEv1R z@cNXD!X=KinzT)|$rFoM>lEH?MvoZd)X7_W8$hx{TTl|JFYSu+}f$?y`C>J`q1DcO8(kb@Q3=2$9#V^A1hP_`{2A bA7uMqb$;S#w_f|;_`AQ6Gv5+lbO-(mN~BA$ delta 3251 zcmdtjYfzNe83*uxC=g#j#Ik@G1p<*^rFaR}V$fa)2*`B-U5kT~AU|${(I|jr*Q1pI)w7*zMXauCB3oC*d zY5%86q7|@nV5GDiN^Te+l{+i(6=p6_0mLmU?e2ixb4JOcv;_cC+C`;pl5HxUQ(E5v zq#`CDb%rY0;ed1~VZ{t1eGu#nM<~Zqq ze#K=*I>=qLn_{GNCM)%EUb_%RG9TgMcCn0PO;Ls(08#@pmogib95-f8*<4)eJgrz( z0aE5YB`XQAn`NX-?yPk9%8Ek9LYR?pA9iInKq}?rQV%=ZeZolAIb}Eukjg?73lo#d z7ZvjYtD=6MyHqowv@`)yt+Qg90!&jp|56T=GE9nTFJF*hTrqQU>DUb=pYNpVd1Z*> z>|7YB@k^!Z5g-k7m!yFirN4@aNq5N1kAVcG;4?rn-c$-B0m+!B9A(8)!zHDJyC7Ar z=$-_m#(w4K82eK*ladO$SLhh2cb0|8kJ5Ujo?ByA$4C{dP^#eqQuP5P|84F7<#BuM zZZlHHoKn@!%BgTlX<6ddQ%90gyT~J;Di@wVKhXS<(sT~6W7SP$*rt^5xm3TP6miS# zJQykWnNrR|qzZl;q;4iHb?#7H*4pFo z2pM^~>^~H7OZD0LBauMu~X6pNZu~^_iJmAM!i}!OiUZM+0KrnsEwlxuOpdD#I zST5jP&Mjg8N-#c$&h+>2@-3hKa;8>Ul{n)9!=76iueHZyyjsmyYmvol>k!eu$GdF!4;ljdP#j zVyC(2DhqIr&yuo$Su(q`apf>?65Y=LY-Jq4GjZ<$KA|~I7B2t<4ugDZLHuN7hT|FCZ3rG zJ>yx|a|iTtawam{#qTc1R&nAQj}LH-3U|V-l(OJ~rc9*n&{;*G<0Wuh9>C zuoJuSIwG+FyYL;1!XF#q2X~xAKfZ^(=t3HfVFXP$fJRiI68R`Z0gPxtA9}GKfmnwU zbmNDpK?=5G8}{J`SYyTj;xLG#D8)FB(S#f{;2`RefFul~9WNsQMJPut>d=F56k`Hq z$c8`$Ea*f9j-vy5Bx4MTXvHb`!V5n5CUo#bI^xlWX1s*&A_B4aF;2sZAsj&z-ozU) z{|MFCiZJZQVHl8yT%3RnS;)j|*nw!o;L!hb{hPi{{ofGR;)A9mLkw%DXCq3r>8Pj= z92~PB{p_J|kNLS{ATGCx_hPaf7?xw#i|~EVoG#vtdH8El9_KI8V~hUV<5jUYewFIg zY)!?9pY-2!R^J=-+U3oRww5aVS(#J zQg@2>v85;3_4=)dt8%$+KD+MkB_?`O-2d=? z%X8VUN2Zr1JgN%ZKS)n{Ec579k2n;A)o2D5rod4%~cIp>< z`tr3CzJ?{a_JBCwXViAS7I@E>twG`0pRe8N_4>VhHzeBnjjp!4p11wjvN8wT8#?jt z{$%Z3V#nWQk703ez^LWDS%xAY)#Q_?z(qH z?!%}sSWC3o`h5Goof6lrM(ufE`1^A7n0S3S-_>Jv;{5=&-sEUQw6}P7I9WS&fAEf6 pdt7*p6gmAV)VT1nSUaK #pragma comment(lib, "dwmapi.lib") @@ -189,6 +198,12 @@ namespace { namespace DarkMode { + UINT msgSetDarkMode() { + // No need to threadguard this, should be main thread only, not much harm even if it's not + static UINT val = 0; + if (val == 0) val = RegisterWindowMessage(L"libPPUI:msgSetDarkMode"); + return val; + } bool IsSupportedSystem() { static bool ret = IsWindows10OrGreater(); return ret; @@ -864,7 +879,8 @@ namespace DarkMode { ds.hDC = dc; ds.rcItem = rcPart; - GetParent().SendMessage(WM_DRAWITEM, (WPARAM)m_hWnd, (LPARAM)&ds); + DCStateScope scope(dc); + GetParent().SendMessage(WM_DRAWITEM, GetDlgCtrlID(), (LPARAM)&ds); } else { CRect rcText = rcPart; int defMargin = rcText.Height() / 4; @@ -921,10 +937,15 @@ namespace DarkMode { MSG_WM_PRINTCLIENT(OnPaint) MSG_WM_ERASEBKGND(OnEraseBkgnd) MSG_WM_UPDATEUISTATE(OnUpdateUIState) + + // Note that checkbox implementation likes to paint on its own in response to events + // instead of invalidating and handling WM_PAINT + // We have to specifically trigger WM_PAINT to override their rendering with ours MESSAGE_HANDLER_EX(WM_SETFOCUS, OnMsgRedraw) MESSAGE_HANDLER_EX(WM_KILLFOCUS, OnMsgRedraw) MESSAGE_HANDLER_EX(WM_ENABLE, OnMsgRedraw) MESSAGE_HANDLER_EX(WM_SETTEXT, OnMsgRedraw) + MESSAGE_HANDLER_EX(msgSetDarkMode(), OnSetDarkMode) END_MSG_MAP() @@ -937,12 +958,27 @@ namespace DarkMode { } LRESULT OnMsgRedraw(UINT, WPARAM, LPARAM) { - Invalidate(); SetMsgHandled(FALSE); return 0; + if ( m_dark ) { + // PROBLEM: + // Can't invalidate prior to their handling of the message + // Causes bugs with specific chains of events - EnableWindow() followed immediately SetWindowText() + LRESULT ret = DefWindowProc(); + Invalidate(); + return ret; + } + SetMsgHandled(FALSE); return 0; } void OnUpdateUIState(WORD nAction, WORD nState) { (void)nAction; - if (nState & (UISF_HIDEACCEL | UISF_HIDEFOCUS)) Invalidate(); + if ( m_dark && (nState & (UISF_HIDEACCEL | UISF_HIDEFOCUS)) != 0) { + // PROBLEM: + // Can't invalidate prior to their handling of the message + // Causes bugs with specific chains of events - EnableWindow() followed immediately SetWindowText() + DefWindowProc(); + Invalidate(); + return; + } SetMsgHandled(FALSE); } void PaintHandler(CDCHandle dc) { @@ -1457,6 +1493,50 @@ namespace DarkMode { dc.DrawText(L"˅", 1, layout.lower, DT_SINGLELINE | DT_VCENTER | DT_CENTER | DT_NOPREFIX); } }; + + class CNCFrameHook : public CWindowImpl { + public: + CNCFrameHook(bool dark) : m_dark(dark) {} + + BEGIN_MSG_MAP_EX(CNCFrameHook) + MESSAGE_HANDLER_EX(msgSetDarkMode(), OnSetDarkMode) + MSG_WM_NCPAINT(OnNCPaint) + END_MSG_MAP() + + void SetDark(bool v) { + if (v != m_dark) { + m_dark = v; ApplyDark(); + } + } + BOOL SubclassWindow(HWND wnd) { + auto rv = __super::SubclassWindow(wnd); + if (rv) { + ApplyDark(); + } + return rv; + } + private: + void OnNCPaint(HRGN rgn) { + if (m_dark) { + NCPaintDarkFrame(m_hWnd, rgn); + return; + } + SetMsgHandled(FALSE); + } + void ApplyDark() { + ApplyDarkThemeCtrl(m_hWnd, m_dark); + Invalidate(); + } + LRESULT OnSetDarkMode(UINT, WPARAM wp, LPARAM) { + switch (wp) { + case 0: SetDark(false); break; + case 1: SetDark(true); break; + } + return 1; + } + + bool m_dark; + }; } void CHooks::AddPopup(HWND wnd) { @@ -1493,7 +1573,15 @@ namespace DarkMode { void CHooks::AddComboBoxEx(HWND wnd) { this->AddControls(wnd); // recurse to add the combo box } - void CHooks::AddEditBox(HWND wnd) { AddGeneric(wnd); } + void CHooks::AddEditBox(HWND wnd) { +#if 0 // Experimental + auto hook = new ImplementOnFinalMessage(m_dark); + hook->SubclassWindow( wnd ); + AddCtrlMsg( wnd ); +#else + AddGeneric(wnd); +#endif + } void CHooks::AddButton(HWND wnd) { CButton btn(wnd); auto style = btn.GetButtonStyle(); @@ -1575,8 +1663,7 @@ namespace DarkMode { }); } void CHooks::AddListBox(HWND wnd) { - // Not needed! Yay! - // Handling WM_CTLCOLOR* is enough + this->AddGeneric( wnd ); #if 0 auto subst = CListControl_ReplaceListBox(wnd); if (subst) AddPPListControl(subst); @@ -1679,16 +1766,89 @@ namespace DarkMode { m_cleanup.clear(); } - UINT msgSetDarkMode() { - // No need to threadguard this, should be main thread only, not much harm even if it's not - static UINT val = 0; - if (val == 0) val = RegisterWindowMessage(L"libPPUI:msgSetDarkMode"); - return val; - } - void CHooks::AddApp() { addOp([this] { SetAppDarkMode(this->m_dark); }); } + + void NCPaintDarkFrame(HWND wnd_, HRGN rgn_) { + // rgn is in SCREEN COORDINATES, possibly (HRGN)1 to indicate no clipping / whole nonclient area redraw + // we're working with SCREEN COORDINATES until actual DC painting + CWindow wnd = wnd_; + + CRect rcWindow, rcClient; + WIN32_OP_D( wnd.GetWindowRect(rcWindow) ); + WIN32_OP_D( wnd.GetClientRect(rcClient) ); + WIN32_OP_D( wnd.ClientToScreen( rcClient ) ); // transform all to same coordinate system + + CRgn rgnClip; + WIN32_OP_D( rgnClip.CreateRectRgnIndirect(rcWindow) != NULL ); + if (rgn_ != NULL && rgn_ != (HRGN)1) { + // we have a valid HRGN from caller? + if (rgnClip.CombineRgn(rgn_, RGN_AND) == NULLREGION) return; // nothing to draw, exit early + } + + { + // Have scroll bars? Have DefWindowProc() them then exclude from our rgnClip. + SCROLLBARINFO si = { sizeof(si) }; + if (::GetScrollBarInfo(wnd, OBJID_VSCROLL, &si) && (si.rgstate[0] & STATE_SYSTEM_INVISIBLE) == 0 && si.rcScrollBar.left < si.rcScrollBar.right) { + CRect rc = si.rcScrollBar; + // rcClient.right = rc.right; + CRgn rgn; WIN32_OP_D( rgn.CreateRectRgnIndirect(rc) ); + int status = SIMPLEREGION; + if (rgnClip) { + status = rgn.CombineRgn(rgn, rgnClip, RGN_AND); + } + if (status != NULLREGION) { + DefWindowProc(wnd, WM_NCPAINT, (WPARAM)rgn.m_hRgn, 0); + rgnClip.CombineRgn(rgn, RGN_DIFF); // exclude from further drawing + } + } + if (::GetScrollBarInfo(wnd, OBJID_HSCROLL, &si) && (si.rgstate[0] & STATE_SYSTEM_INVISIBLE) == 0 && si.rcScrollBar.top < si.rcScrollBar.bottom) { + CRect rc = si.rcScrollBar; + // rcClient.bottom = rc.bottom; + CRgn rgn; WIN32_OP_D(rgn.CreateRectRgnIndirect(rc)); + int status = SIMPLEREGION; + if (rgnClip) { + status = rgn.CombineRgn(rgn, rgnClip, RGN_AND); + } + if (status != NULLREGION) { + DefWindowProc(wnd, WM_NCPAINT, (WPARAM)rgn.m_hRgn, 0); + rgnClip.CombineRgn(rgn, RGN_DIFF); // exclude from further drawing + } + } + } + + const auto colorLight = DarkMode::GetSysColor(COLOR_BTNHIGHLIGHT); + const auto colorDark = DarkMode::GetSysColor(COLOR_BTNSHADOW); + + CWindowDC dc( wnd ); + if (dc.IsNull()) { + PFC_ASSERT(!"???"); + return; + } + + + // Window DC has (0,0) in upper-left corner of our window (not screen, not client) + // Turn rcWindow to (0,0), (winWidth, winHeight) + CPoint origin = rcWindow.TopLeft(); + rcWindow.OffsetRect(-origin); + rcClient.OffsetRect(-origin); + + if (!rgnClip.IsNull()) { + // rgnClip is still in screen coordinates, fix this here + rgnClip.OffsetRgn(-origin); + dc.SelectClipRgn(rgnClip); + } + + // bottom + dc.FillSolidRect(CRect(rcClient.left, rcClient.bottom, rcWindow.right, rcWindow.bottom), colorLight); + // right + dc.FillSolidRect(CRect(rcClient.right, rcWindow.top, rcWindow.right, rcClient.bottom), colorLight); + // top + dc.FillSolidRect(CRect(rcWindow.left, rcWindow.top, rcWindow.right, rcClient.top), colorDark); + // left + dc.FillSolidRect(CRect(rcWindow.left, rcClient.top, rcClient.left, rcWindow.bottom), colorDark); + } } diff --git a/sdk/libPPUI/DarkMode.h b/sdk/libPPUI/DarkMode.h index 1145487..2717942 100644 --- a/sdk/libPPUI/DarkMode.h +++ b/sdk/libPPUI/DarkMode.h @@ -31,6 +31,9 @@ namespace DarkMode { // Can be used with NOTIFY_CODE_HANDLER() directly LRESULT OnCustomDraw(int, NMHDR*, BOOL & bHandled); + // Handle WM_NCPAINT drawing dark frame + void NCPaintDarkFrame(HWND ctrl, HRGN rgn); + bool IsHighContrast(); // msgSetDarkMode diff --git a/sdk/libPPUI/EditBoxFix.cpp b/sdk/libPPUI/EditBoxFix.cpp new file mode 100644 index 0000000..b894b71 --- /dev/null +++ b/sdk/libPPUI/EditBoxFix.cpp @@ -0,0 +1,19 @@ +#include "stdafx.h" +#include "EditBoxFixes.h" +#include "wtl-pp.h" +#include "windowLifetime.h" + +namespace PP { + void editBoxFix(HWND wndEdit) { + PFC_ASSERT( IsWindow(wndEdit) ); + PP::subclassThisWindow(wndEdit); + } + void comboBoxFix(HWND wndCombo) { + PFC_ASSERT( IsWindow(wndCombo) ); + CComboBox combo = wndCombo; + COMBOBOXINFO info = { sizeof(info) }; + if (combo.GetComboBoxInfo(&info)) { + if ( info.hwndItem != NULL ) editBoxFix( info.hwndItem ); + } + } +} \ No newline at end of file diff --git a/sdk/libPPUI/EditBoxFixes.h b/sdk/libPPUI/EditBoxFixes.h new file mode 100644 index 0000000..e333743 --- /dev/null +++ b/sdk/libPPUI/EditBoxFixes.h @@ -0,0 +1,7 @@ +#pragma once + +namespace PP { + // One-line methods to inject our edit box shims: Ctrl+A, Ctrl+Backspace, etc + void editBoxFix(HWND wndEdit); + void comboBoxFix(HWND wndCombo); +} \ No newline at end of file diff --git a/sdk/libPPUI/PaintUtils.cpp b/sdk/libPPUI/PaintUtils.cpp index 913cf72..15b1505 100644 --- a/sdk/libPPUI/PaintUtils.cpp +++ b/sdk/libPPUI/PaintUtils.cpp @@ -191,6 +191,7 @@ namespace PaintUtils { eh << graphics.DrawLine(&penSH, points[3], points[0]); } catch (std::exception const& e) { (void)e; + PFC_ASSERT(!"???"); // console::print(e.what()); } } @@ -218,6 +219,7 @@ namespace PaintUtils { eh << graphics.DrawLine(&penSH, points[2], points[0] + Gdiplus::Point(0, -1)); } catch (std::exception const& e) { (void)e; + PFC_ASSERT(!"???"); // console::print(e.what()); } } @@ -241,6 +243,7 @@ namespace PaintUtils { eh << graphics.DrawLine(&pen, points[0], points[1]); } catch(std::exception const & e) { (void) e; + PFC_ASSERT(!"???"); // console::print(e.what()); } } diff --git a/sdk/libPPUI/libPPUI.vcxproj b/sdk/libPPUI/libPPUI.vcxproj index e49f3ac..7da9c40 100644 --- a/sdk/libPPUI/libPPUI.vcxproj +++ b/sdk/libPPUI/libPPUI.vcxproj @@ -355,6 +355,7 @@ + @@ -398,6 +399,7 @@ + @@ -425,7 +427,17 @@ + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + \ No newline at end of file diff --git a/sdk/libPPUI/libPPUI.vcxproj.filters b/sdk/libPPUI/libPPUI.vcxproj.filters index 5b67d43..3b9c628 100644 --- a/sdk/libPPUI/libPPUI.vcxproj.filters +++ b/sdk/libPPUI/libPPUI.vcxproj.filters @@ -197,6 +197,9 @@ Header Files + + Header Files + @@ -286,9 +289,15 @@ Source Files + + Source Files + + + + \ No newline at end of file diff --git a/sdk/libPPUI/packages.config b/sdk/libPPUI/packages.config new file mode 100644 index 0000000..1c54a40 --- /dev/null +++ b/sdk/libPPUI/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/sdk/libPPUI/windowLifetime.h b/sdk/libPPUI/windowLifetime.h index f1f7ca8..a49be03 100644 --- a/sdk/libPPUI/windowLifetime.h +++ b/sdk/libPPUI/windowLifetime.h @@ -1,5 +1,6 @@ #pragma once #include "ImplementOnFinalMessage.h" +#include "win32_op.h" #include namespace PP { @@ -15,6 +16,7 @@ namespace PP { //! OnFinalMessage() is automatically overridden to delete the window subclass object. template obj_t* subclassThisWindow(HWND wnd, arg_t && ... arg) { + PFC_ASSERT( wnd != NULL ); auto ret = newWindowObj(std::forward(arg) ...); WIN32_OP_D(ret->SubclassWindow(wnd)); return ret; diff --git a/sdk/libPPUI/wtl-pp.h b/sdk/libPPUI/wtl-pp.h index 16c577a..255ed80 100644 --- a/sdk/libPPUI/wtl-pp.h +++ b/sdk/libPPUI/wtl-pp.h @@ -174,7 +174,7 @@ class CCheckBox : public CButton { class CEditPPHooks : public CWindowImpl { public: - bool HandleCtrlA = true, NoEscSteal = false, NoEnterSteal = false; + bool HandleCtrlA = true, NoEscSteal = false, NoEnterSteal = false, WantAllKeys = false; std::function onEnterKey; std::function onEscKey; @@ -196,14 +196,9 @@ class CEditPPHooks : public CWindowImpl { static void DeleteLastWord( CEdit wnd ) { if ( wnd.GetWindowLong(GWL_STYLE) & ES_READONLY ) return; - int len = wnd.GetWindowTextLength(); - if ( len <= 0 ) return; - TCHAR * buffer = new TCHAR [ len + 1 ]; - if ( wnd.GetWindowText( buffer, len + 1 ) <= 0 ) { - delete[] buffer; - return; - } - buffer[len] = 0; + CString buffer; + if ( wnd.GetWindowText(buffer) <= 0 ) return; + const int len = buffer.GetLength(); int selStart = len, selEnd = len; wnd.GetSel(selStart, selEnd); if ( selStart < 0 || selStart > len ) selStart = len; // sanity @@ -211,18 +206,25 @@ class CEditPPHooks : public CWindowImpl { int work = selStart; if ( work == selEnd ) { // Only do our stuff if there is nothing yet selected. Otherwise first delete selection. - while( work > 0 && isWordDelimiter(buffer[work-1]) ) --work; - while( work > 0 && !isWordDelimiter(buffer[work-1] ) ) --work; + + if ( work > 0 && isSpecial(buffer[work-1])) { + do --work; while( work > 0 && isSpecial(buffer[work-1])); + } else { + while( work > 0 && isWordDelimiter(buffer[work-1]) ) --work; + while( work > 0 && (!isWordDelimiter(buffer[work-1]) && !isSpecial(buffer[work-1]))) --work; + } } - delete[] buffer; if ( selEnd > work ) { wnd.SetSel(work, selEnd, TRUE ); wnd.ReplaceSel( TEXT(""), TRUE ); } } private: - static bool isWordDelimiter( TCHAR c ) { - return (unsigned) c <= ' ' || c == ',' || c == '.' || c == ';' || c == ':'; + static bool isSpecial( wchar_t c ) { + return (unsigned) c < ' '; + } + static bool isWordDelimiter( wchar_t c ) { + return c == ' ' || c == ',' || c == '.' || c == ';' || c == ':'; } void OnChar(UINT nChar, UINT, UINT nFlags) { if (m_suppressChar != 0) { @@ -263,6 +265,7 @@ class CEditPPHooks : public CWindowImpl { SetMsgHandled(FALSE); } UINT OnEditGetDlgCode(LPMSG lpMsg) { + if (WantAllKeys) return DLGC_WANTALLKEYS; if (lpMsg == NULL) { SetMsgHandled(FALSE); return 0; } else { @@ -430,23 +433,9 @@ class CWindowRegisteredT : public TBaseClass, public CMessageMap { class CSRWlock { public: - CSRWlock() : theLock() { -#if _WIN32_WINNT < 0x600 - auto dll = GetModuleHandle(_T("kernel32")); - Bind(AcquireSRWLockExclusive, dll, "AcquireSRWLockExclusive"); - Bind(AcquireSRWLockShared, dll, "AcquireSRWLockShared"); - Bind(ReleaseSRWLockExclusive, dll, "ReleaseSRWLockExclusive"); - Bind(ReleaseSRWLockShared, dll, "ReleaseSRWLockShared"); -#endif - } + CSRWlock() { } - bool HaveAPI() { -#if _WIN32_WINNT < 0x600 - return AcquireSRWLockExclusive != NULL; -#else - return true; -#endif - } + static bool HaveAPI() { return true; } void EnterShared() { AcquireSRWLockShared( & theLock ); @@ -465,51 +454,5 @@ class CSRWlock { CSRWlock(const CSRWlock&) = delete; void operator=(const CSRWlock&) = delete; - SRWLOCK theLock; -#if _WIN32_WINNT < 0x600 - template static void Bind(func_t & func, HMODULE dll, const char * name) { - func = reinterpret_cast(GetProcAddress( dll, name ) ); - } - - VOID (WINAPI * AcquireSRWLockExclusive)(PSRWLOCK SRWLock); - VOID (WINAPI * AcquireSRWLockShared)(PSRWLOCK SRWLock); - VOID (WINAPI * ReleaseSRWLockExclusive)(PSRWLOCK SRWLock); - VOID (WINAPI * ReleaseSRWLockShared)(PSRWLOCK SRWLock); -#endif + SRWLOCK theLock = {}; }; - -#if _WIN32_WINNT < 0x600 -class CSRWorCS { -public: - CSRWorCS() : cs() { - if (!srw.HaveAPI()) InitializeCriticalSection(&cs); - } - ~CSRWorCS() { - if (!srw.HaveAPI()) DeleteCriticalSection(& cs ); - } - void EnterShared() { - if (srw.HaveAPI()) srw.EnterShared(); - else EnterCriticalSection(&cs); - } - void EnterExclusive() { - if (srw.HaveAPI()) srw.EnterExclusive(); - else EnterCriticalSection(&cs); - } - void LeaveShared() { - if (srw.HaveAPI()) srw.LeaveShared(); - else LeaveCriticalSection(&cs); - } - void LeaveExclusive() { - if (srw.HaveAPI()) srw.LeaveExclusive(); - else LeaveCriticalSection(&cs); - } -private: - CSRWorCS(const CSRWorCS&) = delete; - void operator=(const CSRWorCS&) = delete; - - CSRWlock srw; - CRITICAL_SECTION cs; -}; -#else -typedef CSRWlock CSRWorCS; -#endif diff --git a/sdk/pfc/audio_math.cpp b/sdk/pfc/audio_math.cpp index 1a731d2..63fcf80 100644 --- a/sdk/pfc/audio_math.cpp +++ b/sdk/pfc/audio_math.cpp @@ -33,6 +33,10 @@ static const bool haveAVX = pfc::query_cpu_feature_set(pfc::CPU_HAVE_AVX); #include #endif +#if defined( __aarch64__ ) || defined( _M_ARM64) || defined( _M_ARM64EC ) +#define AUDIO_MATH_ARM64 +#endif + template inline static float_t noopt_calculate_peak(const float_t *p_src, t_size p_num) { float_t peak = 0; @@ -229,7 +233,7 @@ inline static void neon_convert_from_int16(const t_int16 * __restrict p_source,t noopt_convert_from_int16( p_source, rem, p_output, p_scale ); } - +#ifdef AUDIO_MATH_ARM64 inline static void neon_convert_to_int16(const double* __restrict p_source, t_size p_count, int16_t* __restrict p_output, double p_scale) { size_t num = p_count / 4; @@ -255,8 +259,8 @@ inline static void neon_convert_to_int16(const double* __restrict p_source, t_si } noopt_convert_to_16bit(p_source, rem, p_output, p_scale); - } + inline static void neon_convert_from_int16(const t_int16* __restrict p_source, t_size p_count, double* __restrict p_output, double p_scale) { size_t num = p_count / 4; @@ -280,7 +284,9 @@ inline static void neon_convert_from_int16(const t_int16* __restrict p_source, t noopt_convert_from_int16(p_source, rem, p_output, p_scale); } -#endif +#endif // AUDIO_MATH_ARM64 + +#endif // AUDIO_MATH_NEON #if defined(AUDIO_MATH_SSE) @@ -776,7 +782,7 @@ namespace pfc { { convert_to_16bit_sse2(p_source, p_count, p_output, scale); } -#elif defined( AUDIO_MATH_NEON ) +#elif defined( AUDIO_MATH_ARM64 ) neon_convert_to_int16(p_source, p_count, p_output, scale); #else noopt_convert_to_16bit(p_source, p_count, p_output, scale); @@ -807,7 +813,7 @@ namespace pfc { { convert_from_int16_sse2(p_source, p_count, p_output, scale); } -#elif defined( AUDIO_MATH_NEON ) +#elif defined( AUDIO_MATH_ARM64 ) neon_convert_from_int16(p_source, p_count, p_output, scale); #else noopt_convert_from_int16(p_source, p_count, p_output, scale); diff --git a/sdk/pfc/cpuid.cpp b/sdk/pfc/cpuid.cpp index 19d0eae..9fff5c5 100644 --- a/sdk/pfc/cpuid.cpp +++ b/sdk/pfc/cpuid.cpp @@ -64,16 +64,8 @@ namespace pfc { namespace pfc { const char* cpuArch() { -#ifdef _M_ARM64EC - return "ARM64EC"; -#elif defined(_M_X64) || defined(__x86_64__) - return "x64"; -#elif defined(_M_IX86) || defined(__i386__) - return "x86"; -#elif defined(_M_ARM64) || defined(__aarch64__) - return "ARM64"; -#elif defined(_M_ARM) || defined(__arm__) - return "ARM"; +#ifdef PFC_CPU_ARCH + return PFC_CPU_ARCH; #else return "Unknown"; #endif diff --git a/sdk/pfc/cpuid.h b/sdk/pfc/cpuid.h index 1c7bd8f..4757cbd 100644 --- a/sdk/pfc/cpuid.h +++ b/sdk/pfc/cpuid.h @@ -24,4 +24,16 @@ namespace pfc { namespace pfc { const char* cpuArch(); -} \ No newline at end of file +} + +#ifdef _M_ARM64EC +#define PFC_CPU_ARCH "ARM64EC" +#elif defined(_M_X64) || defined(__x86_64__) +#define PFC_CPU_ARCH "x64" +#elif defined(_M_IX86) || defined(__i386__) +#define PFC_CPU_ARCH "x86" +#elif defined(_M_ARM64) || defined(__aarch64__) +#define PFC_CPU_ARCH "ARM64" +#elif defined(_M_ARM) || defined(__arm__) +#define PFC_CPU_ARCH "ARM" +#endif diff --git a/sdk/pfc/debug.h b/sdk/pfc/debug.h index 6d01467..f7fb1ee 100644 --- a/sdk/pfc/debug.h +++ b/sdk/pfc/debug.h @@ -42,3 +42,9 @@ namespace pfc { #define PFC_SET_THREAD_DESCRIPTION(X) { ::pfc::setCurrentThreadDescription(X); } #define PFC_SET_THREAD_DESCRIPTION_SUPPORTED + +#if PFC_DEBUG +#define PFC_DEBUG_PRINT(...) ::pfc::outputDebugLine(pfc::format(__VA_ARGS__)) +#else +#define PFC_DEBUG_PRINT(...) +#endif \ No newline at end of file diff --git a/sdk/pfc/pathUtils.cpp b/sdk/pfc/pathUtils.cpp index 7e9e829..68db25a 100644 --- a/sdk/pfc/pathUtils.cpp +++ b/sdk/pfc/pathUtils.cpp @@ -80,23 +80,23 @@ const char * charReplaceDefault(char c) { const char * charReplaceModern(char c) { switch (c) { case '*': - return u8"∗"; + return reinterpret_cast( u8"∗" ); case '\"': - return u8"''"; + return reinterpret_cast( u8"''" ); case ':': - return u8"∶"; + return reinterpret_cast( u8"∶" ); case '/': - return u8"\u2215"; + return reinterpret_cast( u8"\u2215" ); case '\\': - return u8"⧵"; + return reinterpret_cast( u8"⧵" ); case '?': - return u8"?"; + return reinterpret_cast( u8"?" ); case '<': - return u8"˂"; + return reinterpret_cast( u8"˂" ); case '>': - return u8"˃"; + return reinterpret_cast( u8"˃" ); case '|': - return u8"∣"; + return reinterpret_cast( u8"∣" ); default: return "_"; } diff --git a/sdk/pfc/string_base.cpp b/sdk/pfc/string_base.cpp index bca94a4..d920bce 100644 --- a/sdk/pfc/string_base.cpp +++ b/sdk/pfc/string_base.cpp @@ -960,6 +960,29 @@ string8 format_file_size_short(uint64_t size, uint64_t * outUsedScale) { return ret; } +pfc::string8 format_index(size_t idx) { + return idx == SIZE_MAX ? "" : pfc::format_uint(idx); +} + +pfc::string8 format_permutation(const size_t* arg, size_t n) { + pfc::string_formatter ret; + for( size_t walk = 0; walk < n; ++ walk ) { + if (arg[walk] != walk) { + if ( !ret.is_empty() ) ret << ", "; + ret << arg[walk] << "->" << walk; + } + } + return ret; +} +pfc::string8 format_mask(pfc::bit_array const& mask, size_t n) { + pfc::string_formatter ret; + mask.for_each(true, 0, n, [&] (size_t idx) { + if (!ret.is_empty() ) ret << ", "; + ret << n; + }); + return ret; +} + bool string_base::truncate_eol(t_size start) { const char * ptr = get_ptr() + start; diff --git a/sdk/pfc/string_base.h b/sdk/pfc/string_base.h index a2ae836..56dfbed 100644 --- a/sdk/pfc/string_base.h +++ b/sdk/pfc/string_base.h @@ -258,6 +258,9 @@ namespace pfc { string8 format_file_size_short(uint64_t size, uint64_t * outScaleUsed = nullptr); + string8 format_index(size_t idx); + string8 format_permutation(const size_t* arg, size_t n); + string8 format_mask(bit_array const& mask, size_t n); } inline pfc::string_base & operator<<(pfc::string_base & p_fmt,const char * p_source) {p_fmt.add_string_(p_source); return p_fmt;} diff --git a/sdk/pfc/win-objects.cpp b/sdk/pfc/win-objects.cpp index eb50c39..0bacb83 100644 --- a/sdk/pfc/win-objects.cpp +++ b/sdk/pfc/win-objects.cpp @@ -421,6 +421,43 @@ namespace pfc { } #endif } + pfc::string8 format_window(HWND wnd) { + pfc::string_formatter ret; + ret << "0x" << format_hex( (size_t)wnd ); + auto title = getWindowText(wnd); + if (title.length() > 0) { + ret << " [" << title << "]"; + } + return ret; + } + +#define _(X) {X, #X} + struct winStyle_t { + DWORD v; const char * n; + }; + static const winStyle_t winStyles[] = { + _(WS_POPUP), _(WS_CHILD), _(WS_MINIMIZE), _(WS_VISIBLE), + _(WS_DISABLED), _(WS_CLIPSIBLINGS), _(WS_CLIPCHILDREN), _(WS_MAXIMIZE), + _(WS_BORDER), _(WS_DLGFRAME), _(WS_VSCROLL), _(WS_HSCROLL), + _(WS_SYSMENU), _(WS_THICKFRAME), _(WS_GROUP), _(WS_TABSTOP), + _(WS_MINIMIZEBOX), _(WS_MAXIMIZEBOX) + }; + + pfc::string8 format_windowStyle(DWORD style) { + pfc::string_formatter ret; + ret << "0x" << format_hex( style, 8 ); + if (style != 0) { + pfc::string_formatter label; + for (auto& s : winStyles) if (style & s.v) { + if ( label.length() > 0 ) label << "|"; + label << s.n; + } + if (label.length() > 0) { + ret << " [" << label << "]"; + } + } + return ret; + } } #else diff --git a/sdk/pfc/win-objects.h b/sdk/pfc/win-objects.h index 7a98e91..29eb282 100644 --- a/sdk/pfc/win-objects.h +++ b/sdk/pfc/win-objects.h @@ -333,5 +333,8 @@ namespace pfc { #ifdef PFC_WINDOWS_DESKTOP_APP void winSetThreadDescription(HANDLE hThread, const wchar_t * desc); + + pfc::string8 format_window(HWND wnd); + pfc::string8 format_windowStyle(DWORD); #endif // PFC_WINDOWS_DESKTOP_APP } diff --git a/sdk/sdk-readme.html b/sdk/sdk-readme.html index 8ff0f82..29d786f 100644 --- a/sdk/sdk-readme.html +++ b/sdk/sdk-readme.html @@ -8,11 +8,11 @@

-foobar2000 SDK, version 2023-02-22 +foobar2000 SDK, version 2023-04-18

Documentation:
-SDK release notes
+SDK Change Log
foobar2000 Development Overview

From 9c6f1101edf7d33e4b53c19208cfa65e95457bb2 Mon Sep 17 00:00:00 2001 From: Hyperblast Date: Wed, 12 Feb 2025 08:28:42 +0500 Subject: [PATCH 06/12] update to SDK-2023-05-10 --- cmake/FileLists.cmake | 3 +- sdk/foobar2000/SDK/file.h | 39 +++- sdk/foobar2000/SDK/file_info.cpp | 45 ++++- sdk/foobar2000/SDK/file_info.h | 7 + sdk/foobar2000/SDK/filesystem.cpp | 187 +++++++++++++++--- sdk/foobar2000/SDK/filesystem.h | 22 +++ sdk/foobar2000/SDK/filesystem_transacted.h | 36 ---- sdk/foobar2000/SDK/foobar2000-versions.h | 2 +- sdk/foobar2000/SDK/fsItem.cpp | 54 +++-- sdk/foobar2000/SDK/fsitem.h | 2 + sdk/foobar2000/SDK/guids.cpp | 4 +- sdk/foobar2000/SDK/hasher_md5.h | 4 + sdk/foobar2000/SDK/input.cpp | 26 ++- sdk/foobar2000/SDK/input.h | 3 + sdk/foobar2000/SDK/library_index.h | 12 +- sdk/foobar2000/SDK/playlist_loader.cpp | 4 +- sdk/foobar2000/SDK/playlist_loader.h | 3 - sdk/foobar2000/SDK/search_tools.h | 19 +- sdk/foobar2000/SDK/service.h | 13 +- sdk/foobar2000/SDK/service_impl.h | 4 +- sdk/foobar2000/SDK/system_time_keeper.h | 7 +- sdk/foobar2000/SDK/threadsLite.h | 2 + sdk/foobar2000/helpers/cfg_objList.h | 10 +- sdk/foobar2000/helpers/file_readonly.h | 4 - sdk/foobar2000/helpers/file_win32_wrapper.cpp | 49 +++++ sdk/foobar2000/helpers/file_win32_wrapper.h | 3 +- .../helpers/foobar2000_sdk_helpers.vcxproj | 15 +- .../foobar2000_sdk_helpers.vcxproj.filters | 9 +- sdk/foobar2000/helpers/packages.config | 4 - sdk/foobar2000/helpers/readers.cpp | 60 ++++++ sdk/foobar2000/helpers/readers_lite.h | 6 + sdk/foobar2000/shared/fb2kdebug.h | 2 +- sdk/libPPUI/CListControl.cpp | 2 +- sdk/libPPUI/CListControlHeaderImpl.cpp | 4 +- sdk/libPPUI/CListControlHeaderImpl.h | 2 +- sdk/libPPUI/CListControlWithSelection.cpp | 33 +++- sdk/libPPUI/CListControlWithSelection.h | 5 + sdk/libPPUI/DarkMode.cpp | 89 +++++++-- sdk/libPPUI/DarkMode.h | 4 + sdk/libPPUI/libPPUI.vcxproj | 14 +- sdk/libPPUI/libPPUI.vcxproj.filters | 6 +- sdk/libPPUI/packages.config | 4 - sdk/libPPUI/win32_utility.h | 2 +- sdk/libPPUI/wtl-pp.cpp | 47 +++++ sdk/libPPUI/wtl-pp.h | 40 ++-- sdk/sdk-readme.html | 2 +- 46 files changed, 687 insertions(+), 227 deletions(-) delete mode 100644 sdk/foobar2000/helpers/file_readonly.h delete mode 100644 sdk/foobar2000/helpers/packages.config create mode 100644 sdk/foobar2000/helpers/readers_lite.h delete mode 100644 sdk/libPPUI/packages.config create mode 100644 sdk/libPPUI/wtl-pp.cpp diff --git a/cmake/FileLists.cmake b/cmake/FileLists.cmake index a0a82ef..d7f8a49 100644 --- a/cmake/FileLists.cmake +++ b/cmake/FileLists.cmake @@ -438,7 +438,6 @@ set( sdk/foobar2000/helpers/fb2k_threads.h sdk/foobar2000/helpers/fb2k_wfx.h sdk/foobar2000/helpers/fileReadAhead.h - sdk/foobar2000/helpers/file_readonly.h sdk/foobar2000/helpers/foobar2000+atl.h sdk/foobar2000/helpers/foobar2000-lite+atl.h sdk/foobar2000/helpers/fullFileBuffer.h @@ -482,6 +481,7 @@ set( sdk/foobar2000/helpers/ProcessUtils.h sdk/foobar2000/helpers/ProfileCache.h sdk/foobar2000/helpers/readers.h + sdk/foobar2000/helpers/readers_lite.h sdk/foobar2000/helpers/reader_pretend_nonseekable.h sdk/foobar2000/helpers/readWriteLock.h sdk/foobar2000/helpers/rethrow.h @@ -536,6 +536,7 @@ set( sdk/libPPUI/TypeFind.cpp sdk/libPPUI/win32_op.cpp sdk/libPPUI/win32_utility.cpp + sdk/libPPUI/wtl-pp.cpp ) set( diff --git a/sdk/foobar2000/SDK/file.h b/sdk/foobar2000/SDK/file.h index 9f04ed7..6a339c7 100644 --- a/sdk/foobar2000/SDK/file.h +++ b/sdk/foobar2000/SDK/file.h @@ -30,6 +30,9 @@ namespace foobar2000_io inline bool operator==(const t_filestats& param) const { return m_size == param.m_size && m_timestamp == param.m_timestamp; } inline bool operator!=(const t_filestats& param) const { return m_size != param.m_size || m_timestamp != param.m_timestamp; } + + pfc::string8 describe() const; + pfc::string8 debug() const { return describe(); } }; struct t_filestats2 { @@ -86,6 +89,11 @@ namespace foobar2000_io bool operator!=(const t_filestats2& other) const { return !equals(*this, other); } pfc::string8 describe() const; + pfc::string8 debug() const { return describe(); } + + bool haveSize() const { return m_size != filesize_invalid; } + bool haveTimestamp() const { return m_timestamp != filetimestamp_invalid; } + bool haveTimestampCreate() const { return m_timestampCreate != filetimestamp_invalid; } }; enum { stats2_size = 1 << 0, @@ -368,9 +376,19 @@ namespace foobar2000_io //! file_v2 wrapper. t_filestats2 get_stats2_(uint32_t f, abort_callback& a); + //! file_v2 wrapper. + void set_stats(t_filestats2 const&, abort_callback&); + //! file_v2 wrapper. t_filetimestamp get_time_created(abort_callback& a); + //! Alternate version of read() intended for network resources.\n + //! See: stream_receive::receive(); \n + //! If not implemented by this object, uses plain read(). + size_t receive(void*, size_t, abort_callback&); + + void commit(abort_callback& a) {flushFileBuffers(a);} + FB2K_MAKE_SERVICE_INTERFACE(file, service_base); }; @@ -453,11 +471,16 @@ namespace foobar2000_io 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; } - bool is_remote() { return true; } + bool get_content_type(pfc::string_base& out) { + if (m_contentType.length() > 0) { out = m_contentType; return true; } else return false; + } + bool is_remote() { return m_remote; } void reopen(abort_callback&) {} void seek(t_filesize, abort_callback&) { throw exception_io_object_not_seekable(); } bool can_seek() { return false; } + + pfc::string8 m_contentType; + bool m_remote = true; }; //! \since 2.0 @@ -486,4 +509,14 @@ namespace foobar2000_io virtual void get_connected_path(pfc::string_base& out) = 0; }; -} \ No newline at end of file + + //! \since 2.1 + //! Extension to file object, implemented by network readers. Adds receive() method. + class stream_receive : public service_base { + FB2K_MAKE_SERVICE_INTERFACE(stream_receive, service_base); + public: + //! Alternate version of read() intended for network resources.\n + //! Returns as soon as any data is available (usually less than requested), or EOF has been reached (0 returned). + virtual size_t receive(void*, size_t, abort_callback&) = 0; + }; +} diff --git a/sdk/foobar2000/SDK/file_info.cpp b/sdk/foobar2000/SDK/file_info.cpp index ee435fc..1c0845b 100644 --- a/sdk/foobar2000/SDK/file_info.cpp +++ b/sdk/foobar2000/SDK/file_info.cpp @@ -872,7 +872,6 @@ bool file_info::unicode_normalize_C() { const size_t total = this->meta_get_count(); bool changed = false; for (size_t mwalk = 0; mwalk < total; ++mwalk) { - const char* name = this->meta_enum_name(mwalk); const size_t totalV = this->meta_enum_value_count(mwalk); for (size_t vwalk = 0; vwalk < totalV; ++vwalk) { const char* val = this->meta_enum_value(mwalk, vwalk); @@ -898,4 +897,46 @@ void file_info::meta_enumerate(meta_enumerate_t cb) const { cb(name, value); } } -} \ No newline at end of file +} + +#ifdef FOOBAR2000_MOBILE +#include "album_art.h" +#include "hasher_md5.h" + +void file_info::info_set_pictures( const GUID * guids, size_t size ) { + this->info_set("pictures", album_art_ids::ids_to_string(guids, size) ); +} + +pfc::array_t file_info::info_get_pictures( ) const { + return album_art_ids::string_to_ids( this->info_get( "pictures" ) ); +} + +uint64_t file_info::makeMetaHash() const { + pfc::string_formatter temp; + + auto doMeta = [&] ( const char * meta ) { + const char * p = meta_get(meta, 0); + if (p != nullptr) temp << p; + temp << "\n"; + }; + auto doMetaInt = [&] ( const char * meta ) { + const char * p = meta_get(meta, 0); + if (p != nullptr) { + auto s = strchr(p, '/' ); if ( s != nullptr ) p = s+1; + while(*p == '0') ++p; + temp << p; + } + temp << "\n"; + }; + doMeta("title"); + doMeta("artist"); + doMeta("album"); + doMetaInt("tracknumber"); + doMetaInt("discnumber"); + + if (temp.length() == 5) return 0; + + return hasher_md5::get()->process_single( temp.c_str(), temp.length( ) ).xorHalve(); +} + +#endif // FOOBAR2000_MOBILE diff --git a/sdk/foobar2000/SDK/file_info.h b/sdk/foobar2000/SDK/file_info.h index 2a7037d..8f89845 100644 --- a/sdk/foobar2000/SDK/file_info.h +++ b/sdk/foobar2000/SDK/file_info.h @@ -306,6 +306,13 @@ class NOVTABLE file_info { //! Normalize values to Unicode form C //! @returns true if changed, false otherwise bool unicode_normalize_C(); + + +#ifdef FOOBAR2000_MOBILE + void info_set_pictures( const GUID * guids, size_t size ); + pfc::array_t info_get_pictures( ) const; + uint64_t makeMetaHash() const; +#endif protected: file_info() {} ~file_info() {} diff --git a/sdk/foobar2000/SDK/filesystem.cpp b/sdk/foobar2000/SDK/filesystem.cpp index 10005bb..5d264f9 100644 --- a/sdk/foobar2000/SDK/filesystem.cpp +++ b/sdk/foobar2000/SDK/filesystem.cpp @@ -1129,8 +1129,13 @@ bool foobar2000_io::_extract_native_path_ptr(const char * & p_fspath) { return true; } bool foobar2000_io::extract_native_path(const char * p_fspath,pfc::string_base & p_native) { - if (!_extract_native_path_ptr(p_fspath)) return false; + if (strstr(p_fspath, "://") != nullptr) { + if (!_extract_native_path_ptr(p_fspath)) return false; + } p_native = p_fspath; +#ifndef _WIN32 + expandHomeDir( p_native ); +#endif return true; } @@ -1453,8 +1458,36 @@ bool filesystem::directory_exists(const char * path, abort_callback & abort) { directory_callback_dummy cb; list_directory(path, cb, abort); return true; - } catch (exception_io const &) { return false; } + } catch (exception_io) { return false; } } + +bool filesystem::exists(const char* path, abort_callback& a) { + // for rare cases of code test if EITHER FILE OR FOLDER exists at path + filesystem_v3::ptr v3; + if (v3 &= this) { + try { + v3->get_stats2(path, stats2_fileOrFolder, a); + return true; + } catch (exception_io_not_found) { return false; } + } + filesystem_v2::ptr v2; + if (v2 &= this) { + return v2->file_exists(path, a) || v2->directory_exists(path, a); + } + + try { + t_filestats stats; bool writable; + get_stats(path, stats, writable, a); + return true; + } catch (exception_io) { } + try { + directory_callback_dummy cb; + list_directory(path, cb, a); + return true; + } catch (exception_io) { } + return false; +} + bool filesystem::file_exists(const char * path, abort_callback & abort) { filesystem_v2::ptr v2; if ( v2 &= this ) { @@ -1569,8 +1602,12 @@ void filesystem::read_whole_file_fallback(const char * path, mem_block_container } bool filesystem::is_transacted() { +#if FB2K_SUPPORT_TRANSACTED_FILESYSTEM filesystem_transacted::ptr p; return ( p &= this ); +#else + return false; +#endif } void filesystem::rewrite_file(const char* path, abort_callback& abort, double opTimeout, const void* payload, size_t bytes) { @@ -1681,7 +1718,7 @@ bool filesystem_v2::make_directory_check(const char * path, abort_callback & abo return rv; } - +#if FB2K_SUPPORT_TRANSACTED_FILESYSTEM filesystem_transacted::ptr filesystem_transacted::create( const char * pathFor ) { service_enum_t e; filesystem_transacted_entry::ptr p; @@ -1693,13 +1730,16 @@ filesystem_transacted::ptr filesystem_transacted::create( const char * pathFor ) } return nullptr; } +#endif bool filesystem::commit_if_transacted(abort_callback &abort) { bool rv = false; +#if FB2K_SUPPORT_TRANSACTED_FILESYSTEM filesystem_transacted::ptr t; if ( t &= this ) { t->commit( abort ); rv = true; } +#endif return rv; } @@ -2003,18 +2043,13 @@ fsItemBase::ptr filesystem_v3::findItem(const char* path, abort_callback& p_abor try { #endif pfc::string8 canonical; - get_canonical_path(path, canonical); - - if (this->is_remote(canonical)) { - // Do not perform expensive checks for remote filesystems - return makeItemFileStd(canonical); - } - - if (this->file_exists(canonical, p_abort)) { - return makeItemFileStd(canonical); - } - if (this->directory_exists(canonical, p_abort)) { - return makeItemFolderStd(canonical); + if (get_canonical_path(path, canonical)) { + auto stats = this->get_stats2(path, stats2_all, p_abort); + if ( stats.is_folder() ) { + return makeItemFolderStd(canonical, stats); + } else { + return makeItemFileStd(canonical, stats ); + } } throw exception_io_not_found(); #if PFC_DEBUG @@ -2032,9 +2067,11 @@ fsItemFile::ptr filesystem_v3::findItemFile(const char* path, abort_callback& p_ try { #endif pfc::string8 canonical; - get_canonical_path(path, canonical); - if (this->is_remote(canonical) || this->file_exists(canonical, p_abort)) { - return makeItemFileStd(canonical); + if (get_canonical_path(path, canonical)) { + auto stats = this->get_stats2( canonical, stats2_all, p_abort); + if ( stats.is_file() ) { + return makeItemFileStd(canonical, stats ); + } } throw exception_io_not_found(); #if PFC_DEBUG @@ -2052,9 +2089,11 @@ fsItemFolder::ptr filesystem_v3::findItemFolder(const char* path, abort_callback try { #endif pfc::string8 canonical; - if (!get_canonical_path(path, canonical)) throw exception_io_not_found(); - if (this->is_remote(canonical) || this->directory_exists(canonical, p_abort)) { - return makeItemFolderStd(canonical); + if (get_canonical_path(path, canonical)) { + auto stats = this->get_stats2( canonical, stats2_all, p_abort); + if ( stats.is_folder() ) { + return makeItemFolderStd(canonical, stats ); + } } throw exception_io_not_found(); #if PFC_DEBUG @@ -2086,7 +2125,7 @@ fb2k::stringRef filesystem_v3::fileNameSanity(const char* fn) { return ret; } -void filesystem_v3::readStatsMulti(fb2k::arrayRef items, uint32_t s2flags, t_filestats2* outStats, abort_callback& abort) { +static void readStatsMultiStd(fb2k::arrayRef items, uint32_t s2flags, t_filestats2* outStats, abort_callback& abort) { const size_t count = items->size(); for (size_t w = 0; w < count; ++w) { abort.check(); @@ -2102,6 +2141,23 @@ void filesystem_v3::readStatsMulti(fb2k::arrayRef items, uint32_t s2flags, t_fil } } +void filesystem_v3::readStatsMulti(fb2k::arrayRef items, uint32_t s2flags, t_filestats2* outStats, abort_callback& abort) { + readStatsMultiStd(items, s2flags, outStats, abort); +} + +pfc::string8 t_filestats::describe() const { + pfc::string8 ret; + ret << "size: "; + if (m_size != filesize_invalid) ret << m_size; + else ret << "N/A"; + ret << "\n"; + ret << "last-modified: "; + if (m_timestamp != filetimestamp_invalid) ret << m_timestamp; + else ret << "N/A"; + ret << "\n"; + return ret; +} + pfc::string8 t_filestats2::describe() const { pfc::string8 ret; ret << "size: "; @@ -2147,10 +2203,15 @@ bool foobar2000_io::nixQueryDirectory( const struct stat & st ) { t_filestats2 foobar2000_io::nixMakeFileStats2(const struct stat &st) { t_filestats2 ret = t_filestats2::from_legacy( nixMakeFileStats( st ) ); +#ifndef __ANDROID__ + // Android Java API does not report creation time + // We could return it from here, but then different fb2k APIs will return different info about the same object, which is not acceptable. ret.m_timestampCreate = pfc::fileTimeUtoW( st.st_birthtimespec ); +#endif ret.set_readonly(nixQueryReadonly(st)); if ( nixQueryDirectory( st ) ) ret.set_folder(); else ret.set_file(); + ret.set_remote(false); return ret; } @@ -2205,3 +2266,85 @@ bool filesystem::g_get_display_name_short( const char * path, pfc::string_base & out = path; return false; } + + +bool filesystem::g_compare_paths(const char* p1, const char* p2, int& result) { + if (strcmp(p1, p2) == 0) { + result = 0; return true; + } + + { + auto s1 = strstr(p1, "://"); + auto s2 = strstr(p2, "://"); + if (s1 == nullptr || s2 == nullptr) { + PFC_ASSERT(!"Invalid arguments"); + return false; + } + size_t prefix = s1 - p1; + if (prefix != s2 - p2) return false; // protocol mismatch + if (memcmp(p1, p2, prefix) != 0) return false; // protocol mismatch + } + + filesystem::ptr fs; + if (!g_get_interface(fs, p1)) { + PFC_ASSERT(!"Invalid arguments"); + return false; + } + pfc::string8 temp1(p1), temp2(p2); + auto delim = fs->pathSeparator(); + temp1.end_with(delim); temp2.end_with(delim); + if (strcmp(temp1, temp2) == 0) { result = 0; return true; } + + //result 1 if p2 is a subpath of p1, -1 if p1 is a subpath of p2 + if (pfc::string_has_prefix(temp1, temp2)) { + // temp1 starts with temp2 + // p1 a subfolder of p2 + result = -1; + return true; + } else if (pfc::string_has_prefix(temp2, temp1)) { + // temp2 starts with temp1 + // p2 a subfolder of p1 + result = 1; + return true; + } else { + return false; + } +} + +size_t file::receive(void* ptr, size_t bytes, abort_callback& a) { + stream_receive::ptr obj; + if (obj &= this) return obj->receive(ptr, bytes, a); + else return this->read(ptr, bytes, a); +} + +void filesystem::g_readStatsMulti(fb2k::arrayRef items, uint32_t s2flags, t_filestats2* outStats, abort_callback& abort) { + if (items->size() == 0) return; + fsItemPtr aFile; aFile ^= items->itemAt(0); + filesystem_v3::ptr fs; + if (fs &= aFile->getFS()) { + fs->readStatsMulti(items, s2flags, outStats, abort); + } else { + readStatsMultiStd(items, s2flags, outStats, abort); + } +} + +void file::set_stats(t_filestats2 const& stats, abort_callback& a) { + if (stats.haveTimestamp() || stats.haveTimestampCreate()) { + filetimes_t ft; + ft.creation = stats.m_timestampCreate; + ft.lastWrite = stats.m_timestamp; + this->setFileTimes(ft, a); + } +} + +fb2k::stringRef filesystem::fileNameSanity_(const char* fn) { + filesystem_v3::ptr v3; + if (v3 &= this) return v3->fileNameSanity(fn); + throw pfc::exception_not_implemented(); +} + +drivespace_t filesystem::getDriveSpace_(const char* pathAt, abort_callback& abort) { + filesystem_v3::ptr v3; + if (v3 &= this) return v3->getDriveSpace(pathAt, abort); + throw pfc::exception_not_implemented(); +} diff --git a/sdk/foobar2000/SDK/filesystem.h b/sdk/foobar2000/SDK/filesystem.h index 93d48cd..74c5508 100644 --- a/sdk/foobar2000/SDK/filesystem.h +++ b/sdk/foobar2000/SDK/filesystem.h @@ -169,8 +169,13 @@ namespace foobar2000_io //! Bool retval version of make_directory(). bool make_directory_check( const char * path, abort_callback & abort ); + //! Returns whether a directory exists at path, false if doesn't exist or not a directory. bool directory_exists(const char * path, abort_callback & abort); + //! Returns whether a file exists at path, false if doesn't exist or not a file. bool file_exists( const char * path, abort_callback & abort ); + //! Returns whether either a file or a directory exists at path. Effectively directory_exists() || file_exists(), but somewhat more efficient. + bool exists(const char* path, abort_callback& a); + char pathSeparator(); //! Extracts the filename.ext portion of the path. \n //! The filename is ready to be presented to the user - URL decoding and such (similar to get_display_path()) is applied. @@ -220,11 +225,28 @@ namespace foobar2000_io fsItemFolder::ptr makeItemFolderStd(const char* pathCanonical, t_filestats2 const& stats = filestats2_invalid ); fsItemFile::ptr makeItemFileStd(const char* pathCanonical, t_filestats2 const& stats = filestats2_invalid ); + fsItemBase::ptr findItem_(const char* path, abort_callback& p_abort); + fsItemFile::ptr findItemFile_(const char* path, abort_callback& p_abort); + fsItemFolder::ptr findItemFolder_(const char* path, abort_callback& p_abort); typedef std::function list_callback_t; void list_directory_(const char* path, list_callback_t cb, unsigned listMode,abort_callback& a); + //! Compares two paths determining if one is a subpath of another, + //! Returns false if the paths are unrelated. + //! Returns true if the paths are related, and then: result is set 0 if they are equal, 1 if p2 is a subpath of p1, -1 if p1 is a subpath of p2 + static bool g_compare_paths(const char* p1, const char* p2, int& result); + + //! Batch file stats read. Some filesystems provide an optimized implementation of this. + static void g_readStatsMulti(fb2k::arrayRef items, uint32_t s2flags, t_filestats2* outStats, abort_callback& abort); + + //! See filesystem_v3::fileNameSanity(). Throws pfc::exception_not_implemented() if not available. + fb2k::stringRef fileNameSanity_(const char* fn); + + //! See filesystem_v3::getDriveSpace(). Throws pfc::exception_not_implemented() if not available. + drivespace_t getDriveSpace_(const char* pathAt, abort_callback& abort); + protected: static bool get_parent_helper(const char * path, char separator, pfc::string_base & out); void read_whole_file_fallback( const char * path, mem_block_container & out, pfc::string_base & outContentType, size_t maxBytes, abort_callback & abort ); diff --git a/sdk/foobar2000/SDK/filesystem_transacted.h b/sdk/foobar2000/SDK/filesystem_transacted.h index 9574ecc..e93eaee 100644 --- a/sdk/foobar2000/SDK/filesystem_transacted.h +++ b/sdk/foobar2000/SDK/filesystem_transacted.h @@ -2,42 +2,6 @@ #include "filesystem.h" -//! Object cannot be opened in transacted mode. -PFC_DECLARE_EXCEPTION(exception_io_transactions_unsupported, exception_io, "Transactions unsupported on this volume"); -PFC_DECLARE_EXCEPTION(exception_io_transactional_conflict, exception_io, "Transactional conflict"); -PFC_DECLARE_EXCEPTION(exception_io_transaction_aborted, exception_io, "Transaction aborted"); - -//! An instance of a filesystem transaction. Inherits from filesystem API and provides all the methods. \n -//! To perform a transacted filesystem update, you must call methods on this object specifically - not static methods of filesystem class, not methods of a filesystem instance obtained from someplace else. \n -//! Call commit() when done, then release the object. If you release the object without having called commit(), the update will be rolled back. \n -//! Please keep in mind that you must not explicitly rely on this API and always provide a fallback mechanism. \n -//! A transacted operation may be impossible for the following reasons: \n -//! Too old foobar2000 version - filesystem_transacted was first published at version 1.4 beta 7 - obtaining a filesystem_transacted instance will fail. \n -//! Too old Windows OS - transacted APIs are available starting from Vista, not available on XP - obtaining a filesystem_transacted instance will fail. \n -//! Functionality disabled by user - obtaining a filesystem_transacted instance will fail. \n -//! The volume you're trying to work with does not support transacted updates - network share, non-NTFS USB stick, etc - create() will succeed but operations will fail with exception_io_transactions_unsupported. \n -class filesystem_transacted : public filesystem_v2 { - FB2K_MAKE_SERVICE_INTERFACE(filesystem_transacted, filesystem_v2); -public: - //! Commits the transaction. You should release this filesystem_transacted object when done. \n - //! If you don't call commit, all operations made with this filesystem_transacted instance will be rolled back. - virtual void commit(abort_callback & abort) = 0; - - //! Helper to obtain a new instance. Will return null if filesystem_transacted is unavailable. - static filesystem_transacted::ptr create( const char * pathFor ); -}; - -//! \since 1.4 -//! An entrypoint interface to create filesystem_transacted instances. Use filesystem_transacted::create() instead of calling this directly. -class filesystem_transacted_entry : public service_base { - FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(filesystem_transacted_entry); -public: - //! May return null if transacted ops are not available in this location for one reason or another. - virtual filesystem_transacted::ptr create( const char * pathFor ) = 0; - - 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. diff --git a/sdk/foobar2000/SDK/foobar2000-versions.h b/sdk/foobar2000/SDK/foobar2000-versions.h index 43f4e3e..aff1eff 100644 --- a/sdk/foobar2000/SDK/foobar2000-versions.h +++ b/sdk/foobar2000/SDK/foobar2000-versions.h @@ -19,7 +19,7 @@ // Use this to determine what foobar2000 SDK version is in use, undefined for releases older than 2018 -#define FOOBAR2000_SDK_VERSION 20230418 +#define FOOBAR2000_SDK_VERSION 20230510 // cfg_var downgrade support, experimental, intended for specific components only. // Allows new style configStore data to be imported back to old foobar2000 friendly cfg_vars. diff --git a/sdk/foobar2000/SDK/fsItem.cpp b/sdk/foobar2000/SDK/fsItem.cpp index 83a65b0..f5e77c1 100644 --- a/sdk/foobar2000/SDK/fsItem.cpp +++ b/sdk/foobar2000/SDK/fsItem.cpp @@ -118,6 +118,7 @@ namespace { class fsItemFileStd : public fsItemFile { public: fsItemFileStd(filesystem::ptr fs, stringRef canonicalPath, t_filestats2 const & opportunistStats) : m_fs(fs), m_path(canonicalPath), m_opportunistStats(opportunistStats) { + PFC_ASSERT( m_opportunistStats.m_attribsValid & t_filestats2::attr_remote ); m_opportunistStats.set_folder(false); } @@ -195,6 +196,7 @@ namespace { class fsItemFolderStd : public fsItemFolder { public: fsItemFolderStd(filesystem::ptr fs, stringRef canonicalPath, t_filestats2 const & opportunistStats) : m_fs(fs), m_path(canonicalPath), m_opportunistStats(opportunistStats) { + PFC_ASSERT( m_opportunistStats.m_attribsValid & t_filestats2::attr_remote ); m_opportunistStats.set_folder(true); } @@ -373,36 +375,46 @@ fsItemFolder::ptr filesystem::makeItemFolderStd(const char* pathCanonical, t_fil fsItemFile::ptr filesystem::makeItemFileStd(const char* pathCanonical, t_filestats2 const & opportunistStats) { return new service_impl_t(this, makeString(pathCanonical), opportunistStats); } - -fsItemBase::ptr fsItemBase::fromPath(const char* path, abort_callback& aborter) { - auto fs = filesystem::get(path); - +fsItemBase::ptr filesystem::findItem_(const char* path, abort_callback& p_abort) { filesystem_v3::ptr v3; - if (v3 &= fs) return v3->findItem(path, aborter); + if (v3 &= this) { + return v3->findItem(path, p_abort); + } + auto stats = this->get_stats2_(path, stats2_fileOrFolder, p_abort); + if (stats.is_folder()) return this->makeItemFolderStd(path, stats); + else return this->makeItemFileStd(path, stats); - auto stats = fs->get_stats2_(path, stats2_fileOrFolder, aborter); - if (stats.is_folder()) return fs->makeItemFolderStd(path, stats); - else return fs->makeItemFileStd(path, stats); } +fsItemFile::ptr filesystem::findItemFile_(const char* path, abort_callback& p_abort) { + filesystem_v3::ptr v3; + if (v3 &= this) return v3->findItemFile(path, p_abort); -fsItemFile::ptr fsItemFile::fromPath(const char* path, abort_callback& aborter) { - auto fs = filesystem::get(path); - + auto stats = this->get_stats2_(path, stats2_fileOrFolder, p_abort); + if (!stats.is_folder()) return this->makeItemFileStd(path, stats); + throw exception_io_not_found(); +} +fsItemFolder::ptr filesystem::findItemFolder_(const char* path, abort_callback& p_abort) { filesystem_v3::ptr v3; - if ( v3 &= fs ) return v3->findItemFile(path, aborter); + if (v3 &= this) return v3->findItemFolder(path, p_abort); - auto stats = fs->get_stats2_(path, stats2_fileOrFolder, aborter); - if (!stats.is_folder()) return fs->makeItemFileStd(path, stats); + auto stats = this->get_stats2_(path, stats2_fileOrFolder, p_abort); + if (stats.is_folder()) return this->makeItemFolderStd(path, stats); throw exception_io_not_found(); } -fsItemFolder::ptr fsItemFolder::fromPath(const char* path, abort_callback& aborter) { - auto fs = filesystem::get(path); - filesystem_v3::ptr v3; - if (v3 &= fs) return v3->findItemFolder(path, aborter); +fsItemBase::ptr fsItemBase::fromPath(const char* path, abort_callback& aborter) { + return filesystem::get(path)->findItem_(path, aborter); +} - auto stats = fs->get_stats2_(path, stats2_fileOrFolder, aborter); - if (stats.is_folder()) return fs->makeItemFolderStd(path, stats); - throw exception_io_not_found(); +fsItemFile::ptr fsItemFile::fromPath(const char* path, abort_callback& aborter) { + return filesystem::get(path)->findItemFile_(path, aborter); +} + +fsItemFolder::ptr fsItemFolder::fromPath(const char* path, abort_callback& aborter) { + return filesystem::get(path)->findItemFolder_(path, aborter); +} + +t_filestats fsItemBase::getStats(abort_callback& a) { + return getStats2(stats2_all, a).to_legacy(); } diff --git a/sdk/foobar2000/SDK/fsitem.h b/sdk/foobar2000/SDK/fsitem.h index ca9d498..1814b16 100644 --- a/sdk/foobar2000/SDK/fsitem.h +++ b/sdk/foobar2000/SDK/fsitem.h @@ -84,6 +84,8 @@ namespace foobar2000_io { virtual service_ptr_t getFS() = 0; static fsItemBase::ptr fromPath(const char* path, abort_callback& aborter); + + t_filestats getStats(abort_callback& a); }; class fsItemFile : public fsItemBase { diff --git a/sdk/foobar2000/SDK/guids.cpp b/sdk/foobar2000/SDK/guids.cpp index 5203bef..bf22cca 100644 --- a/sdk/foobar2000/SDK/guids.cpp +++ b/sdk/foobar2000/SDK/guids.cpp @@ -1405,8 +1405,6 @@ FOOGUIDDECL const GUID file_format_sanitizer_v2::class_guid = { 0xe61986b7, 0x12 #endif // FOOBAR2000_HAVE_FILE_FORMAT_SANITIZER -FOOGUIDDECL const GUID filesystem_transacted::class_guid = { 0x35637f92, 0x6b65, 0x47b8,{ 0x9e, 0xe, 0x48, 0x47, 0x97, 0x62, 0x34, 0x3 } }; -FOOGUIDDECL const GUID filesystem_transacted_entry::class_guid = { 0xfd6e6849, 0x7006, 0x44db,{ 0x9b, 0x87, 0x45, 0x58, 0x3c, 0xf7, 0x5d, 0x18 } }; FOOGUIDDECL const GUID config_io_callback_v3::class_guid = { 0x8e633dd, 0x625e, 0x402c,{ 0xbe, 0xab, 0x74, 0x9, 0xd0, 0x1d, 0x41, 0xdf } }; FOOGUIDDECL const GUID filesystem_v2::class_guid = { 0xdaf04ce2, 0x36a5, 0x4346,{ 0x80, 0x7f, 0x77, 0x8c, 0x5b, 0x5c, 0x26, 0xaa } }; FOOGUIDDECL const GUID filesystem_v3::class_guid = { 0x7166094e, 0xbc64, 0x4c97, { 0xaa, 0x53, 0x62, 0xbd, 0x7a, 0x34, 0xb8, 0xf6 } }; @@ -1509,3 +1507,5 @@ FOOGUIDDECL const GUID library_manager_v6::class_guid = { 0x92eea180, 0x93d0, 0x FOOGUIDDECL const GUID play_callback_manager_v2::class_guid = { 0x7e59a4e6, 0x810d, 0x433b, { 0xb6, 0x9, 0x12, 0xf4, 0xde, 0x7f, 0x7f, 0x47 } }; FOOGUIDDECL const GUID metadb_hint_list_v4::class_guid = { 0xe7908ec9, 0xa26a, 0x418e, { 0xac, 0x13, 0xb4, 0x17, 0x67, 0x8c, 0xa, 0x4 } }; FOOGUIDDECL const GUID metadb_pre_update_callback::class_guid = { 0xc81865af, 0x1da2, 0x4361, { 0x92, 0x88, 0xac, 0xf7, 0x83, 0x89, 0xe1, 0x9c } }; + +FOOGUIDDECL const GUID stream_receive::class_guid = { 0x1d36b5af, 0xaa6b, 0x450d, { 0xa4, 0x1f, 0x58, 0x19, 0x13, 0x4e, 0xdb, 0x57 } }; diff --git a/sdk/foobar2000/SDK/hasher_md5.h b/sdk/foobar2000/SDK/hasher_md5.h index ad186f1..dccf922 100644 --- a/sdk/foobar2000/SDK/hasher_md5.h +++ b/sdk/foobar2000/SDK/hasher_md5.h @@ -11,9 +11,11 @@ struct hasher_md5_result { t_uint64 xorHalve() const; GUID asGUID() const; pfc::string8 asString() const; + pfc::string8 toString() const { return asString(); } GUID toGUID() const; static hasher_md5_result null() {hasher_md5_result h = {}; return h;} + static int compare(hasher_md5_result const & h1, hasher_md5_result const & h2) { return memcmp(&h1, &h2, sizeof(hasher_md5_result)); } }; FB2K_STREAM_READER_OVERLOAD(hasher_md5_result) { @@ -25,6 +27,8 @@ FB2K_STREAM_WRITER_OVERLOAD(hasher_md5_result) { 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;} +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; } namespace pfc { template<> class traits_t : public traits_rawobject {}; diff --git a/sdk/foobar2000/SDK/input.cpp b/sdk/foobar2000/SDK/input.cpp index 9dbf0cd..fc3a0e3 100644 --- a/sdk/foobar2000/SDK/input.cpp +++ b/sdk/foobar2000/SDK/input.cpp @@ -350,13 +350,15 @@ void input_open_file_helper(service_ptr_t & 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 +#if defined(FOOBAR2000_DESKTOP) && FOOBAR2000_TARGET_VERSION >= 80 return input_manager_v3::get()->flags_for_path(path, mask); #else +#ifdef FOOBAR2000_DESKTOP input_manager_v3::ptr api; if ( input_manager_v3::tryGet(api) ) { return api->flags_for_path(path, mask); } +#endif uint32_t ret = 0; service_enum_t e; input_entry::ptr p; auto ext = pfc::string_extension(path); @@ -368,14 +370,16 @@ uint32_t input_entry::g_flags_for_path( const char * path, uint32_t mask ) { #endif } uint32_t input_entry::g_flags_for_content_type( const char * ct, uint32_t mask ) { -#if FOOBAR2000_TARGET_VERSION >= 80 +#if defined(FOOBAR2000_DESKTOP) && FOOBAR2000_TARGET_VERSION >= 80 return input_manager_v3::get()->flags_for_content_type(ct, mask); #else +#ifdef FOOBAR2000_DESKTOP input_manager_v3::ptr api; if ( input_manager_v3::tryGet(api) ) { return api->flags_for_content_type( ct, mask ); } - uint32_t ret = 0; +#endif + uint32_t ret = 0; service_enum_t e; input_entry::ptr p; while(e.next(p)) { uint32_t f = p->get_flags() & mask; @@ -428,4 +432,20 @@ t_filestats2 input_info_reader::get_stats2_(const char* fallbackPath, uint32_t f } catch (exception_io) {} } return ret; +} + +GUID input_entry::get_guid_() { + auto ret = pfc::guid_null; + input_entry_v2::ptr v2; + if ( v2 &= this ) ret = v2->get_guid(); + return ret; +} +input_entry::ptr input_entry::g_find_by_guid(const GUID& guid) { + for (auto ptr : enumerate()) { + input_entry_v2::ptr v2; + if (v2 &= ptr) { + if ( guid == v2->get_guid() ) return v2; + } + } + return nullptr; } \ No newline at end of file diff --git a/sdk/foobar2000/SDK/input.h b/sdk/foobar2000/SDK/input.h index be857e7..75a294f 100644 --- a/sdk/foobar2000/SDK/input.h +++ b/sdk/foobar2000/SDK/input.h @@ -277,6 +277,9 @@ class NOVTABLE input_entry : public service_base { 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 ); + + GUID get_guid_(); + static input_entry::ptr g_find_by_guid( const GUID & ); }; //! \since 1.4 diff --git a/sdk/foobar2000/SDK/library_index.h b/sdk/foobar2000/SDK/library_index.h index db415a9..eec04fa 100644 --- a/sdk/foobar2000/SDK/library_index.h +++ b/sdk/foobar2000/SDK/library_index.h @@ -2,24 +2,16 @@ #include "search_tools.h" -//! \since 2.0 -//! Provides access to indexed searches of media library content, \n -//! which in typical scenarios are much faster than running whole library content via search filters. \n -//! Not every search query is supported by library index - in particular, queries relying on title formatting cannot be optimized. \n -//! In such cases, search() will fall through to legacy search filter use. \n -//! Note that if your query looks like: cond1 AND cond2 AND cond3 (...), and only some of the conditions cannot be searched using index, \n -//! search() will use the supported subset of your query to only feed relevant subset of your library to slow search filters. +//! OBSOLETE, DO NOT USE \n +//! Please use search_index instead. class NOVTABLE library_index : public service_base { FB2K_MAKE_SERVICE_COREAPI(library_index); public: - //! Same as using search filters, provided for consistency. Use search() instead. virtual void hit_test(search_filter::ptr pattern, metadb_handle_list_cref items, bool* out, abort_callback & a) = 0; enum { flag_sort = 1 << 0, }; - //! @returns list of metadb_handles. Safe to use arr->as_list_of() to get a pfc::list_base_const_t - //! @param flags Optional; set flag_sort to sort output. virtual fb2k::arrayRef search(search_filter::ptr pattern, uint32_t flags, abort_callback& abort) = 0; }; \ No newline at end of file diff --git a/sdk/foobar2000/SDK/playlist_loader.cpp b/sdk/foobar2000/SDK/playlist_loader.cpp index 85e6836..ab14942 100644 --- a/sdk/foobar2000/SDK/playlist_loader.cpp +++ b/sdk/foobar2000/SDK/playlist_loader.cpp @@ -25,7 +25,9 @@ bool playlist_loader::g_try_load_playlist(file::ptr fileHint,const char * p_path filesystem::ptr fs; if (filesystem::g_get_interface(fs,filepath)) { if (fs->supports_content_types()) { - fs->open(l_file,filepath,filesystem::open_mode_read,p_abort); + try { + fs->open(l_file,filepath,filesystem::open_mode_read,p_abort); + } catch(exception_io) { return false; } // fall thru } } } diff --git a/sdk/foobar2000/SDK/playlist_loader.h b/sdk/foobar2000/SDK/playlist_loader.h index c70a3a1..04d4e34 100644 --- a/sdk/foobar2000/SDK/playlist_loader.h +++ b/sdk/foobar2000/SDK/playlist_loader.h @@ -1,6 +1,5 @@ #pragma once -#if FOOBAR2000_TARGET_VERSION >= 76 //! Callback interface receiving item locations from playlist loader. \n //! Typically, you call one of standard services such as playlist_incoming_item_filter instead of implementing this interface and calling playlist_loader methods directly. class NOVTABLE playlist_loader_callback : public service_base { @@ -133,5 +132,3 @@ class NOVTABLE playlist_loader : public service_base { template class playlist_loader_factory_t : public service_factory_single_t {}; - -#endif \ No newline at end of file diff --git a/sdk/foobar2000/SDK/search_tools.h b/sdk/foobar2000/SDK/search_tools.h index 05be2c6..4b7b232 100644 --- a/sdk/foobar2000/SDK/search_tools.h +++ b/sdk/foobar2000/SDK/search_tools.h @@ -110,12 +110,19 @@ class search_index : public service_base { //! @returns list of metadb_handles. Safe to use arr->as_list_of() to get a pfc::list_base_const_t //! @param subset Optional: pass subset of tracks in this index to search - whole index is searched if nullptr is passed. //! @param flags Optional: set flag_sort to sort output + //! Thread safety: call from any thread. virtual fb2k::arrayRef search(search_filter::ptr pattern, metadb_handle_list_cptr subset, uint32_t flags, abort_callback& abort) = 0; - //! Performs hit test on a group of tracks that are a subset of tracks in this index. + //! Performs hit test on a group of tracks that are a subset of tracks in this index. \n + //! Thread safety: call from any thread. virtual void test(search_filter::ptr pattern, metadb_handle_list_cref items, bool* out, abort_callback& abort) = 0; - + //! Add tracks to a custom index. \n + //! Illegal to call on library or playlist indexes. \n + //! Thread safety: call from any thread. virtual void add_tracks(metadb_handle_list_cref, metadb_io_callback_v2_data* dataIfAvail) = 0; + //! Remove tracks from a custom index. \n + //! Illegal to call on library or playlist indexes. \n + //! Thread safety: call from any thread. virtual void remove_tracks(metadb_handle_list_cref) = 0; }; @@ -123,12 +130,16 @@ class search_index : public service_base { class search_index_manager : public service_base { FB2K_MAKE_SERVICE_COREAPI(search_index_manager); public: + //! Create a custom index on any data set. \n + //! OK to call from any thread. virtual search_index::ptr create_index(metadb_handle_list_cref items, metadb_io_callback_v2_data* dataIfAvail) = 0; //! Create a search index referencing a playlist. \n - //! Specify null GUID to follow active playlist (typical playlist search). + //! Specify null GUID to follow active playlist (typical playlist search). \n + //! Call from main thread to obtain index, then can use obtained object from any thread. virtual search_index::ptr create_playlist_index(const GUID& playlistID = pfc::guid_null) = 0; - //! Returns a shared object indexing user's media library. + //! Returns a shared object indexing user's media library. \n + //! Call from main thread to obtain index, then can use obtained object from any thread. virtual search_index::ptr get_library_index() = 0; }; \ No newline at end of file diff --git a/sdk/foobar2000/SDK/service.h b/sdk/foobar2000/SDK/service.h index 956b903..7625788 100644 --- a/sdk/foobar2000/SDK/service.h +++ b/sdk/foobar2000/SDK/service.h @@ -774,6 +774,17 @@ class service_factory_t : public service_factory_base_t +class service_factory_singleton_t : public service_factory_base_t { +public: + void instance_create(service_ptr_t & p_out) override { + this->pass_instance(p_out, &FB2K_SERVICE_SINGLETON(T) ); + } + + inline T& get_static_instance() { return &FB2K_SERVICE_SINGLETON(T); } + inline const T& get_static_instance() const { return &FB2K_SERVICE_SINGLETON(T); } +}; + template class service_factory_single_t : public service_factory_base_t { service_impl_single_t g_instance; @@ -843,7 +854,7 @@ class service_factory_single_transparent_t : public service_factory_base_t _FB2K_UNIQUE_NAME(g_factory_) FB2K_SERVICE_FACTORY_ATTR; +#define FB2K_SERVICE_FACTORY( TYPE ) static ::service_factory_singleton_t< TYPE > _FB2K_UNIQUE_NAME(g_factory_) FB2K_SERVICE_FACTORY_ATTR; #define FB2K_SERVICE_FACTORY_LATEINIT( TYPE ) static ::service_factory_single_v2_t< TYPE > _FB2K_UNIQUE_NAME(g_factory_) FB2K_SERVICE_FACTORY_ATTR; #define FB2K_SERVICE_FACTORY_PARAMS( TYPE, ... ) static ::service_factory_single_t< TYPE > _FB2K_UNIQUE_NAME(g_factory_) ( __VA_ARGS__ ); #define FB2K_SERVICE_FACTORY_DYNAMIC( TYPE ) static ::service_factory_t< TYPE > _FB2K_UNIQUE_NAME(g_factory_) FB2K_SERVICE_FACTORY_ATTR; diff --git a/sdk/foobar2000/SDK/service_impl.h b/sdk/foobar2000/SDK/service_impl.h index 1304643..88415a0 100644 --- a/sdk/foobar2000/SDK/service_impl.h +++ b/sdk/foobar2000/SDK/service_impl.h @@ -135,4 +135,6 @@ namespace fb2k { service_ptr_t service_new(arg_t && ... arg) { return new service_impl_t< obj_t > ( std::forward (arg) ... ); } -} \ No newline at end of file +} + +#define FB2K_SERVICE_SINGLETON(class_t) PFC_SINGLETON( service_impl_single_t< class_t> ) \ No newline at end of file diff --git a/sdk/foobar2000/SDK/system_time_keeper.h b/sdk/foobar2000/SDK/system_time_keeper.h index 27b9cec..7f9860d 100644 --- a/sdk/foobar2000/SDK/system_time_keeper.h +++ b/sdk/foobar2000/SDK/system_time_keeper.h @@ -24,7 +24,7 @@ class system_time_keeper : public service_base { class system_time_callback_impl : public system_time_callback { public: - system_time_callback_impl() : m_registered() {} + system_time_callback_impl() {} ~system_time_callback_impl() {stop_timer();} void stop_timer() { @@ -40,10 +40,11 @@ class system_time_callback_impl : public system_time_callback { m_registered = true; } - void on_time_changed(t_filetimestamp newVal) {} + //! Override me + void on_time_changed(t_filetimestamp newVal) override {} PFC_CLASS_NOT_COPYABLE_EX(system_time_callback_impl) private: - bool m_registered; + bool m_registered = false; }; diff --git a/sdk/foobar2000/SDK/threadsLite.h b/sdk/foobar2000/SDK/threadsLite.h index 28a7a1b..a6c7256 100644 --- a/sdk/foobar2000/SDK/threadsLite.h +++ b/sdk/foobar2000/SDK/threadsLite.h @@ -4,6 +4,8 @@ namespace fb2k { void splitTask(std::function); void splitTask(pfc::thread::arg_t const&, std::function); abort_callback& mainAborter(); + + void inCpuWorkerThread(std::function f); } diff --git a/sdk/foobar2000/helpers/cfg_objList.h b/sdk/foobar2000/helpers/cfg_objList.h index e2b5a24..7da35a5 100644 --- a/sdk/foobar2000/helpers/cfg_objList.h +++ b/sdk/foobar2000/helpers/cfg_objList.h @@ -113,16 +113,16 @@ namespace cfg_var_modern { void init() { std::call_once(m_init, [this] { auto blob = fb2k::configStore::get()->getConfigBlob(formatName(), nullptr); - if (blob.is_valid()) { + if (blob.is_valid()) try { stream_reader_formatter_simple<> reader(blob->data(), blob->size()); std::vector data; uint32_t count; reader >> count; data.resize(count); for (auto& v : data) reader >> v; set_(std::move(data), false); - } else { - set_(m_defaults, false); - } - }); + return; + } catch(...) {} // fall through, set defaults + set_(m_defaults, false); + }); } template void set_(arg_t&& arg, bool bSave = true) { diff --git a/sdk/foobar2000/helpers/file_readonly.h b/sdk/foobar2000/helpers/file_readonly.h deleted file mode 100644 index 03cb87c..0000000 --- a/sdk/foobar2000/helpers/file_readonly.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once -// fb2k mobile compat - -#include "../SDK/filesystem_helper.h" \ No newline at end of file diff --git a/sdk/foobar2000/helpers/file_win32_wrapper.cpp b/sdk/foobar2000/helpers/file_win32_wrapper.cpp index 4a7a640..b79ae0d 100644 --- a/sdk/foobar2000/helpers/file_win32_wrapper.cpp +++ b/sdk/foobar2000/helpers/file_win32_wrapper.cpp @@ -257,6 +257,55 @@ namespace file_win32_helpers { out.set_system((in & FILE_ATTRIBUTE_SYSTEM) != 0); out.set_remote(false); } + + + // Seek penalty query, effectively: is this an SSD? + // Credit: + // https://devblogs.microsoft.com/oldnewthing/20201023-00/?p=104395 + static bool queryVolumeSeekPenalty(HANDLE hVolume, bool& out) { + STORAGE_PROPERTY_QUERY query = {}; + query.PropertyId = StorageDeviceSeekPenaltyProperty; + query.QueryType = PropertyStandardQuery; + DWORD count = 1; + DEVICE_SEEK_PENALTY_DESCRIPTOR result = {}; + if (!DeviceIoControl(hVolume, IOCTL_STORAGE_QUERY_PROPERTY, &query, sizeof(query), &result, sizeof(result), &count, nullptr)) { + return false; + } + out = result.IncursSeekPenalty; + return true; + } + + static HANDLE GetVolumeHandleForFile(PCWSTR filePath) { + wchar_t volumePath[MAX_PATH] = {}; + WIN32_OP_D(GetVolumePathName(filePath, volumePath, ARRAYSIZE(volumePath))); + + wchar_t volumeName[MAX_PATH] = {}; + WIN32_OP_D(GetVolumeNameForVolumeMountPoint(volumePath, volumeName, ARRAYSIZE(volumeName))); + + auto length = wcslen(volumeName); + if ( length == 0 ) { + PFC_ASSERT(!"???"); + return NULL; + } + if (length && volumeName[length - 1] == L'\\') { + volumeName[length - 1] = L'\0'; + } + + HANDLE ret; + WIN32_OP_D( ret = CreateFile(volumeName, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr) ); + return ret; + } + bool querySeekPenalty(const wchar_t* nativePath, bool& out) { + CHandle h; + h.Attach( GetVolumeHandleForFile( nativePath ) ); + if (!h) return false; + return queryVolumeSeekPenalty(h, out); + } + bool querySeekPenalty(const char* fb2k_path, bool& out) { + const char * path = fb2k_path; + if ( matchProtocol(path, "file")) path = afterProtocol(path); + return querySeekPenalty(pfc::wideFromUTF8(path), out); + } } #endif // _WIN32 diff --git a/sdk/foobar2000/helpers/file_win32_wrapper.h b/sdk/foobar2000/helpers/file_win32_wrapper.h index b199ea5..8d8c6d4 100644 --- a/sdk/foobar2000/helpers/file_win32_wrapper.h +++ b/sdk/foobar2000/helpers/file_win32_wrapper.h @@ -16,7 +16,8 @@ namespace file_win32_helpers { size_t readStreamOverlapped(HANDLE handle, HANDLE myEvent, void * out, size_t outBytes, abort_callback & abort); HANDLE createFile(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile, abort_callback & abort); size_t lowLevelIO(HANDLE hFile, const GUID & guid, size_t arg1, void * arg2, size_t arg2size, bool canWrite, abort_callback & abort); - + bool querySeekPenalty(const char * fb2k_path, bool & out); + bool querySeekPenalty(const wchar_t * nativePath, bool & out); static uint64_t make_uint64(t_uint32 p_low, t_uint32 p_high) { return ((t_uint64)p_low) + ((t_uint64)p_high << 32); diff --git a/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj b/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj index 1cceafa..8e8712f 100644 --- a/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj +++ b/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj @@ -525,7 +525,6 @@ - @@ -569,6 +568,7 @@ + @@ -592,17 +592,6 @@ - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - + \ No newline at end of file diff --git a/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj.filters b/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj.filters index 1a2fc16..912c4e9 100644 --- a/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj.filters +++ b/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj.filters @@ -352,9 +352,6 @@ Header Files - - Header Files - Header Files @@ -415,8 +412,8 @@ Header Files - - - + + Header Files + \ No newline at end of file diff --git a/sdk/foobar2000/helpers/packages.config b/sdk/foobar2000/helpers/packages.config deleted file mode 100644 index 1c54a40..0000000 --- a/sdk/foobar2000/helpers/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/sdk/foobar2000/helpers/readers.cpp b/sdk/foobar2000/helpers/readers.cpp index 2c819db..39fa6ad 100644 --- a/sdk/foobar2000/helpers/readers.cpp +++ b/sdk/foobar2000/helpers/readers.cpp @@ -1,5 +1,6 @@ #include "StdAfx.h" #include "readers.h" +#include "readers_lite.h" #include "fullFileBuffer.h" #include "fileReadAhead.h" #include @@ -383,3 +384,62 @@ file::ptr fileCreateReadAhead(file::ptr chain, size_t readAheadBytes, abort_call file_v2::ptr temp = std::move(obj); return std::move(temp); } + + + +namespace { + class CFileWithMemBlock : public reader_membuffer_base { + public: + CFileWithMemBlock(fb2k::memBlockRef mem, t_filestats const& stats, const char* contentType, bool remote) { + m_mem = mem; + m_stats = stats; + m_stats.m_size = mem->size(); + if (contentType != nullptr) m_contentType = contentType; + m_remote = remote; + } + const void* get_buffer() { + return m_mem->get_ptr(); + } + t_size get_buffer_size() { + return m_mem->get_size(); + } + t_filestats get_stats(abort_callback& p_abort) { + p_abort.check(); + return m_stats; + } + bool get_content_type(pfc::string_base& out) { + if (m_contentType.is_empty()) return false; + out = m_contentType; + return true; + } + bool is_remote() { + return m_remote; + } + private: + bool m_remote; + fb2k::memBlockRef m_mem; + pfc::string8 m_contentType; + t_filestats m_stats; + }; +} + +file::ptr createFileWithMemBlock(fb2k::memBlock::ptr mem, t_filestats stats, const char* contentType, bool remote) { + return new service_impl_t< CFileWithMemBlock >(mem, stats, contentType, remote); +} + +file::ptr createFileLimited(file::ptr base, t_filesize offset, t_filesize size, abort_callback& abort) { + return reader_limited::g_create(base, offset, size, abort); +} + +file::ptr createFileBigMemMirror(file::ptr source, abort_callback& abort) { + if (source->is_in_memory()) return source; + auto r = fb2k::service_new(); + r->init(source, abort); + return r; +} + +file::ptr createFileMemMirror(file::ptr source, abort_callback& abort) { + file::ptr ret; + if (!reader_membuffer_mirror::g_create(ret, source, abort)) ret = source; + return ret; +} diff --git a/sdk/foobar2000/helpers/readers_lite.h b/sdk/foobar2000/helpers/readers_lite.h new file mode 100644 index 0000000..7e3634a --- /dev/null +++ b/sdk/foobar2000/helpers/readers_lite.h @@ -0,0 +1,6 @@ +#pragma once + +file::ptr createFileWithMemBlock(fb2k::memBlock::ptr mem, t_filestats stats = filestats_invalid, const char* contentType = nullptr, bool remote = false); +file::ptr createFileLimited(file::ptr base, t_filesize offset, t_filesize size, abort_callback& abort); +file::ptr createFileBigMemMirror(file::ptr source, abort_callback& abort); +file::ptr createFileMemMirror(file::ptr source, abort_callback& abort); diff --git a/sdk/foobar2000/shared/fb2kdebug.h b/sdk/foobar2000/shared/fb2kdebug.h index 76e8a60..e4f5d26 100644 --- a/sdk/foobar2000/shared/fb2kdebug.h +++ b/sdk/foobar2000/shared/fb2kdebug.h @@ -37,7 +37,7 @@ extern "C" #endif #ifdef _WIN32 - static inline void uAddDebugEvent(const char * msg) {uPrintCrashInfo_OnEvent(msg, strlen(msg));} + static inline void uAddDebugEvent(const char * msg) {uPrintCrashInfo_OnEvent(msg, SIZE_MAX);} #else static inline void uAddDebugEvent( const char * msg ) { uOutputDebugString(pfc::format(msg, "\n")); } #endif diff --git a/sdk/libPPUI/CListControl.cpp b/sdk/libPPUI/CListControl.cpp index fadf920..1efe02a 100644 --- a/sdk/libPPUI/CListControl.cpp +++ b/sdk/libPPUI/CListControl.cpp @@ -518,7 +518,7 @@ void CListControlImpl::MinGroupHeight2ChangedForGroup(groupID_t groupID, bool re void CListControlImpl::UpdateGroupOverlayByID(groupID_t groupID, int xFrom, int xTo) { t_size base, count; if (GetItemRangeAbs(GetVisibleRectAbs(), base, count)) { - bool on = false; // Have to walk whole range - there may be multiple groups with the same ID because fuck you + bool on = false; // Have to walk whole range - there may be multiple groups with the same ID for (size_t walk = 0; walk < count; ++walk) { bool test = (groupID == GetItemGroup(base + walk)); if (test && !on) { diff --git a/sdk/libPPUI/CListControlHeaderImpl.cpp b/sdk/libPPUI/CListControlHeaderImpl.cpp index fb44858..d2c12c1 100644 --- a/sdk/libPPUI/CListControlHeaderImpl.cpp +++ b/sdk/libPPUI/CListControlHeaderImpl.cpp @@ -750,8 +750,8 @@ t_uint32 CListControlHeaderImpl::GetOptimalSubItemWidth(t_size item, t_size subI } t_uint32 CListControlHeaderImpl::GetOptimalWidth_Cache::GetStringTempWidth() { - if (m_stringTemp.replace_string_ex(m_stringTempUnfuckAmpersands, "&", "&&") > 0) { - m_convertTemp.convert(m_stringTempUnfuckAmpersands); + if (m_stringTemp.replace_string_ex(m_stringTempFixAmpersands, "&", "&&") > 0) { + m_convertTemp.convert(m_stringTempFixAmpersands); } else { m_convertTemp.convert(m_stringTemp); } diff --git a/sdk/libPPUI/CListControlHeaderImpl.h b/sdk/libPPUI/CListControlHeaderImpl.h index ad7abb2..166c595 100644 --- a/sdk/libPPUI/CListControlHeaderImpl.h +++ b/sdk/libPPUI/CListControlHeaderImpl.h @@ -89,7 +89,7 @@ class CListControlHeaderImpl : public CListControlFontOps { struct GetOptimalWidth_Cache { //! For temporary use. - pfc::string8_fastalloc m_stringTemp, m_stringTempUnfuckAmpersands; + pfc::string8_fastalloc m_stringTemp, m_stringTempFixAmpersands; //! For temporary use. pfc::stringcvt::string_wide_from_utf8_t m_convertTemp; //! Our DC for measuring text. Correct font pre-selected. diff --git a/sdk/libPPUI/CListControlWithSelection.cpp b/sdk/libPPUI/CListControlWithSelection.cpp index add2158..436e4f7 100644 --- a/sdk/libPPUI/CListControlWithSelection.cpp +++ b/sdk/libPPUI/CListControlWithSelection.cpp @@ -1109,14 +1109,31 @@ bool CListControlWithSelectionBase::GetFocusRectAbs(CRect & p_rect) { return false; } +bool CListControlWithSelectionBase::GetContextMenuPoint2(CPoint& ptInOut) { + CPoint ptInvalid(-1,-1); + if (ptInOut == ptInvalid) { + ptInOut = GetContextMenuPointDefault(); + return ptInOut != ptInvalid; + } else { + CRect rc = this->GetClientRectHook(); + WIN32_OP_D( ClientToScreen(rc) ); + return !!rc.PtInRect(ptInOut); + } +} + +CPoint CListControlWithSelectionBase::GetContextMenuPointDefault() { + CRect rect; + if (!GetFocusRectAbs(rect)) return CPoint(-1,-1); + EnsureVisibleRectAbs(rect); + CPoint pt = rect.CenterPoint() - GetViewOffset(); + ClientToScreen(&pt); + return pt; +} + CPoint CListControlWithSelectionBase::GetContextMenuPoint(CPoint ptGot) { CPoint pt; if (ptGot.x == -1 && ptGot.y == -1) { - CRect rect; - if (!GetFocusRectAbs(rect)) return 0; - EnsureVisibleRectAbs(rect); - pt = rect.CenterPoint() - GetViewOffset(); - ClientToScreen(&pt); + pt = GetContextMenuPointDefault(); } else { pt = ptGot; } @@ -1126,11 +1143,7 @@ CPoint CListControlWithSelectionBase::GetContextMenuPoint(CPoint ptGot) { CPoint CListControlWithSelectionBase::GetContextMenuPoint(LPARAM lp) { CPoint pt; if (lp == -1) { - CRect rect; - if (!GetFocusRectAbs(rect)) return 0; - EnsureVisibleRectAbs(rect); - pt = rect.CenterPoint() - GetViewOffset(); - ClientToScreen(&pt); + pt = GetContextMenuPointDefault(); } else { pt = lp; } diff --git a/sdk/libPPUI/CListControlWithSelection.h b/sdk/libPPUI/CListControlWithSelection.h index 7341229..6ce20d6 100644 --- a/sdk/libPPUI/CListControlWithSelection.h +++ b/sdk/libPPUI/CListControlWithSelection.h @@ -124,6 +124,11 @@ class CListControlWithSelectionBase : public CListControl { //! Input & output in screen coordinates, per WM_CONTEXTMENU conventions. CPoint GetContextMenuPoint(LPARAM lp); CPoint GetContextMenuPoint(CPoint ptGot); + //! Import context menu point coordinates: turn (-1,-1) to something that makes sense; \n + //! Returns false if clicked point was outside client area so WM_CONTEXTMENU should be left unhandled. + bool GetContextMenuPoint2(CPoint & ptInOut); + //! Returns center-of-focused-item point for context menu, in screen coordinates. + CPoint GetContextMenuPointDefault(); protected: void ToggleDDScroll(bool p_state); diff --git a/sdk/libPPUI/DarkMode.cpp b/sdk/libPPUI/DarkMode.cpp index 7e480ea..2fd774d 100644 --- a/sdk/libPPUI/DarkMode.cpp +++ b/sdk/libPPUI/DarkMode.cpp @@ -65,6 +65,9 @@ Set text/bk colors explicitly Text color: 0xdedede Background: 0x191919 +Label-editing: +Pass WM_CTLCOLOR* to parent, shim TVM_EDITLABEL to pass theme to the editbox (not really necessary tho) + == Rebar == Can be beaten into working to some extent with a combination of: @@ -122,7 +125,6 @@ But the latter doesn't require undocumented function calls and doesn't infect al */ namespace { - // 1903 18362 enum class PreferredAppMode { Default, @@ -172,7 +174,7 @@ namespace { }; #if DARKMODE_ALLOW_HAX using fnAllowDarkModeForWindow = bool (WINAPI*)(HWND hWnd, bool allow); // ordinal 133 - using fnSetPreferredAppMode = PreferredAppMode(WINAPI*)(PreferredAppMode appMode); // ordinal 135, in 1903 + using fnSetPreferredAppMode = PreferredAppMode(WINAPI*)(PreferredAppMode appMode); // ordinal 135, since 1809 using fnFlushMenuThemes = void (WINAPI*)(); // ordinal 136 fnAllowDarkModeForWindow _AllowDarkModeForWindow = nullptr; fnSetPreferredAppMode _SetPreferredAppMode = nullptr; @@ -182,7 +184,7 @@ namespace { void InitImports() { if (ImportsInited) return; - if (IsWindows10OrGreater()) { + if (DarkMode::IsSupportedSystem()) { HMODULE hUxtheme = LoadLibraryEx(L"uxtheme.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); if (hUxtheme) { _AllowDarkModeForWindow = reinterpret_cast(GetProcAddress(hUxtheme, MAKEINTRESOURCEA(133))); @@ -205,8 +207,7 @@ namespace DarkMode { return val; } bool IsSupportedSystem() { - static bool ret = IsWindows10OrGreater(); - return ret; + return Win10BuildNumber() >= 17763; // require at least Win10 1809 / Server 2019 } bool IsWindows11() { return Win10BuildNumber() >= 22000; @@ -581,6 +582,56 @@ namespace DarkMode { if (m_hWnd != NULL) Invalidate(); } + class CTreeViewHook : public CWindowImpl { + bool m_dark; + public: + CTreeViewHook(bool v) : m_dark(v) {} + + BEGIN_MSG_MAP_EX(CTreeViewHook) + MESSAGE_RANGE_HANDLER_EX(WM_CTLCOLORMSGBOX, WM_CTLCOLORSTATIC, OnCtlColor) + MESSAGE_HANDLER_EX(msgSetDarkMode(), OnSetDarkMode) + MESSAGE_HANDLER_EX(TVM_EDITLABEL, OnEditLabel) + END_MSG_MAP() + + LRESULT OnCtlColor(UINT uMsg, WPARAM wParam, LPARAM lParam) { + return GetParent().SendMessage(uMsg, wParam, lParam); + } + LRESULT OnEditLabel(UINT, WPARAM, LPARAM) { + LRESULT ret = DefWindowProc(); + if (ret != 0) { + HWND edit = (HWND) ret; + PFC_ASSERT( ::IsWindow(edit) ); + ApplyDarkThemeCtrl( edit, m_dark ); + } + return ret; + } + void SetDark(bool v) { + if (m_dark == v) return; + m_dark = v; + ApplyDark(); + } + void ApplyDark() { + ApplyDarkThemeCtrl(m_hWnd, m_dark); + COLORREF bk = m_dark ? GetSysColor(COLOR_WINDOW) : (COLORREF)(-1); + COLORREF tx = m_dark ? GetSysColor(COLOR_WINDOWTEXT) : (COLORREF)(-1); + this->SetTextColor(tx); this->SetLineColor(tx); + this->SetBkColor(bk); + } + + void SubclassWindow(HWND wnd) { + WIN32_OP_D( __super::SubclassWindow(wnd) ); + this->ApplyDark(); + } + + LRESULT OnSetDarkMode(UINT, WPARAM wp, LPARAM) { + switch (wp) { + case 0: SetDark(false); break; + case 1: SetDark(true); break; + } + return 1; + } + }; + class CDialogHook : public CWindowImpl { bool m_enabled; public: @@ -843,6 +894,9 @@ namespace DarkMode { } void Paint(CDCHandle dc) { + CRect rcClient; WIN32_OP_D(GetClientRect(rcClient)); + dc.FillSolidRect(rcClient, GetSysColor(COLOR_BTNFACE)); // Wine seems to not call our WM_ERASEBKGND handler, fill the background here too + dc.SelectFont(GetFont()); dc.SetBkMode(TRANSPARENT); dc.SetTextColor(GetSysColor(COLOR_WINDOWTEXT)); @@ -891,7 +945,6 @@ namespace DarkMode { } if (GetStyle() & SBARS_SIZEGRIP) { - CRect rcClient; WIN32_OP_D(GetClientRect(rcClient)); CSize size; auto theme = OpenThemeData(*this, L"status"); PFC_ASSERT(theme != NULL); @@ -1568,7 +1621,18 @@ namespace DarkMode { AddCtrlMsg(wnd); } void CHooks::AddComboBox(HWND wnd) { - addOp([wnd, this] { SetWindowTheme(wnd, m_dark ? L"DarkMode_CFD" : L"Explorer", NULL);}); + { + CComboBox combo = wnd; + COMBOBOXINFO info = {sizeof(info)}; + WIN32_OP_D( combo.GetComboBoxInfo(&info) ); + if (info.hwndList != NULL) { + AddListBox( info.hwndList ); + } + } + + addOp([wnd, this] { + SetWindowTheme(wnd, m_dark ? L"DarkMode_CFD" : L"Explorer", NULL); + }); } void CHooks::AddComboBoxEx(HWND wnd) { this->AddControls(wnd); // recurse to add the combo box @@ -1653,14 +1717,9 @@ namespace DarkMode { } void CHooks::AddTreeView(HWND wnd) { - this->addOp([wnd, this] { - CTreeViewCtrl tv(wnd); - ApplyDarkThemeCtrl(tv, m_dark); - COLORREF bk = m_dark ? GetSysColor(COLOR_WINDOW) : (COLORREF)(-1); - COLORREF tx = m_dark ? GetSysColor(COLOR_WINDOWTEXT) : (COLORREF)(-1); - tv.SetTextColor(tx); tv.SetLineColor(tx); - tv.SetBkColor(bk); - }); + auto hook = new ImplementOnFinalMessage(m_dark); + hook->SubclassWindow(wnd); + this->AddCtrlMsg(wnd); } void CHooks::AddListBox(HWND wnd) { this->AddGeneric( wnd ); diff --git a/sdk/libPPUI/DarkMode.h b/sdk/libPPUI/DarkMode.h index 2717942..de6fbb1 100644 --- a/sdk/libPPUI/DarkMode.h +++ b/sdk/libPPUI/DarkMode.h @@ -3,10 +3,14 @@ #include namespace DarkMode { + // Is dark mode supported on this system or not? bool IsSupportedSystem(); + // Is system in dark mode or not? bool QueryUserOption(); + // Darken menus etc app-wide void SetAppDarkMode(bool bDark); + // Darken window title bar void UpdateTitleBar(HWND wnd, bool bDark ); void ApplyDarkThemeCtrl(HWND ctrl, bool bDark, const wchar_t * ThemeID = L"Explorer"); void AllowDarkModeForWindow(HWND wnd, bool bDark); diff --git a/sdk/libPPUI/libPPUI.vcxproj b/sdk/libPPUI/libPPUI.vcxproj index 7da9c40..60361f9 100644 --- a/sdk/libPPUI/libPPUI.vcxproj +++ b/sdk/libPPUI/libPPUI.vcxproj @@ -422,22 +422,12 @@ + - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - + \ No newline at end of file diff --git a/sdk/libPPUI/libPPUI.vcxproj.filters b/sdk/libPPUI/libPPUI.vcxproj.filters index 3b9c628..16f4b4d 100644 --- a/sdk/libPPUI/libPPUI.vcxproj.filters +++ b/sdk/libPPUI/libPPUI.vcxproj.filters @@ -292,12 +292,12 @@ Source Files + + Source Files + - - - \ No newline at end of file diff --git a/sdk/libPPUI/packages.config b/sdk/libPPUI/packages.config deleted file mode 100644 index 1c54a40..0000000 --- a/sdk/libPPUI/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/sdk/libPPUI/win32_utility.h b/sdk/libPPUI/win32_utility.h index f03bfdb..80ee2c0 100644 --- a/sdk/libPPUI/win32_utility.h +++ b/sdk/libPPUI/win32_utility.h @@ -46,7 +46,7 @@ void SetDefaultMenuItem(HMENU p_menu, unsigned p_id); void GetOSVersionString(pfc::string_base & out); WORD GetOSVersionCode(); bool IsWine(); -DWORD Win10BuildNumber(); +DWORD Win10BuildNumber(); // See https://en.wikipedia.org/wiki/Windows_10_version_history for build number reference void EnumChildWindows(HWND, std::function); // Recursive void EnumChildWindowsHere(HWND, std::function); // Non-recursive \ No newline at end of file diff --git a/sdk/libPPUI/wtl-pp.cpp b/sdk/libPPUI/wtl-pp.cpp new file mode 100644 index 0000000..1b0baf2 --- /dev/null +++ b/sdk/libPPUI/wtl-pp.cpp @@ -0,0 +1,47 @@ +#include "stdafx.h" +#include "wtl-pp.h" + +void CEditPPHooks::DeleteLastWord( CEdit wnd, bool bForward ) { + if ( wnd.GetWindowLong(GWL_STYLE) & ES_READONLY ) return; + CString buffer; + if ( wnd.GetWindowText(buffer) <= 0 ) return; + const int len = buffer.GetLength(); + int selStart = len, selEnd = len; + wnd.GetSel(selStart, selEnd); + if ( selStart < 0 || selStart > len ) selStart = len; // sanity + if ( selEnd < selStart ) selEnd = selStart; // sanity + int work = selStart; + if ( work == selEnd ) { + // Only do our stuff if there is nothing yet selected. Otherwise first delete selection. + if (bForward) { + // go forward (ctrl+del) + if (work < len && isSpecial(buffer[work])) { // linebreaks etc? + do ++ work; while( work < len && isSpecial(buffer[work])); + } else { + // delete apparent spacing + while ( work < len && isWordDelimiter(buffer[work])) ++ work; + // delete apparent word + while ( work < len && (!isWordDelimiter(buffer[work]) && !isSpecial(buffer[work]))) ++ work; + } + + if ( selEnd < work ) { + wnd.SetSel(selEnd, work, TRUE ); + wnd.ReplaceSel( TEXT(""), TRUE ); + } + } else { + // go backward (ctrl+backspace) + if ( work > 0 && isSpecial(buffer[work-1])) { // linebreaks etc? + do --work; while( work > 0 && isSpecial(buffer[work-1])); + } else { + // delete apparent spacing + while( work > 0 && isWordDelimiter(buffer[work-1]) ) --work; + // delete apparent word + while( work > 0 && (!isWordDelimiter(buffer[work-1]) && !isSpecial(buffer[work-1]))) --work; + } + if ( selEnd > work ) { + wnd.SetSel(work, selEnd, TRUE ); + wnd.ReplaceSel( TEXT(""), TRUE ); + } + } + } +} diff --git a/sdk/libPPUI/wtl-pp.h b/sdk/libPPUI/wtl-pp.h index 255ed80..bf932d5 100644 --- a/sdk/libPPUI/wtl-pp.h +++ b/sdk/libPPUI/wtl-pp.h @@ -127,14 +127,14 @@ void InjectParentCtlColorHandler(HWND); } - +// Obsolete, use CImageListManaged instead class CImageListContainer : public CImageList { public: CImageListContainer() {} ~CImageListContainer() {Destroy();} -private: - const CImageListContainer & operator=(const CImageListContainer&); - CImageListContainer(const CImageListContainer&); + + void operator=(const CImageListContainer&) = delete; + CImageListContainer(const CImageListContainer&) = delete; }; @@ -194,31 +194,7 @@ class CEditPPHooks : public CWindowImpl { END_MSG_MAP() - static void DeleteLastWord( CEdit wnd ) { - if ( wnd.GetWindowLong(GWL_STYLE) & ES_READONLY ) return; - CString buffer; - if ( wnd.GetWindowText(buffer) <= 0 ) return; - const int len = buffer.GetLength(); - int selStart = len, selEnd = len; - wnd.GetSel(selStart, selEnd); - if ( selStart < 0 || selStart > len ) selStart = len; // sanity - if ( selEnd < selStart ) selEnd = selStart; // sanity - int work = selStart; - if ( work == selEnd ) { - // Only do our stuff if there is nothing yet selected. Otherwise first delete selection. - - if ( work > 0 && isSpecial(buffer[work-1])) { - do --work; while( work > 0 && isSpecial(buffer[work-1])); - } else { - while( work > 0 && isWordDelimiter(buffer[work-1]) ) --work; - while( work > 0 && (!isWordDelimiter(buffer[work-1]) && !isSpecial(buffer[work-1]))) --work; - } - } - if ( selEnd > work ) { - wnd.SetSel(work, selEnd, TRUE ); - wnd.ReplaceSel( TEXT(""), TRUE ); - } - } + static void DeleteLastWord( CEdit wnd, bool bForward = false ); private: static bool isSpecial( wchar_t c ) { return (unsigned) c < ' '; @@ -253,6 +229,12 @@ class CEditPPHooks : public CWindowImpl { DeleteLastWord( *this ) ; return; } } + if ( nChar == VK_DELETE ) { + if (GetHotkeyModifierFlags() == MOD_CONTROL) { + m_suppressScanCode = nFlags & 0xFF; + DeleteLastWord( *this, true ) ; return; + } + } if ( nChar == VK_RETURN && onEnterKey ) { m_suppressChar = nChar; onEnterKey(); return; diff --git a/sdk/sdk-readme.html b/sdk/sdk-readme.html index 29d786f..4201831 100644 --- a/sdk/sdk-readme.html +++ b/sdk/sdk-readme.html @@ -8,7 +8,7 @@

-foobar2000 SDK, version 2023-04-18 +foobar2000 SDK, version 2023-05-10

Documentation:
From 75349933df3d7b397dc082f7225876296b3ff0fd Mon Sep 17 00:00:00 2001 From: Hyperblast Date: Wed, 12 Feb 2025 08:36:40 +0500 Subject: [PATCH 07/12] update to SDK-2023-09-06 --- cmake/FileLists.cmake | 9 +- sdk/foobar2000/SDK/archive.h | 11 +- sdk/foobar2000/SDK/audio_chunk.h | 7 +- sdk/foobar2000/SDK/chapterizer.h | 3 +- sdk/foobar2000/SDK/commandline.h | 4 +- sdk/foobar2000/SDK/commonObjects-Apple.h | 21 + sdk/foobar2000/SDK/commonObjects-Apple.mm | 29 + sdk/foobar2000/SDK/componentversion.h | 4 +- sdk/foobar2000/SDK/dsp.cpp | 9 +- sdk/foobar2000/SDK/dsp.h | 30 +- sdk/foobar2000/SDK/dsp_manager.cpp | 6 +- sdk/foobar2000/SDK/dsp_manager.h | 4 +- sdk/foobar2000/SDK/file.h | 29 +- sdk/foobar2000/SDK/fileDialog.h | 15 +- sdk/foobar2000/SDK/file_info.cpp | 33 + sdk/foobar2000/SDK/file_info.h | 8 +- sdk/foobar2000/SDK/file_info_merge.cpp | 14 + sdk/foobar2000/SDK/filesystem.cpp | 89 +- sdk/foobar2000/SDK/foobar2000-versions.h | 4 +- sdk/foobar2000/SDK/foobar2000-winver.h | 3 + sdk/foobar2000/SDK/foobar2000.h | 3 + .../foobar2000_SDK.xcodeproj/project.pbxproj | 1115 ++++++++++++++++ sdk/foobar2000/SDK/fsItem.cpp | 34 +- sdk/foobar2000/SDK/fsitem.h | 8 +- sdk/foobar2000/SDK/genrand.h | 1 + sdk/foobar2000/SDK/guids.cpp | 15 +- sdk/foobar2000/SDK/info_lookup_handler.h | 6 +- sdk/foobar2000/SDK/input.cpp | 8 + sdk/foobar2000/SDK/input.h | 16 +- sdk/foobar2000/SDK/input_impl.h | 31 +- sdk/foobar2000/SDK/library_manager.h | 4 +- sdk/foobar2000/SDK/menu_helpers.h | 3 +- sdk/foobar2000/SDK/metadb_handle.h | 10 + sdk/foobar2000/SDK/metadb_handle_list.cpp | 157 ++- sdk/foobar2000/SDK/output.cpp | 33 +- sdk/foobar2000/SDK/output.h | 33 +- sdk/foobar2000/SDK/playlist.cpp | 18 + sdk/foobar2000/SDK/playlist.h | 6 +- sdk/foobar2000/SDK/preferences_page.h | 14 + sdk/foobar2000/SDK/tag_processor.cpp | 16 +- sdk/foobar2000/SDK/threadsLite.h | 4 + sdk/foobar2000/SDK/utility.cpp | 26 +- sdk/foobar2000/foo_sample/IO.cpp | 52 +- .../foo_sample/Mac/fooSampleDSPView.h | 12 + .../foo_sample/Mac/fooSampleDSPView.mm | 41 + .../foo_sample/Mac/fooSampleDSPView.xib | 68 + .../foo_sample/Mac/fooSampleMacPreferences.h | 12 + .../foo_sample/Mac/fooSampleMacPreferences.mm | 58 + .../Mac/fooSampleMacPreferences.xib | 93 ++ sdk/foobar2000/foo_sample/contextmenu.cpp | 7 +- sdk/foobar2000/foo_sample/decode.cpp | 6 +- .../foo_sample/{dsp.cpp => dsp_sample.cpp} | 37 +- sdk/foobar2000/foo_sample/dsp_sample.h | 19 + sdk/foobar2000/foo_sample/foo_sample.vcxproj | 14 +- .../foo_sample/foo_sample.vcxproj.filters | 10 +- .../foo_sample.xcodeproj/project.pbxproj | 447 +++++++ .../contents.xcworkspacedata | 22 + sdk/foobar2000/foo_sample/initquit.cpp | 24 +- .../foo_sample/mainmenu-dynamic.cpp | 7 +- sdk/foobar2000/foo_sample/mainmenu.cpp | 2 +- sdk/foobar2000/foo_sample/packages.config | 4 - .../foo_sample/playback_stream_capture.cpp | 31 +- sdk/foobar2000/foo_sample/preferences.cpp | 19 +- sdk/foobar2000/foo_sample/rating.cpp | 18 +- sdk/foobar2000/foo_sample/stdafx.h | 5 + sdk/foobar2000/foo_sample/ui_and_threads.cpp | 10 + .../component_client.cpp | 39 +- .../project.pbxproj | 282 ++++ sdk/foobar2000/helpers-mac/CFObject.h | 57 + .../helpers-mac/NSAttributedString+ppaddons.h | 9 + .../helpers-mac/NSAttributedString+ppaddons.m | 49 + sdk/foobar2000/helpers-mac/NSButton+checked.h | 7 + sdk/foobar2000/helpers-mac/NSButton+checked.m | 13 + sdk/foobar2000/helpers-mac/NSComboBox+fb2k.h | 9 + sdk/foobar2000/helpers-mac/NSComboBox+fb2k.mm | 24 + sdk/foobar2000/helpers-mac/NSEvent+ppstuff.h | 13 + sdk/foobar2000/helpers-mac/NSEvent+ppstuff.m | 17 + sdk/foobar2000/helpers-mac/NSMenu+ppaddons.h | 18 + sdk/foobar2000/helpers-mac/NSMenu+ppaddons.m | 63 + .../helpers-mac/NSTextField+grayed.h | 7 + .../helpers-mac/NSTextField+grayed.m | 14 + sdk/foobar2000/helpers-mac/NSView+embed.h | 6 + sdk/foobar2000/helpers-mac/NSView+embed.m | 25 + .../helpers-mac/NSView+ppsubviews.h | 11 + .../helpers-mac/NSView+ppsubviews.m | 52 + sdk/foobar2000/helpers-mac/fb2k-platform.h | 28 + sdk/foobar2000/helpers-mac/fb2k-platform.mm | 68 + .../helpers-mac/fooDecibelFormatter.h | 8 + .../helpers-mac/fooDecibelFormatter.m | 58 + sdk/foobar2000/helpers-mac/fooGenericDialog.h | 5 + .../helpers-mac/fooGenericDialog.mm | 31 + .../helpers-mac/fooGenericDialog.xib | 60 + .../helpers-mac/fooPreferencesCommon.h | 12 + sdk/foobar2000/helpers-mac/fooTimeFormatter.h | 16 + .../helpers-mac/fooTimeFormatter.mm | 37 + .../helpers-mac/fooWindowWithCancel.h | 9 + .../helpers-mac/fooWindowWithCancel.m | 10 + .../helpers/CListControlFb2kColors.h | 21 + sdk/foobar2000/helpers/atl-misc.h | 4 +- .../helpers/cuesheet_index_list.cpp | 4 +- sdk/foobar2000/helpers/file_streamstub.h | 19 + sdk/foobar2000/helpers/filetimetools.cpp | 336 +---- sdk/foobar2000/helpers/filetimetools.h | 3 - .../project.pbxproj | 819 ++++++++++++ .../helpers/foobar2000_sdk_helpers.vcxproj | 1 + .../foobar2000_sdk_helpers.vcxproj.filters | 3 + sdk/foobar2000/helpers/input_helpers.cpp | 17 +- sdk/foobar2000/helpers/readers.cpp | 158 ++- sdk/foobar2000/helpers/readers_lite.h | 1 + sdk/foobar2000/helpers/win32_dialog.cpp | 2 +- sdk/foobar2000/helpers/win32_misc.cpp | 2 +- .../helpers/window_placement_helper.cpp | 2 +- sdk/foobar2000/shared/Utility.cpp | 138 ++ sdk/foobar2000/shared/audio_math.cpp | 137 ++ sdk/foobar2000/shared/crash_info.cpp | 651 +++++++++ sdk/foobar2000/shared/filedialogs.cpp | 317 +++++ sdk/foobar2000/shared/filedialogs_vista.cpp | 497 +++++++ sdk/foobar2000/shared/font_description.cpp | 126 ++ sdk/foobar2000/shared/minidump.cpp | 251 ++++ sdk/foobar2000/shared/modal_dialog.cpp | 66 + sdk/foobar2000/shared/shared-apple.mm | 31 + sdk/foobar2000/shared/shared-nix.cpp | 195 +++ sdk/foobar2000/shared/shared.h | 2 +- sdk/foobar2000/shared/shared.vcxproj | 420 ++++++ sdk/foobar2000/shared/shared.vcxproj.filters | 75 ++ .../shared/shared.xcodeproj/project.pbxproj | 352 +++++ sdk/foobar2000/shared/stdafx.cpp | 1 + sdk/foobar2000/shared/systray.cpp | 108 ++ sdk/foobar2000/shared/text_drawing.cpp | 230 ++++ sdk/foobar2000/shared/utf8.cpp | 226 ++++ sdk/foobar2000/shared/utf8api.cpp | 1186 +++++++++++++++++ sdk/libPPUI/CDialogResizeHelper.h | 11 + sdk/libPPUI/CEditWithButtons.cpp | 19 + sdk/libPPUI/CEditWithButtons.h | 20 +- sdk/libPPUI/CListControl.h | 2 +- .../CListControlTruncationTooltipImpl.cpp | 10 + .../CListControlTruncationTooltipImpl.h | 1 + sdk/libPPUI/Controls.cpp | 32 +- sdk/libPPUI/DarkMode-CHyperLink.h | 6 +- sdk/libPPUI/DarkMode.cpp | 34 +- sdk/libPPUI/HyperLinkCtrl.h | 8 + sdk/libPPUI/libPPUI.vcxproj | 1 + sdk/libPPUI/libPPUI.vcxproj.filters | 3 + sdk/pfc/audio_math.cpp | 24 +- sdk/pfc/bigmem.cpp | 2 +- sdk/pfc/bigmem.h | 2 +- sdk/pfc/filetimetools.cpp | 330 +++++ sdk/pfc/filetimetools.h | 20 + sdk/pfc/obj-c.mm | 22 +- sdk/pfc/pfc.vcxproj | 3 + sdk/pfc/pfc.vcxproj.filters | 9 + sdk/pfc/pfc.xcodeproj/project.pbxproj | 885 ++++++++++++ sdk/pfc/sort.cpp | 11 + sdk/pfc/sort2.h | 34 + sdk/pfc/string-compare.cpp | 27 +- sdk/pfc/string-compare.h | 7 + sdk/pfc/string-lite.h | 3 +- sdk/pfc/string_conv.h | 68 +- sdk/pfc/threads.h | 3 + sdk/pfc/win-objects.cpp | 13 + sdk/pfc/win-objects.h | 6 + sdk/sdk-readme.html | 2 +- 162 files changed, 11279 insertions(+), 708 deletions(-) create mode 100644 sdk/foobar2000/SDK/commonObjects-Apple.h create mode 100644 sdk/foobar2000/SDK/commonObjects-Apple.mm create mode 100644 sdk/foobar2000/SDK/foobar2000_SDK.xcodeproj/project.pbxproj create mode 100644 sdk/foobar2000/foo_sample/Mac/fooSampleDSPView.h create mode 100644 sdk/foobar2000/foo_sample/Mac/fooSampleDSPView.mm create mode 100644 sdk/foobar2000/foo_sample/Mac/fooSampleDSPView.xib create mode 100644 sdk/foobar2000/foo_sample/Mac/fooSampleMacPreferences.h create mode 100644 sdk/foobar2000/foo_sample/Mac/fooSampleMacPreferences.mm create mode 100644 sdk/foobar2000/foo_sample/Mac/fooSampleMacPreferences.xib rename sdk/foobar2000/foo_sample/{dsp.cpp => dsp_sample.cpp} (85%) create mode 100644 sdk/foobar2000/foo_sample/dsp_sample.h create mode 100644 sdk/foobar2000/foo_sample/foo_sample.xcodeproj/project.pbxproj create mode 100644 sdk/foobar2000/foo_sample/foo_sample.xcworkspace/contents.xcworkspacedata delete mode 100644 sdk/foobar2000/foo_sample/packages.config create mode 100644 sdk/foobar2000/foobar2000_component_client/foobar2000_component_client.xcodeproj/project.pbxproj create mode 100644 sdk/foobar2000/helpers-mac/CFObject.h create mode 100644 sdk/foobar2000/helpers-mac/NSAttributedString+ppaddons.h create mode 100644 sdk/foobar2000/helpers-mac/NSAttributedString+ppaddons.m create mode 100644 sdk/foobar2000/helpers-mac/NSButton+checked.h create mode 100644 sdk/foobar2000/helpers-mac/NSButton+checked.m create mode 100644 sdk/foobar2000/helpers-mac/NSComboBox+fb2k.h create mode 100644 sdk/foobar2000/helpers-mac/NSComboBox+fb2k.mm create mode 100644 sdk/foobar2000/helpers-mac/NSEvent+ppstuff.h create mode 100644 sdk/foobar2000/helpers-mac/NSEvent+ppstuff.m create mode 100644 sdk/foobar2000/helpers-mac/NSMenu+ppaddons.h create mode 100644 sdk/foobar2000/helpers-mac/NSMenu+ppaddons.m create mode 100644 sdk/foobar2000/helpers-mac/NSTextField+grayed.h create mode 100644 sdk/foobar2000/helpers-mac/NSTextField+grayed.m create mode 100644 sdk/foobar2000/helpers-mac/NSView+embed.h create mode 100644 sdk/foobar2000/helpers-mac/NSView+embed.m create mode 100644 sdk/foobar2000/helpers-mac/NSView+ppsubviews.h create mode 100644 sdk/foobar2000/helpers-mac/NSView+ppsubviews.m create mode 100644 sdk/foobar2000/helpers-mac/fb2k-platform.h create mode 100644 sdk/foobar2000/helpers-mac/fb2k-platform.mm create mode 100644 sdk/foobar2000/helpers-mac/fooDecibelFormatter.h create mode 100644 sdk/foobar2000/helpers-mac/fooDecibelFormatter.m create mode 100644 sdk/foobar2000/helpers-mac/fooGenericDialog.h create mode 100644 sdk/foobar2000/helpers-mac/fooGenericDialog.mm create mode 100644 sdk/foobar2000/helpers-mac/fooGenericDialog.xib create mode 100644 sdk/foobar2000/helpers-mac/fooPreferencesCommon.h create mode 100644 sdk/foobar2000/helpers-mac/fooTimeFormatter.h create mode 100644 sdk/foobar2000/helpers-mac/fooTimeFormatter.mm create mode 100644 sdk/foobar2000/helpers-mac/fooWindowWithCancel.h create mode 100644 sdk/foobar2000/helpers-mac/fooWindowWithCancel.m create mode 100644 sdk/foobar2000/helpers/file_streamstub.h create mode 100644 sdk/foobar2000/helpers/foobar2000_SDK_helpers.xcodeproj/project.pbxproj create mode 100644 sdk/foobar2000/shared/Utility.cpp create mode 100644 sdk/foobar2000/shared/audio_math.cpp create mode 100644 sdk/foobar2000/shared/crash_info.cpp create mode 100644 sdk/foobar2000/shared/filedialogs.cpp create mode 100644 sdk/foobar2000/shared/filedialogs_vista.cpp create mode 100644 sdk/foobar2000/shared/font_description.cpp create mode 100644 sdk/foobar2000/shared/minidump.cpp create mode 100644 sdk/foobar2000/shared/modal_dialog.cpp create mode 100644 sdk/foobar2000/shared/shared-apple.mm create mode 100644 sdk/foobar2000/shared/shared-nix.cpp create mode 100644 sdk/foobar2000/shared/shared.vcxproj create mode 100644 sdk/foobar2000/shared/shared.vcxproj.filters create mode 100644 sdk/foobar2000/shared/shared.xcodeproj/project.pbxproj create mode 100644 sdk/foobar2000/shared/stdafx.cpp create mode 100644 sdk/foobar2000/shared/systray.cpp create mode 100644 sdk/foobar2000/shared/text_drawing.cpp create mode 100644 sdk/foobar2000/shared/utf8.cpp create mode 100644 sdk/foobar2000/shared/utf8api.cpp create mode 100644 sdk/libPPUI/HyperLinkCtrl.h create mode 100644 sdk/pfc/filetimetools.cpp create mode 100644 sdk/pfc/filetimetools.h create mode 100644 sdk/pfc/pfc.xcodeproj/project.pbxproj create mode 100644 sdk/pfc/sort2.h diff --git a/cmake/FileLists.cmake b/cmake/FileLists.cmake index d7f8a49..e880204 100644 --- a/cmake/FileLists.cmake +++ b/cmake/FileLists.cmake @@ -47,6 +47,7 @@ set( sdk/pfc/cpuid.cpp sdk/pfc/crashWithMessage.cpp sdk/pfc/filehandle.cpp + sdk/pfc/filetimetools.cpp sdk/pfc/guid.cpp sdk/pfc/other.cpp sdk/pfc/pathUtils.cpp @@ -92,6 +93,7 @@ set( sdk/pfc/debug.h sdk/pfc/event.h sdk/pfc/filehandle.h + sdk/pfc/filetimetools.h sdk/pfc/fixed_map.h sdk/pfc/fpu.h sdk/pfc/guid.h @@ -126,6 +128,7 @@ set( sdk/pfc/SmartStrStr-twoCharMappings.h sdk/pfc/SmartStrStr.h sdk/pfc/sort.h + sdk/pfc/sort2.h sdk/pfc/splitString.h sdk/pfc/splitString2.h sdk/pfc/stdsort.h @@ -242,6 +245,7 @@ set( sdk/foobar2000/SDK/cfg_var_legacy.h sdk/foobar2000/SDK/chapterizer.h sdk/foobar2000/SDK/commandline.h + sdk/foobar2000/SDK/commonObjects-Apple.h sdk/foobar2000/SDK/commonObjects.h sdk/foobar2000/SDK/completion_notify.h sdk/foobar2000/SDK/component_client.h @@ -438,6 +442,7 @@ set( sdk/foobar2000/helpers/fb2k_threads.h sdk/foobar2000/helpers/fb2k_wfx.h sdk/foobar2000/helpers/fileReadAhead.h + sdk/foobar2000/helpers/file_streamstub.h sdk/foobar2000/helpers/foobar2000+atl.h sdk/foobar2000/helpers/foobar2000-lite+atl.h sdk/foobar2000/helpers/fullFileBuffer.h @@ -585,6 +590,7 @@ set( sdk/libPPUI/GDIUtils.h sdk/libPPUI/gesture.h sdk/libPPUI/hookWindowMessages.h + sdk/libPPUI/HyperLinkCtrl.h sdk/libPPUI/IDataObjectUtils.h sdk/libPPUI/ImageEncoder.h sdk/libPPUI/ImplementOnFinalMessage.h @@ -615,7 +621,7 @@ set( SAMPLE_SOURCES sdk/foobar2000/foo_sample/contextmenu.cpp sdk/foobar2000/foo_sample/decode.cpp - sdk/foobar2000/foo_sample/dsp.cpp + sdk/foobar2000/foo_sample/dsp_sample.cpp sdk/foobar2000/foo_sample/initquit.cpp sdk/foobar2000/foo_sample/input_raw.cpp sdk/foobar2000/foo_sample/listcontrol-advanced.cpp @@ -637,6 +643,7 @@ set( set( SAMPLE_HEADERS + sdk/foobar2000/foo_sample/dsp_sample.h sdk/foobar2000/foo_sample/playback_stream_capture.h sdk/foobar2000/foo_sample/resource.h sdk/foobar2000/foo_sample/stdafx.h diff --git a/sdk/foobar2000/SDK/archive.h b/sdk/foobar2000/SDK/archive.h index a9a6b4f..d2ad63e 100644 --- a/sdk/foobar2000/SDK/archive.h +++ b/sdk/foobar2000/SDK/archive.h @@ -55,9 +55,15 @@ namespace foobar2000_io { //! Returns a list of extensions, colon delimited, e.g.: "zip,rar,7z" virtual void list_extensions(pfc::string_base & out) = 0; }; + //! \since 2.1 + class NOVTABLE archive_v4 : public archive_v3 { + FB2K_MAKE_SERVICE_INTERFACE(archive_v4, archive_v3) + public: + virtual fb2k::arrayRef archive_list_v4( fsItemFilePtr item, file::ptr readerOptional, abort_callback & a) = 0; + }; //! Root class for archive implementations. Derive from this instead of from archive directly. - class NOVTABLE archive_impl : public service_multi_inherit { + class NOVTABLE archive_impl : public service_multi_inherit { protected: //do not override these bool get_canonical_path(const char * path,pfc::string_base & out) override; @@ -80,6 +86,9 @@ namespace foobar2000_io { void list_extensions(pfc::string_base & out) override { out = get_archive_type(); } bool supports_content_types() override { return false; } char pathSeparator() override { return '/'; } + void extract_filename_ext(const char * path, pfc::string_base & outFN) override; + bool get_display_name_short(const char* in, pfc::string_base& out) override; + fb2k::arrayRef archive_list_v4( fsItemFilePtr item, file::ptr readerOptional, abort_callback & a ) override; protected: //override these virtual const char * get_archive_type()=0;//eg. "zip", must be lowercase diff --git a/sdk/foobar2000/SDK/audio_chunk.h b/sdk/foobar2000/SDK/audio_chunk.h index bc8b7dd..eda0889 100644 --- a/sdk/foobar2000/SDK/audio_chunk.h +++ b/sdk/foobar2000/SDK/audio_chunk.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include "exception_io.h" #ifdef _WIN32 @@ -220,10 +221,10 @@ class NOVTABLE audio_chunk { void pad_with_silence_ex(t_size samples,unsigned hint_nch,unsigned hint_srate); //! Appends silent samples at the end of the chunk. \n //! The chunk must have valid sample rate & channel count prior to this call. - //! @param Number of silent samples to append.s + //! @param samples Number of silent samples to append.s void pad_with_silence(t_size samples); //! Inserts silence at the beginning of the audio chunk. - //! @param Number of silent samples to insert. + //! @param samples Number of silent samples to insert. void insert_silence_fromstart(t_size samples); //! Helper; removes N first samples from the chunk. \n //! If the chunk contains fewer samples than requested, it becomes empty. @@ -239,7 +240,7 @@ class NOVTABLE audio_chunk { //! Any existing audio sdata will be discarded. \n //! Expects sample rate and channel count to be set first. \n //! Also allocates memory for the requested amount of data see: set_data_size(). - //! @param samples Desired duration in seconds. + //! @param seconds Desired duration in seconds. void set_silence_seconds( double seconds ); //! Helper; skips first samples of the chunk updating a remaining to-skip counter. diff --git a/sdk/foobar2000/SDK/chapterizer.h b/sdk/foobar2000/SDK/chapterizer.h index b066d78..adc897a 100644 --- a/sdk/foobar2000/SDK/chapterizer.h +++ b/sdk/foobar2000/SDK/chapterizer.h @@ -17,7 +17,7 @@ class NOVTABLE chapter_list { //! Sets number of chapters. virtual void set_chapter_count(t_size p_count) = 0; //! Modifies description of specified chapter. - //! @param p_chapter_index Index of chapter to modify, greater or equal zero and less than get_chapter_count() value. If p_chapter value is out of valid range, results are undefined (e.g. crash). + //! @param p_chapter Index of chapter to modify, greater or equal zero and less than get_chapter_count() value. If p_chapter value is out of valid range, results are undefined (e.g. crash). //! @param p_info New chapter description. Note that length part of file_info is used to calculate chapter marks. virtual void set_info(t_size p_chapter,const file_info & p_info) = 0; @@ -67,7 +67,6 @@ class NOVTABLE chapterizer : public service_base { FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(chapterizer); public: //! Tests whether specified path is supported by this implementation. - //! @param p_ext Extension of the file being processed. virtual bool is_our_path(const char * p_path) = 0; //! Writes new chapter list to specified file. diff --git a/sdk/foobar2000/SDK/commandline.h b/sdk/foobar2000/SDK/commandline.h index 45e29bc..a2cb741 100644 --- a/sdk/foobar2000/SDK/commandline.h +++ b/sdk/foobar2000/SDK/commandline.h @@ -25,9 +25,9 @@ class commandline_handler_metadb_handle : public commandline_handler { bool want_directories() override {return true;} public: //! Override me - virtual result on_token(const char * token) = 0; + virtual result on_token(const char * token) override = 0; //! Override me - virtual void on_files_done() {}; + virtual void on_files_done() override {}; //! Override me virtual void on_file(const metadb_handle_ptr & ptr) = 0; }; diff --git a/sdk/foobar2000/SDK/commonObjects-Apple.h b/sdk/foobar2000/SDK/commonObjects-Apple.h new file mode 100644 index 0000000..2d36045 --- /dev/null +++ b/sdk/foobar2000/SDK/commonObjects-Apple.h @@ -0,0 +1,21 @@ +#pragma once + +#ifdef __APPLE__ + +namespace fb2k { + class NSObjectWrapper : public service_base { + FB2K_MAKE_SERVICE_INTERFACE(NSObjectWrapper, service_base); + public: + virtual void * get_() = 0; +#ifdef __OBJC__ + id get() { return (__bridge id) get_(); } +#endif + + }; +#ifdef __OBJC__ + service_ptr wrapNSObject(id); + id unwrapNSObject(service_ptr); +#endif +} + +#endif diff --git a/sdk/foobar2000/SDK/commonObjects-Apple.mm b/sdk/foobar2000/SDK/commonObjects-Apple.mm new file mode 100644 index 0000000..2e6dac3 --- /dev/null +++ b/sdk/foobar2000/SDK/commonObjects-Apple.mm @@ -0,0 +1,29 @@ +#include "foobar2000-sdk-pch.h" +#include "commonObjects-Apple.h" +#include + +namespace { + class NSObjectWrapperImpl : public fb2k::NSObjectWrapper { + public: + id obj; + void * get_() override { + return (__bridge void*) obj; + } + }; +} +namespace fb2k { + service_ptr wrapNSObject(id arg) { + if (!arg) return nullptr; + auto ret = fb2k::service_new(); + ret->obj = arg; + return ret; + } + id unwrapNSObject(service_ptr arg) { + id ret = nil; + fb2k::NSObjectWrapper::ptr obj; + if ( obj &= arg ) { + ret = obj->get(); + } + return ret; + } +} diff --git a/sdk/foobar2000/SDK/componentversion.h b/sdk/foobar2000/SDK/componentversion.h index ae3afa0..6edf038 100644 --- a/sdk/foobar2000/SDK/componentversion.h +++ b/sdk/foobar2000/SDK/componentversion.h @@ -1,3 +1,5 @@ +#pragma once + //! Entrypoint interface for declaring component's version information. Instead of implementing this directly, use DECLARE_COMPONENT_VERSION(). class NOVTABLE componentversion : public service_base { public: @@ -66,7 +68,6 @@ class componentversion_impl_copy_factory : public __componentversion_impl_copy_f static componentversion_impl_copy_factory g_componentversion_service(NAME,VERSION,ABOUT); -#ifdef _WIN32 //! \since 1.0 //! Allows components to cleanly abort app startup in case the installation appears to have become corrupted. class component_installation_validator : public service_base { @@ -79,6 +80,7 @@ class component_installation_validator : public service_base { FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(component_installation_validator) }; +#ifdef _WIN32 //! Simple implementation of component_installation_validator that makes sure that our component DLL has not been renamed around by idiot users. class component_installation_validator_filename : public component_installation_validator { public: diff --git a/sdk/foobar2000/SDK/dsp.cpp b/sdk/foobar2000/SDK/dsp.cpp index 98addd5..1d23b94 100644 --- a/sdk/foobar2000/SDK/dsp.cpp +++ b/sdk/foobar2000/SDK/dsp.cpp @@ -119,10 +119,17 @@ bool dsp_entry_hidden::g_instantiate( dsp::ptr & out, const dsp_preset & preset return i->instantiate(out, preset); } -bool dsp_entry::g_instantiate(service_ptr_t & p_out,const dsp_preset & p_preset) +bool dsp_entry::g_instantiate(service_ptr_t & p_out,const dsp_preset & p_preset, unsigned flags ) { service_ptr_t ptr; if (!g_get_interface(ptr,p_preset.get_owner())) return false; + if ( flags != 0 ) { + dsp_entry_v4::ptr v4; + if (v4 &= ptr) { + p_out = v4->instantiate_v4(p_preset, flags); + return true; + } + } return ptr->instantiate(p_out,p_preset); } diff --git a/sdk/foobar2000/SDK/dsp.h b/sdk/foobar2000/SDK/dsp.h index 001b002..caf941f 100644 --- a/sdk/foobar2000/SDK/dsp.h +++ b/sdk/foobar2000/SDK/dsp.h @@ -331,16 +331,20 @@ class NOVTABLE dsp_entry : public service_base { //! Blocks until done. Returns true if preset has been altered, false otherwise. virtual bool show_config_popup(dsp_preset & p_data,fb2k::hwnd_t p_parent) = 0; #else - //! Shows configuration popup. Main thread only! + //! Shows configuration popup. Main thread only! \n + //! Mac: returns NSObjectWrapper holding NSViewController virtual service_ptr show_config_popup( fb2k::hwnd_t parent, dsp_preset_edit_callback_v2::ptr callback ); #endif //! Obsolete method, hidden DSPs now use a different entry class. bool is_user_accessible() { return true; } + static constexpr unsigned flag_playback = 1 << 0, + flag_conversion = 1 << 1; + static bool g_get_interface(service_ptr_t & p_out,const GUID & p_guid); static service_ptr_t g_get_interface(const GUID&); - static bool g_instantiate(service_ptr_t & p_out,const dsp_preset & p_preset); + static bool g_instantiate(service_ptr_t & p_out,const dsp_preset & p_preset, unsigned flags = 0); static bool g_instantiate_default(service_ptr_t & p_out,const GUID & p_guid); static bool g_name_from_guid(pfc::string_base & p_out,const GUID & p_guid); static bool g_dsp_exists(const GUID & p_guid); @@ -389,6 +393,7 @@ class NOVTABLE dsp_entry_v2 : public dsp_entry { FB2K_MAKE_SERVICE_INTERFACE(dsp_entry_v2,dsp_entry); }; +//! \since Late 1.6.x class NOVTABLE dsp_entry_v3 : public dsp_entry_v2 { FB2K_MAKE_SERVICE_INTERFACE(dsp_entry_v3, dsp_entry_v2); public: @@ -405,6 +410,13 @@ class NOVTABLE dsp_entry_v3 : public dsp_entry_v2 { #endif }; +//! \since 2.1 +class NOVTABLE dsp_entry_v4 : public dsp_entry_v3 { + FB2K_MAKE_SERVICE_INTERFACE(dsp_entry_v4, dsp_entry_v3); +public: + virtual dsp::ptr instantiate_v4( const dsp_preset & arg, unsigned flags ) = 0; +}; + class NOVTABLE dsp_entry_hidden : public service_base { FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(dsp_entry_hidden); public: @@ -499,6 +511,15 @@ class dsp_entry_v3_impl_t : public dsp_entry_v2_impl_t { #endif }; +template +class dsp_entry_v4_impl_t : public dsp_entry_v3_impl_t< dsp_t, entry_t > { +public: + dsp::ptr instantiate_v4( const dsp_preset & arg, unsigned flags ) override { + PFC_ASSERT( arg.get_owner() == dsp_t::g_get_guid() ); + return new service_impl_t< dsp_t > ( arg, flags ); + } +}; + template class dsp_entry_hidden_t : public dsp_entry_hidden { public: @@ -646,4 +667,9 @@ class dsp_preset_builder : public stream_writer_formatter<> { stream_writer_buffer_simple _m_stream; }; +#ifdef __APPLE__ +// NSObjectWrapper +#include "commonObjects-Apple.h" +#endif + #endif diff --git a/sdk/foobar2000/SDK/dsp_manager.cpp b/sdk/foobar2000/SDK/dsp_manager.cpp index 9d0822d..3567bcc 100644 --- a/sdk/foobar2000/SDK/dsp_manager.cpp +++ b/sdk/foobar2000/SDK/dsp_manager.cpp @@ -96,9 +96,9 @@ double dsp_manager::run(dsp_chunk_list * p_list,const metadb_handle_ptr & p_cur_ } } - for(t_dsp_chain::iterator iter = newchain.first(); iter.is_valid(); ++iter) { - if (iter->m_dsp.is_empty()) { - if (!dsp_entry::g_instantiate(iter->m_dsp,iter->m_preset) && !dsp_entry_hidden::g_instantiate(iter->m_dsp, iter->m_preset)) uBugCheck(); + for( auto & iter : newchain ) { + if (iter.m_dsp.is_empty()) { + if (!dsp_entry::g_instantiate(iter.m_dsp,iter.m_preset, m_creationFlags) && !dsp_entry_hidden::g_instantiate(iter.m_dsp, iter.m_preset)) uBugCheck(); } } diff --git a/sdk/foobar2000/SDK/dsp_manager.h b/sdk/foobar2000/SDK/dsp_manager.h index 311ac49..e1976d6 100644 --- a/sdk/foobar2000/SDK/dsp_manager.h +++ b/sdk/foobar2000/SDK/dsp_manager.h @@ -6,7 +6,8 @@ //! Helper class for running audio data through a DSP chain. class dsp_manager { public: - dsp_manager() {} + //! @param creationFlags See dsp_entry::flag_* + dsp_manager(unsigned creationFlags = 0) : m_creationFlags(creationFlags) {} //! 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 ); @@ -24,6 +25,7 @@ class dsp_manager { bool need_track_change_mark() const; private: + const unsigned m_creationFlags; struct t_dsp_chain_entry { service_ptr_t m_dsp; dsp_preset_impl m_preset; diff --git a/sdk/foobar2000/SDK/file.h b/sdk/foobar2000/SDK/file.h index 6a339c7..f889b73 100644 --- a/sdk/foobar2000/SDK/file.h +++ b/sdk/foobar2000/SDK/file.h @@ -164,7 +164,7 @@ namespace foobar2000_io //! Helper function; reads a string (with a 32-bit header indicating length in bytes followed by UTF-8 encoded data without a null terminator). void read_string(pfc::string_base& p_out, abort_callback& p_abort); //! Helper function; alternate way of storing strings; assumes string takes space up to end of stream. - void read_string_raw(pfc::string_base& p_out, abort_callback& p_abort); + void read_string_raw(pfc::string_base& p_out, abort_callback& p_abort, size_t sanity = SIZE_MAX); //! Helper function; reads a string (with a 32-bit header indicating length in bytes followed by UTF-8 encoded data without a null terminator). pfc::string read_string(abort_callback& p_abort); @@ -291,6 +291,7 @@ namespace foobar2000_io //! Retrieves mime type of the file. //! @param p_out Receives content type string on success. virtual bool get_content_type(pfc::string_base& p_out) = 0; + pfc::string8 get_content_type(); //! Hint, returns whether the file is already fully buffered into memory. virtual bool is_in_memory() { return false; } @@ -332,6 +333,7 @@ namespace foobar2000_io //! Security helper; fails early with exception_io_data_truncation if it is not possible to read this amount of bytes from this file at this position. void probe_remaining(t_filesize bytes, abort_callback& p_abort); + bool probe_remaining_ex(t_filesize bytes, abort_callback& p_abort); //! Helper; throws exception_io_object_not_seekable if file is not seekable. void ensure_seekable(); @@ -461,28 +463,11 @@ namespace foobar2000_io //! Implementation helper - contains dummy implementations of methods that modify the file template class file_readonly_t : public t_base { public: - void resize(t_filesize p_size, abort_callback& p_abort) { throw exception_io_denied(); } - void write(const void* p_buffer, t_size p_bytes, abort_callback& p_abort) { throw exception_io_denied(); } + void resize(t_filesize p_size, abort_callback& p_abort) override { throw exception_io_denied(); } + void write(const void* p_buffer, t_size p_bytes, abort_callback& p_abort) override { throw exception_io_denied(); } }; typedef file_readonly_t file_readonly; - 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& out) { - if (m_contentType.length() > 0) { out = m_contentType; return true; } else return false; - } - bool is_remote() { return m_remote; } - void reopen(abort_callback&) {} - void seek(t_filesize, abort_callback&) { throw exception_io_object_not_seekable(); } - bool can_seek() { return false; } - - pfc::string8 m_contentType; - bool m_remote = true; - }; - //! \since 2.0 class file_v2 : public file { FB2K_MAKE_SERVICE_INTERFACE(file_v2, file); @@ -497,8 +482,10 @@ namespace foobar2000_io virtual size_t lowLevelIO(const GUID& guid, size_t arg1, void* arg2, size_t arg2size, abort_callback& abort) { return 0; } - // Old method wrapped to get_stats2() + // Old methods wrapped to get_stats2() t_filetimestamp get_timestamp(abort_callback& p_abort) override; + bool is_remote() override; + t_filesize get_size(abort_callback& p_abort) override; }; //! \since 1.6.7 diff --git a/sdk/foobar2000/SDK/fileDialog.h b/sdk/foobar2000/SDK/fileDialog.h index ab3bfb1..87b0f24 100644 --- a/sdk/foobar2000/SDK/fileDialog.h +++ b/sdk/foobar2000/SDK/fileDialog.h @@ -3,18 +3,21 @@ #include namespace fb2k { - + + typedef std::function fileDialogReply_t; + typedef std::function fileDialogGetPath_t; + class NOVTABLE fileDialogNotify : public service_base { FB2K_MAKE_SERVICE_INTERFACE( fileDialogNotify, service_base ); public: //! Called when user has cancelled the dialog. virtual void dialogCancelled() = 0; //! Called when the user has dismissed the dialog having selected some content. - //! @param fsItems Array of fsItemBase objects or strings, depending on the platform. Should accept either form. Typically, file dialogs will handle fsItems but Add Location will handle path strings. Special case: playlist format chooser sends chosen format name as a string (one array item). + //! @param items Array of fsItemBase objects or strings, depending on the platform. Should accept either form. Typically, file dialogs will handle fsItems but Add Location will handle path strings. Special case: playlist format chooser sends chosen format name as a string (one array item). virtual void dialogOK2( arrayRef items ) = 0; - static fileDialogNotify::ptr create( std::function recv ); - }; + static fileDialogNotify::ptr create( fileDialogReply_t recv ); + }; class NOVTABLE fileDialogSetup : public service_base { FB2K_MAKE_SERVICE_INTERFACE( fileDialogSetup, service_base ); @@ -52,6 +55,10 @@ namespace fb2k { //! For an example, on Windows most filedialogs work synchronously while on OSX all of them work asynchronously. //! @param notify Notify object invoked upon dialog completion. virtual void run(fileDialogNotify::ptr notify) = 0; + + //! Helper, creates fileDialogNotify for you. + void run (fileDialogReply_t reply); + void runSimple (fileDialogGetPath_t reply); }; class NOVTABLE fileDialog : public service_base { diff --git a/sdk/foobar2000/SDK/file_info.cpp b/sdk/foobar2000/SDK/file_info.cpp index 1c0845b..d5c721d 100644 --- a/sdk/foobar2000/SDK/file_info.cpp +++ b/sdk/foobar2000/SDK/file_info.cpp @@ -97,6 +97,22 @@ void file_info::overwrite_meta(const file_info & p_source) { } } +bool file_info::overwrite_meta_if_changed( const file_info & source ) { + const t_size total = source.meta_get_count(); + bool changed = false; + for(t_size walk = 0; walk < total; ++walk) { + auto name = source.meta_enum_name(walk); + auto idx = this->meta_find(name); + if ( idx != SIZE_MAX ) { + if (field_value_equals(*this, idx, source, walk)) continue; + } + + copy_meta_single(source, walk); + changed = true; + } + return changed; +} + void file_info::copy_meta_single(const file_info & p_source,t_size p_index) { copy_meta_single_rename(p_source,p_index,p_source.meta_enum_name(p_index)); @@ -287,7 +303,24 @@ unsigned file_info::info_get_decoded_bps() const val = info_get_int("bitspersample"); if (is_valid_bps(val)) return (unsigned)val; return 0; +} +bool file_info::info_get_codec_long(pfc::string_base& out, const char * delim) const { + const char * codec; + codec = this->info_get("codec_long"); + if (codec != nullptr) { + out = codec; return true; + } + codec = this->info_get("codec"); + if (codec != nullptr) { + out = codec; + const char * profile = this->info_get("codec_profile"); + if (profile != nullptr) { + out << delim << profile; + } + return true; + } + return false; } void file_info::reset() diff --git a/sdk/foobar2000/SDK/file_info.h b/sdk/foobar2000/SDK/file_info.h index 8f89845..c4530cc 100644 --- a/sdk/foobar2000/SDK/file_info.h +++ b/sdk/foobar2000/SDK/file_info.h @@ -205,6 +205,7 @@ class NOVTABLE file_info { 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);} void overwrite_info(const file_info & p_source); void overwrite_meta(const file_info & p_source); + bool overwrite_meta_if_changed( const file_info & source ); t_int64 info_get_int(const char * name) const; t_int64 info_get_length_samples() const; @@ -217,9 +218,9 @@ class NOVTABLE file_info { void info_set_replaygain_album_peak(float value); inline t_int64 info_get_bitrate_vbr() const {return info_get_int("bitrate_dynamic");} - inline void info_set_bitrate_vbr(t_int64 val) {info_set_int("bitrate_dynamic",val);} + inline void info_set_bitrate_vbr(t_int64 val_kbps) {info_set_int("bitrate_dynamic",val_kbps);} inline t_int64 info_get_bitrate() const {return info_get_int("bitrate");} - inline void info_set_bitrate(t_int64 val) { PFC_ASSERT(val > 0); info_set_int("bitrate", val); } + inline void info_set_bitrate(t_int64 val_kbps) { PFC_ASSERT(val_kbps > 0); info_set_int("bitrate", val_kbps); } //! Set number of channels @@ -251,6 +252,9 @@ class NOVTABLE file_info { //! Returns decoder-output bit depth - what sample format is being converted to foobar2000 audio_sample. 0 if unknown. unsigned info_get_decoded_bps() const; + //! Foramts long codec name ( codec + profile ) + bool info_get_codec_long( pfc::string_base & out, const char * delim = " / ") const; + private: void merge(const pfc::list_base_const_t & p_sources); public: diff --git a/sdk/foobar2000/SDK/file_info_merge.cpp b/sdk/foobar2000/SDK/file_info_merge.cpp index f1e424f..d3c9462 100644 --- a/sdk/foobar2000/SDK/file_info_merge.cpp +++ b/sdk/foobar2000/SDK/file_info_merge.cpp @@ -164,6 +164,13 @@ void file_info::_set_tag(const file_info & tag) { this->info_set(n, tag.info_enum_value( iWalk ) ); } } + +#ifdef FOOBAR2000_FILE_INFO_PICTURES + { + auto p = tag.info_get("pictures"); + if ( p != nullptr ) this->info_set("pictures", p); + } +#endif } void file_info::_add_tag(const file_info & otherTag) { @@ -188,4 +195,11 @@ void file_info::_add_tag(const file_info & otherTag) { } } } + +#ifdef FOOBAR2000_FILE_INFO_PICTURES + if (this->info_get("pictures") == nullptr) { + auto p = otherTag.info_get("pictures"); + if ( p != nullptr ) info_set("pictures", p); + } +#endif } diff --git a/sdk/foobar2000/SDK/filesystem.cpp b/sdk/foobar2000/SDK/filesystem.cpp index 5d264f9..baa2679 100644 --- a/sdk/foobar2000/SDK/filesystem.cpp +++ b/sdk/foobar2000/SDK/filesystem.cpp @@ -350,6 +350,21 @@ bool archive::is_our_archive( const char * path ) { return true; // accept all files } +void archive_impl::extract_filename_ext(const char * path, pfc::string_base & outFN) { + pfc::string8 dummy, subpath; + if (archive_impl::g_parse_unpack_path(path, dummy, subpath)) { + outFN = pfc::filename_ext_v2( subpath ); + } else { + PFC_ASSERT(!"???"); + filesystem_v3::extract_filename_ext(path, outFN); + } +} + +bool archive_impl::get_display_name_short(const char* in, pfc::string_base& out) { + extract_filename_ext(in ,out); + return true; +} + bool archive_impl::get_canonical_path(const char * path,pfc::string_base & out) { if (is_our_path(path)) @@ -494,6 +509,27 @@ void archive_impl::g_make_unpack_path(pfc::string_base & path,const char * archi void archive_impl::make_unpack_path(pfc::string_base & path,const char * archive,const char * file) {g_make_unpack_path(path,archive,file,get_archive_type());} +fb2k::arrayRef archive_impl::archive_list_v4( fsItemFilePtr item, file::ptr readerOptional, abort_callback & a ) { + + const auto baseStats = item->getStatsOpportunist(); + PFC_ASSERT( ! baseStats.is_folder() ); + auto ret = fb2k::arrayMutable::arrayWithCapacity(256); + + auto reader = readerOptional; + if ( reader.is_empty() ) reader = item->openRead(a); + try { + this->archive_list( item->canonicalPath()->c_str(), reader, [&] ( const char * URL, t_filestats const & stats, file::ptr ) { + t_filestats2 stats2 = t_filestats2::from_legacy( stats ); + stats2.set_file(); stats2.set_remote( baseStats.is_remote() ); stats2.set_readonly(true); + archive * blah = this; // multi inheritance fix, more than one path to filesystem which has makeItemFileStd() + ret->add(blah->makeItemFileStd(URL, stats2)); + }, false, a); + } catch( exception_io_data ) { + if ( ret->count() == 0 ) throw; + } + return ret->makeConst(); + +} namespace { @@ -812,17 +848,20 @@ void stream_reader::read_string(pfc::string_base & p_out,abort_callback & p_abor read_string_ex(p_out,length,p_abort); } -void stream_reader::read_string_raw(pfc::string_base & p_out,abort_callback & p_abort) { - enum {delta = 256}; +void stream_reader::read_string_raw(pfc::string_base & p_out,abort_callback & p_abort, size_t sanity) { + enum {delta = 1024}; char buffer[delta]; p_out.reset(); + size_t didRead = 0; for(;;) { - t_size delta_done; - delta_done = read(buffer,delta,p_abort); + auto delta_done = read(buffer,delta,p_abort); p_out.add_string(buffer,delta_done); if (delta_done < delta) break; + didRead += delta; + if (didRead > sanity) throw exception_io_data(); } } + void stream_writer::write_string(const char * p_string,t_size p_len,abort_callback & p_abort) { t_uint32 len = pfc::downcast_guarded(pfc::strlen_max(p_string,p_len)); write_lendian_t(len,p_abort); @@ -1039,14 +1078,18 @@ t_filesize file::get_remaining(abort_callback & p_abort) { return length - position; } -void file::probe_remaining(t_filesize bytes, abort_callback & p_abort) { +bool file::probe_remaining_ex(t_filesize bytes, abort_callback& p_abort) { t_filesize length = get_size(p_abort); - if (length != ~0) { + if (length != filesize_invalid) { t_filesize remaining = length - get_position(p_abort); - if (remaining < bytes) throw exception_io_data_truncation(); + if (remaining < bytes) return false; } + return true; } +void file::probe_remaining(t_filesize bytes, abort_callback & p_abort) { + if (!probe_remaining_ex(bytes, p_abort)) throw exception_io_data_truncation(); +} t_filesize file::g_transfer(service_ptr_t p_src,service_ptr_t p_dst,t_filesize p_bytes,abort_callback & p_abort) { return g_transfer(pfc::implicit_cast(p_src.get_ptr()),pfc::implicit_cast(p_dst.get_ptr()),p_bytes,p_abort); @@ -1851,7 +1894,20 @@ void filesystem_v3::get_stats(const char* p_path, t_filestats& p_stats, bool& p_ t_filetimestamp file_v2::get_timestamp(abort_callback& p_abort) { return this->get_stats2(stats2_timestamp, p_abort).m_timestamp; } +bool file_v2::is_remote() { + return this->get_stats2(stats2_remote, fb2k::noAbort).is_remote(); +} + +t_filesize file_v2::get_size(abort_callback& p_abort) { + return this->get_stats2(stats2_size, p_abort).m_size; +} + +pfc::string8 file::get_content_type() { + pfc::string8 ret; + if (!this->get_content_type(ret)) ret.clear(); + return ret; +} t_filestats2 file::get_stats2_(uint32_t f, abort_callback& a) { t_filestats2 ret; @@ -2182,13 +2238,10 @@ pfc::string8 t_filestats2::describe() const { t_filestats foobar2000_io::nixMakeFileStats(const struct stat & st) { t_filestats out = filestats_invalid; out.m_size = st.st_size; -#if defined(__ANDROID__) - out.m_timestamp = pfc::fileTimeUtoW(st.st_mtime /* + st.st_mtime_nsec / 1000000000 */ ); -#elif !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE) - out.m_timestamp = pfc::fileTimeUtoW(st.st_mtimespec ); - // out.m_timestampCreate = pfc::fileTimeUtoW( st.st_birthtimespec ); -#else - out.m_timestamp = pfc::fileTimeUtoW(st.st_mtime); +#ifdef __APPLE__ + out.m_timestamp = pfc::fileTimeUtoW(st.st_mtimespec); +#else // Linux + out.m_timestamp = pfc::fileTimeUtoW(st.st_mtim); #endif return out; } @@ -2203,10 +2256,10 @@ bool foobar2000_io::nixQueryDirectory( const struct stat & st ) { t_filestats2 foobar2000_io::nixMakeFileStats2(const struct stat &st) { t_filestats2 ret = t_filestats2::from_legacy( nixMakeFileStats( st ) ); -#ifndef __ANDROID__ - // Android Java API does not report creation time - // We could return it from here, but then different fb2k APIs will return different info about the same object, which is not acceptable. - ret.m_timestampCreate = pfc::fileTimeUtoW( st.st_birthtimespec ); +#ifdef __APPLE__ + ret.m_timestampCreate = pfc::fileTimeUtoW(st.st_birthtimespec); +#else // Linux + ret.m_timestampCreate = pfc::fileTimeUtoW(st.st_ctim); #endif ret.set_readonly(nixQueryReadonly(st)); if ( nixQueryDirectory( st ) ) ret.set_folder(); diff --git a/sdk/foobar2000/SDK/foobar2000-versions.h b/sdk/foobar2000/SDK/foobar2000-versions.h index aff1eff..8b780ed 100644 --- a/sdk/foobar2000/SDK/foobar2000-versions.h +++ b/sdk/foobar2000/SDK/foobar2000-versions.h @@ -3,8 +3,8 @@ // foobar2000 SDK version and target API levels are declared in this header // This SDK does NOT SUPPORT targets older than API 80 / foobar2000 v1.5 -#define FOOBAR2000_TARGET_VERSION 80 // 1.5, 1.6 -// #define FOOBAR2000_TARGET_VERSION 81 // 2.0 +// #define FOOBAR2000_TARGET_VERSION 80 // 1.5, 1.6 +#define FOOBAR2000_TARGET_VERSION 81 // 2.0 #ifdef _M_IX86 #define FOOBAR2000_TARGET_VERSION_COMPATIBLE 72 diff --git a/sdk/foobar2000/SDK/foobar2000-winver.h b/sdk/foobar2000/SDK/foobar2000-winver.h index c0c9bd7..7aab1d8 100644 --- a/sdk/foobar2000/SDK/foobar2000-winver.h +++ b/sdk/foobar2000/SDK/foobar2000-winver.h @@ -21,6 +21,9 @@ #define FOOBAR2000_HAVE_KEYBOARD_SHORTCUTS #endif +#ifdef __APPLE__ +#define FOOBAR2000_SUPPORT_DLLS 1 +#endif #ifndef FOOBAR2000_SUPPORT_DLLS #define FOOBAR2000_SUPPORT_DLLS 0 diff --git a/sdk/foobar2000/SDK/foobar2000.h b/sdk/foobar2000/SDK/foobar2000.h index 6e5796a..9845c1f 100644 --- a/sdk/foobar2000/SDK/foobar2000.h +++ b/sdk/foobar2000/SDK/foobar2000.h @@ -116,4 +116,7 @@ #include "ui_edit_context.h" #include "toolbarDropDown.h" +#include "commonObjects-Apple.h" + #endif //_FOOBAR2000_H_ + diff --git a/sdk/foobar2000/SDK/foobar2000_SDK.xcodeproj/project.pbxproj b/sdk/foobar2000/SDK/foobar2000_SDK.xcodeproj/project.pbxproj new file mode 100644 index 0000000..5745ae3 --- /dev/null +++ b/sdk/foobar2000/SDK/foobar2000_SDK.xcodeproj/project.pbxproj @@ -0,0 +1,1115 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 0F75F4942A6B1CA800A45078 /* foosort.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F3C82A6B1CA000A45078 /* foosort.cpp */; }; + 0F75F4952A6B1CA800A45078 /* genrand.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3C92A6B1CA000A45078 /* genrand.h */; }; + 0F75F4962A6B1CA800A45078 /* ui_element_typable_window_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3CA2A6B1CA000A45078 /* ui_element_typable_window_manager.h */; }; + 0F75F4972A6B1CA800A45078 /* titleformat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F3CB2A6B1CA000A45078 /* titleformat.cpp */; }; + 0F75F4982A6B1CA800A45078 /* file_info_merge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F3CC2A6B1CA000A45078 /* file_info_merge.cpp */; }; + 0F75F4992A6B1CA800A45078 /* audio_chunk.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3CD2A6B1CA000A45078 /* audio_chunk.h */; }; + 0F75F49A2A6B1CA800A45078 /* output.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3CE2A6B1CA000A45078 /* output.h */; }; + 0F75F49B2A6B1CA800A45078 /* file_operation_callback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F3CF2A6B1CA000A45078 /* file_operation_callback.cpp */; }; + 0F75F49C2A6B1CA800A45078 /* abort_callback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F3D02A6B1CA000A45078 /* abort_callback.cpp */; }; + 0F75F49D2A6B1CA800A45078 /* playlist_loader.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3D12A6B1CA000A45078 /* playlist_loader.h */; }; + 0F75F49E2A6B1CA800A45078 /* threaded_process.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3D22A6B1CA000A45078 /* threaded_process.h */; }; + 0F75F49F2A6B1CA800A45078 /* service_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3D32A6B1CA000A45078 /* service_impl.h */; }; + 0F75F4A02A6B1CA800A45078 /* main_thread_callback.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3D42A6B1CA000A45078 /* main_thread_callback.h */; }; + 0F75F4A12A6B1CA800A45078 /* filesystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F3D52A6B1CA000A45078 /* filesystem.cpp */; }; + 0F75F4A22A6B1CA800A45078 /* stdafx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F3D62A6B1CA000A45078 /* stdafx.cpp */; }; + 0F75F4A32A6B1CA800A45078 /* progress_meter.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3D72A6B1CA000A45078 /* progress_meter.h */; }; + 0F75F4A42A6B1CA800A45078 /* app_close_blocker.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3D82A6B1CA000A45078 /* app_close_blocker.h */; }; + 0F75F4A52A6B1CA800A45078 /* mem_block_container.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F3D92A6B1CA000A45078 /* mem_block_container.cpp */; }; + 0F75F4A62A6B1CA800A45078 /* filesystem.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3DA2A6B1CA000A45078 /* filesystem.h */; }; + 0F75F4A72A6B1CA800A45078 /* commonObjects.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F3DB2A6B1CA000A45078 /* commonObjects.cpp */; }; + 0F75F4A82A6B1CA800A45078 /* threadPool.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3DC2A6B1CA000A45078 /* threadPool.h */; }; + 0F75F4A92A6B1CA800A45078 /* noInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3DD2A6B1CA000A45078 /* noInfo.h */; }; + 0F75F4AA2A6B1CA800A45078 /* unpack.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3DE2A6B1CA000A45078 /* unpack.h */; }; + 0F75F4AB2A6B1CA800A45078 /* output.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F3DF2A6B1CA000A45078 /* output.cpp */; }; + 0F75F4AC2A6B1CA800A45078 /* menu_helpers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F3E02A6B1CA000A45078 /* menu_helpers.cpp */; }; + 0F75F4AD2A6B1CA800A45078 /* service.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3E12A6B1CA000A45078 /* service.h */; }; + 0F75F4AE2A6B1CA800A45078 /* file_info_const_impl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F3E22A6B1CA100A45078 /* file_info_const_impl.cpp */; }; + 0F75F4AF2A6B1CA800A45078 /* chapterizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3E32A6B1CA100A45078 /* chapterizer.h */; }; + 0F75F4B02A6B1CA800A45078 /* audio_chunk_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3E42A6B1CA100A45078 /* audio_chunk_impl.h */; }; + 0F75F4B12A6B1CA800A45078 /* audio_chunk_channel_config.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F3E52A6B1CA100A45078 /* audio_chunk_channel_config.cpp */; }; + 0F75F4B22A6B1CA800A45078 /* event_logger.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3E62A6B1CA100A45078 /* event_logger.h */; }; + 0F75F4B32A6B1CA800A45078 /* foobar2000-pfc.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3E72A6B1CA100A45078 /* foobar2000-pfc.h */; }; + 0F75F4B42A6B1CA800A45078 /* http_client.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3E82A6B1CA100A45078 /* http_client.h */; }; + 0F75F4B52A6B1CA800A45078 /* hasher_md5.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3E92A6B1CA100A45078 /* hasher_md5.h */; }; + 0F75F4B62A6B1CA800A45078 /* component.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3EA2A6B1CA100A45078 /* component.h */; }; + 0F75F4B72A6B1CA800A45078 /* forward_types.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3EB2A6B1CA100A45078 /* forward_types.h */; }; + 0F75F4B82A6B1CA800A45078 /* replaygain.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3EC2A6B1CA100A45078 /* replaygain.h */; }; + 0F75F4B92A6B1CA800A45078 /* metadb.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3ED2A6B1CA100A45078 /* metadb.h */; }; + 0F75F4BA2A6B1CA800A45078 /* menu_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F3EE2A6B1CA100A45078 /* menu_manager.cpp */; }; + 0F75F4BB2A6B1CA800A45078 /* resampler.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3EF2A6B1CA100A45078 /* resampler.h */; }; + 0F75F4BC2A6B1CA800A45078 /* initquit.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3F02A6B1CA100A45078 /* initquit.h */; }; + 0F75F4BD2A6B1CA800A45078 /* foobar2000-winver.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3F12A6B1CA100A45078 /* foobar2000-winver.h */; }; + 0F75F4BE2A6B1CA800A45078 /* timer.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3F22A6B1CA100A45078 /* timer.h */; }; + 0F75F4BF2A6B1CA800A45078 /* playlist.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3F32A6B1CA100A45078 /* playlist.h */; }; + 0F75F4C02A6B1CA800A45078 /* track_property.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F3F42A6B1CA100A45078 /* track_property.cpp */; }; + 0F75F4C12A6B1CA800A45078 /* ui.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F3F52A6B1CA100A45078 /* ui.cpp */; }; + 0F75F4C22A6B1CA800A45078 /* titleformat.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3F62A6B1CA100A45078 /* titleformat.h */; }; + 0F75F4C32A6B1CA800A45078 /* file_info_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3F72A6B1CA100A45078 /* file_info_impl.h */; }; + 0F75F4C42A6B1CA800A45078 /* filesystem_helper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F3F82A6B1CA100A45078 /* filesystem_helper.cpp */; }; + 0F75F4C52A6B1CA800A45078 /* filesystem_helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3F92A6B1CA100A45078 /* filesystem_helper.h */; }; + 0F75F4C62A6B1CA800A45078 /* audio_chunk.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F3FA2A6B1CA100A45078 /* audio_chunk.cpp */; }; + 0F75F4C72A6B1CA800A45078 /* console_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3FB2A6B1CA100A45078 /* console_manager.h */; }; + 0F75F4C82A6B1CA800A45078 /* filesystem_transacted.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3FC2A6B1CA100A45078 /* filesystem_transacted.h */; }; + 0F75F4C92A6B1CA800A45078 /* service.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F3FD2A6B1CA100A45078 /* service.cpp */; }; + 0F75F4CA2A6B1CA800A45078 /* threaded_process.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F3FE2A6B1CA200A45078 /* threaded_process.cpp */; }; + 0F75F4CB2A6B1CA800A45078 /* coreDarkMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F3FF2A6B1CA200A45078 /* coreDarkMode.h */; }; + 0F75F4CC2A6B1CA800A45078 /* cfg_var_legacy.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4002A6B1CA200A45078 /* cfg_var_legacy.h */; }; + 0F75F4CD2A6B1CA800A45078 /* menu.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4012A6B1CA200A45078 /* menu.h */; }; + 0F75F4CE2A6B1CA800A45078 /* file_info_filter_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4022A6B1CA200A45078 /* file_info_filter_impl.h */; }; + 0F75F4CF2A6B1CA800A45078 /* advconfig.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F4032A6B1CA200A45078 /* advconfig.cpp */; }; + 0F75F4D02A6B1CA800A45078 /* packet_decoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4042A6B1CA200A45078 /* packet_decoder.h */; }; + 0F75F4D12A6B1CA800A45078 /* decode_postprocessor.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4052A6B1CA200A45078 /* decode_postprocessor.h */; }; + 0F75F4D22A6B1CA800A45078 /* exception_io.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4062A6B1CA200A45078 /* exception_io.h */; }; + 0F75F4D32A6B1CA800A45078 /* search_tools.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4072A6B1CA200A45078 /* search_tools.h */; }; + 0F75F4D42A6B1CA800A45078 /* metadb_callbacks.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4082A6B1CA200A45078 /* metadb_callbacks.h */; }; + 0F75F4D52A6B1CA800A45078 /* configStore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F4092A6B1CA200A45078 /* configStore.cpp */; }; + 0F75F4D62A6B1CA800A45078 /* modeless_dialog.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F40A2A6B1CA200A45078 /* modeless_dialog.h */; }; + 0F75F4D72A6B1CA800A45078 /* foosort.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F40B2A6B1CA200A45078 /* foosort.h */; }; + 0F75F4D82A6B1CA800A45078 /* console.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F40C2A6B1CA200A45078 /* console.cpp */; }; + 0F75F4D92A6B1CA800A45078 /* playback_control.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F40D2A6B1CA200A45078 /* playback_control.h */; }; + 0F75F4DA2A6B1CA800A45078 /* playback_stream_capture.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F40E2A6B1CA200A45078 /* playback_stream_capture.h */; }; + 0F75F4DB2A6B1CA800A45078 /* file_info.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F40F2A6B1CA200A45078 /* file_info.cpp */; }; + 0F75F4DC2A6B1CA800A45078 /* dsp.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4102A6B1CA200A45078 /* dsp.h */; }; + 0F75F4DD2A6B1CA800A45078 /* library_callbacks.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4112A6B1CA200A45078 /* library_callbacks.h */; }; + 0F75F4DE2A6B1CA800A45078 /* threadsLite.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4122A6B1CA200A45078 /* threadsLite.h */; }; + 0F75F4DF2A6B1CA800A45078 /* mem_block_container.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4132A6B1CA200A45078 /* mem_block_container.h */; }; + 0F75F4E02A6B1CA800A45078 /* foobar2000-all.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4142A6B1CA200A45078 /* foobar2000-all.h */; }; + 0F75F4E12A6B1CA800A45078 /* image.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F4152A6B1CA200A45078 /* image.cpp */; }; + 0F75F4E22A6B1CA800A45078 /* utility.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F4162A6B1CA200A45078 /* utility.cpp */; }; + 0F75F4E32A6B1CA800A45078 /* track_property.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4172A6B1CA200A45078 /* track_property.h */; }; + 0F75F4E42A6B1CA800A45078 /* cfg_var.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F4182A6B1CA200A45078 /* cfg_var.cpp */; }; + 0F75F4E52A6B1CA800A45078 /* shortcut_actions.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4192A6B1CA200A45078 /* shortcut_actions.h */; }; + 0F75F4E62A6B1CA800A45078 /* foosortstring.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F41A2A6B1CA200A45078 /* foosortstring.cpp */; }; + 0F75F4E72A6B1CA800A45078 /* exceptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F41B2A6B1CA200A45078 /* exceptions.h */; }; + 0F75F4E82A6B1CA800A45078 /* component_client.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F41C2A6B1CA200A45078 /* component_client.h */; }; + 0F75F4E92A6B1CA800A45078 /* playable_location.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F41D2A6B1CA200A45078 /* playable_location.cpp */; }; + 0F75F4EA2A6B1CA800A45078 /* metadb.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F41E2A6B1CA200A45078 /* metadb.cpp */; }; + 0F75F4EB2A6B1CA800A45078 /* input_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F41F2A6B1CA200A45078 /* input_impl.h */; }; + 0F75F4EC2A6B1CA800A45078 /* service_compat.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4202A6B1CA200A45078 /* service_compat.h */; }; + 0F75F4ED2A6B1CA800A45078 /* keyValueIO.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4212A6B1CA300A45078 /* keyValueIO.h */; }; + 0F75F4EE2A6B1CA800A45078 /* tracks.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4222A6B1CA300A45078 /* tracks.h */; }; + 0F75F4EF2A6B1CA800A45078 /* playlistColumnProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4232A6B1CA300A45078 /* playlistColumnProvider.h */; }; + 0F75F4F02A6B1CA800A45078 /* imageLoaderLite.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4242A6B1CA300A45078 /* imageLoaderLite.h */; }; + 0F75F4F12A6B1CA800A45078 /* playlist.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F4252A6B1CA300A45078 /* playlist.cpp */; }; + 0F75F4F22A6B1CA800A45078 /* preferences_page.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F4262A6B1CA300A45078 /* preferences_page.cpp */; }; + 0F75F4F32A6B1CA800A45078 /* config_io_callback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F4272A6B1CA300A45078 /* config_io_callback.cpp */; }; + 0F75F4F42A6B1CA800A45078 /* packet_decoder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F4282A6B1CA300A45078 /* packet_decoder.cpp */; }; + 0F75F4F52A6B1CA800A45078 /* ole_interaction.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4292A6B1CA300A45078 /* ole_interaction.h */; }; + 0F75F4F62A6B1CA800A45078 /* info_lookup_handler.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F42A2A6B1CA300A45078 /* info_lookup_handler.h */; }; + 0F75F4F72A6B1CA800A45078 /* library_index.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F42B2A6B1CA300A45078 /* library_index.h */; }; + 0F75F4F82A6B1CA800A45078 /* audioEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F42C2A6B1CA300A45078 /* audioEncoder.h */; }; + 0F75F4F92A6B1CA800A45078 /* commandline.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F42D2A6B1CA300A45078 /* commandline.cpp */; }; + 0F75F4FA2A6B1CA800A45078 /* image.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F42E2A6B1CA300A45078 /* image.h */; }; + 0F75F4FB2A6B1CA800A45078 /* link_resolver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F42F2A6B1CA300A45078 /* link_resolver.cpp */; }; + 0F75F4FC2A6B1CA800A45078 /* metadb_handle.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4302A6B1CA300A45078 /* metadb_handle.h */; }; + 0F75F4FD2A6B1CA800A45078 /* advconfig_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4312A6B1CA300A45078 /* advconfig_impl.h */; }; + 0F75F4FE2A6B1CA800A45078 /* foobar2000-versions.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4322A6B1CA300A45078 /* foobar2000-versions.h */; }; + 0F75F4FF2A6B1CA800A45078 /* componentversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4332A6B1CA300A45078 /* componentversion.h */; }; + 0F75F5002A6B1CA800A45078 /* contextmenu.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4342A6B1CA300A45078 /* contextmenu.h */; }; + 0F75F5012A6B1CA800A45078 /* advconfig_impl_legacy.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4352A6B1CA300A45078 /* advconfig_impl_legacy.h */; }; + 0F75F5022A6B1CA800A45078 /* file.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4362A6B1CA300A45078 /* file.h */; }; + 0F75F5032A6B1CA800A45078 /* ui_element.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F4372A6B1CA300A45078 /* ui_element.cpp */; }; + 0F75F5042A6B1CA800A45078 /* guids.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F4382A6B1CA300A45078 /* guids.cpp */; }; + 0F75F5052A6B1CA800A45078 /* tag_processor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F4392A6B1CA300A45078 /* tag_processor.cpp */; }; + 0F75F5062A6B1CA800A45078 /* config_object.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F43A2A6B1CA300A45078 /* config_object.h */; }; + 0F75F5072A6B1CA800A45078 /* config_object.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F43B2A6B1CA300A45078 /* config_object.cpp */; }; + 0F75F5082A6B1CA800A45078 /* ui.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F43C2A6B1CA300A45078 /* ui.h */; }; + 0F75F5092A6B1CA800A45078 /* link_resolver.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F43D2A6B1CA300A45078 /* link_resolver.h */; }; + 0F75F50A2A6B1CA800A45078 /* playable_location.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F43E2A6B1CA300A45078 /* playable_location.h */; }; + 0F75F50B2A6B1CA800A45078 /* file_lock_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F43F2A6B1CA300A45078 /* file_lock_manager.h */; }; + 0F75F50C2A6B1CA800A45078 /* configStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4402A6B1CA300A45078 /* configStore.h */; }; + 0F75F50D2A6B1CA800A45078 /* input.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F4412A6B1CA300A45078 /* input.cpp */; }; + 0F75F50E2A6B1CA800A45078 /* contextmenu_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4422A6B1CA300A45078 /* contextmenu_manager.h */; }; + 0F75F50F2A6B1CA800A45078 /* config_io_callback.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4432A6B1CA400A45078 /* config_io_callback.h */; }; + 0F75F5102A6B1CA800A45078 /* menu_common.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4442A6B1CA400A45078 /* menu_common.h */; }; + 0F75F5112A6B1CA800A45078 /* completion_notify.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F4452A6B1CA400A45078 /* completion_notify.cpp */; }; + 0F75F5122A6B1CA800A45078 /* metadb_info_container_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4462A6B1CA400A45078 /* metadb_info_container_impl.h */; }; + 0F75F5132A6B1CA800A45078 /* abort_callback.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4472A6B1CA400A45078 /* abort_callback.h */; }; + 0F75F5142A6B1CA800A45078 /* completion_notify.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4482A6B1CA400A45078 /* completion_notify.h */; }; + 0F75F5152A6B1CA800A45078 /* toolbarDropDown.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4492A6B1CA400A45078 /* toolbarDropDown.h */; }; + 0F75F5162A6B1CA800A45078 /* dsp_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F44A2A6B1CA400A45078 /* dsp_manager.h */; }; + 0F75F5172A6B1CA800A45078 /* messageBox.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F44B2A6B1CA400A45078 /* messageBox.h */; }; + 0F75F5182A6B1CA800A45078 /* ui_edit_context.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F44C2A6B1CA400A45078 /* ui_edit_context.h */; }; + 0F75F5192A6B1CA800A45078 /* ui_element.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F44D2A6B1CA400A45078 /* ui_element.h */; }; + 0F75F51A2A6B1CA800A45078 /* menu_item.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F44E2A6B1CA400A45078 /* menu_item.cpp */; }; + 0F75F51B2A6B1CA800A45078 /* callback_merit.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F44F2A6B1CA400A45078 /* callback_merit.h */; }; + 0F75F51C2A6B1CA800A45078 /* foosortstring.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4502A6B1CA400A45078 /* foosortstring.h */; }; + 0F75F51D2A6B1CA800A45078 /* imageViewer.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4512A6B1CA400A45078 /* imageViewer.h */; }; + 0F75F51E2A6B1CA800A45078 /* popup_message.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F4522A6B1CA400A45078 /* popup_message.cpp */; }; + 0F75F51F2A6B1CA800A45078 /* fsItem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F4532A6B1CA400A45078 /* fsItem.cpp */; }; + 0F75F5202A6B1CA800A45078 /* cfg_var_legacy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F4542A6B1CA400A45078 /* cfg_var_legacy.cpp */; }; + 0F75F5212A6B1CA800A45078 /* vis.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4552A6B1CA500A45078 /* vis.h */; }; + 0F75F5222A6B1CA800A45078 /* console.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4562A6B1CA500A45078 /* console.h */; }; + 0F75F5232A6B1CA800A45078 /* componentversion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F4572A6B1CA500A45078 /* componentversion.cpp */; }; + 0F75F5242A6B1CA800A45078 /* chapterizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F4582A6B1CA500A45078 /* chapterizer.cpp */; }; + 0F75F5252A6B1CA800A45078 /* components_menu.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4592A6B1CA500A45078 /* components_menu.h */; }; + 0F75F5262A6B1CA800A45078 /* metadb_handle_list.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F45A2A6B1CA500A45078 /* metadb_handle_list.cpp */; }; + 0F75F5272A6B1CA800A45078 /* preferences_page.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F45B2A6B1CA500A45078 /* preferences_page.h */; }; + 0F75F5282A6B1CA800A45078 /* core_api.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F45C2A6B1CA500A45078 /* core_api.h */; }; + 0F75F5292A6B1CA800A45078 /* config_object_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F45D2A6B1CA500A45078 /* config_object_impl.h */; }; + 0F75F52A2A6B1CA800A45078 /* configCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F45E2A6B1CA500A45078 /* configCache.h */; }; + 0F75F52B2A6B1CA800A45078 /* metadb_display_field_provider.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F45F2A6B1CA500A45078 /* metadb_display_field_provider.h */; }; + 0F75F52C2A6B1CA800A45078 /* dsp-frontend.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4602A6B1CA500A45078 /* dsp-frontend.h */; }; + 0F75F52D2A6B1CA800A45078 /* foobar2000-sdk-pch.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4612A6B1CA500A45078 /* foobar2000-sdk-pch.h */; }; + 0F75F52E2A6B1CA800A45078 /* file_cached_impl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F4622A6B1CA500A45078 /* file_cached_impl.cpp */; }; + 0F75F52F2A6B1CA800A45078 /* replaygain_info.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F4632A6B1CA500A45078 /* replaygain_info.cpp */; }; + 0F75F5302A6B1CA800A45078 /* metadb_index.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4642A6B1CA500A45078 /* metadb_index.h */; }; + 0F75F5312A6B1CA800A45078 /* mainmenu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F4652A6B1CA500A45078 /* mainmenu.cpp */; }; + 0F75F5322A6B1CA800A45078 /* app_close_blocker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F4662A6B1CA500A45078 /* app_close_blocker.cpp */; }; + 0F75F5332A6B1CA800A45078 /* file_info_impl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F4672A6B1CA500A45078 /* file_info_impl.cpp */; }; + 0F75F5342A6B1CA800A45078 /* tag_processor_id3v2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F4682A6B1CA500A45078 /* tag_processor_id3v2.cpp */; }; + 0F75F5352A6B1CA800A45078 /* audio_postprocessor.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4692A6B1CA500A45078 /* audio_postprocessor.h */; }; + 0F75F5362A6B1CA800A45078 /* file_info.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F46A2A6B1CA500A45078 /* file_info.h */; }; + 0F75F5372A6B1CA800A45078 /* replaygain.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F46B2A6B1CA500A45078 /* replaygain.cpp */; }; + 0F75F5382A6B1CA800A45078 /* input.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F46C2A6B1CA500A45078 /* input.h */; }; + 0F75F5392A6B1CA800A45078 /* file_format_sanitizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F46D2A6B1CA600A45078 /* file_format_sanitizer.h */; }; + 0F75F53A2A6B1CA800A45078 /* commonObjects.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F46E2A6B1CA600A45078 /* commonObjects.h */; }; + 0F75F53B2A6B1CA800A45078 /* powerManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F46F2A6B1CA600A45078 /* powerManager.h */; }; + 0F75F53C2A6B1CA800A45078 /* popup_message.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4702A6B1CA600A45078 /* popup_message.h */; }; + 0F75F53D2A6B1CA800A45078 /* archive.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4712A6B1CA600A45078 /* archive.h */; }; + 0F75F53E2A6B1CA800A45078 /* system_time_keeper.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4722A6B1CA600A45078 /* system_time_keeper.h */; }; + 0F75F53F2A6B1CA800A45078 /* play_callback.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4732A6B1CA600A45078 /* play_callback.h */; }; + 0F75F5402A6B1CA800A45078 /* file_info_const_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4742A6B1CA600A45078 /* file_info_const_impl.h */; }; + 0F75F5412A6B1CA800A45078 /* file_operation_callback.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4752A6B1CA600A45078 /* file_operation_callback.h */; }; + 0F75F5422A6B1CA800A45078 /* album_art.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F4762A6B1CA600A45078 /* album_art.cpp */; }; + 0F75F5432A6B1CA800A45078 /* main_thread_callback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F4772A6B1CA600A45078 /* main_thread_callback.cpp */; }; + 0F75F5442A6B1CA800A45078 /* replaygain_scanner.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4782A6B1CA600A45078 /* replaygain_scanner.h */; }; + 0F75F5452A6B1CA800A45078 /* tag_processor.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4792A6B1CA600A45078 /* tag_processor.h */; }; + 0F75F5462A6B1CA800A45078 /* input_file_type.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F47A2A6B1CA700A45078 /* input_file_type.cpp */; }; + 0F75F5472A6B1CA800A45078 /* album_art.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F47B2A6B1CA700A45078 /* album_art.h */; }; + 0F75F5482A6B1CA800A45078 /* advconfig.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F47C2A6B1CA700A45078 /* advconfig.h */; }; + 0F75F5492A6B1CA800A45078 /* fsitem.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F47D2A6B1CA700A45078 /* fsitem.h */; }; + 0F75F54A2A6B1CA800A45078 /* icon_remap.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F47E2A6B1CA700A45078 /* icon_remap.h */; }; + 0F75F54B2A6B1CA800A45078 /* keyValueIOimpl.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F47F2A6B1CA700A45078 /* keyValueIOimpl.h */; }; + 0F75F54C2A6B1CA800A45078 /* fileDialog.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4802A6B1CA700A45078 /* fileDialog.h */; }; + 0F75F54D2A6B1CA800A45078 /* autoplaylist.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4812A6B1CA700A45078 /* autoplaylist.h */; }; + 0F75F54E2A6B1CA800A45078 /* input_file_type.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4822A6B1CA700A45078 /* input_file_type.h */; }; + 0F75F54F2A6B1CA800A45078 /* album_art_helpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4832A6B1CA700A45078 /* album_art_helpers.h */; }; + 0F75F5502A6B1CA800A45078 /* hasher_md5.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F4842A6B1CA700A45078 /* hasher_md5.cpp */; }; + 0F75F5512A6B1CA800A45078 /* message_loop.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4852A6B1CA700A45078 /* message_loop.h */; }; + 0F75F5522A6B1CA800A45078 /* playlist_loader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F4862A6B1CA700A45078 /* playlist_loader.cpp */; }; + 0F75F5532A6B1CA800A45078 /* service_by_guid.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4872A6B1CA700A45078 /* service_by_guid.h */; }; + 0F75F5542A6B1CA800A45078 /* library_manager.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4882A6B1CA700A45078 /* library_manager.h */; }; + 0F75F5552A6B1CA800A45078 /* foobar2000-lite.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4892A6B1CA700A45078 /* foobar2000-lite.h */; }; + 0F75F5562A6B1CA800A45078 /* commandline.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F48A2A6B1CA700A45078 /* commandline.h */; }; + 0F75F5572A6B1CA800A45078 /* coreversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F48B2A6B1CA700A45078 /* coreversion.h */; }; + 0F75F5582A6B1CA800A45078 /* dsp_manager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F48C2A6B1CA700A45078 /* dsp_manager.cpp */; }; + 0F75F5592A6B1CA800A45078 /* playback_control.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F48D2A6B1CA700A45078 /* playback_control.cpp */; }; + 0F75F55A2A6B1CA800A45078 /* foobar2000.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F48E2A6B1CA700A45078 /* foobar2000.h */; }; + 0F75F55B2A6B1CA800A45078 /* file_info_filter.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F48F2A6B1CA700A45078 /* file_info_filter.h */; }; + 0F75F55C2A6B1CA800A45078 /* metadb_handle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F4902A6B1CA800A45078 /* metadb_handle.cpp */; }; + 0F75F55D2A6B1CA800A45078 /* dsp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F4912A6B1CA800A45078 /* dsp.cpp */; }; + 0F75F55E2A6B1CA800A45078 /* cfg_var.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4922A6B1CA800A45078 /* cfg_var.h */; }; + 0F75F55F2A6B1CA800A45078 /* menu_helpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4932A6B1CA800A45078 /* menu_helpers.h */; }; + 0FCA711C2AA2210C001CB0F2 /* commonObjects-Apple.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0FCA711A2AA2210C001CB0F2 /* commonObjects-Apple.mm */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 0F75F3C82A6B1CA000A45078 /* foosort.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = foosort.cpp; sourceTree = ""; }; + 0F75F3C92A6B1CA000A45078 /* genrand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = genrand.h; sourceTree = ""; }; + 0F75F3CA2A6B1CA000A45078 /* ui_element_typable_window_manager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ui_element_typable_window_manager.h; sourceTree = ""; }; + 0F75F3CB2A6B1CA000A45078 /* titleformat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = titleformat.cpp; sourceTree = ""; }; + 0F75F3CC2A6B1CA000A45078 /* file_info_merge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = file_info_merge.cpp; sourceTree = ""; }; + 0F75F3CD2A6B1CA000A45078 /* audio_chunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = audio_chunk.h; sourceTree = ""; }; + 0F75F3CE2A6B1CA000A45078 /* output.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = output.h; sourceTree = ""; }; + 0F75F3CF2A6B1CA000A45078 /* file_operation_callback.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = file_operation_callback.cpp; sourceTree = ""; }; + 0F75F3D02A6B1CA000A45078 /* abort_callback.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = abort_callback.cpp; sourceTree = ""; }; + 0F75F3D12A6B1CA000A45078 /* playlist_loader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = playlist_loader.h; sourceTree = ""; }; + 0F75F3D22A6B1CA000A45078 /* threaded_process.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = threaded_process.h; sourceTree = ""; }; + 0F75F3D32A6B1CA000A45078 /* service_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = service_impl.h; sourceTree = ""; }; + 0F75F3D42A6B1CA000A45078 /* main_thread_callback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = main_thread_callback.h; sourceTree = ""; }; + 0F75F3D52A6B1CA000A45078 /* filesystem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = filesystem.cpp; sourceTree = ""; }; + 0F75F3D62A6B1CA000A45078 /* stdafx.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = stdafx.cpp; sourceTree = ""; }; + 0F75F3D72A6B1CA000A45078 /* progress_meter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = progress_meter.h; sourceTree = ""; }; + 0F75F3D82A6B1CA000A45078 /* app_close_blocker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = app_close_blocker.h; sourceTree = ""; }; + 0F75F3D92A6B1CA000A45078 /* mem_block_container.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mem_block_container.cpp; sourceTree = ""; }; + 0F75F3DA2A6B1CA000A45078 /* filesystem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = filesystem.h; sourceTree = ""; }; + 0F75F3DB2A6B1CA000A45078 /* commonObjects.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = commonObjects.cpp; sourceTree = ""; }; + 0F75F3DC2A6B1CA000A45078 /* threadPool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = threadPool.h; sourceTree = ""; }; + 0F75F3DD2A6B1CA000A45078 /* noInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = noInfo.h; sourceTree = ""; }; + 0F75F3DE2A6B1CA000A45078 /* unpack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = unpack.h; sourceTree = ""; }; + 0F75F3DF2A6B1CA000A45078 /* output.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = output.cpp; sourceTree = ""; }; + 0F75F3E02A6B1CA000A45078 /* menu_helpers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = menu_helpers.cpp; sourceTree = ""; }; + 0F75F3E12A6B1CA000A45078 /* service.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = service.h; sourceTree = ""; }; + 0F75F3E22A6B1CA100A45078 /* file_info_const_impl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = file_info_const_impl.cpp; sourceTree = ""; }; + 0F75F3E32A6B1CA100A45078 /* chapterizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = chapterizer.h; sourceTree = ""; }; + 0F75F3E42A6B1CA100A45078 /* audio_chunk_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = audio_chunk_impl.h; sourceTree = ""; }; + 0F75F3E52A6B1CA100A45078 /* audio_chunk_channel_config.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = audio_chunk_channel_config.cpp; sourceTree = ""; }; + 0F75F3E62A6B1CA100A45078 /* event_logger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = event_logger.h; sourceTree = ""; }; + 0F75F3E72A6B1CA100A45078 /* foobar2000-pfc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "foobar2000-pfc.h"; sourceTree = ""; }; + 0F75F3E82A6B1CA100A45078 /* http_client.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = http_client.h; sourceTree = ""; }; + 0F75F3E92A6B1CA100A45078 /* hasher_md5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hasher_md5.h; sourceTree = ""; }; + 0F75F3EA2A6B1CA100A45078 /* component.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = component.h; sourceTree = ""; }; + 0F75F3EB2A6B1CA100A45078 /* forward_types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = forward_types.h; sourceTree = ""; }; + 0F75F3EC2A6B1CA100A45078 /* replaygain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = replaygain.h; sourceTree = ""; }; + 0F75F3ED2A6B1CA100A45078 /* metadb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = metadb.h; sourceTree = ""; }; + 0F75F3EE2A6B1CA100A45078 /* menu_manager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = menu_manager.cpp; sourceTree = ""; }; + 0F75F3EF2A6B1CA100A45078 /* resampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = resampler.h; sourceTree = ""; }; + 0F75F3F02A6B1CA100A45078 /* initquit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = initquit.h; sourceTree = ""; }; + 0F75F3F12A6B1CA100A45078 /* foobar2000-winver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "foobar2000-winver.h"; sourceTree = ""; }; + 0F75F3F22A6B1CA100A45078 /* timer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = timer.h; sourceTree = ""; }; + 0F75F3F32A6B1CA100A45078 /* playlist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = playlist.h; sourceTree = ""; }; + 0F75F3F42A6B1CA100A45078 /* track_property.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = track_property.cpp; sourceTree = ""; }; + 0F75F3F52A6B1CA100A45078 /* ui.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ui.cpp; sourceTree = ""; }; + 0F75F3F62A6B1CA100A45078 /* titleformat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = titleformat.h; sourceTree = ""; }; + 0F75F3F72A6B1CA100A45078 /* file_info_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = file_info_impl.h; sourceTree = ""; }; + 0F75F3F82A6B1CA100A45078 /* filesystem_helper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = filesystem_helper.cpp; sourceTree = ""; }; + 0F75F3F92A6B1CA100A45078 /* filesystem_helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = filesystem_helper.h; sourceTree = ""; }; + 0F75F3FA2A6B1CA100A45078 /* audio_chunk.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = audio_chunk.cpp; sourceTree = ""; }; + 0F75F3FB2A6B1CA100A45078 /* console_manager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = console_manager.h; sourceTree = ""; }; + 0F75F3FC2A6B1CA100A45078 /* filesystem_transacted.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = filesystem_transacted.h; sourceTree = ""; }; + 0F75F3FD2A6B1CA100A45078 /* service.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = service.cpp; sourceTree = ""; }; + 0F75F3FE2A6B1CA200A45078 /* threaded_process.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = threaded_process.cpp; sourceTree = ""; }; + 0F75F3FF2A6B1CA200A45078 /* coreDarkMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = coreDarkMode.h; sourceTree = ""; }; + 0F75F4002A6B1CA200A45078 /* cfg_var_legacy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cfg_var_legacy.h; sourceTree = ""; }; + 0F75F4012A6B1CA200A45078 /* menu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = menu.h; sourceTree = ""; }; + 0F75F4022A6B1CA200A45078 /* file_info_filter_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = file_info_filter_impl.h; sourceTree = ""; }; + 0F75F4032A6B1CA200A45078 /* advconfig.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = advconfig.cpp; sourceTree = ""; }; + 0F75F4042A6B1CA200A45078 /* packet_decoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = packet_decoder.h; sourceTree = ""; }; + 0F75F4052A6B1CA200A45078 /* decode_postprocessor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = decode_postprocessor.h; sourceTree = ""; }; + 0F75F4062A6B1CA200A45078 /* exception_io.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = exception_io.h; sourceTree = ""; }; + 0F75F4072A6B1CA200A45078 /* search_tools.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = search_tools.h; sourceTree = ""; }; + 0F75F4082A6B1CA200A45078 /* metadb_callbacks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = metadb_callbacks.h; sourceTree = ""; }; + 0F75F4092A6B1CA200A45078 /* configStore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = configStore.cpp; sourceTree = ""; }; + 0F75F40A2A6B1CA200A45078 /* modeless_dialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = modeless_dialog.h; sourceTree = ""; }; + 0F75F40B2A6B1CA200A45078 /* foosort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = foosort.h; sourceTree = ""; }; + 0F75F40C2A6B1CA200A45078 /* console.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = console.cpp; sourceTree = ""; }; + 0F75F40D2A6B1CA200A45078 /* playback_control.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = playback_control.h; sourceTree = ""; }; + 0F75F40E2A6B1CA200A45078 /* playback_stream_capture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = playback_stream_capture.h; sourceTree = ""; }; + 0F75F40F2A6B1CA200A45078 /* file_info.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = file_info.cpp; sourceTree = ""; }; + 0F75F4102A6B1CA200A45078 /* dsp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dsp.h; sourceTree = ""; }; + 0F75F4112A6B1CA200A45078 /* library_callbacks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = library_callbacks.h; sourceTree = ""; }; + 0F75F4122A6B1CA200A45078 /* threadsLite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = threadsLite.h; sourceTree = ""; }; + 0F75F4132A6B1CA200A45078 /* mem_block_container.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mem_block_container.h; sourceTree = ""; }; + 0F75F4142A6B1CA200A45078 /* foobar2000-all.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "foobar2000-all.h"; sourceTree = ""; }; + 0F75F4152A6B1CA200A45078 /* image.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = image.cpp; sourceTree = ""; }; + 0F75F4162A6B1CA200A45078 /* utility.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = utility.cpp; sourceTree = ""; }; + 0F75F4172A6B1CA200A45078 /* track_property.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = track_property.h; sourceTree = ""; }; + 0F75F4182A6B1CA200A45078 /* cfg_var.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cfg_var.cpp; sourceTree = ""; }; + 0F75F4192A6B1CA200A45078 /* shortcut_actions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = shortcut_actions.h; sourceTree = ""; }; + 0F75F41A2A6B1CA200A45078 /* foosortstring.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = foosortstring.cpp; sourceTree = ""; }; + 0F75F41B2A6B1CA200A45078 /* exceptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = exceptions.h; sourceTree = ""; }; + 0F75F41C2A6B1CA200A45078 /* component_client.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = component_client.h; sourceTree = ""; }; + 0F75F41D2A6B1CA200A45078 /* playable_location.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = playable_location.cpp; sourceTree = ""; }; + 0F75F41E2A6B1CA200A45078 /* metadb.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = metadb.cpp; sourceTree = ""; }; + 0F75F41F2A6B1CA200A45078 /* input_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = input_impl.h; sourceTree = ""; }; + 0F75F4202A6B1CA200A45078 /* service_compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = service_compat.h; sourceTree = ""; }; + 0F75F4212A6B1CA300A45078 /* keyValueIO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = keyValueIO.h; sourceTree = ""; }; + 0F75F4222A6B1CA300A45078 /* tracks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tracks.h; sourceTree = ""; }; + 0F75F4232A6B1CA300A45078 /* playlistColumnProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = playlistColumnProvider.h; sourceTree = ""; }; + 0F75F4242A6B1CA300A45078 /* imageLoaderLite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = imageLoaderLite.h; sourceTree = ""; }; + 0F75F4252A6B1CA300A45078 /* playlist.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = playlist.cpp; sourceTree = ""; }; + 0F75F4262A6B1CA300A45078 /* preferences_page.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = preferences_page.cpp; sourceTree = ""; }; + 0F75F4272A6B1CA300A45078 /* config_io_callback.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = config_io_callback.cpp; sourceTree = ""; }; + 0F75F4282A6B1CA300A45078 /* packet_decoder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = packet_decoder.cpp; sourceTree = ""; }; + 0F75F4292A6B1CA300A45078 /* ole_interaction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ole_interaction.h; sourceTree = ""; }; + 0F75F42A2A6B1CA300A45078 /* info_lookup_handler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = info_lookup_handler.h; sourceTree = ""; }; + 0F75F42B2A6B1CA300A45078 /* library_index.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = library_index.h; sourceTree = ""; }; + 0F75F42C2A6B1CA300A45078 /* audioEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = audioEncoder.h; sourceTree = ""; }; + 0F75F42D2A6B1CA300A45078 /* commandline.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = commandline.cpp; sourceTree = ""; }; + 0F75F42E2A6B1CA300A45078 /* image.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = image.h; sourceTree = ""; }; + 0F75F42F2A6B1CA300A45078 /* link_resolver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = link_resolver.cpp; sourceTree = ""; }; + 0F75F4302A6B1CA300A45078 /* metadb_handle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = metadb_handle.h; sourceTree = ""; }; + 0F75F4312A6B1CA300A45078 /* advconfig_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = advconfig_impl.h; sourceTree = ""; }; + 0F75F4322A6B1CA300A45078 /* foobar2000-versions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "foobar2000-versions.h"; sourceTree = ""; }; + 0F75F4332A6B1CA300A45078 /* componentversion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = componentversion.h; sourceTree = ""; }; + 0F75F4342A6B1CA300A45078 /* contextmenu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = contextmenu.h; sourceTree = ""; }; + 0F75F4352A6B1CA300A45078 /* advconfig_impl_legacy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = advconfig_impl_legacy.h; sourceTree = ""; }; + 0F75F4362A6B1CA300A45078 /* file.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = file.h; sourceTree = ""; }; + 0F75F4372A6B1CA300A45078 /* ui_element.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ui_element.cpp; sourceTree = ""; }; + 0F75F4382A6B1CA300A45078 /* guids.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = guids.cpp; sourceTree = ""; }; + 0F75F4392A6B1CA300A45078 /* tag_processor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tag_processor.cpp; sourceTree = ""; }; + 0F75F43A2A6B1CA300A45078 /* config_object.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config_object.h; sourceTree = ""; }; + 0F75F43B2A6B1CA300A45078 /* config_object.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = config_object.cpp; sourceTree = ""; }; + 0F75F43C2A6B1CA300A45078 /* ui.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ui.h; sourceTree = ""; }; + 0F75F43D2A6B1CA300A45078 /* link_resolver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = link_resolver.h; sourceTree = ""; }; + 0F75F43E2A6B1CA300A45078 /* playable_location.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = playable_location.h; sourceTree = ""; }; + 0F75F43F2A6B1CA300A45078 /* file_lock_manager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = file_lock_manager.h; sourceTree = ""; }; + 0F75F4402A6B1CA300A45078 /* configStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = configStore.h; sourceTree = ""; }; + 0F75F4412A6B1CA300A45078 /* input.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = input.cpp; sourceTree = ""; }; + 0F75F4422A6B1CA300A45078 /* contextmenu_manager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = contextmenu_manager.h; sourceTree = ""; }; + 0F75F4432A6B1CA400A45078 /* config_io_callback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config_io_callback.h; sourceTree = ""; }; + 0F75F4442A6B1CA400A45078 /* menu_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = menu_common.h; sourceTree = ""; }; + 0F75F4452A6B1CA400A45078 /* completion_notify.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = completion_notify.cpp; sourceTree = ""; }; + 0F75F4462A6B1CA400A45078 /* metadb_info_container_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = metadb_info_container_impl.h; sourceTree = ""; }; + 0F75F4472A6B1CA400A45078 /* abort_callback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = abort_callback.h; sourceTree = ""; }; + 0F75F4482A6B1CA400A45078 /* completion_notify.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = completion_notify.h; sourceTree = ""; }; + 0F75F4492A6B1CA400A45078 /* toolbarDropDown.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = toolbarDropDown.h; sourceTree = ""; }; + 0F75F44A2A6B1CA400A45078 /* dsp_manager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dsp_manager.h; sourceTree = ""; }; + 0F75F44B2A6B1CA400A45078 /* messageBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = messageBox.h; sourceTree = ""; }; + 0F75F44C2A6B1CA400A45078 /* ui_edit_context.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ui_edit_context.h; sourceTree = ""; }; + 0F75F44D2A6B1CA400A45078 /* ui_element.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ui_element.h; sourceTree = ""; }; + 0F75F44E2A6B1CA400A45078 /* menu_item.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = menu_item.cpp; sourceTree = ""; }; + 0F75F44F2A6B1CA400A45078 /* callback_merit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = callback_merit.h; sourceTree = ""; }; + 0F75F4502A6B1CA400A45078 /* foosortstring.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = foosortstring.h; sourceTree = ""; }; + 0F75F4512A6B1CA400A45078 /* imageViewer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = imageViewer.h; sourceTree = ""; }; + 0F75F4522A6B1CA400A45078 /* popup_message.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = popup_message.cpp; sourceTree = ""; }; + 0F75F4532A6B1CA400A45078 /* fsItem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = fsItem.cpp; sourceTree = ""; }; + 0F75F4542A6B1CA400A45078 /* cfg_var_legacy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cfg_var_legacy.cpp; sourceTree = ""; }; + 0F75F4552A6B1CA500A45078 /* vis.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vis.h; sourceTree = ""; }; + 0F75F4562A6B1CA500A45078 /* console.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = console.h; sourceTree = ""; }; + 0F75F4572A6B1CA500A45078 /* componentversion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = componentversion.cpp; sourceTree = ""; }; + 0F75F4582A6B1CA500A45078 /* chapterizer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = chapterizer.cpp; sourceTree = ""; }; + 0F75F4592A6B1CA500A45078 /* components_menu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = components_menu.h; sourceTree = ""; }; + 0F75F45A2A6B1CA500A45078 /* metadb_handle_list.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = metadb_handle_list.cpp; sourceTree = ""; }; + 0F75F45B2A6B1CA500A45078 /* preferences_page.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = preferences_page.h; sourceTree = ""; }; + 0F75F45C2A6B1CA500A45078 /* core_api.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = core_api.h; sourceTree = ""; }; + 0F75F45D2A6B1CA500A45078 /* config_object_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config_object_impl.h; sourceTree = ""; }; + 0F75F45E2A6B1CA500A45078 /* configCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = configCache.h; sourceTree = ""; }; + 0F75F45F2A6B1CA500A45078 /* metadb_display_field_provider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = metadb_display_field_provider.h; sourceTree = ""; }; + 0F75F4602A6B1CA500A45078 /* dsp-frontend.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "dsp-frontend.h"; sourceTree = ""; }; + 0F75F4612A6B1CA500A45078 /* foobar2000-sdk-pch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "foobar2000-sdk-pch.h"; sourceTree = ""; }; + 0F75F4622A6B1CA500A45078 /* file_cached_impl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = file_cached_impl.cpp; sourceTree = ""; }; + 0F75F4632A6B1CA500A45078 /* replaygain_info.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = replaygain_info.cpp; sourceTree = ""; }; + 0F75F4642A6B1CA500A45078 /* metadb_index.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = metadb_index.h; sourceTree = ""; }; + 0F75F4652A6B1CA500A45078 /* mainmenu.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mainmenu.cpp; sourceTree = ""; }; + 0F75F4662A6B1CA500A45078 /* app_close_blocker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = app_close_blocker.cpp; sourceTree = ""; }; + 0F75F4672A6B1CA500A45078 /* file_info_impl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = file_info_impl.cpp; sourceTree = ""; }; + 0F75F4682A6B1CA500A45078 /* tag_processor_id3v2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tag_processor_id3v2.cpp; sourceTree = ""; }; + 0F75F4692A6B1CA500A45078 /* audio_postprocessor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = audio_postprocessor.h; sourceTree = ""; }; + 0F75F46A2A6B1CA500A45078 /* file_info.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = file_info.h; sourceTree = ""; }; + 0F75F46B2A6B1CA500A45078 /* replaygain.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = replaygain.cpp; sourceTree = ""; }; + 0F75F46C2A6B1CA500A45078 /* input.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = input.h; sourceTree = ""; }; + 0F75F46D2A6B1CA600A45078 /* file_format_sanitizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = file_format_sanitizer.h; sourceTree = ""; }; + 0F75F46E2A6B1CA600A45078 /* commonObjects.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = commonObjects.h; sourceTree = ""; }; + 0F75F46F2A6B1CA600A45078 /* powerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = powerManager.h; sourceTree = ""; }; + 0F75F4702A6B1CA600A45078 /* popup_message.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = popup_message.h; sourceTree = ""; }; + 0F75F4712A6B1CA600A45078 /* archive.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = archive.h; sourceTree = ""; }; + 0F75F4722A6B1CA600A45078 /* system_time_keeper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = system_time_keeper.h; sourceTree = ""; }; + 0F75F4732A6B1CA600A45078 /* play_callback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = play_callback.h; sourceTree = ""; }; + 0F75F4742A6B1CA600A45078 /* file_info_const_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = file_info_const_impl.h; sourceTree = ""; }; + 0F75F4752A6B1CA600A45078 /* file_operation_callback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = file_operation_callback.h; sourceTree = ""; }; + 0F75F4762A6B1CA600A45078 /* album_art.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = album_art.cpp; sourceTree = ""; }; + 0F75F4772A6B1CA600A45078 /* main_thread_callback.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main_thread_callback.cpp; sourceTree = ""; }; + 0F75F4782A6B1CA600A45078 /* replaygain_scanner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = replaygain_scanner.h; sourceTree = ""; }; + 0F75F4792A6B1CA600A45078 /* tag_processor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tag_processor.h; sourceTree = ""; }; + 0F75F47A2A6B1CA700A45078 /* input_file_type.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = input_file_type.cpp; sourceTree = ""; }; + 0F75F47B2A6B1CA700A45078 /* album_art.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = album_art.h; sourceTree = ""; }; + 0F75F47C2A6B1CA700A45078 /* advconfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = advconfig.h; sourceTree = ""; }; + 0F75F47D2A6B1CA700A45078 /* fsitem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fsitem.h; sourceTree = ""; }; + 0F75F47E2A6B1CA700A45078 /* icon_remap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = icon_remap.h; sourceTree = ""; }; + 0F75F47F2A6B1CA700A45078 /* keyValueIOimpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = keyValueIOimpl.h; sourceTree = ""; }; + 0F75F4802A6B1CA700A45078 /* fileDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fileDialog.h; sourceTree = ""; }; + 0F75F4812A6B1CA700A45078 /* autoplaylist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = autoplaylist.h; sourceTree = ""; }; + 0F75F4822A6B1CA700A45078 /* input_file_type.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = input_file_type.h; sourceTree = ""; }; + 0F75F4832A6B1CA700A45078 /* album_art_helpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = album_art_helpers.h; sourceTree = ""; }; + 0F75F4842A6B1CA700A45078 /* hasher_md5.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = hasher_md5.cpp; sourceTree = ""; }; + 0F75F4852A6B1CA700A45078 /* message_loop.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = message_loop.h; sourceTree = ""; }; + 0F75F4862A6B1CA700A45078 /* playlist_loader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = playlist_loader.cpp; sourceTree = ""; }; + 0F75F4872A6B1CA700A45078 /* service_by_guid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = service_by_guid.h; sourceTree = ""; }; + 0F75F4882A6B1CA700A45078 /* library_manager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = library_manager.h; sourceTree = ""; }; + 0F75F4892A6B1CA700A45078 /* foobar2000-lite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "foobar2000-lite.h"; sourceTree = ""; }; + 0F75F48A2A6B1CA700A45078 /* commandline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = commandline.h; sourceTree = ""; }; + 0F75F48B2A6B1CA700A45078 /* coreversion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = coreversion.h; sourceTree = ""; }; + 0F75F48C2A6B1CA700A45078 /* dsp_manager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dsp_manager.cpp; sourceTree = ""; }; + 0F75F48D2A6B1CA700A45078 /* playback_control.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = playback_control.cpp; sourceTree = ""; }; + 0F75F48E2A6B1CA700A45078 /* foobar2000.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = foobar2000.h; sourceTree = ""; }; + 0F75F48F2A6B1CA700A45078 /* file_info_filter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = file_info_filter.h; sourceTree = ""; }; + 0F75F4902A6B1CA800A45078 /* metadb_handle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = metadb_handle.cpp; sourceTree = ""; }; + 0F75F4912A6B1CA800A45078 /* dsp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dsp.cpp; sourceTree = ""; }; + 0F75F4922A6B1CA800A45078 /* cfg_var.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cfg_var.h; sourceTree = ""; }; + 0F75F4932A6B1CA800A45078 /* menu_helpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = menu_helpers.h; sourceTree = ""; }; + 0FCA711A2AA2210C001CB0F2 /* commonObjects-Apple.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = "commonObjects-Apple.mm"; sourceTree = ""; }; + 0FCA711E2AA2715E001CB0F2 /* commonObjects-Apple.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "commonObjects-Apple.h"; sourceTree = ""; }; + B166962019ACC1450001728F /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + B166962E19ACC1450001728F /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; + B166963119ACC1450001728F /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; }; + B1DD3657198A721800EF7043 /* libfoobar2000_SDK.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libfoobar2000_SDK.a; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + B1DD3654198A721800EF7043 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + B166961F19ACC1450001728F /* Frameworks */ = { + isa = PBXGroup; + children = ( + B166962019ACC1450001728F /* Foundation.framework */, + B166962E19ACC1450001728F /* XCTest.framework */, + B166963119ACC1450001728F /* UIKit.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + B1DD364E198A721800EF7043 = { + isa = PBXGroup; + children = ( + B1DD3670198A725100EF7043 /* Source */, + B166961F19ACC1450001728F /* Frameworks */, + B1DD3658198A721800EF7043 /* Products */, + ); + sourceTree = ""; + }; + B1DD3658198A721800EF7043 /* Products */ = { + isa = PBXGroup; + children = ( + B1DD3657198A721800EF7043 /* libfoobar2000_SDK.a */, + ); + name = Products; + sourceTree = ""; + }; + B1DD3670198A725100EF7043 /* Source */ = { + isa = PBXGroup; + children = ( + 0F75F3D02A6B1CA000A45078 /* abort_callback.cpp */, + 0F75F4472A6B1CA400A45078 /* abort_callback.h */, + 0F75F4352A6B1CA300A45078 /* advconfig_impl_legacy.h */, + 0F75F4312A6B1CA300A45078 /* advconfig_impl.h */, + 0F75F4032A6B1CA200A45078 /* advconfig.cpp */, + 0F75F47C2A6B1CA700A45078 /* advconfig.h */, + 0F75F4832A6B1CA700A45078 /* album_art_helpers.h */, + 0F75F4762A6B1CA600A45078 /* album_art.cpp */, + 0F75F47B2A6B1CA700A45078 /* album_art.h */, + 0F75F4662A6B1CA500A45078 /* app_close_blocker.cpp */, + 0F75F3D82A6B1CA000A45078 /* app_close_blocker.h */, + 0F75F4712A6B1CA600A45078 /* archive.h */, + 0F75F3E52A6B1CA100A45078 /* audio_chunk_channel_config.cpp */, + 0F75F3E42A6B1CA100A45078 /* audio_chunk_impl.h */, + 0F75F3FA2A6B1CA100A45078 /* audio_chunk.cpp */, + 0F75F3CD2A6B1CA000A45078 /* audio_chunk.h */, + 0F75F4692A6B1CA500A45078 /* audio_postprocessor.h */, + 0F75F42C2A6B1CA300A45078 /* audioEncoder.h */, + 0F75F4812A6B1CA700A45078 /* autoplaylist.h */, + 0F75F44F2A6B1CA400A45078 /* callback_merit.h */, + 0F75F4542A6B1CA400A45078 /* cfg_var_legacy.cpp */, + 0F75F4002A6B1CA200A45078 /* cfg_var_legacy.h */, + 0F75F4182A6B1CA200A45078 /* cfg_var.cpp */, + 0F75F4922A6B1CA800A45078 /* cfg_var.h */, + 0F75F4582A6B1CA500A45078 /* chapterizer.cpp */, + 0F75F3E32A6B1CA100A45078 /* chapterizer.h */, + 0F75F42D2A6B1CA300A45078 /* commandline.cpp */, + 0F75F48A2A6B1CA700A45078 /* commandline.h */, + 0F75F3DB2A6B1CA000A45078 /* commonObjects.cpp */, + 0F75F46E2A6B1CA600A45078 /* commonObjects.h */, + 0F75F4452A6B1CA400A45078 /* completion_notify.cpp */, + 0F75F4482A6B1CA400A45078 /* completion_notify.h */, + 0F75F41C2A6B1CA200A45078 /* component_client.h */, + 0F75F3EA2A6B1CA100A45078 /* component.h */, + 0F75F4592A6B1CA500A45078 /* components_menu.h */, + 0F75F4572A6B1CA500A45078 /* componentversion.cpp */, + 0F75F4332A6B1CA300A45078 /* componentversion.h */, + 0F75F4272A6B1CA300A45078 /* config_io_callback.cpp */, + 0F75F4432A6B1CA400A45078 /* config_io_callback.h */, + 0F75F45D2A6B1CA500A45078 /* config_object_impl.h */, + 0F75F43B2A6B1CA300A45078 /* config_object.cpp */, + 0F75F43A2A6B1CA300A45078 /* config_object.h */, + 0F75F45E2A6B1CA500A45078 /* configCache.h */, + 0F75F4092A6B1CA200A45078 /* configStore.cpp */, + 0F75F4402A6B1CA300A45078 /* configStore.h */, + 0F75F3FB2A6B1CA100A45078 /* console_manager.h */, + 0F75F40C2A6B1CA200A45078 /* console.cpp */, + 0F75F4562A6B1CA500A45078 /* console.h */, + 0F75F4422A6B1CA300A45078 /* contextmenu_manager.h */, + 0F75F4342A6B1CA300A45078 /* contextmenu.h */, + 0F75F45C2A6B1CA500A45078 /* core_api.h */, + 0F75F3FF2A6B1CA200A45078 /* coreDarkMode.h */, + 0F75F48B2A6B1CA700A45078 /* coreversion.h */, + 0F75F4052A6B1CA200A45078 /* decode_postprocessor.h */, + 0F75F48C2A6B1CA700A45078 /* dsp_manager.cpp */, + 0F75F44A2A6B1CA400A45078 /* dsp_manager.h */, + 0F75F4602A6B1CA500A45078 /* dsp-frontend.h */, + 0F75F4912A6B1CA800A45078 /* dsp.cpp */, + 0F75F4102A6B1CA200A45078 /* dsp.h */, + 0F75F3E62A6B1CA100A45078 /* event_logger.h */, + 0F75F4062A6B1CA200A45078 /* exception_io.h */, + 0F75F41B2A6B1CA200A45078 /* exceptions.h */, + 0F75F4622A6B1CA500A45078 /* file_cached_impl.cpp */, + 0F75F46D2A6B1CA600A45078 /* file_format_sanitizer.h */, + 0F75F3E22A6B1CA100A45078 /* file_info_const_impl.cpp */, + 0F75F4742A6B1CA600A45078 /* file_info_const_impl.h */, + 0F75F4022A6B1CA200A45078 /* file_info_filter_impl.h */, + 0F75F48F2A6B1CA700A45078 /* file_info_filter.h */, + 0F75F4672A6B1CA500A45078 /* file_info_impl.cpp */, + 0F75F3F72A6B1CA100A45078 /* file_info_impl.h */, + 0F75F3CC2A6B1CA000A45078 /* file_info_merge.cpp */, + 0F75F40F2A6B1CA200A45078 /* file_info.cpp */, + 0F75F46A2A6B1CA500A45078 /* file_info.h */, + 0F75F43F2A6B1CA300A45078 /* file_lock_manager.h */, + 0F75F3CF2A6B1CA000A45078 /* file_operation_callback.cpp */, + 0F75F4752A6B1CA600A45078 /* file_operation_callback.h */, + 0F75F4362A6B1CA300A45078 /* file.h */, + 0F75F4802A6B1CA700A45078 /* fileDialog.h */, + 0F75F3F82A6B1CA100A45078 /* filesystem_helper.cpp */, + 0F75F3F92A6B1CA100A45078 /* filesystem_helper.h */, + 0F75F3FC2A6B1CA100A45078 /* filesystem_transacted.h */, + 0F75F3D52A6B1CA000A45078 /* filesystem.cpp */, + 0F75F3DA2A6B1CA000A45078 /* filesystem.h */, + 0F75F4142A6B1CA200A45078 /* foobar2000-all.h */, + 0F75F4892A6B1CA700A45078 /* foobar2000-lite.h */, + 0F75F3E72A6B1CA100A45078 /* foobar2000-pfc.h */, + 0F75F4612A6B1CA500A45078 /* foobar2000-sdk-pch.h */, + 0F75F4322A6B1CA300A45078 /* foobar2000-versions.h */, + 0F75F3F12A6B1CA100A45078 /* foobar2000-winver.h */, + 0F75F48E2A6B1CA700A45078 /* foobar2000.h */, + 0F75F3C82A6B1CA000A45078 /* foosort.cpp */, + 0F75F40B2A6B1CA200A45078 /* foosort.h */, + 0F75F41A2A6B1CA200A45078 /* foosortstring.cpp */, + 0F75F4502A6B1CA400A45078 /* foosortstring.h */, + 0F75F3EB2A6B1CA100A45078 /* forward_types.h */, + 0F75F4532A6B1CA400A45078 /* fsItem.cpp */, + 0F75F47D2A6B1CA700A45078 /* fsitem.h */, + 0F75F3C92A6B1CA000A45078 /* genrand.h */, + 0F75F4382A6B1CA300A45078 /* guids.cpp */, + 0F75F4842A6B1CA700A45078 /* hasher_md5.cpp */, + 0F75F3E92A6B1CA100A45078 /* hasher_md5.h */, + 0F75F3E82A6B1CA100A45078 /* http_client.h */, + 0F75F47E2A6B1CA700A45078 /* icon_remap.h */, + 0F75F4152A6B1CA200A45078 /* image.cpp */, + 0F75F42E2A6B1CA300A45078 /* image.h */, + 0F75F4242A6B1CA300A45078 /* imageLoaderLite.h */, + 0F75F4512A6B1CA400A45078 /* imageViewer.h */, + 0F75F42A2A6B1CA300A45078 /* info_lookup_handler.h */, + 0F75F3F02A6B1CA100A45078 /* initquit.h */, + 0F75F47A2A6B1CA700A45078 /* input_file_type.cpp */, + 0F75F4822A6B1CA700A45078 /* input_file_type.h */, + 0F75F41F2A6B1CA200A45078 /* input_impl.h */, + 0F75F4412A6B1CA300A45078 /* input.cpp */, + 0F75F46C2A6B1CA500A45078 /* input.h */, + 0F75F4212A6B1CA300A45078 /* keyValueIO.h */, + 0F75F47F2A6B1CA700A45078 /* keyValueIOimpl.h */, + 0F75F4112A6B1CA200A45078 /* library_callbacks.h */, + 0F75F42B2A6B1CA300A45078 /* library_index.h */, + 0F75F4882A6B1CA700A45078 /* library_manager.h */, + 0F75F42F2A6B1CA300A45078 /* link_resolver.cpp */, + 0F75F43D2A6B1CA300A45078 /* link_resolver.h */, + 0F75F4772A6B1CA600A45078 /* main_thread_callback.cpp */, + 0F75F3D42A6B1CA000A45078 /* main_thread_callback.h */, + 0F75F4652A6B1CA500A45078 /* mainmenu.cpp */, + 0F75F3D92A6B1CA000A45078 /* mem_block_container.cpp */, + 0F75F4132A6B1CA200A45078 /* mem_block_container.h */, + 0F75F4442A6B1CA400A45078 /* menu_common.h */, + 0F75F3E02A6B1CA000A45078 /* menu_helpers.cpp */, + 0F75F4932A6B1CA800A45078 /* menu_helpers.h */, + 0F75F44E2A6B1CA400A45078 /* menu_item.cpp */, + 0F75F3EE2A6B1CA100A45078 /* menu_manager.cpp */, + 0F75F4012A6B1CA200A45078 /* menu.h */, + 0F75F4852A6B1CA700A45078 /* message_loop.h */, + 0F75F44B2A6B1CA400A45078 /* messageBox.h */, + 0F75F4082A6B1CA200A45078 /* metadb_callbacks.h */, + 0F75F45F2A6B1CA500A45078 /* metadb_display_field_provider.h */, + 0F75F45A2A6B1CA500A45078 /* metadb_handle_list.cpp */, + 0F75F4902A6B1CA800A45078 /* metadb_handle.cpp */, + 0F75F4302A6B1CA300A45078 /* metadb_handle.h */, + 0F75F4642A6B1CA500A45078 /* metadb_index.h */, + 0F75F4462A6B1CA400A45078 /* metadb_info_container_impl.h */, + 0F75F41E2A6B1CA200A45078 /* metadb.cpp */, + 0F75F3ED2A6B1CA100A45078 /* metadb.h */, + 0F75F40A2A6B1CA200A45078 /* modeless_dialog.h */, + 0F75F3DD2A6B1CA000A45078 /* noInfo.h */, + 0F75F4292A6B1CA300A45078 /* ole_interaction.h */, + 0F75F3DF2A6B1CA000A45078 /* output.cpp */, + 0F75F3CE2A6B1CA000A45078 /* output.h */, + 0F75F4282A6B1CA300A45078 /* packet_decoder.cpp */, + 0F75F4042A6B1CA200A45078 /* packet_decoder.h */, + 0F75F4732A6B1CA600A45078 /* play_callback.h */, + 0F75F41D2A6B1CA200A45078 /* playable_location.cpp */, + 0F75F43E2A6B1CA300A45078 /* playable_location.h */, + 0F75F48D2A6B1CA700A45078 /* playback_control.cpp */, + 0F75F40D2A6B1CA200A45078 /* playback_control.h */, + 0F75F40E2A6B1CA200A45078 /* playback_stream_capture.h */, + 0F75F4862A6B1CA700A45078 /* playlist_loader.cpp */, + 0F75F3D12A6B1CA000A45078 /* playlist_loader.h */, + 0F75F4252A6B1CA300A45078 /* playlist.cpp */, + 0F75F3F32A6B1CA100A45078 /* playlist.h */, + 0F75F4232A6B1CA300A45078 /* playlistColumnProvider.h */, + 0F75F4522A6B1CA400A45078 /* popup_message.cpp */, + 0F75F4702A6B1CA600A45078 /* popup_message.h */, + 0F75F46F2A6B1CA600A45078 /* powerManager.h */, + 0F75F4262A6B1CA300A45078 /* preferences_page.cpp */, + 0F75F45B2A6B1CA500A45078 /* preferences_page.h */, + 0F75F3D72A6B1CA000A45078 /* progress_meter.h */, + 0F75F4632A6B1CA500A45078 /* replaygain_info.cpp */, + 0F75F4782A6B1CA600A45078 /* replaygain_scanner.h */, + 0F75F46B2A6B1CA500A45078 /* replaygain.cpp */, + 0F75F3EC2A6B1CA100A45078 /* replaygain.h */, + 0F75F3EF2A6B1CA100A45078 /* resampler.h */, + 0F75F4072A6B1CA200A45078 /* search_tools.h */, + 0F75F4872A6B1CA700A45078 /* service_by_guid.h */, + 0F75F4202A6B1CA200A45078 /* service_compat.h */, + 0F75F3D32A6B1CA000A45078 /* service_impl.h */, + 0F75F3FD2A6B1CA100A45078 /* service.cpp */, + 0F75F3E12A6B1CA000A45078 /* service.h */, + 0F75F4192A6B1CA200A45078 /* shortcut_actions.h */, + 0F75F3D62A6B1CA000A45078 /* stdafx.cpp */, + 0F75F4722A6B1CA600A45078 /* system_time_keeper.h */, + 0F75F4682A6B1CA500A45078 /* tag_processor_id3v2.cpp */, + 0F75F4392A6B1CA300A45078 /* tag_processor.cpp */, + 0F75F4792A6B1CA600A45078 /* tag_processor.h */, + 0F75F3FE2A6B1CA200A45078 /* threaded_process.cpp */, + 0F75F3D22A6B1CA000A45078 /* threaded_process.h */, + 0F75F3DC2A6B1CA000A45078 /* threadPool.h */, + 0F75F4122A6B1CA200A45078 /* threadsLite.h */, + 0F75F3F22A6B1CA100A45078 /* timer.h */, + 0F75F3CB2A6B1CA000A45078 /* titleformat.cpp */, + 0F75F3F62A6B1CA100A45078 /* titleformat.h */, + 0F75F4492A6B1CA400A45078 /* toolbarDropDown.h */, + 0F75F3F42A6B1CA100A45078 /* track_property.cpp */, + 0F75F4172A6B1CA200A45078 /* track_property.h */, + 0F75F4222A6B1CA300A45078 /* tracks.h */, + 0F75F44C2A6B1CA400A45078 /* ui_edit_context.h */, + 0F75F3CA2A6B1CA000A45078 /* ui_element_typable_window_manager.h */, + 0F75F4372A6B1CA300A45078 /* ui_element.cpp */, + 0F75F44D2A6B1CA400A45078 /* ui_element.h */, + 0F75F3F52A6B1CA100A45078 /* ui.cpp */, + 0F75F43C2A6B1CA300A45078 /* ui.h */, + 0F75F3DE2A6B1CA000A45078 /* unpack.h */, + 0F75F4162A6B1CA200A45078 /* utility.cpp */, + 0F75F4552A6B1CA500A45078 /* vis.h */, + 0FCA711A2AA2210C001CB0F2 /* commonObjects-Apple.mm */, + 0FCA711E2AA2715E001CB0F2 /* commonObjects-Apple.h */, + ); + name = Source; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + B1DD3655198A721800EF7043 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 0F75F5092A6B1CA800A45078 /* link_resolver.h in Headers */, + 0F75F4D42A6B1CA800A45078 /* metadb_callbacks.h in Headers */, + 0F75F4D12A6B1CA800A45078 /* decode_postprocessor.h in Headers */, + 0F75F50E2A6B1CA800A45078 /* contextmenu_manager.h in Headers */, + 0F75F4D32A6B1CA800A45078 /* search_tools.h in Headers */, + 0F75F4C72A6B1CA800A45078 /* console_manager.h in Headers */, + 0F75F4C82A6B1CA800A45078 /* filesystem_transacted.h in Headers */, + 0F75F4CE2A6B1CA800A45078 /* file_info_filter_impl.h in Headers */, + 0F75F5222A6B1CA800A45078 /* console.h in Headers */, + 0F75F4EC2A6B1CA800A45078 /* service_compat.h in Headers */, + 0F75F4EF2A6B1CA800A45078 /* playlistColumnProvider.h in Headers */, + 0F75F4DF2A6B1CA800A45078 /* mem_block_container.h in Headers */, + 0F75F4D62A6B1CA800A45078 /* modeless_dialog.h in Headers */, + 0F75F5532A6B1CA800A45078 /* service_by_guid.h in Headers */, + 0F75F5182A6B1CA800A45078 /* ui_edit_context.h in Headers */, + 0F75F50B2A6B1CA800A45078 /* file_lock_manager.h in Headers */, + 0F75F54F2A6B1CA800A45078 /* album_art_helpers.h in Headers */, + 0F75F4D02A6B1CA800A45078 /* packet_decoder.h in Headers */, + 0F75F4B02A6B1CA800A45078 /* audio_chunk_impl.h in Headers */, + 0F75F4FD2A6B1CA800A45078 /* advconfig_impl.h in Headers */, + 0F75F53C2A6B1CA800A45078 /* popup_message.h in Headers */, + 0F75F4D22A6B1CA800A45078 /* exception_io.h in Headers */, + 0F75F52A2A6B1CA800A45078 /* configCache.h in Headers */, + 0F75F4992A6B1CA800A45078 /* audio_chunk.h in Headers */, + 0F75F4E72A6B1CA800A45078 /* exceptions.h in Headers */, + 0F75F4DC2A6B1CA800A45078 /* dsp.h in Headers */, + 0F75F54C2A6B1CA800A45078 /* fileDialog.h in Headers */, + 0F75F5102A6B1CA800A45078 /* menu_common.h in Headers */, + 0F75F4CB2A6B1CA800A45078 /* coreDarkMode.h in Headers */, + 0F75F5082A6B1CA800A45078 /* ui.h in Headers */, + 0F75F55B2A6B1CA800A45078 /* file_info_filter.h in Headers */, + 0F75F5292A6B1CA800A45078 /* config_object_impl.h in Headers */, + 0F75F54D2A6B1CA800A45078 /* autoplaylist.h in Headers */, + 0F75F4C32A6B1CA800A45078 /* file_info_impl.h in Headers */, + 0F75F4952A6B1CA800A45078 /* genrand.h in Headers */, + 0F75F4962A6B1CA800A45078 /* ui_element_typable_window_manager.h in Headers */, + 0F75F5062A6B1CA800A45078 /* config_object.h in Headers */, + 0F75F51C2A6B1CA800A45078 /* foosortstring.h in Headers */, + 0F75F55A2A6B1CA800A45078 /* foobar2000.h in Headers */, + 0F75F5002A6B1CA800A45078 /* contextmenu.h in Headers */, + 0F75F4CC2A6B1CA800A45078 /* cfg_var_legacy.h in Headers */, + 0F75F4BB2A6B1CA800A45078 /* resampler.h in Headers */, + 0F75F4DE2A6B1CA800A45078 /* threadsLite.h in Headers */, + 0F75F5282A6B1CA800A45078 /* core_api.h in Headers */, + 0F75F5152A6B1CA800A45078 /* toolbarDropDown.h in Headers */, + 0F75F5172A6B1CA800A45078 /* messageBox.h in Headers */, + 0F75F49E2A6B1CA800A45078 /* threaded_process.h in Headers */, + 0F75F4FA2A6B1CA800A45078 /* image.h in Headers */, + 0F75F4BF2A6B1CA800A45078 /* playlist.h in Headers */, + 0F75F4EB2A6B1CA800A45078 /* input_impl.h in Headers */, + 0F75F5012A6B1CA800A45078 /* advconfig_impl_legacy.h in Headers */, + 0F75F5412A6B1CA800A45078 /* file_operation_callback.h in Headers */, + 0F75F4B42A6B1CA800A45078 /* http_client.h in Headers */, + 0F75F4F82A6B1CA800A45078 /* audioEncoder.h in Headers */, + 0F75F4DA2A6B1CA800A45078 /* playback_stream_capture.h in Headers */, + 0F75F5512A6B1CA800A45078 /* message_loop.h in Headers */, + 0F75F55F2A6B1CA800A45078 /* menu_helpers.h in Headers */, + 0F75F4C22A6B1CA800A45078 /* titleformat.h in Headers */, + 0F75F4ED2A6B1CA800A45078 /* keyValueIO.h in Headers */, + 0F75F5212A6B1CA800A45078 /* vis.h in Headers */, + 0F75F51D2A6B1CA800A45078 /* imageViewer.h in Headers */, + 0F75F4F62A6B1CA800A45078 /* info_lookup_handler.h in Headers */, + 0F75F5302A6B1CA800A45078 /* metadb_index.h in Headers */, + 0F75F4B22A6B1CA800A45078 /* event_logger.h in Headers */, + 0F75F50A2A6B1CA800A45078 /* playable_location.h in Headers */, + 0F75F53E2A6B1CA800A45078 /* system_time_keeper.h in Headers */, + 0F75F4D92A6B1CA800A45078 /* playback_control.h in Headers */, + 0F75F4F02A6B1CA800A45078 /* imageLoaderLite.h in Headers */, + 0F75F5402A6B1CA800A45078 /* file_info_const_impl.h in Headers */, + 0F75F52C2A6B1CA800A45078 /* dsp-frontend.h in Headers */, + 0F75F5482A6B1CA800A45078 /* advconfig.h in Headers */, + 0F75F54B2A6B1CA800A45078 /* keyValueIOimpl.h in Headers */, + 0F75F53A2A6B1CA800A45078 /* commonObjects.h in Headers */, + 0F75F5492A6B1CA800A45078 /* fsitem.h in Headers */, + 0F75F4AF2A6B1CA800A45078 /* chapterizer.h in Headers */, + 0F75F5442A6B1CA800A45078 /* replaygain_scanner.h in Headers */, + 0F75F4A82A6B1CA800A45078 /* threadPool.h in Headers */, + 0F75F5142A6B1CA800A45078 /* completion_notify.h in Headers */, + 0F75F4A02A6B1CA800A45078 /* main_thread_callback.h in Headers */, + 0F75F5192A6B1CA800A45078 /* ui_element.h in Headers */, + 0F75F5272A6B1CA800A45078 /* preferences_page.h in Headers */, + 0F75F5542A6B1CA800A45078 /* library_manager.h in Headers */, + 0F75F4AA2A6B1CA800A45078 /* unpack.h in Headers */, + 0F75F4FE2A6B1CA800A45078 /* foobar2000-versions.h in Headers */, + 0F75F4A32A6B1CA800A45078 /* progress_meter.h in Headers */, + 0F75F5022A6B1CA800A45078 /* file.h in Headers */, + 0F75F4F52A6B1CA800A45078 /* ole_interaction.h in Headers */, + 0F75F5392A6B1CA800A45078 /* file_format_sanitizer.h in Headers */, + 0F75F5572A6B1CA800A45078 /* coreversion.h in Headers */, + 0F75F50C2A6B1CA800A45078 /* configStore.h in Headers */, + 0F75F53D2A6B1CA800A45078 /* archive.h in Headers */, + 0F75F4D72A6B1CA800A45078 /* foosort.h in Headers */, + 0F75F5122A6B1CA800A45078 /* metadb_info_container_impl.h in Headers */, + 0F75F4E32A6B1CA800A45078 /* track_property.h in Headers */, + 0F75F5162A6B1CA800A45078 /* dsp_manager.h in Headers */, + 0F75F53B2A6B1CA800A45078 /* powerManager.h in Headers */, + 0F75F4E82A6B1CA800A45078 /* component_client.h in Headers */, + 0F75F52D2A6B1CA800A45078 /* foobar2000-sdk-pch.h in Headers */, + 0F75F5562A6B1CA800A45078 /* commandline.h in Headers */, + 0F75F4B52A6B1CA800A45078 /* hasher_md5.h in Headers */, + 0F75F4A42A6B1CA800A45078 /* app_close_blocker.h in Headers */, + 0F75F4FF2A6B1CA800A45078 /* componentversion.h in Headers */, + 0F75F4B92A6B1CA800A45078 /* metadb.h in Headers */, + 0F75F54A2A6B1CA800A45078 /* icon_remap.h in Headers */, + 0F75F4FC2A6B1CA800A45078 /* metadb_handle.h in Headers */, + 0F75F4BD2A6B1CA800A45078 /* foobar2000-winver.h in Headers */, + 0F75F4BE2A6B1CA800A45078 /* timer.h in Headers */, + 0F75F4B72A6B1CA800A45078 /* forward_types.h in Headers */, + 0F75F4F72A6B1CA800A45078 /* library_index.h in Headers */, + 0F75F4EE2A6B1CA800A45078 /* tracks.h in Headers */, + 0F75F5552A6B1CA800A45078 /* foobar2000-lite.h in Headers */, + 0F75F49A2A6B1CA800A45078 /* output.h in Headers */, + 0F75F4CD2A6B1CA800A45078 /* menu.h in Headers */, + 0F75F4B32A6B1CA800A45078 /* foobar2000-pfc.h in Headers */, + 0F75F53F2A6B1CA800A45078 /* play_callback.h in Headers */, + 0F75F5132A6B1CA800A45078 /* abort_callback.h in Headers */, + 0F75F4BC2A6B1CA800A45078 /* initquit.h in Headers */, + 0F75F5472A6B1CA800A45078 /* album_art.h in Headers */, + 0F75F55E2A6B1CA800A45078 /* cfg_var.h in Headers */, + 0F75F49F2A6B1CA800A45078 /* service_impl.h in Headers */, + 0F75F4A62A6B1CA800A45078 /* filesystem.h in Headers */, + 0F75F4B62A6B1CA800A45078 /* component.h in Headers */, + 0F75F5352A6B1CA800A45078 /* audio_postprocessor.h in Headers */, + 0F75F52B2A6B1CA800A45078 /* metadb_display_field_provider.h in Headers */, + 0F75F5362A6B1CA800A45078 /* file_info.h in Headers */, + 0F75F4E52A6B1CA800A45078 /* shortcut_actions.h in Headers */, + 0F75F4C52A6B1CA800A45078 /* filesystem_helper.h in Headers */, + 0F75F4DD2A6B1CA800A45078 /* library_callbacks.h in Headers */, + 0F75F50F2A6B1CA800A45078 /* config_io_callback.h in Headers */, + 0F75F49D2A6B1CA800A45078 /* playlist_loader.h in Headers */, + 0F75F54E2A6B1CA800A45078 /* input_file_type.h in Headers */, + 0F75F5452A6B1CA800A45078 /* tag_processor.h in Headers */, + 0F75F5382A6B1CA800A45078 /* input.h in Headers */, + 0F75F4E02A6B1CA800A45078 /* foobar2000-all.h in Headers */, + 0F75F5252A6B1CA800A45078 /* components_menu.h in Headers */, + 0F75F51B2A6B1CA800A45078 /* callback_merit.h in Headers */, + 0F75F4AD2A6B1CA800A45078 /* service.h in Headers */, + 0F75F4B82A6B1CA800A45078 /* replaygain.h in Headers */, + 0F75F4A92A6B1CA800A45078 /* noInfo.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + B1DD3656198A721800EF7043 /* foobar2000_SDK */ = { + isa = PBXNativeTarget; + buildConfigurationList = B1DD365B198A721800EF7043 /* Build configuration list for PBXNativeTarget "foobar2000_SDK" */; + buildPhases = ( + B1DD3653198A721800EF7043 /* Sources */, + B1DD3654198A721800EF7043 /* Frameworks */, + B1DD3655198A721800EF7043 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = foobar2000_SDK; + productName = foobar2000_SDK; + productReference = B1DD3657198A721800EF7043 /* libfoobar2000_SDK.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + B1DD364F198A721800EF7043 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1250; + ORGANIZATIONNAME = "___FULLUSERNAME___"; + }; + buildConfigurationList = B1DD3652198A721800EF7043 /* Build configuration list for PBXProject "foobar2000_SDK" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = B1DD364E198A721800EF7043; + productRefGroup = B1DD3658198A721800EF7043 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + B1DD3656198A721800EF7043 /* foobar2000_SDK */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + B1DD3653198A721800EF7043 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0F75F5042A6B1CA800A45078 /* guids.cpp in Sources */, + 0F75F5242A6B1CA800A45078 /* chapterizer.cpp in Sources */, + 0F75F50D2A6B1CA800A45078 /* input.cpp in Sources */, + 0F75F5372A6B1CA800A45078 /* replaygain.cpp in Sources */, + 0F75F5462A6B1CA800A45078 /* input_file_type.cpp in Sources */, + 0FCA711C2AA2210C001CB0F2 /* commonObjects-Apple.mm in Sources */, + 0F75F5332A6B1CA800A45078 /* file_info_impl.cpp in Sources */, + 0F75F4C62A6B1CA800A45078 /* audio_chunk.cpp in Sources */, + 0F75F4D82A6B1CA800A45078 /* console.cpp in Sources */, + 0F75F4C02A6B1CA800A45078 /* track_property.cpp in Sources */, + 0F75F4BA2A6B1CA800A45078 /* menu_manager.cpp in Sources */, + 0F75F5322A6B1CA800A45078 /* app_close_blocker.cpp in Sources */, + 0F75F5112A6B1CA800A45078 /* completion_notify.cpp in Sources */, + 0F75F49B2A6B1CA800A45078 /* file_operation_callback.cpp in Sources */, + 0F75F5422A6B1CA800A45078 /* album_art.cpp in Sources */, + 0F75F5262A6B1CA800A45078 /* metadb_handle_list.cpp in Sources */, + 0F75F5072A6B1CA800A45078 /* config_object.cpp in Sources */, + 0F75F5432A6B1CA800A45078 /* main_thread_callback.cpp in Sources */, + 0F75F4A72A6B1CA800A45078 /* commonObjects.cpp in Sources */, + 0F75F51E2A6B1CA800A45078 /* popup_message.cpp in Sources */, + 0F75F52F2A6B1CA800A45078 /* replaygain_info.cpp in Sources */, + 0F75F5232A6B1CA800A45078 /* componentversion.cpp in Sources */, + 0F75F5592A6B1CA800A45078 /* playback_control.cpp in Sources */, + 0F75F4E22A6B1CA800A45078 /* utility.cpp in Sources */, + 0F75F4942A6B1CA800A45078 /* foosort.cpp in Sources */, + 0F75F5052A6B1CA800A45078 /* tag_processor.cpp in Sources */, + 0F75F4E12A6B1CA800A45078 /* image.cpp in Sources */, + 0F75F5202A6B1CA800A45078 /* cfg_var_legacy.cpp in Sources */, + 0F75F51F2A6B1CA800A45078 /* fsItem.cpp in Sources */, + 0F75F4C12A6B1CA800A45078 /* ui.cpp in Sources */, + 0F75F4CF2A6B1CA800A45078 /* advconfig.cpp in Sources */, + 0F75F4F32A6B1CA800A45078 /* config_io_callback.cpp in Sources */, + 0F75F4F42A6B1CA800A45078 /* packet_decoder.cpp in Sources */, + 0F75F4DB2A6B1CA800A45078 /* file_info.cpp in Sources */, + 0F75F4AC2A6B1CA800A45078 /* menu_helpers.cpp in Sources */, + 0F75F4CA2A6B1CA800A45078 /* threaded_process.cpp in Sources */, + 0F75F5032A6B1CA800A45078 /* ui_element.cpp in Sources */, + 0F75F4A12A6B1CA800A45078 /* filesystem.cpp in Sources */, + 0F75F4A52A6B1CA800A45078 /* mem_block_container.cpp in Sources */, + 0F75F5312A6B1CA800A45078 /* mainmenu.cpp in Sources */, + 0F75F49C2A6B1CA800A45078 /* abort_callback.cpp in Sources */, + 0F75F52E2A6B1CA800A45078 /* file_cached_impl.cpp in Sources */, + 0F75F5522A6B1CA800A45078 /* playlist_loader.cpp in Sources */, + 0F75F4AE2A6B1CA800A45078 /* file_info_const_impl.cpp in Sources */, + 0F75F4982A6B1CA800A45078 /* file_info_merge.cpp in Sources */, + 0F75F4F22A6B1CA800A45078 /* preferences_page.cpp in Sources */, + 0F75F4C92A6B1CA800A45078 /* service.cpp in Sources */, + 0F75F4EA2A6B1CA800A45078 /* metadb.cpp in Sources */, + 0F75F4A22A6B1CA800A45078 /* stdafx.cpp in Sources */, + 0F75F51A2A6B1CA800A45078 /* menu_item.cpp in Sources */, + 0F75F4FB2A6B1CA800A45078 /* link_resolver.cpp in Sources */, + 0F75F4AB2A6B1CA800A45078 /* output.cpp in Sources */, + 0F75F4F12A6B1CA800A45078 /* playlist.cpp in Sources */, + 0F75F4E42A6B1CA800A45078 /* cfg_var.cpp in Sources */, + 0F75F55D2A6B1CA800A45078 /* dsp.cpp in Sources */, + 0F75F4B12A6B1CA800A45078 /* audio_chunk_channel_config.cpp in Sources */, + 0F75F4D52A6B1CA800A45078 /* configStore.cpp in Sources */, + 0F75F5342A6B1CA800A45078 /* tag_processor_id3v2.cpp in Sources */, + 0F75F4E92A6B1CA800A45078 /* playable_location.cpp in Sources */, + 0F75F5502A6B1CA800A45078 /* hasher_md5.cpp in Sources */, + 0F75F55C2A6B1CA800A45078 /* metadb_handle.cpp in Sources */, + 0F75F5582A6B1CA800A45078 /* dsp_manager.cpp in Sources */, + 0F75F4E62A6B1CA800A45078 /* foosortstring.cpp in Sources */, + 0F75F4C42A6B1CA800A45078 /* filesystem_helper.cpp in Sources */, + 0F75F4F92A6B1CA800A45078 /* commandline.cpp in Sources */, + 0F75F4972A6B1CA800A45078 /* titleformat.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + B1DD3659198A721800EF7043 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "foobar2000-sdk-pch.h"; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + .., + ../.., + ); + IPHONEOS_DEPLOYMENT_TARGET = 12.1; + MACOSX_DEPLOYMENT_TARGET = 10.13; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + B1DD365A198A721800EF7043 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "foobar2000-sdk-pch.h"; + GCC_PREPROCESSOR_DEFINITIONS = "NDEBUG=1"; + GCC_SYMBOLS_PRIVATE_EXTERN = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + .., + ../.., + ); + IPHONEOS_DEPLOYMENT_TARGET = 12.1; + MACOSX_DEPLOYMENT_TARGET = 10.13; + SDKROOT = macosx; + SKIP_INSTALL = YES; + }; + name = Release; + }; + B1DD365C198A721800EF7043 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + EXECUTABLE_PREFIX = lib; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + B1DD365D198A721800EF7043 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + EXECUTABLE_PREFIX = lib; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + B1DD3652198A721800EF7043 /* Build configuration list for PBXProject "foobar2000_SDK" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B1DD3659198A721800EF7043 /* Debug */, + B1DD365A198A721800EF7043 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B1DD365B198A721800EF7043 /* Build configuration list for PBXNativeTarget "foobar2000_SDK" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B1DD365C198A721800EF7043 /* Debug */, + B1DD365D198A721800EF7043 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = B1DD364F198A721800EF7043 /* Project object */; +} diff --git a/sdk/foobar2000/SDK/fsItem.cpp b/sdk/foobar2000/SDK/fsItem.cpp index f5e77c1..2161848 100644 --- a/sdk/foobar2000/SDK/fsItem.cpp +++ b/sdk/foobar2000/SDK/fsItem.cpp @@ -118,8 +118,8 @@ namespace { class fsItemFileStd : public fsItemFile { public: fsItemFileStd(filesystem::ptr fs, stringRef canonicalPath, t_filestats2 const & opportunistStats) : m_fs(fs), m_path(canonicalPath), m_opportunistStats(opportunistStats) { - PFC_ASSERT( m_opportunistStats.m_attribsValid & t_filestats2::attr_remote ); m_opportunistStats.set_folder(false); + m_opportunistStats.set_remote(fs->is_remote(canonicalPath->c_str())); } filesystem::ptr getFS() override { return m_fs; } @@ -185,7 +185,9 @@ namespace { PFC_ASSERT(!"Should not get here"); break; } - return m_fs->makeItemFileStd(dst); + auto stats = m_opportunistStats; + stats.set_file(); + return m_fs->makeItemFileStd(dst, stats); } } private: @@ -196,8 +198,8 @@ namespace { class fsItemFolderStd : public fsItemFolder { public: fsItemFolderStd(filesystem::ptr fs, stringRef canonicalPath, t_filestats2 const & opportunistStats) : m_fs(fs), m_path(canonicalPath), m_opportunistStats(opportunistStats) { - PFC_ASSERT( m_opportunistStats.m_attribsValid & t_filestats2::attr_remote ); m_opportunistStats.set_folder(true); + m_opportunistStats.set_remote(fs->is_remote(canonicalPath->c_str())); } filesystem::ptr getFS() override { return m_fs; } @@ -241,7 +243,7 @@ namespace { fsItemFile::ptr findChildFile(const char* fileName, abort_callback& aborter) override { auto sub = subPath(fileName); - auto stats = m_fs->get_stats2_(sub->c_str(), stats2_fileOrFolder, aborter); + auto stats = m_fs->get_stats2_(sub->c_str(), stats2_fileOrFolder | foobar2000_io::stats2_remote, aborter); if (!stats.is_folder()) { return m_fs->makeItemFileStd(sub->c_str(), stats); } @@ -249,14 +251,15 @@ namespace { } fsItemFolder::ptr findChildFolder(const char* fileName, abort_callback& aborter) override { auto sub = subPath(fileName); - if (m_fs->directory_exists(sub->c_str(), aborter)) { - return m_fs->makeItemFolderStd(sub->c_str()); + auto stats = m_fs->get_stats2_(sub->c_str(), stats2_fileOrFolder | foobar2000_io::stats2_remote, aborter); + if (stats.is_folder()) { + return m_fs->makeItemFolderStd(sub->c_str(), stats); } throw exception_io_not_found(); } fsItemBase::ptr findChild(const char* fileName, abort_callback& aborter) override { auto sub = subPath(fileName); - auto stats = m_fs->get_stats2_(sub->c_str(), stats2_fileOrFolder, aborter); + auto stats = m_fs->get_stats2_(sub->c_str(), stats2_fileOrFolder | foobar2000_io::stats2_remote, aborter); if ( stats.is_folder() ) { return m_fs->makeItemFileStd(sub->c_str(), stats ); } else { @@ -268,7 +271,13 @@ namespace { pfc::string8 fn(fileName); uniqueFn(fn, add); auto sub = subPath(fn); - const bool bDidExist = m_fs->file_exists(sub->c_str(), aborter); + t_filestats2 stats; + + bool bDidExist = false; + try { + stats = m_fs->get_stats2_( sub->c_str(), stats2_all, aborter ); + bDidExist = stats.is_file(); + } catch(exception_io_not_found) {} switch (createMode) { case createMode::allowExisting: break; // OK @@ -289,9 +298,9 @@ namespace { // FIX ME this should be atomic with exists() check file::ptr creator; m_fs->open(creator, sub->c_str(), filesystem::open_mode_write_new, aborter); - // creator->commit(aborter); + stats = creator->get_stats2_( stats2_all, aborter ); } - return m_fs->makeItemFileStd(sub->c_str()); + return m_fs->makeItemFileStd(sub->c_str(), stats); } } fsItemFolder::ptr createFolder(const char* fileName, unsigned createMode, abort_callback& aborter) override { @@ -319,7 +328,8 @@ namespace { PFC_ASSERT(!"Should not get here"); break; } - return m_fs->makeItemFolderStd(sub->c_str()); + // Inherit opportunist stats + return m_fs->makeItemFolderStd(sub->c_str(), this->m_opportunistStats); } } fsItemPtr moveTo(fsItemFolderPtr folder, const char* desiredName, unsigned createMode, abort_callback& aborter) override { @@ -352,7 +362,7 @@ namespace { break; } - return m_fs->makeItemFolderStd(dst); + return m_fs->makeItemFolderStd(dst, m_opportunistStats); } } diff --git a/sdk/foobar2000/SDK/fsitem.h b/sdk/foobar2000/SDK/fsitem.h index 1814b16..1fcc4af 100644 --- a/sdk/foobar2000/SDK/fsitem.h +++ b/sdk/foobar2000/SDK/fsitem.h @@ -3,8 +3,14 @@ // fsItem API // Alternate, object-based way of accessing the local filesystem. // It is recommended to use fsItem methods to operate on user-specified media folders. -// In some cases, most notably Android and UWP, accessing user's documents/media over paths requires expensive resolving of objects representing them. +// In some cases, notably Android and WinPhone/UWP, accessing user's documents/media over paths requires expensive resolving of objects representing them. // fsItem can cache platform specific resources necessary to manipulate the files, allowing efficient opening of files returned by directory enumeration. +// +// Note that as of 2023, fsItem is just a convenience API. +// WinPhone/UWP has been dropped; slow and buggy Android DocumentFile (*) wrapper is being abandoned. On neither of these platforms foobar2000 supports loading components. +// Nothing in current-generation foobar2000 gains performance from using fsItem methods over plain filesystem with paths. +// +// (*) Android DocumentFile is slow and buggy, not the wrapper. Google sucks. #include "file.h" #include "commonObjects.h" diff --git a/sdk/foobar2000/SDK/genrand.h b/sdk/foobar2000/SDK/genrand.h index 256668e..70aae87 100644 --- a/sdk/foobar2000/SDK/genrand.h +++ b/sdk/foobar2000/SDK/genrand.h @@ -3,6 +3,7 @@ class NOVTABLE genrand_service : public service_base { public: + void seedAuto() {seed( 0 ) ;} //! Seeds the PRNG with specified value. \n //! Default value of zero seeds automatically using available system functions. virtual void seed(unsigned val = 0) = 0; diff --git a/sdk/foobar2000/SDK/guids.cpp b/sdk/foobar2000/SDK/guids.cpp index bf22cca..35b5961 100644 --- a/sdk/foobar2000/SDK/guids.cpp +++ b/sdk/foobar2000/SDK/guids.cpp @@ -50,6 +50,7 @@ FOOGUIDDECL const GUID dsp_v3::class_guid = { 0x3743c03a, 0xae20, 0x40e3, { 0x90 FOOGUIDDECL const GUID dsp_entry_v2::class_guid = { 0x9ec5d45e, 0x10f5, 0x46a7, { 0x95, 0x46, 0xf3, 0xac, 0xec, 0x68, 0xb1, 0x49 } }; FOOGUIDDECL const GUID dsp_entry_hidden::class_guid = { 0xe3f0c95f, 0x7a0b, 0x48bc, { 0x96, 0x58, 0x71, 0xa4, 0x69, 0x68, 0x88, 0x76 } }; FOOGUIDDECL const GUID dsp_entry_v3::class_guid = { 0xb4d5a127, 0x5e59, 0x466d, { 0x93, 0x6b, 0x39, 0x5e, 0xdf, 0xb9, 0x37, 0xa4 } }; +FOOGUIDDECL const GUID dsp_entry_v4::class_guid = { 0xf13a5ce9, 0xd6e8, 0x4ad8, { 0x9e, 0xba, 0x9d, 0x6a, 0x34, 0x84, 0x29, 0x61 } }; FOOGUIDDECL const GUID dsp_preset_edit_callback_v2::class_guid = { 0x904173f6, 0x345e, 0x47d0, { 0x88, 0x60, 0x63, 0xa2, 0xc9, 0xd0, 0x9, 0x52 } }; @@ -194,6 +195,10 @@ FOOGUIDDECL const GUID archive_v2::class_guid = FOOGUIDDECL const GUID archive_v3::class_guid = { 0x8d3f8b2d, 0xa866, 0x4f1f, { 0x9a, 0x4f, 0xff, 0x23, 0x92, 0x9e, 0xd6, 0xda } }; +// {FD3AE540-4C46-43AD-A331-2337737A64C6} +FOOGUIDDECL const GUID archive_v4::class_guid = +{ 0xfd3ae540, 0x4c46, 0x43ad, { 0xa3, 0x31, 0x23, 0x37, 0x73, 0x7a, 0x64, 0xc6 } }; + // {B2F9FC40-3E55-4b23-A2C9-22BAAD8795B1} FOOGUIDDECL const GUID file::class_guid = { 0xb2f9fc40, 0x3e55, 0x4b23, { 0xa2, 0xc9, 0x22, 0xba, 0xad, 0x87, 0x95, 0xb1 } }; @@ -843,8 +848,10 @@ FOOGUIDDECL const GUID preferences_page::guid_keyboard_shortcuts = { 0xa4dbfa19, FOOGUIDDECL const GUID preferences_page_v2::class_guid = { 0xce4ebc9e, 0xab20, 0x46f9, { 0x92, 0x5f, 0x88, 0x3b, 0x8, 0x4f, 0x5, 0x69 } }; FOOGUIDDECL const GUID preferences_branch_v2::class_guid = { 0x167ebeb9, 0x8334, 0x4b21, { 0xaf, 0x58, 0xa7, 0x40, 0xa5, 0xd5, 0xb6, 0x66 } }; +#ifdef _WIN32 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 } }; +#endif 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 } }; @@ -864,7 +871,6 @@ FOOGUIDDECL const GUID input_decoder_v4::class_guid = { 0x7bbf10b5, 0x2064, 0x4d 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 } }; FOOGUIDDECL const GUID input_params::is_tag_write_safe = { 0x9f44a346, 0x73f0, 0x459b, { 0x98, 0x47, 0xf4, 0x86, 0x9b, 0x29, 0xbc, 0x93 } }; FOOGUIDDECL const GUID input_info_reader::class_guid = { 0x8e9bb1d4, 0xa52b, 0x4df6, { 0xa9, 0x29, 0x1a, 0xae, 0x40, 0x75, 0x38, 0x8a } }; FOOGUIDDECL const GUID input_info_reader_v2::class_guid = { 0x42486bca, 0xd37, 0x4e02, { 0xb7, 0x72, 0x4d, 0x30, 0xd6, 0xf8, 0x50, 0xbe } }; @@ -1099,6 +1105,7 @@ FOOGUIDDECL const GUID standard_commands::guid_seek_back_10min = FOOGUIDDECL const GUID standard_commands::guid_library_configure = { 0xa305602d, 0x4716, 0x4fc2, { 0x91, 0x57, 0xc6, 0x33, 0x9c, 0x4b, 0x1c, 0xe9 } }; FOOGUIDDECL const GUID standard_commands::guid_library_rescan = { 0xb21d432e, 0xb14d, 0x4c8d, { 0xaf, 0xda, 0xf, 0x45, 0xc7, 0xb6, 0x22, 0x26 } }; +FOOGUIDDECL const GUID standard_commands::guid_internet_radio = { 0x58712f87, 0x3d7b, 0x4f2e, { 0x88, 0xe5, 0x7d, 0xea, 0xe1, 0xa5, 0xf2, 0x3d } }; // {97215C5E-7228-4237-B52C-A2B5504EF726} FOOGUIDDECL const GUID playback_statistics_collector::class_guid = @@ -1312,9 +1319,7 @@ FOOGUIDDECL const GUID mainmenu_node::class_guid = { 0xabba6512, 0x377d, 0x414f, FOOGUIDDECL const GUID system_time_keeper::class_guid = { 0xdc5d4938, 0x7927, 0x48ba, { 0xbf, 0x84, 0xda, 0x2f, 0xb1, 0xb, 0x36, 0xf2 } }; -#ifdef _WIN32 FOOGUIDDECL const GUID component_installation_validator::class_guid = { 0x639283e, 0x3004, 0x4e5c, { 0xb1, 0xb3, 0x6d, 0xff, 0x8, 0xa7, 0x92, 0x84 } }; -#endif FOOGUIDDECL const GUID playback_stream_capture::class_guid = { 0x9423439e, 0x8cd5, 0x45d7, { 0xaa, 0x6d, 0x4b, 0x98, 0xc, 0x22, 0x93, 0x3e } }; FOOGUIDDECL const GUID playback_stream_capture_v2::class_guid = { 0x801e6865, 0x6040, 0x42a6, { 0x8c, 0x43, 0x57, 0x91, 0x8a, 0xdc, 0xee, 0xb7 } }; @@ -1509,3 +1514,7 @@ FOOGUIDDECL const GUID metadb_hint_list_v4::class_guid = { 0xe7908ec9, 0xa26a, 0 FOOGUIDDECL const GUID metadb_pre_update_callback::class_guid = { 0xc81865af, 0x1da2, 0x4361, { 0x92, 0x88, 0xac, 0xf7, 0x83, 0x89, 0xe1, 0x9c } }; FOOGUIDDECL const GUID stream_receive::class_guid = { 0x1d36b5af, 0xaa6b, 0x450d, { 0xa4, 0x1f, 0x58, 0x19, 0x13, 0x4e, 0xdb, 0x57 } }; + +#ifdef __APPLE__ +FOOGUIDDECL const GUID fb2k::NSObjectWrapper::class_guid = { 0x6ec55805, 0x96f7, 0x4a8f, { 0x92, 0xb3, 0xbd, 0x33, 0xee, 0x10, 0x53, 0x17 } }; +#endif diff --git a/sdk/foobar2000/SDK/info_lookup_handler.h b/sdk/foobar2000/SDK/info_lookup_handler.h index 56822aa..fdf194a 100644 --- a/sdk/foobar2000/SDK/info_lookup_handler.h +++ b/sdk/foobar2000/SDK/info_lookup_handler.h @@ -16,9 +16,9 @@ class NOVTABLE info_lookup_handler : public service_base { virtual fb2k::hicon_t get_icon(int p_width, int p_height) = 0; //! Performs a lookup. Creates a modeless dialog and returns immediately. - //! @param p_items Items to look up. - //! @param p_notify Callback to notify caller when the operation has completed. Call on_completion with status code 0 to signal failure/abort, or with code 1 to signal success / new infos in metadb. - //! @param p_parent Parent window for the lookup dialog. Caller will typically disable the window while lookup is in progress and enable it back when completion is signaled. + //! @param items Items to look up. + //! @param notify Callback to notify caller when the operation has completed. Call on_completion with status code 0 to signal failure/abort, or with code 1 to signal success / new infos in metadb. + //! @param parent Parent window for the lookup dialog. Caller will typically disable the window while lookup is in progress and enable it back when completion is signaled. virtual void lookup(metadb_handle_list_cref items,completion_notify::ptr notify,fb2k::hwnd_t parent) = 0; FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(info_lookup_handler); diff --git a/sdk/foobar2000/SDK/input.cpp b/sdk/foobar2000/SDK/input.cpp index fc3a0e3..1452a6d 100644 --- a/sdk/foobar2000/SDK/input.cpp +++ b/sdk/foobar2000/SDK/input.cpp @@ -440,6 +440,14 @@ GUID input_entry::get_guid_() { if ( v2 &= this ) ret = v2->get_guid(); return ret; } + +const char* input_entry::get_name_() { + const char * ret = ""; + input_entry_v2::ptr v2; + if ( v2 &= this ) ret = v2->get_name(); + return ret; +} + input_entry::ptr input_entry::g_find_by_guid(const GUID& guid) { for (auto ptr : enumerate()) { input_entry_v2::ptr v2; diff --git a/sdk/foobar2000/SDK/input.h b/sdk/foobar2000/SDK/input.h index 75a294f..f49dc15 100644 --- a/sdk/foobar2000/SDK/input.h +++ b/sdk/foobar2000/SDK/input.h @@ -97,8 +97,7 @@ class NOVTABLE input_decoder : public input_info_reader //! @returns false to keep old info, or true to indicate that changes have been made to p_info and those should be displayed. virtual bool get_dynamic_info_track(file_info & p_out, double & p_timestamp_delta) = 0; - //! Called from playback thread before sleeping. - //! @param p_abort abort_callback object signaling user aborting the operation. + //! Obsolete, do not use, do not rely on. virtual void on_idle(abort_callback & p_abort) = 0; @@ -154,17 +153,7 @@ class input_params { //! 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; - - //! Asks whether it is OK to externally rewrite tags on this file without closing and reopening the decoder. \n + //! Asks whether it is OK to externally rewrite tags on this file without closing and reopening the decoder. \n //! Return 1 if the decoder reads all relevant content in open() without leaving the file open afterwards, 0 otherwise (the default). static const GUID is_tag_write_safe; }; @@ -279,6 +268,7 @@ class NOVTABLE input_entry : public service_base { static uint32_t g_flags_for_content_type( const char * ct, uint32_t mask = UINT32_MAX ); GUID get_guid_(); + const char * get_name_(); static input_entry::ptr g_find_by_guid( const GUID & ); }; diff --git a/sdk/foobar2000/SDK/input_impl.h b/sdk/foobar2000/SDK/input_impl.h index e131e62..69e0e6f 100644 --- a/sdk/foobar2000/SDK/input_impl.h +++ b/sdk/foobar2000/SDK/input_impl.h @@ -28,7 +28,8 @@ class input_impl //! - input_open_info_read - info retrieval methods are valid; \n //! - input_open_decode - info retrieval and decoding methods are valid; \n //! - input_open_info_write - info retrieval and retagging methods are valid; \n - //! Note that info retrieval methods are valid in all cases, and they may be called at any point of decoding/retagging process. Results of info retrieval methods (other than get_subsong_count() / get_subsong()) between retag_set_info() and retag_commit() are undefined however; those should not be called during that period. + //! Note that info retrieval methods are valid in all cases, and they may be called at any point of decoding/retagging process. Results of info retrieval methods (other than get_subsong_count() / get_subsong()) between retag_set_info() and retag_commit() are undefined however; those should not be called during that period. \n + //! If your implementation does not support writing tags, throw exception_tagging_unsupported in response to input_open_info_write and do not implement other tag writing methods (they will not be called). //! @param p_abort abort_callback object signaling user aborting the operation. void open(service_ptr_t p_filehint,const char * p_path,t_input_open_reason p_reason,abort_callback & p_abort); @@ -53,13 +54,20 @@ class input_impl bool decode_get_dynamic_info(file_info & p_out, double & p_timestamp_delta); //! See: input_decoder::get_dynamic_info_track(). Valid after decode_initialize(). bool decode_get_dynamic_info_track(file_info & p_out, double & p_timestamp_delta); - //! See: input_decoder::on_idle(). Valid after decode_initialize(). + //! Obsolete, do not use, do not rely on. void decode_on_idle(abort_callback & p_abort); - //! See: input_info_writer::set_info(). Valid after open() with input_open_info_write reason. + //! See: input_info_writer::set_info(). Valid after open() with input_open_info_write reason. \n + //! If your implementation does not support writing tags, throw exception_tagging_unsupported from open() and retag_* methods will never be called. void retag_set_info(t_uint32 p_subsong,const file_info & p_info,abort_callback & p_abort); - //! See: input_info_writer::commit(). Valid after open() with input_open_info_write reason. - void retag_commit(abort_callback & p_abort); + //! See: input_info_writer::commit(). Valid after open() with input_open_info_write reason. \n + //! If your implementation does not support writing tags, throw exception_tagging_unsupported from open() and retag_* methods will never be called. + void retag_commit(abort_callback & p_abort); + + //! See: input_info_writer_v2::remove_tags(). Valid after open() with input_open_info_write reason. \n + //! If possible, entirely remove tags from the file (truncate ID3/APE tags away etc); otherwise set blank metadata. \n + //! If your implementation does not support writing tags, throw exception_tagging_unsupported from open() and remove_tags() will never be called. + void remove_tags(abort_callback & p_abort); //! See: input_entry::is_our_content_type(). static bool g_is_our_content_type(const char * p_content_type); @@ -121,7 +129,8 @@ class input_singletrack_impl //! - input_open_info_read - info retrieval methods are valid; \n //! - input_open_decode - info retrieval and decoding methods are valid; \n //! - input_open_info_write - info retrieval and retagging methods are valid; \n - //! Note that info retrieval methods are valid in all cases, and they may be called at any point of decoding/retagging process. Results of info retrieval methods (other than get_subsong_count() / get_subsong()) between retag_set_info() and retag_commit() are undefined however; those should not be called during that period. + //! Note that info retrieval methods are valid in all cases, and they may be called at any point of decoding/retagging process. Results of info retrieval methods (other than get_subsong_count() / get_subsong()) between retag_set_info() and retag_commit() are undefined however; those should not be called during that period. \n + //! If your implementation does not support writing tags, throw exception_tagging_unsupported in response to input_open_info_write and do not implement other tag writing methods (they will not be called). //! @param p_abort abort_callback object signaling user aborting the operation. void open(service_ptr_t p_filehint,const char * p_path,t_input_open_reason p_reason,abort_callback & p_abort); @@ -144,12 +153,18 @@ class input_singletrack_impl bool decode_get_dynamic_info(file_info & p_out, double & p_timestamp_delta); //! See: input_decoder::get_dynamic_info_track(). Valid after decode_initialize(). bool decode_get_dynamic_info_track(file_info & p_out, double & p_timestamp_delta); - //! See: input_decoder::on_idle(). Valid after decode_initialize(). + //! Obsolete, do not use, do not rely on. void decode_on_idle(abort_callback & p_abort); - //! See: input_info_writer::set_info(). Note that input_info_writer::commit() call isn't forwarded because it's useless in case of non-multitrack-enabled inputs. Valid after open() with input_open_info_write reason. + //! See: input_info_writer::set_info(). Note that input_info_writer::commit() call isn't forwarded because it's useless in case of non-multitrack-enabled inputs. Valid after open() with input_open_info_write reason. \n + //! If your implementation does not support writing tags, throw exception_tagging_unsupported from open() and retag() will never be called. void retag(const file_info & p_info,abort_callback & p_abort); + //! See: input_info_writer_v2::remove_tags(). Valid after open() with input_open_info_write reason. \n + //! If possible, entirely remove tags from the file (truncate ID3/APE tags away etc); otherwise set blank metadata. \n + //! If your implementation does not support writing tags, throw exception_tagging_unsupported from open() and remove_tags() will never be called. + void remove_tags(abort_callback & p_abort); + //! See: input_entry::is_our_content_type(). static bool g_is_our_content_type(const char * p_content_type); //! See: input_entry::is_our_path(). diff --git a/sdk/foobar2000/SDK/library_manager.h b/sdk/foobar2000/SDK/library_manager.h index 94b3b4b..b7ceb83 100644 --- a/sdk/foobar2000/SDK/library_manager.h +++ b/sdk/foobar2000/SDK/library_manager.h @@ -107,7 +107,7 @@ class NOVTABLE library_manager_v4 : public library_manager_v3 { FB2K_MAKE_SERVICE_COREAPI_EXTENSION(library_manager_v4, library_manager_v3); }; -//! \since 2.0 beta 13 +//! \since 2.0 class NOVTABLE library_manager_v5 : public library_manager_v4 { FB2K_MAKE_SERVICE_COREAPI_EXTENSION(library_manager_v5, library_manager_v4); public: @@ -120,7 +120,7 @@ class NOVTABLE library_manager_v5 : public library_manager_v4 { bool is_current_callback_from_hook() { return library_status(status_current_callback_from_hook, 0, nullptr, 0) != 0; } }; -//! \since 2.0 beta 18 +//! \since 2.0 class NOVTABLE library_manager_v6 : public library_manager_v5 { FB2K_MAKE_SERVICE_COREAPI_EXTENSION(library_manager_v6, library_manager_v5); public: diff --git a/sdk/foobar2000/SDK/menu_helpers.h b/sdk/foobar2000/SDK/menu_helpers.h index d944bbc..ac3c7ba 100644 --- a/sdk/foobar2000/SDK/menu_helpers.h +++ b/sdk/foobar2000/SDK/menu_helpers.h @@ -108,7 +108,8 @@ class standard_commands guid_seek_back_1s, guid_seek_back_5s, guid_seek_back_10s, guid_seek_back_30s, guid_seek_back_1min, guid_seek_back_2min, guid_seek_back_5min, guid_seek_back_10min, - guid_library_configure, guid_library_rescan + guid_library_configure, guid_library_rescan, + guid_internet_radio ; static bool run_main(const GUID & guid); diff --git a/sdk/foobar2000/SDK/metadb_handle.h b/sdk/foobar2000/SDK/metadb_handle.h index ecd0b03..af11b76 100644 --- a/sdk/foobar2000/SDK/metadb_handle.h +++ b/sdk/foobar2000/SDK/metadb_handle.h @@ -224,6 +224,16 @@ namespace metadb_handle_list_helper { void sort_by_format_get_order_v2( metadb_handle_list_cref p_list, size_t * order, const service_ptr_t & script, titleformat_hook * hook, int direction, abort_callback & aborter ); void sort_by_format_v2(metadb_handle_list_ref p_list, const service_ptr_t & script, titleformat_hook * hook, int direction, abort_callback & aborter); + struct sorter_t { + service_ptr_t < titleformat_object > obj; + int direction = 1; + titleformat_hook* hook = nullptr; + }; + + //! Late-2023 addition (new fb2k not required) \n + //! Multilayer stablesort using single info query pass, with multiple sort objects that can have different directions. + //! @param inOutOrder input & output order, please set to a valid permutration (such as identity) on input. + void sort_by_format_get_order_v3(metadb_handle_list_cref p_list, size_t* inOutOrder, sorter_t const * sorters, size_t nSorters, abort_callback& aborter); }; template class t_alloc = pfc::alloc_fast > diff --git a/sdk/foobar2000/SDK/metadb_handle_list.cpp b/sdk/foobar2000/SDK/metadb_handle_list.cpp index c9c6c8e..802b20f 100644 --- a/sdk/foobar2000/SDK/metadb_handle_list.cpp +++ b/sdk/foobar2000/SDK/metadb_handle_list.cpp @@ -9,24 +9,35 @@ namespace { + struct custom_sort_data_multi { + static constexpr unsigned numLocal = 4; + void setup(size_t count) { + if (count > numLocal) texts2 = std::make_unique< fb2k::sortString_t[] >( count - numLocal ); + } + fb2k::sortString_t& operator[] (size_t which) { + return which < numLocal ? texts1[which] : texts2[which - numLocal]; + } + const fb2k::sortString_t& operator[] (size_t which) const { + return which < numLocal ? texts1[which] : texts2[which - numLocal]; + } + + fb2k::sortString_t texts1[numLocal]; + std::unique_ptr< fb2k::sortString_t[] > texts2; + size_t index; + }; struct custom_sort_data { fb2k::sortString_t text; - t_size index; + size_t index; }; -} + template + static int custom_sort_compare(const custom_sort_data& elem1, const custom_sort_data& elem2) { + int ret = direction * fb2k::sortStringCompare(elem1.text, elem2.text); + if (ret == 0) ret = pfc::sgn_t((t_ssize)elem1.index - (t_ssize)elem2.index); + return ret; + } -template -static int custom_sort_compare(const custom_sort_data & elem1, const custom_sort_data & elem2 ) { - int ret = direction * fb2k::sortStringCompare(elem1.text,elem2.text); - if (ret == 0) ret = pfc::sgn_t((t_ssize)elem1.index - (t_ssize)elem2.index); - return ret; } - -template -static int _custom_sort_compare(const void * v1, const void * v2) { - return custom_sort_compare(*reinterpret_cast(v1),*reinterpret_cast(v2)); -} void metadb_handle_list_helper::sort_by_format(metadb_handle_list_ref p_list,const char * spec,titleformat_hook * p_hook) { service_ptr_t script; @@ -319,14 +330,34 @@ void metadb_handle_list_helper::sort_by_format_v2(metadb_handle_list_ref p_list, } void metadb_handle_list_helper::sort_by_format_get_order_v2(metadb_handle_list_cref p_list, size_t * order, const service_ptr_t & p_script, titleformat_hook * p_hook, int p_direction, abort_callback & aborter) { + sorter_t s = { p_script, p_direction, p_hook }; + size_t total = p_list.get_count(); + for (size_t walk = 0; walk < total; ++walk) order[walk] = walk; + sort_by_format_get_order_v3(p_list, order, &s, 1, aborter); +} + +void metadb_handle_list_helper::sort_by_format_get_order_v3(metadb_handle_list_cref p_list, size_t* order,sorter_t const* sorters, size_t nSorters, abort_callback& aborter) { // pfc::hires_timer timer; timer.start(); + typedef custom_sort_data_multi data_t; + const t_size count = p_list.get_count(); if (count == 0) return; - auto data = std::make_unique< custom_sort_data[] >(count); + + PFC_ASSERT(pfc::permutation_is_valid(order, count)); + + auto data = std::make_unique< data_t[] >(count); #if FOOBAR2000_TARGET_VERSION >= 81 - if ( p_script->requires_metadb_info_()) { + bool need_info = false; + for (size_t iSorter = 0; iSorter < nSorters; ++iSorter) { + auto& s = sorters[iSorter]; + PFC_ASSERT(s.direction == -1 || s.direction == 1); + if (s.obj->requires_metadb_info_()) { + need_info = true; break; + } + } + if (need_info) { // FB2K_console_formatter() << "sorting with queryMultiParallelEx_<>"; struct qmpc_context { qmpc_context() { @@ -337,14 +368,22 @@ void metadb_handle_list_helper::sort_by_format_get_order_v2(metadb_handle_list_c }; metadb_v2::get()->queryMultiParallelEx_< qmpc_context >(p_list, [&](size_t idx, metadb_v2::rec_t const& rec, qmpc_context& ctx) { aborter.check(); - if (p_hook) { - titleformat_hook_impl_splitter hookSplitter(&ctx.myHook, p_hook); - p_list[idx]->formatTitle_v2_(rec, &hookSplitter, ctx.temp, p_script, nullptr); - } else { - p_list[idx]->formatTitle_v2_(rec, &ctx.myHook, ctx.temp, p_script, nullptr); + auto& out = data[idx]; + out.setup(nSorters); + out.index = order[idx]; + + auto h = p_list[idx]; + + for (size_t iSorter = 0; iSorter < nSorters; ++iSorter) { + auto& s = sorters[iSorter]; + if (s.hook) { + titleformat_hook_impl_splitter hookSplitter(&ctx.myHook, s.hook); + h->formatTitle_v2_(rec, &hookSplitter, ctx.temp, s.obj, nullptr); + } else { + h->formatTitle_v2_(rec, &ctx.myHook, ctx.temp, s.obj, nullptr); + } + out[iSorter] = fb2k::makeSortString(ctx.temp); } - data[idx].index = idx; - data[idx].text = fb2k::makeSortString(ctx.temp); }); } else { // FB2K_console_formatter() << "sorting with blank metadb info"; @@ -358,18 +397,25 @@ void metadb_handle_list_helper::sort_by_format_get_order_v2(metadb_handle_list_c aborter.check(); size_t idx = walk++; if (idx >= count) return; - - if (p_hook) { - titleformat_hook_impl_splitter hookSplitter(&myHook, p_hook); - p_list[idx]->formatTitle_v2_(rec, &hookSplitter, temp, p_script, nullptr); - } else { - p_list[idx]->formatTitle_v2_(rec, &myHook, temp, p_script, nullptr); + + auto& out = data[idx]; + out.setup(nSorters); + out.index = order[idx]; + + for (size_t iSorter = 0; iSorter < nSorters; ++iSorter) { + auto& s = sorters[iSorter]; + if (s.hook) { + titleformat_hook_impl_splitter hookSplitter(&myHook, s.hook); + p_list[idx]->formatTitle_v2_(rec, &hookSplitter, temp, s.obj, nullptr); + } else { + p_list[idx]->formatTitle_v2_(rec, &myHook, temp, s.obj, nullptr); + } + + out[iSorter] = fb2k::makeSortString(temp); } - data[idx].index = idx; - data[idx].text = fb2k::makeSortString(temp); } - }, api->numRunsSanity( (count + 1999)/2000 ) ); - + }, api->numRunsSanity((count + 1999) / 2000)); + } #else { @@ -377,17 +423,27 @@ void metadb_handle_list_helper::sort_by_format_get_order_v2(metadb_handle_list_c auto work = [&] { tfhook_sort myHook; - titleformat_hook_impl_splitter hookSplitter(&myHook, p_hook); - titleformat_hook * const hookPtr = p_hook ? pfc::implicit_cast(&hookSplitter) : &myHook; pfc::string8_fastalloc temp; temp.prealloc(512); - const t_size total = p_list.get_size(); - for ( ;; ) { + for (;; ) { const t_size index = (counter)++; - if (index >= total || aborter.is_set()) break; - data[index].index = index; - p_list[index]->format_title(hookPtr, temp, p_script, 0); - data[index].text = fb2k::makeSortString(temp); + if (index >= count || aborter.is_set()) break; + + auto& out = data[index]; + out.setup(nSorters); + out.index = order[index]; + + for (size_t iSorter = 0; iSorter < nSorters; ++iSorter) { + auto& s = sorters[iSorter]; + if (s.hook) { + titleformat_hook_impl_splitter hookSplitter(&myHook, s.hook); + p_list[index]->format_title(&hookSplitter, temp, s.obj, 0); + } else { + p_list[index]->format_title(&myHook, temp, s.obj, 0); + } + + out[iSorter] = fb2k::makeSortString(temp); + } } }; @@ -402,30 +458,37 @@ void metadb_handle_list_helper::sort_by_format_get_order_v2(metadb_handle_list_c aborter.check(); // console::formatter() << "metadb_handle sort: prepared in " << pfc::format_time_ex(timer.query(),6); - + { + auto compare = [&](data_t const& elem1, data_t const& elem2) -> int { + for (size_t iSorter = 0; iSorter < nSorters; ++iSorter) { + int v = fb2k::sortStringCompare(elem1[iSorter], elem2[iSorter]); + if (v) return v * sorters[iSorter].direction; + } + + return pfc::sgn_t((t_ssize)elem1.index - (t_ssize)elem2.index); + }; + typedef decltype(data) container_t; - auto compare = p_direction > 0 ? custom_sort_compare<1> : custom_sort_compare<-1>; typedef decltype(compare) compare_t; pfc::sort_callback_impl_simple_wrap_t cb(data, compare); - - //pfc::sort_t(data, p_direction > 0 ? custom_sort_compare<1> : custom_sort_compare<-1>, count); - size_t concurrency = pfc::getOptimalWorkerThreadCountEx( count / 4096 ); - fb2k::sort( cb, count, concurrency, aborter ); + size_t concurrency = pfc::getOptimalWorkerThreadCountEx(count / 4096); + fb2k::sort(cb, count, concurrency, aborter); } - + //qsort(data.get_ptr(),count,sizeof(custom_sort_data),p_direction > 0 ? _custom_sort_compare<1> : _custom_sort_compare<-1>); // console::formatter() << "metadb_handle sort: sorted in " << pfc::format_time_ex(timer.query(),6); - for (t_size n = 0; nsend_force_play(); } } size_t retCanWriteSamples = 0; @@ -98,8 +104,12 @@ size_t output_impl::update_v2() { t_size cw = can_write_samples() * m_incoming_spec.chanCount; t_size delta = pfc::min_t(m_incoming.get_size() - m_incoming_ptr,cw); if (delta > 0) { + PFC_ASSERT(!m_sent_force_play); write(audio_chunk_temp_impl(m_incoming.get_ptr()+m_incoming_ptr,delta / m_incoming_spec.chanCount,m_incoming_spec.sampleRate,m_incoming_spec.chanCount,m_incoming_spec.chanMask)); m_incoming_ptr += delta; + if ( m_eos && this->queue_empty() ) { + this->send_force_play(); + } } retCanWriteSamples = (cw - delta) / m_incoming_spec.chanCount; } else if ( m_incoming_ptr == m_incoming.get_size() ) { @@ -118,8 +128,21 @@ double output_impl::get_latency() { } return ret; } + +void output_impl::force_play() { + if ( m_eos ) return; + m_eos = true; + if (queue_empty()) send_force_play(); +} +void output_impl::send_force_play() { + if (m_sent_force_play) return; + m_sent_force_play = true; + this->on_force_play(); +} + void output_impl::process_samples(const audio_chunk & p_chunk) { - pfc::dynamic_assert(m_incoming_ptr == m_incoming.get_size()); + PFC_ASSERT(queue_empty()); + PFC_ASSERT( !m_eos ); auto spec = p_chunk.get_spec(); if (!spec.is_valid()) pfc::throw_exception_with_message< exception_io_data >("Invalid audio stream specifications"); m_incoming_spec = spec; diff --git a/sdk/foobar2000/SDK/output.h b/sdk/foobar2000/SDK/output.h index d7fe1b5..459edbd 100644 --- a/sdk/foobar2000/SDK/output.h +++ b/sdk/foobar2000/SDK/output.h @@ -222,7 +222,7 @@ class output_factory_t : public service_factory_single_t class output_impl : public output_v5 { protected: - output_impl() : m_incoming_ptr(0) {} + output_impl() {} virtual void on_update() = 0; //! Will never get more input than as returned by can_write_samples(). virtual void write(const audio_chunk & p_data) = 0; @@ -232,22 +232,33 @@ class output_impl : public output_v5 { virtual void on_flush_changing_track() {on_flush();} virtual void open(audio_chunk::spec_t const & p_spec) = 0; - virtual void pause(bool p_state) = 0; - virtual void force_play() = 0; - virtual void volume_set(double p_val) = 0; + // base class virtual methods + // virtual void pause(bool p_state) = 0; + // virtual void volume_set(double p_val) = 0; + + //! Override this, not force_play(). \n + //! output_impl will defer call to on_force_play() until out of data in its buffer. + virtual void on_force_play() = 0; protected: void on_need_reopen() {m_active_spec.clear(); } 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); + void flush() override final; + void flush_changing_track() override final; + void update(bool & p_ready) override final; + size_t update_v2() override final; + double get_latency() override final; + void process_samples(const audio_chunk & p_chunk) override final; + void force_play() override final; + void on_flush_internal(); + void send_force_play(); + + bool queue_empty() const { return m_incoming_ptr == m_incoming.get_size(); } pfc::array_t m_incoming; - t_size m_incoming_ptr; + t_size m_incoming_ptr = 0; audio_chunk::spec_t m_incoming_spec,m_active_spec; + bool m_eos = false; // EOS issued by caller / no more data expected until a flush + bool m_sent_force_play = false; // set if sent on_force_play() }; diff --git a/sdk/foobar2000/SDK/playlist.cpp b/sdk/foobar2000/SDK/playlist.cpp index 9ac2b34..e306c02 100644 --- a/sdk/foobar2000/SDK/playlist.cpp +++ b/sdk/foobar2000/SDK/playlist.cpp @@ -978,3 +978,21 @@ void playlist_manager::on_file_rechaptered(const char* path, metadb_handle_list_ // obsolete method on_files_rechaptered(newItems); } + +namespace { + class process_locations_notify_lambda : public process_locations_notify { + public: + process_locations_notify::func_t f; + void on_completion(metadb_handle_list_cref p_items) override { + PFC_ASSERT(f != nullptr); + f(p_items); + } + void on_aborted() override {} + }; +} +process_locations_notify::ptr process_locations_notify::create(func_t arg) { + PFC_ASSERT(arg != nullptr); + auto ret = fb2k::service_new< process_locations_notify_lambda >(); + ret->f = arg; + return ret; +} \ No newline at end of file diff --git a/sdk/foobar2000/SDK/playlist.h b/sdk/foobar2000/SDK/playlist.h index 341ecdb..13dc23d 100644 --- a/sdk/foobar2000/SDK/playlist.h +++ b/sdk/foobar2000/SDK/playlist.h @@ -820,11 +820,13 @@ class NOVTABLE playlist_incoming_item_filter : public service_base { //! For use with playlist_incoming_item_filter_v2::process_locations_async(). //! \since 0.9.3 class NOVTABLE process_locations_notify : public service_base { + FB2K_MAKE_SERVICE_INTERFACE(process_locations_notify, service_base); public: - virtual void on_completion(const pfc::list_base_const_t & p_items) = 0; + virtual void on_completion(metadb_handle_list_cref p_items) = 0; virtual void on_aborted() = 0; - FB2K_MAKE_SERVICE_INTERFACE(process_locations_notify,service_base); + typedef std::function func_t; + static process_locations_notify::ptr create(func_t); }; typedef service_ptr_t process_locations_notify_ptr; diff --git a/sdk/foobar2000/SDK/preferences_page.h b/sdk/foobar2000/SDK/preferences_page.h index 3a01e96..b7e19d0 100644 --- a/sdk/foobar2000/SDK/preferences_page.h +++ b/sdk/foobar2000/SDK/preferences_page.h @@ -26,18 +26,28 @@ class preferences_state { //! 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 { public: +#ifdef _WIN32 //! Obsolete. virtual fb2k::hwnd_t create(fb2k::hwnd_t p_parent) { uBugCheck(); } +#endif + +#ifdef __APPLE__ + //! Returns fb2k::NSObjectWrapper holding your NSViewController + virtual service_ptr instantiate( ) = 0; +#endif + //! Retrieves name of the preferences page to be displayed in preferences tree (static string). virtual const char * get_name() = 0; //! Retrieves GUID of the page. virtual GUID get_guid() = 0; //! Retrieves GUID of parent page/branch of this page. See preferences_page::guid_* constants for list of standard parent GUIDs. Can also be a GUID of another page or a branch (see: preferences_branch). virtual GUID get_parent_guid() = 0; +#ifdef _WIN32 //! Obsolete. virtual bool reset_query() { return false; } //! Obsolete. virtual void reset() {} +#endif //! Retrieves help URL. Without overriding it, it will redirect to foobar2000 wiki. virtual bool get_help_url(pfc::string_base & p_out); @@ -108,6 +118,7 @@ class preferences_branch_factory : public _preferences_branch_factory { }; +#ifdef _WIN32 class preferences_page_callback : public service_base { FB2K_MAKE_SERVICE_INTERFACE(preferences_page_callback, service_base) public: @@ -132,13 +143,16 @@ class preferences_page_instance : public service_base { //! Resets this page's content to the default values. Does not apply any changes - lets user preview the changes before hitting "apply". virtual void reset() = 0; }; +#endif //! \since 1.0 //! Implements a preferences page. class preferences_page_v3 : public preferences_page_v2 { FB2K_MAKE_SERVICE_INTERFACE(preferences_page_v3, preferences_page_v2) public: +#ifdef _WIN32 virtual preferences_page_instance::ptr instantiate(fb2k::hwnd_t parent, preferences_page_callback::ptr callback) = 0; +#endif }; //! \since 1.5 diff --git a/sdk/foobar2000/SDK/tag_processor.cpp b/sdk/foobar2000/SDK/tag_processor.cpp index fd780e3..04b5884 100644 --- a/sdk/foobar2000/SDK/tag_processor.cpp +++ b/sdk/foobar2000/SDK/tag_processor.cpp @@ -135,20 +135,15 @@ void tag_processor::read_id3v2_trailing(const service_ptr_t & p_file,file_ bool have_id3v2 = true, have_trailing = true; try { read_id3v2(p_file,id3v2,p_abort); - } catch(exception_io_data) { + } catch(exception_io_data const &) { have_id3v2 = false; } - if (have_id3v2) { - // Disregard empty ID3v2 - if (id3v2.meta_get_count() == 0 && id3v2.get_replaygain().get_value_count() == 0) { - have_id3v2 = false; - } - } - - if (!have_id3v2 || !p_file->is_remote()) try { + const bool have_id3v2_text = have_id3v2 && id3v2.meta_get_count() > 0; + + if (!have_id3v2_text || !p_file->is_remote()) try { read_trailing(p_file,trailing,p_abort); - } catch(exception_io_data) { + } catch(exception_io_data const &) { have_trailing = false; } @@ -157,6 +152,7 @@ void tag_processor::read_id3v2_trailing(const service_ptr_t & p_file,file_ if (have_id3v2) { p_info._set_tag(id3v2); if (have_trailing) p_info._add_tag(trailing); + if (! have_id3v2_text ) p_info.copy_meta(trailing); } else { p_info._set_tag(trailing); } diff --git a/sdk/foobar2000/SDK/threadsLite.h b/sdk/foobar2000/SDK/threadsLite.h index a6c7256..ca5ab18 100644 --- a/sdk/foobar2000/SDK/threadsLite.h +++ b/sdk/foobar2000/SDK/threadsLite.h @@ -29,4 +29,8 @@ namespace fb2k { //! Uses new foobar2000 v2.0 methods if available, synchronizing to main thread via SendMessage(). \n //! Introduced to help recovering from method-called-from-wrong-context scenarios. Does *not* guarentee FIFO execution order contrary to plain inMainThread(). void inMainThreadSynchronous2(std::function f); + + //! Helper class for threads that call fb2k objects. Mainly needed for Android shims. You can safely ignore this. \n + //! Guaranteed to have startHere(), isActive() and waitTillDone() methods only. + typedef pfc::thread2 thread; } diff --git a/sdk/foobar2000/SDK/utility.cpp b/sdk/foobar2000/SDK/utility.cpp index 8af69c8..8218b87 100644 --- a/sdk/foobar2000/SDK/utility.cpp +++ b/sdk/foobar2000/SDK/utility.cpp @@ -259,6 +259,7 @@ void fb2k::keyValueIO::putInt( const char * name, int val ) { // fileDialog.h functionality #include "fileDialog.h" +#include "fsitem.h" namespace { using namespace fb2k; @@ -279,6 +280,27 @@ fb2k::fileDialogNotify::ptr fb2k::fileDialogNotify::create( std::functionrun(fb2k::fileDialogNotify::create(reply)); +} +void fb2k::fileDialogSetup::runSimple(fileDialogGetPath_t reply) { + fb2k::fileDialogReply_t wrapper = [reply] (fb2k::arrayRef arg) { + if ( arg.is_empty() ) {PFC_ASSERT(!"???"); return; } + if ( arg->size() != 1 ) { PFC_ASSERT(!"???"); return; } + auto obj = arg->itemAt(0); + fsItemBase::ptr fsitem; + if ( fsitem &= obj ) { + reply( fsitem->canonicalPath() ); return; + } + fb2k::stringRef str; + if ( str &= obj ) { + reply(str); return; + } + PFC_ASSERT( !"???" ); + }; + this->run(wrapper); +} + #include "input_file_type.h" void fb2k::fileDialogSetup::setAudioFileTypes() { @@ -311,13 +333,13 @@ namespace fb2k { #endif } +#if FB2K_SUPPORT_LOW_MEM_MODE static bool _isLowMemModeActive() { auto api = fb2k::configStore::tryGet(); if (api.is_empty()) return false; return api->getConfigBool("core.lowMemMode"); } -#if FB2K_SUPPORT_LOW_MEM_MODE bool isLowMemModeActive() { static bool cached = _isLowMemModeActive(); return cached; @@ -378,4 +400,4 @@ bool message_filter_remap_f1::pretranslate_message(MSG * p_msg) { return false; } -#endif \ No newline at end of file +#endif diff --git a/sdk/foobar2000/foo_sample/IO.cpp b/sdk/foobar2000/foo_sample/IO.cpp index e103538..febad04 100644 --- a/sdk/foobar2000/foo_sample/IO.cpp +++ b/sdk/foobar2000/foo_sample/IO.cpp @@ -1,12 +1,12 @@ #include "stdafx.h" #include #include +#include void RunIOTest() { try { - abort_callback_dummy noAbort; auto request = http_client::get()->create_request("GET"); - request->run("https://www.foobar2000.org", noAbort); + request->run("https://www.foobar2000.org", fb2k::noAbort); } catch (std::exception const & e) { popup_message::g_show( PFC_string_formatter() << "Network test failure:\n" << e, "Information"); return; @@ -21,7 +21,7 @@ namespace { // anon namespace local classes for good measure m_lstFiles.init_from_list( items ); } - void on_init(HWND p_wnd) override { + void on_init(ctx_t p_wnd) override { // Main thread, called before run() gets started } void run(threaded_process_status & p_status, abort_callback & p_abort) override { @@ -135,7 +135,7 @@ namespace { // anon namespace local classes for good measure // .. and delete the incomplete file try { - abort_callback_dummy noAbort; // we might be being aborted, don't let that prevent deletion + auto & noAbort = fb2k::noAbort; // we might be being aborted, don't let that prevent deletion m_outFS->remove( outPath, noAbort ); } catch(...) { // disregard errors - just report original copy error @@ -146,7 +146,7 @@ namespace { // anon namespace local classes for good measure } - void on_done(HWND p_wnd, bool p_was_aborted) override { + void on_done(ctx_t p_wnd, bool p_was_aborted) override { // All done, main thread again if (! p_was_aborted && m_errorLog.length() > 0 ) { @@ -171,8 +171,19 @@ namespace { // anon namespace local classes for good measure }; } +void RunCopyFilesHere(metadb_handle_list_cref data, const char * copyTo, fb2k::hwnd_t wndParent) { + + // Create worker object, a threaded_process_callback implementation. + auto worker = fb2k::service_new(data, copyTo); + const uint32_t flags = threaded_process::flag_show_abort | threaded_process::flag_show_progress | threaded_process::flag_show_item; + // Start the process asynchronously. + threaded_process::get()->run_modeless( worker, flags, wndParent, "Sample Component: Copying Files" ); + + // Our worker is now running. +} void RunCopyFiles(metadb_handle_list_cref data) { +#ifdef _WIN32 // Detect modal dialog wars. // If another modal dialog is active, bump it instead of allowing our modal dialog (uBrowseForFolder) to run. // Suppress this if the relevant code is intended to be launched by a modal dialog. @@ -183,18 +194,21 @@ void RunCopyFiles(metadb_handle_list_cref data) { // shared.dll method if (!uBrowseForFolder( wndParent, "Choose destination folder", copyTo )) return; - // shared.dll methods are win32 API wrappers and return plain paths with no protocol prepended - // Prefix with file:// before passing to fb2k filesystem methods. - // Actually the standard fb2k filesystem implementation recognizes paths even without the prefix, but we enforce it here as a good practice. - pfc::string8 copyTo2 = PFC_string_formatter() << "file://" << copyTo; - - // Create worker object, a threaded_process_callback implementation. - auto worker = fb2k::service_new(data, copyTo2); - const uint32_t flags = threaded_process::flag_show_abort | threaded_process::flag_show_progress | threaded_process::flag_show_item; - // Start the process asynchronously. - threaded_process::get()->run_modeless( worker, flags, wndParent, "Sample Component: Copying Files" ); - - // Our worker is now running. + // shared.dll methods are win32 API wrappers and return plain paths with no protocol prepended + // Prefix with file:// before passing to fb2k filesystem methods. + // Actually the standard fb2k filesystem implementation recognizes paths even without the prefix, but we enforce it here as a good practice. + pfc::string8 copyTo2 = PFC_string_formatter() << "file://" << copyTo; + + RunCopyFilesHere(data, copyTo2, wndParent); +#else + auto tracksCopy = std::make_shared( data ); + auto setup = fb2k::fileDialog::get()->setupOpenFolder(); + setup->setTitle("Choose destination folder"); + setup->runSimple( [tracksCopy] (fb2k::stringRef path) { + RunCopyFilesHere(*tracksCopy, path->c_str(), core_api::get_main_window()); + } ); + +#endif } @@ -278,7 +292,7 @@ namespace { // Touchy subject // Should we let the user abort an incomplete tag write? // Let's better not - abort_callback_dummy noAbort; + auto & noAbort = fb2k::noAbort; // This can be called many times for files with multiple subsongs writer->set_info( subsong, info, noAbort ); @@ -314,7 +328,7 @@ namespace { } void RunAlterTagsLL(metadb_handle_list_cref data) { - const HWND wndParent = core_api::get_main_window(); + const auto wndParent = core_api::get_main_window(); // Our worker object, a threaded_process_callback subclass. auto worker = fb2k::service_new< processLLtags > ( data ); diff --git a/sdk/foobar2000/foo_sample/Mac/fooSampleDSPView.h b/sdk/foobar2000/foo_sample/Mac/fooSampleDSPView.h new file mode 100644 index 0000000..1824b31 --- /dev/null +++ b/sdk/foobar2000/foo_sample/Mac/fooSampleDSPView.h @@ -0,0 +1,12 @@ +// +// fooSampleDSPView.h +// foo_sample +// +// Created by P on 01/09/2023. +// + +#import + + +@interface fooSampleDSPView : NSViewController +@end diff --git a/sdk/foobar2000/foo_sample/Mac/fooSampleDSPView.mm b/sdk/foobar2000/foo_sample/Mac/fooSampleDSPView.mm new file mode 100644 index 0000000..b692d3b --- /dev/null +++ b/sdk/foobar2000/foo_sample/Mac/fooSampleDSPView.mm @@ -0,0 +1,41 @@ +#import "stdafx.h" +#import "fooSampleDSPView.h" +#import "dsp_sample.h" + +@interface fooSampleDSPView () +@property (nonatomic) dsp_preset_edit_callback_v2::ptr callback; +@property (nonatomic) NSNumber * gain; +@end + +@implementation fooSampleDSPView + +- (instancetype)init { + // IMPORTANT: feed OUR NSBundle, bundleForClass works well for this + return [self initWithNibName: @"fooSampleDSPView" bundle:[NSBundle bundleForClass: [self class]]]; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do view setup here. + + dsp_preset_impl preset; + _callback->get_preset(preset); + self.gain = [NSNumber numberWithFloat: parse_preset(preset)]; +} + +- (IBAction)onEdit:(id)sender { + [self apply]; +} + +- (void) apply { + dsp_preset_impl preset; + make_preset( self.gain.floatValue , preset); + _callback->set_preset( preset ); +} +@end + +service_ptr ConfigureSampleDSP( fb2k::hwnd_t parent, dsp_preset_edit_callback_v2::ptr callback ) { + fooSampleDSPView * dialog = [fooSampleDSPView new]; + dialog.callback = callback; + return fb2k::wrapNSObject( dialog ); +} diff --git a/sdk/foobar2000/foo_sample/Mac/fooSampleDSPView.xib b/sdk/foobar2000/foo_sample/Mac/fooSampleDSPView.xib new file mode 100644 index 0000000..799f6e3 --- /dev/null +++ b/sdk/foobar2000/foo_sample/Mac/fooSampleDSPView.xib @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/foobar2000/foo_sample/Mac/fooSampleMacPreferences.h b/sdk/foobar2000/foo_sample/Mac/fooSampleMacPreferences.h new file mode 100644 index 0000000..b8ac208 --- /dev/null +++ b/sdk/foobar2000/foo_sample/Mac/fooSampleMacPreferences.h @@ -0,0 +1,12 @@ +// +// fooSampleMacPreferences.h +// foo_sample +// +// Created by P on 01/09/2023. +// + +#import + +@interface fooSampleMacPreferences : NSViewController + +@end diff --git a/sdk/foobar2000/foo_sample/Mac/fooSampleMacPreferences.mm b/sdk/foobar2000/foo_sample/Mac/fooSampleMacPreferences.mm new file mode 100644 index 0000000..b0b80aa --- /dev/null +++ b/sdk/foobar2000/foo_sample/Mac/fooSampleMacPreferences.mm @@ -0,0 +1,58 @@ +#import "stdafx.h" +#import "fooSampleMacPreferences.h" + +namespace foo_sample { + extern cfg_uint cfg_bogoSetting1, cfg_bogoSetting2; +} + +@interface fooSampleMacPreferences () +@property (nonatomic) NSNumber* bogo1; +@property (nonatomic) NSNumber* bogo2; +@end + +@implementation fooSampleMacPreferences + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do view setup here. +} +- (instancetype)init { + // IMPORTANT: feed OUR NSBundle, bundleForClass works well for this + self = [self initWithNibName: @"fooSampleMacPreferences" bundle:[NSBundle bundleForClass: [self class]]]; + [self loadSettings]; + return self; +} +- (void) loadSettings { + self.bogo1 = [NSNumber numberWithUnsignedLong: foo_sample::cfg_bogoSetting1]; + self.bogo2 = [NSNumber numberWithUnsignedLong: foo_sample::cfg_bogoSetting2]; +} +- (IBAction)onBogo1:(id)sender { + foo_sample::cfg_bogoSetting1 = self.bogo1.unsignedLongValue; +} +- (IBAction)onBogo2:(id)sender { + foo_sample::cfg_bogoSetting2 = self.bogo2.unsignedLongValue; +} + + +@end + + + + + +namespace { +class preferences_page_sample : public preferences_page { + public: + service_ptr instantiate() override { + return fb2k::wrapNSObject( [ fooSampleMacPreferences new ] ); + } + const char * get_name() override {return "Sample Component";} + GUID get_guid() override { + // This is our GUID. Replace with your own when reusing the code. + return GUID { 0x7702c93e, 0x24dc, 0x48ed, { 0x8d, 0xb1, 0x3f, 0x27, 0xb3, 0x8c, 0x7c, 0xc9 } }; + } + GUID get_parent_guid() override {return guid_tools;} + }; + + FB2K_SERVICE_FACTORY(preferences_page_sample); +} diff --git a/sdk/foobar2000/foo_sample/Mac/fooSampleMacPreferences.xib b/sdk/foobar2000/foo_sample/Mac/fooSampleMacPreferences.xib new file mode 100644 index 0000000..82af698 --- /dev/null +++ b/sdk/foobar2000/foo_sample/Mac/fooSampleMacPreferences.xib @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/foobar2000/foo_sample/contextmenu.cpp b/sdk/foobar2000/foo_sample/contextmenu.cpp index dd788a8..f2ae310 100644 --- a/sdk/foobar2000/foo_sample/contextmenu.cpp +++ b/sdk/foobar2000/foo_sample/contextmenu.cpp @@ -32,7 +32,7 @@ namespace { // anon namespace local classes for good measure static void RunAlterTags(metadb_handle_list_cref data) { // Simple alter-file-tags functionality - const HWND wndParent = core_api::get_main_window(); + const auto wndParent = core_api::get_main_window(); // Filter object that applies our edits to the file tags auto filter = fb2k::service_new(); @@ -51,6 +51,7 @@ static void RunAlterTags(metadb_handle_list_cref data) { // Simple context menu item class. class myitem : public contextmenu_item_simple { + typedef contextmenu_item_simple super_t; public: enum { cmd_test1 = 0, @@ -102,14 +103,14 @@ class myitem : public contextmenu_item_simple { bool context_get_display(unsigned p_index,metadb_handle_list_cref p_data,pfc::string_base & p_out,unsigned & p_displayflags,const GUID & p_caller) { switch(p_index) { case cmd_test1: - if (!__super::context_get_display(p_index, p_data, p_out, p_displayflags, p_caller)) return false; + if (!super_t::context_get_display(p_index, p_data, p_out, p_displayflags, p_caller)) return false; // Example context sensitive label: append the count of selected items to the label. p_out << " : " << p_data.get_count() << " item"; if (p_data.get_count() != 1) p_out << "s"; p_out << " selected"; return true; default: - return __super::context_get_display(p_index, p_data, p_out, p_displayflags, p_caller); + return super_t::context_get_display(p_index, p_data, p_out, p_displayflags, p_caller); } } GUID get_item_guid(unsigned p_index) { diff --git a/sdk/foobar2000/foo_sample/decode.cpp b/sdk/foobar2000/foo_sample/decode.cpp index 1f4ab1d..c2536ec 100644 --- a/sdk/foobar2000/foo_sample/decode.cpp +++ b/sdk/foobar2000/foo_sample/decode.cpp @@ -4,8 +4,8 @@ class calculate_peak_process : public threaded_process_callback { public: calculate_peak_process(metadb_handle_list_cref items) : m_items(items), m_peak() {} - void on_init(HWND p_wnd) {} - void run(threaded_process_status & p_status,abort_callback & p_abort) { + void on_init(ctx_t p_wnd) override {} + void run(threaded_process_status & p_status,abort_callback & p_abort) override { try { const t_uint32 decode_flags = input_flag_no_seeking | input_flag_no_looping; // tell the decoders that we won't seek and that we don't want looping on formats that support looping. input_helper input; // this object manages lowlevel input_decoder calls for us. @@ -41,7 +41,7 @@ class calculate_peak_process : public threaded_process_callback { m_failMsg = e.what(); } } - void on_done(HWND p_wnd,bool p_was_aborted) { + void on_done(ctx_t p_wnd,bool p_was_aborted) override { if (!p_was_aborted) { if (!m_failMsg.is_empty()) { popup_message::g_complain("Peak scan failure", m_failMsg); diff --git a/sdk/foobar2000/foo_sample/dsp.cpp b/sdk/foobar2000/foo_sample/dsp_sample.cpp similarity index 85% rename from sdk/foobar2000/foo_sample/dsp.cpp rename to sdk/foobar2000/foo_sample/dsp_sample.cpp index 2b49e3d..9514ef5 100644 --- a/sdk/foobar2000/foo_sample/dsp.cpp +++ b/sdk/foobar2000/foo_sample/dsp_sample.cpp @@ -1,13 +1,22 @@ #include "stdafx.h" +#include "dsp_sample.h" + +#ifdef _WIN32 +#include #include "resource.h" static void RunDSPConfigPopup(const dsp_preset & p_data,HWND p_parent,dsp_preset_edit_callback & p_callback); +#endif + +#ifdef __APPLE__ +// fooSampleDSPView.mm +service_ptr ConfigureSampleDSP( fb2k::hwnd_t parent, dsp_preset_edit_callback_v2::ptr callback ); +#endif class dsp_sample : public dsp_impl_base { public: - dsp_sample(dsp_preset const & in) : m_gain(0) { - parse_preset(m_gain, in); + dsp_sample(dsp_preset const & in) : m_gain(parse_preset(in)) { } static GUID g_get_guid() { @@ -62,18 +71,17 @@ class dsp_sample : public dsp_impl_base make_preset(0, p_out); return true; } +#ifdef _WIN32 static void g_show_config_popup(const dsp_preset & p_data,HWND p_parent,dsp_preset_edit_callback & p_callback) { ::RunDSPConfigPopup(p_data, p_parent, p_callback); } +#endif // _WIN32 +#ifdef __APPLE__ + static service_ptr g_show_config_popup( fb2k::hwnd_t parent, dsp_preset_edit_callback_v2::ptr callback ) { + return ConfigureSampleDSP( parent, callback ); + } +#endif // __APPLE__ static bool g_have_config_popup() {return true;} - static void make_preset(float gain, dsp_preset & out) { - dsp_preset_builder builder; builder << gain; builder.finish(g_get_guid(), out); - } - static void parse_preset(float & gain, const dsp_preset & in) { - try { - dsp_preset_parser parser(in); parser >> gain; - } catch(exception_io_data) {gain = 0;} - } private: float m_gain; }; @@ -81,6 +89,7 @@ class dsp_sample : public dsp_impl_base // Use dsp_factory_nopreset_t<> instead of dsp_factory_t<> if your DSP does not provide preset/configuration functionality. static dsp_factory_t g_dsp_sample_factory; +#ifdef _WIN32 class CMyDSPPopup : public CDialogImpl { public: @@ -105,12 +114,12 @@ class CMyDSPPopup : public CDialogImpl { private: BOOL OnInitDialog(CWindow, LPARAM) { + m_dark.AddDialogWithControls(m_hWnd); m_slider = GetDlgItem(IDC_SLIDER); m_slider.SetRange(0, RangeTotal); { - float val; - dsp_sample::parse_preset(val, m_initData); + float val = parse_preset(m_initData); m_slider.SetPos( pfc::clip_t( pfc::rint32(val), RangeMin, RangeMax ) - RangeMin ); RefreshLabel(val); } @@ -127,7 +136,7 @@ class CMyDSPPopup : public CDialogImpl { { dsp_preset_impl preset; - dsp_sample::make_preset(val, preset); + make_preset(val, preset); m_callback.on_preset_changed(preset); } RefreshLabel(val); @@ -142,6 +151,7 @@ class CMyDSPPopup : public CDialogImpl { dsp_preset_edit_callback & m_callback; CTrackBarCtrl m_slider; + fb2k::CDarkModeHooks m_dark; }; static void RunDSPConfigPopup(const dsp_preset & p_data,HWND p_parent,dsp_preset_edit_callback & p_callback) { @@ -152,3 +162,4 @@ static void RunDSPConfigPopup(const dsp_preset & p_data,HWND p_parent,dsp_preset p_callback.on_preset_changed(p_data); } } +#endif diff --git a/sdk/foobar2000/foo_sample/dsp_sample.h b/sdk/foobar2000/foo_sample/dsp_sample.h new file mode 100644 index 0000000..b0d6a2f --- /dev/null +++ b/sdk/foobar2000/foo_sample/dsp_sample.h @@ -0,0 +1,19 @@ +#pragma once + +namespace dsp_sample_common { + static constexpr GUID guid = { 0x890827b, 0x67df, 0x4c27, { 0xba, 0x1a, 0x4f, 0x95, 0x8d, 0xf, 0xb5, 0xd0 } }; + + static void make_preset(float gain, dsp_preset & out) { + dsp_preset_builder builder; builder << gain; builder.finish(guid, out); + } + static float parse_preset(const dsp_preset & in) { + try { + float gain; + dsp_preset_parser parser(in); parser >> gain; + return gain; + } catch(exception_io_data const &) {return 0;} + } + +} + +using namespace dsp_sample_common; diff --git a/sdk/foobar2000/foo_sample/foo_sample.vcxproj b/sdk/foobar2000/foo_sample/foo_sample.vcxproj index 2b1d488..dc4de5c 100644 --- a/sdk/foobar2000/foo_sample/foo_sample.vcxproj +++ b/sdk/foobar2000/foo_sample/foo_sample.vcxproj @@ -332,7 +332,7 @@ - + @@ -361,6 +361,7 @@ + @@ -369,7 +370,6 @@ - @@ -390,13 +390,5 @@ - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - + \ No newline at end of file diff --git a/sdk/foobar2000/foo_sample/foo_sample.vcxproj.filters b/sdk/foobar2000/foo_sample/foo_sample.vcxproj.filters index e0dae3e..158409b 100644 --- a/sdk/foobar2000/foo_sample/foo_sample.vcxproj.filters +++ b/sdk/foobar2000/foo_sample/foo_sample.vcxproj.filters @@ -21,9 +21,6 @@ Source Files - - Source Files - Source Files @@ -75,6 +72,9 @@ Source Files + + Source Files + @@ -86,6 +86,9 @@ Header Files + + Header Files + @@ -94,6 +97,5 @@ - \ No newline at end of file diff --git a/sdk/foobar2000/foo_sample/foo_sample.xcodeproj/project.pbxproj b/sdk/foobar2000/foo_sample/foo_sample.xcodeproj/project.pbxproj new file mode 100644 index 0000000..c52e3f3 --- /dev/null +++ b/sdk/foobar2000/foo_sample/foo_sample.xcodeproj/project.pbxproj @@ -0,0 +1,447 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 0F1FDDBA2AA0ADDF00DE8967 /* initquit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F1FDDB62AA0ADDF00DE8967 /* initquit.cpp */; }; + 0F1FDDBB2AA0ADDF00DE8967 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F1FDDB72AA0ADDF00DE8967 /* main.cpp */; }; + 0F1FDDC02AA0AE1E00DE8967 /* libfoobar2000_SDK.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0F1FDDBD2AA0AE1E00DE8967 /* libfoobar2000_SDK.a */; }; + 0F1FDDC12AA0AE1E00DE8967 /* libfoobar2000_SDK_helpers.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0F1FDDBE2AA0AE1E00DE8967 /* libfoobar2000_SDK_helpers.a */; }; + 0F1FDDC22AA0AE1E00DE8967 /* libpfc-Mac.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0F1FDDBF2AA0AE1E00DE8967 /* libpfc-Mac.a */; }; + 0F1FDDC82AA0B1F800DE8967 /* libshared.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0F1FDDC72AA0B1F800DE8967 /* libshared.a */; }; + 0F1FDDCA2AA0B1FE00DE8967 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0F1FDDC92AA0B1FE00DE8967 /* Cocoa.framework */; }; + 0F1FDDDE2AA0B34200DE8967 /* libfoobar2000_component_client.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0F1FDDDD2AA0B34200DE8967 /* libfoobar2000_component_client.a */; }; + 0F62440A2AA1E59E004FEC96 /* preferences.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F6244072AA1E4F4004FEC96 /* preferences.cpp */; }; + 0F6D10F12AA3C35C00774EED /* fooDecibelFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 0F6D10EF2AA3C35C00774EED /* fooDecibelFormatter.m */; }; + 0FBE14512AA1E85F00B1F71E /* NSView+embed.m in Sources */ = {isa = PBXBuildFile; fileRef = 0FBE14452AA1E85F00B1F71E /* NSView+embed.m */; }; + 0FBE14552AA1E8C800B1F71E /* fooSampleMacPreferences.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0FBE14532AA1E8C800B1F71E /* fooSampleMacPreferences.mm */; }; + 0FBE14562AA1E8C800B1F71E /* fooSampleMacPreferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0FBE14542AA1E8C800B1F71E /* fooSampleMacPreferences.xib */; }; + 0FBE14622AA1F74200B1F71E /* rating.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FBE14582AA1F74200B1F71E /* rating.cpp */; }; + 0FBE14632AA1F74200B1F71E /* contextmenu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FBE14592AA1F74200B1F71E /* contextmenu.cpp */; }; + 0FBE14642AA1F74200B1F71E /* input_raw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FBE145A2AA1F74200B1F71E /* input_raw.cpp */; }; + 0FBE14652AA1F74200B1F71E /* decode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FBE145B2AA1F74200B1F71E /* decode.cpp */; }; + 0FBE14662AA1F74200B1F71E /* dsp_sample.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FBE145C2AA1F74200B1F71E /* dsp_sample.cpp */; }; + 0FBE14672AA1F74200B1F71E /* mainmenu-dynamic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FBE145D2AA1F74200B1F71E /* mainmenu-dynamic.cpp */; }; + 0FBE14692AA1F74200B1F71E /* IO.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FBE145F2AA1F74200B1F71E /* IO.cpp */; }; + 0FBE146A2AA1F74200B1F71E /* playback_stream_capture.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FBE14602AA1F74200B1F71E /* playback_stream_capture.cpp */; }; + 0FBE146C2AA1FF1500B1F71E /* ui_and_threads.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FBE146B2AA1FF1500B1F71E /* ui_and_threads.cpp */; }; + 0FCA71142AA21F69001CB0F2 /* fooSampleDSPView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0FCA71122AA21F69001CB0F2 /* fooSampleDSPView.mm */; }; + 0FCA71152AA21F69001CB0F2 /* fooSampleDSPView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0FCA71132AA21F69001CB0F2 /* fooSampleDSPView.xib */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 0F1FDDAD2AA0AD9B00DE8967 /* foo_sample.component */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = foo_sample.component; sourceTree = BUILT_PRODUCTS_DIR; }; + 0F1FDDB42AA0ADDF00DE8967 /* mainmenu.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mainmenu.cpp; sourceTree = ""; }; + 0F1FDDB52AA0ADDF00DE8967 /* playback_state.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = playback_state.cpp; sourceTree = ""; }; + 0F1FDDB62AA0ADDF00DE8967 /* initquit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = initquit.cpp; sourceTree = ""; }; + 0F1FDDB72AA0ADDF00DE8967 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + 0F1FDDBD2AA0AE1E00DE8967 /* libfoobar2000_SDK.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libfoobar2000_SDK.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 0F1FDDBE2AA0AE1E00DE8967 /* libfoobar2000_SDK_helpers.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libfoobar2000_SDK_helpers.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 0F1FDDBF2AA0AE1E00DE8967 /* libpfc-Mac.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = "libpfc-Mac.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 0F1FDDC62AA0AF8400DE8967 /* stdafx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stdafx.h; sourceTree = ""; }; + 0F1FDDC72AA0B1F800DE8967 /* libshared.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libshared.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 0F1FDDC92AA0B1FE00DE8967 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 0F1FDDDD2AA0B34200DE8967 /* libfoobar2000_component_client.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libfoobar2000_component_client.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 0F6244072AA1E4F4004FEC96 /* preferences.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = preferences.cpp; sourceTree = ""; }; + 0F6D10EF2AA3C35C00774EED /* fooDecibelFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = fooDecibelFormatter.m; sourceTree = ""; }; + 0F6D10F02AA3C35C00774EED /* fooDecibelFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fooDecibelFormatter.h; sourceTree = ""; }; + 0FBE14402AA1E85F00B1F71E /* NSView+embed.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSView+embed.h"; sourceTree = ""; }; + 0FBE14452AA1E85F00B1F71E /* NSView+embed.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSView+embed.m"; sourceTree = ""; }; + 0FBE14522AA1E8C800B1F71E /* fooSampleMacPreferences.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = fooSampleMacPreferences.h; sourceTree = ""; }; + 0FBE14532AA1E8C800B1F71E /* fooSampleMacPreferences.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = fooSampleMacPreferences.mm; sourceTree = ""; }; + 0FBE14542AA1E8C800B1F71E /* fooSampleMacPreferences.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = fooSampleMacPreferences.xib; sourceTree = ""; }; + 0FBE14582AA1F74200B1F71E /* rating.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = rating.cpp; sourceTree = ""; }; + 0FBE14592AA1F74200B1F71E /* contextmenu.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = contextmenu.cpp; sourceTree = ""; }; + 0FBE145A2AA1F74200B1F71E /* input_raw.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = input_raw.cpp; sourceTree = ""; }; + 0FBE145B2AA1F74200B1F71E /* decode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = decode.cpp; sourceTree = ""; }; + 0FBE145C2AA1F74200B1F71E /* dsp_sample.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dsp_sample.cpp; sourceTree = ""; }; + 0FBE145D2AA1F74200B1F71E /* mainmenu-dynamic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "mainmenu-dynamic.cpp"; sourceTree = ""; }; + 0FBE145E2AA1F74200B1F71E /* readme.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = readme.txt; sourceTree = ""; }; + 0FBE145F2AA1F74200B1F71E /* IO.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IO.cpp; sourceTree = ""; }; + 0FBE14602AA1F74200B1F71E /* playback_stream_capture.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = playback_stream_capture.cpp; sourceTree = ""; }; + 0FBE14612AA1F74200B1F71E /* playback_stream_capture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = playback_stream_capture.h; sourceTree = ""; }; + 0FBE146B2AA1FF1500B1F71E /* ui_and_threads.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ui_and_threads.cpp; sourceTree = ""; }; + 0FCA71112AA21F69001CB0F2 /* fooSampleDSPView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = fooSampleDSPView.h; sourceTree = ""; }; + 0FCA71122AA21F69001CB0F2 /* fooSampleDSPView.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = fooSampleDSPView.mm; sourceTree = ""; }; + 0FCA71132AA21F69001CB0F2 /* fooSampleDSPView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = fooSampleDSPView.xib; sourceTree = ""; }; + 0FD323BF2AA3C45C00C0C2F7 /* dsp_sample.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dsp_sample.h; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 0F1FDDAA2AA0AD9B00DE8967 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 0F1FDDDE2AA0B34200DE8967 /* libfoobar2000_component_client.a in Frameworks */, + 0F1FDDCA2AA0B1FE00DE8967 /* Cocoa.framework in Frameworks */, + 0F1FDDC82AA0B1F800DE8967 /* libshared.a in Frameworks */, + 0F1FDDC02AA0AE1E00DE8967 /* libfoobar2000_SDK.a in Frameworks */, + 0F1FDDC12AA0AE1E00DE8967 /* libfoobar2000_SDK_helpers.a in Frameworks */, + 0F1FDDC22AA0AE1E00DE8967 /* libpfc-Mac.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 0F1FDDA42AA0AD9B00DE8967 = { + isa = PBXGroup; + children = ( + 0FBE146B2AA1FF1500B1F71E /* ui_and_threads.cpp */, + 0FBE14592AA1F74200B1F71E /* contextmenu.cpp */, + 0FBE145B2AA1F74200B1F71E /* decode.cpp */, + 0FBE145C2AA1F74200B1F71E /* dsp_sample.cpp */, + 0FD323BF2AA3C45C00C0C2F7 /* dsp_sample.h */, + 0FBE145A2AA1F74200B1F71E /* input_raw.cpp */, + 0FBE145F2AA1F74200B1F71E /* IO.cpp */, + 0FBE145D2AA1F74200B1F71E /* mainmenu-dynamic.cpp */, + 0FBE14602AA1F74200B1F71E /* playback_stream_capture.cpp */, + 0FBE14612AA1F74200B1F71E /* playback_stream_capture.h */, + 0FBE14582AA1F74200B1F71E /* rating.cpp */, + 0FBE145E2AA1F74200B1F71E /* readme.txt */, + 0FBE14572AA1F41A00B1F71E /* Mac */, + 0F6244072AA1E4F4004FEC96 /* preferences.cpp */, + 0F1FDDC62AA0AF8400DE8967 /* stdafx.h */, + 0F1FDDB62AA0ADDF00DE8967 /* initquit.cpp */, + 0F1FDDB72AA0ADDF00DE8967 /* main.cpp */, + 0F1FDDB42AA0ADDF00DE8967 /* mainmenu.cpp */, + 0F1FDDB52AA0ADDF00DE8967 /* playback_state.cpp */, + 0FBE14362AA1E85F00B1F71E /* helpers-mac */, + 0F1FDDAE2AA0AD9B00DE8967 /* Products */, + 0F1FDDBC2AA0AE1E00DE8967 /* Frameworks */, + ); + sourceTree = ""; + }; + 0F1FDDAE2AA0AD9B00DE8967 /* Products */ = { + isa = PBXGroup; + children = ( + 0F1FDDAD2AA0AD9B00DE8967 /* foo_sample.component */, + ); + name = Products; + sourceTree = ""; + }; + 0F1FDDBC2AA0AE1E00DE8967 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 0F1FDDDD2AA0B34200DE8967 /* libfoobar2000_component_client.a */, + 0F1FDDC92AA0B1FE00DE8967 /* Cocoa.framework */, + 0F1FDDC72AA0B1F800DE8967 /* libshared.a */, + 0F1FDDBD2AA0AE1E00DE8967 /* libfoobar2000_SDK.a */, + 0F1FDDBE2AA0AE1E00DE8967 /* libfoobar2000_SDK_helpers.a */, + 0F1FDDBF2AA0AE1E00DE8967 /* libpfc-Mac.a */, + ); + name = Frameworks; + sourceTree = ""; + }; + 0FBE14362AA1E85F00B1F71E /* helpers-mac */ = { + isa = PBXGroup; + children = ( + 0F6D10F02AA3C35C00774EED /* fooDecibelFormatter.h */, + 0F6D10EF2AA3C35C00774EED /* fooDecibelFormatter.m */, + 0FBE14402AA1E85F00B1F71E /* NSView+embed.h */, + 0FBE14452AA1E85F00B1F71E /* NSView+embed.m */, + ); + name = "helpers-mac"; + path = "../helpers-mac"; + sourceTree = ""; + }; + 0FBE14572AA1F41A00B1F71E /* Mac */ = { + isa = PBXGroup; + children = ( + 0FBE14522AA1E8C800B1F71E /* fooSampleMacPreferences.h */, + 0FBE14532AA1E8C800B1F71E /* fooSampleMacPreferences.mm */, + 0FBE14542AA1E8C800B1F71E /* fooSampleMacPreferences.xib */, + 0FCA71112AA21F69001CB0F2 /* fooSampleDSPView.h */, + 0FCA71122AA21F69001CB0F2 /* fooSampleDSPView.mm */, + 0FCA71132AA21F69001CB0F2 /* fooSampleDSPView.xib */, + ); + path = Mac; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 0F1FDDAC2AA0AD9B00DE8967 /* foo_sample */ = { + isa = PBXNativeTarget; + buildConfigurationList = 0F1FDDB12AA0AD9B00DE8967 /* Build configuration list for PBXNativeTarget "foo_sample" */; + buildPhases = ( + 0F1FDDA92AA0AD9B00DE8967 /* Sources */, + 0F1FDDAA2AA0AD9B00DE8967 /* Frameworks */, + 0F1FDDAB2AA0AD9B00DE8967 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = foo_sample; + productName = foo_sample; + productReference = 0F1FDDAD2AA0AD9B00DE8967 /* foo_sample.component */; + productType = "com.apple.product-type.bundle"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 0F1FDDA52AA0AD9B00DE8967 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastUpgradeCheck = 1500; + TargetAttributes = { + 0F1FDDAC2AA0AD9B00DE8967 = { + CreatedOnToolsVersion = 14.3.1; + }; + }; + }; + buildConfigurationList = 0F1FDDA82AA0AD9B00DE8967 /* Build configuration list for PBXProject "foo_sample" */; + compatibilityVersion = "Xcode 12.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 0F1FDDA42AA0AD9B00DE8967; + productRefGroup = 0F1FDDAE2AA0AD9B00DE8967 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 0F1FDDAC2AA0AD9B00DE8967 /* foo_sample */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 0F1FDDAB2AA0AD9B00DE8967 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0FBE14562AA1E8C800B1F71E /* fooSampleMacPreferences.xib in Resources */, + 0FCA71152AA21F69001CB0F2 /* fooSampleDSPView.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 0F1FDDA92AA0AD9B00DE8967 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0FBE14692AA1F74200B1F71E /* IO.cpp in Sources */, + 0FBE14552AA1E8C800B1F71E /* fooSampleMacPreferences.mm in Sources */, + 0FBE14672AA1F74200B1F71E /* mainmenu-dynamic.cpp in Sources */, + 0FBE14512AA1E85F00B1F71E /* NSView+embed.m in Sources */, + 0FBE14632AA1F74200B1F71E /* contextmenu.cpp in Sources */, + 0FCA71142AA21F69001CB0F2 /* fooSampleDSPView.mm in Sources */, + 0FBE14652AA1F74200B1F71E /* decode.cpp in Sources */, + 0F6D10F12AA3C35C00774EED /* fooDecibelFormatter.m in Sources */, + 0FBE146C2AA1FF1500B1F71E /* ui_and_threads.cpp in Sources */, + 0FBE14662AA1F74200B1F71E /* dsp_sample.cpp in Sources */, + 0F1FDDBB2AA0ADDF00DE8967 /* main.cpp in Sources */, + 0FBE14642AA1F74200B1F71E /* input_raw.cpp in Sources */, + 0F62440A2AA1E59E004FEC96 /* preferences.cpp in Sources */, + 0F1FDDBA2AA0ADDF00DE8967 /* initquit.cpp in Sources */, + 0FBE14622AA1F74200B1F71E /* rating.cpp in Sources */, + 0FBE146A2AA1F74200B1F71E /* playback_stream_capture.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 0F1FDDAF2AA0AD9B00DE8967 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = stdafx.h; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + .., + ../.., + ); + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + 0F1FDDB02AA0AD9B00DE8967 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = stdafx.h; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + .., + ../.., + ); + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = macosx; + }; + name = Release; + }; + 0F1FDDB22AA0AD9B00DE8967 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEAD_CODE_STRIPPING = YES; + DEVELOPMENT_TEAM = ""; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INFOPLIST_KEY_NSPrincipalClass = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles"; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = "com.foobar2000.foo-sample"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + WRAPPER_EXTENSION = component; + }; + name = Debug; + }; + 0F1FDDB32AA0AD9B00DE8967 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEAD_CODE_STRIPPING = YES; + DEVELOPMENT_TEAM = ""; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INFOPLIST_KEY_NSPrincipalClass = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles"; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = "com.foobar2000.foo-sample"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + WRAPPER_EXTENSION = component; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 0F1FDDA82AA0AD9B00DE8967 /* Build configuration list for PBXProject "foo_sample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0F1FDDAF2AA0AD9B00DE8967 /* Debug */, + 0F1FDDB02AA0AD9B00DE8967 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 0F1FDDB12AA0AD9B00DE8967 /* Build configuration list for PBXNativeTarget "foo_sample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0F1FDDB22AA0AD9B00DE8967 /* Debug */, + 0F1FDDB32AA0AD9B00DE8967 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 0F1FDDA52AA0AD9B00DE8967 /* Project object */; +} diff --git a/sdk/foobar2000/foo_sample/foo_sample.xcworkspace/contents.xcworkspacedata b/sdk/foobar2000/foo_sample/foo_sample.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..be803c3 --- /dev/null +++ b/sdk/foobar2000/foo_sample/foo_sample.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + diff --git a/sdk/foobar2000/foo_sample/initquit.cpp b/sdk/foobar2000/foo_sample/initquit.cpp index bcd131b..62ddeb8 100644 --- a/sdk/foobar2000/foo_sample/initquit.cpp +++ b/sdk/foobar2000/foo_sample/initquit.cpp @@ -1,15 +1,17 @@ #include "stdafx.h" -// Sample initquit implementation. See also: initquit class documentation in relevant header. +namespace { + // Sample initquit implementation. See also: initquit class documentation in relevant header. + class myinitquit : public initquit { + public: + void on_init() { + console::print("Sample component: on_init()"); + } + void on_quit() { + console::print("Sample component: on_quit()"); + } + }; -class myinitquit : public initquit { -public: - void on_init() { - console::print("Sample component: on_init()"); - } - void on_quit() { - console::print("Sample component: on_quit()"); - } -}; + FB2K_SERVICE_FACTORY( myinitquit ); -static initquit_factory_t g_myinitquit_factory; +} // namespace diff --git a/sdk/foobar2000/foo_sample/mainmenu-dynamic.cpp b/sdk/foobar2000/foo_sample/mainmenu-dynamic.cpp index a3abad7..6243266 100644 --- a/sdk/foobar2000/foo_sample/mainmenu-dynamic.cpp +++ b/sdk/foobar2000/foo_sample/mainmenu-dynamic.cpp @@ -44,7 +44,7 @@ class sample_command : public mainmenu_node_command { // fb2k hasher_md5 API even provides a convenient method to return MD5 hashes cast to GUIDs for this. return api->get_result_guid( state ); } - bool get_description(pfc::string_base & out) { + bool get_description(pfc::string_base & out) override { out = PFC_string_formatter() << "This is a test menu item #" << m_index << "."; return true; } @@ -84,6 +84,7 @@ class sample_group : public mainmenu_node_group { }; class mainmenu_sample_dynamic : public mainmenu_commands_v2 { + typedef mainmenu_commands_v2 super_t; public: // mainmenu_commands_v2 methods t_uint32 get_command_count() override { return 1; } @@ -111,10 +112,10 @@ class mainmenu_sample_dynamic : public mainmenu_commands_v2 { // please implement it here. // ... or just skip implementing this method entirely. - return __super::dynamic_execute( index, subID, callback ); + return super_t::dynamic_execute( index, subID, callback ); } }; static service_factory_single_t g_mainmenu_sample_dynamic; -} // namespace \ No newline at end of file +} // namespace diff --git a/sdk/foobar2000/foo_sample/mainmenu.cpp b/sdk/foobar2000/foo_sample/mainmenu.cpp index da54fe7..8ab8327 100644 --- a/sdk/foobar2000/foo_sample/mainmenu.cpp +++ b/sdk/foobar2000/foo_sample/mainmenu.cpp @@ -106,7 +106,7 @@ class mainmenu_commands_sample : public mainmenu_commands { } bool get_display(t_uint32 p_index,pfc::string_base & p_text,t_uint32 & p_flags) override { // OPTIONAL method - bool rv = __super::get_display(p_index, p_text, p_flags); + bool rv = mainmenu_commands::get_display(p_index, p_text, p_flags); if (rv) switch(p_index) { case cmd_playback_stream_capture: // Add checkmark if capture is in progress diff --git a/sdk/foobar2000/foo_sample/packages.config b/sdk/foobar2000/foo_sample/packages.config deleted file mode 100644 index 1c54a40..0000000 --- a/sdk/foobar2000/foo_sample/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/sdk/foobar2000/foo_sample/playback_stream_capture.cpp b/sdk/foobar2000/foo_sample/playback_stream_capture.cpp index 51cf587..30cf471 100644 --- a/sdk/foobar2000/foo_sample/playback_stream_capture.cpp +++ b/sdk/foobar2000/foo_sample/playback_stream_capture.cpp @@ -27,9 +27,8 @@ namespace { if (!g_wav_writer.is_open() && ! core_api::is_shutting_down() ) { wav_writer_setup setup; setup.initialize(chunk, 16, false, false); - GUID g; CoCreateGuid(&g); pfc::string_formatter fn; - fn << "capture-" << pfc::print_guid(g) << ".wav"; + fn << "capture-" << pfc::print_guid(pfc::createGUID()) << ".wav"; pfc::string_formatter path = g_outputPath; path.add_filename( fn ); // pretty method to add file path components with auto inserted delimiter g_wav_writer.open(path, setup, abort); @@ -99,7 +98,25 @@ namespace { FB2K_SERVICE_FACTORY( play_callback_psc ); } +static void startCaptureDialogReply( fb2k::arrayRef location ) { + if ( g_active ) return; // already capturing + if ( location.is_empty() ) return; + if ( location->size() != 1 ) return; + auto obj = location->itemAt(0); + fsItemFolderPtr folder; + fb2k::stringRef strFolder; + if ( strFolder &= obj ) { + // OK + } else if ( folder &= obj ) { + strFolder = folder->canonicalPath(); + } + if ( strFolder.is_valid() ) { + g_outputPath = strFolder->c_str(); + StartCapture(); + } +} void ToggleCapture() { +#ifdef _WIN32 // Block modal dialog recursions. // Folder picker below is a modal dialog, don't ever call it if there's another modal dialog in progress. // Also prevents this function from recursing into itself if someone manages to hit the menu item while already picking folder. @@ -115,6 +132,16 @@ void ToggleCapture() { StartCapture(); } } +#else + if ( g_active ) { + StopCapture(); + } else { + auto dlg = fb2k::fileDialog::get()->setupOpenFolder(); + dlg->setTitle( "Choose output folder" ); + dlg->run( fb2k::fileDialogNotify::create( startCaptureDialogReply ) ); + } + +#endif } bool IsCaptureRunning() { diff --git a/sdk/foobar2000/foo_sample/preferences.cpp b/sdk/foobar2000/foo_sample/preferences.cpp index cc45cd7..168a164 100644 --- a/sdk/foobar2000/foo_sample/preferences.cpp +++ b/sdk/foobar2000/foo_sample/preferences.cpp @@ -1,9 +1,13 @@ #include "stdafx.h" -#include "resource.h" -#include + #include #include + +#ifdef _WIN32 +#include "resource.h" +#include #include +#endif // _WIN32 // Sample preferences interface: two meaningless configuration settings accessible through a preferences page and one accessible through advanced preferences. @@ -52,7 +56,10 @@ enum { order_bogoRadio3, }; -static cfg_uint cfg_bogoSetting1(guid_cfg_bogoSetting1, default_cfg_bogo1), cfg_bogoSetting2(guid_cfg_bogoSetting2, default_cfg_bogo2); +namespace foo_sample { // accessed also from Mac specific code hence not static + cfg_uint cfg_bogoSetting1(guid_cfg_bogoSetting1, default_cfg_bogo1), cfg_bogoSetting2(guid_cfg_bogoSetting2, default_cfg_bogo2); +} +using namespace foo_sample; static advconfig_branch_factory g_advconfigBranch("Sample Component", guid_advconfig_branch, advconfig_branch::guid_branch_tools, 0); static advconfig_integer_factory cfg_bogoSetting3("Bogo setting 3","foo_sample.bogo3", guid_cfg_bogoSetting3, guid_advconfig_branch, order_bogo3, default_cfg_bogo3, 0 /*minimum value*/, 9999 /*maximum value*/); @@ -63,6 +70,7 @@ static advconfig_radio_factory cfg_bogoRadio1("Radio 1", "foo_sample.bogoRaidio. static advconfig_radio_factory cfg_bogoRadio2("Radio 2", "foo_sample.bogoRaidio.2", guid_cfg_bogoRadio2, guid_cfg_bogoRadio, order_bogoRadio2, false); static advconfig_radio_factory cfg_bogoRadio3("Radio 3", "foo_sample.bogoRaidio.3", guid_cfg_bogoRadio3, guid_cfg_bogoRadio, order_bogoRadio3, false); +#ifdef _WIN32 class CMyPreferences : public CDialogImpl, public preferences_page_instance { public: //Constructor - invoked by preferences_page_impl helpers - don't do Create() in here, preferences_page_impl does this for us @@ -148,10 +156,11 @@ class preferences_page_myimpl : public preferences_page_impl { const char * get_name() {return "Sample Component";} GUID get_guid() { // This is our GUID. Replace with your own when reusing the code. - static const GUID guid = { 0x7702c93e, 0x24dc, 0x48ed, { 0x8d, 0xb1, 0x3f, 0x27, 0xb3, 0x8c, 0x7c, 0xc9 } }; - return guid; + return GUID { 0x7702c93e, 0x24dc, 0x48ed, { 0x8d, 0xb1, 0x3f, 0x27, 0xb3, 0x8c, 0x7c, 0xc9 } }; } GUID get_parent_guid() {return guid_tools;} }; static preferences_page_factory_t g_preferences_page_myimpl_factory; +#endif // _WIN32 + diff --git a/sdk/foobar2000/foo_sample/rating.cpp b/sdk/foobar2000/foo_sample/rating.cpp index a57d956..37b6912 100644 --- a/sdk/foobar2000/foo_sample/rating.cpp +++ b/sdk/foobar2000/foo_sample/rating.cpp @@ -78,11 +78,10 @@ namespace { // Static cached ptr to metadb_index_manager // Cached because we'll be calling it a lot on per-track basis, let's not pass it everywhere to low level functions // Obtaining the pointer from core is reasonably efficient - log(n) to the number of known service classes, but not good enough for something potentially called hundreds of times - static metadb_index_manager::ptr g_cachedAPI; static metadb_index_manager::ptr theAPI() { - auto ret = g_cachedAPI; - if ( ret.is_empty() ) ret = metadb_index_manager::get(); // since fb2k SDK v1.4, core API interfaces have a static get() method - return ret; + // Raw ptr instead service_ptr, don't release on DLL unload, would cause issues + static metadb_index_manager * cached = metadb_index_manager::get().detach(); + return cached; } // An init_stage_callback to hook ourselves into the metadb @@ -91,8 +90,7 @@ namespace { public: void on_init_stage(t_uint32 stage) { if (stage == init_stages::before_config_read) { - auto api = metadb_index_manager::get(); - g_cachedAPI = api; + auto api = theAPI(); // Important, handle the exceptions here! // This will fail if the files holding our data are somehow corrupted. try { @@ -108,16 +106,8 @@ namespace { } } }; - class initquit_impl : public initquit { - public: - void on_quit() { - // Cleanly kill g_cachedAPI before reaching static object destructors or else - g_cachedAPI.release(); - } - }; static service_factory_single_t g_init_stage_callback_impl; - static service_factory_single_t g_initquit_impl; typedef uint32_t rating_t; static const rating_t rating_invalid = 0; diff --git a/sdk/foobar2000/foo_sample/stdafx.h b/sdk/foobar2000/foo_sample/stdafx.h index 46f3b55..989b384 100644 --- a/sdk/foobar2000/foo_sample/stdafx.h +++ b/sdk/foobar2000/foo_sample/stdafx.h @@ -1,2 +1,7 @@ +#ifdef __cplusplus #include +#endif +#ifdef __OBJC__ +#include +#endif diff --git a/sdk/foobar2000/foo_sample/ui_and_threads.cpp b/sdk/foobar2000/foo_sample/ui_and_threads.cpp index 970585b..dcbf7bb 100644 --- a/sdk/foobar2000/foo_sample/ui_and_threads.cpp +++ b/sdk/foobar2000/foo_sample/ui_and_threads.cpp @@ -4,6 +4,8 @@ // Modern multi threading with C++ // Or: how I learned to stop worrying and love the lambdas +#ifdef _WIN32 + #include // shared_ptr #include #include @@ -284,3 +286,11 @@ void RunUIAndThreads(metadb_handle_list_cref data) { // Equivalent to new CDemoDialog(data), with modeless registration and auto lifetime fb2k::newDialog( data ); } + +#else + +void RunUIAndThreads(metadb_handle_list_cref data) { + popup_message::g_showToast("Not implemented for Mac OS yet"); +} + +#endif diff --git a/sdk/foobar2000/foobar2000_component_client/component_client.cpp b/sdk/foobar2000/foobar2000_component_client/component_client.cpp index 6d0d6d8..7ad217a 100644 --- a/sdk/foobar2000/foobar2000_component_client/component_client.cpp +++ b/sdk/foobar2000/foobar2000_component_client/component_client.cpp @@ -2,8 +2,9 @@ #include #include +#ifdef _WIN32 static HINSTANCE g_hIns; - +#endif static pfc::string_simple g_name,g_full_path; static bool g_services_available = false, g_initialized = false; @@ -13,12 +14,13 @@ static bool g_services_available = false, g_initialized = false; namespace core_api { +#ifdef _WIN32 HINSTANCE get_my_instance() { return g_hIns; } - - HWND get_main_window() +#endif + fb2k::hwnd_t get_main_window() { PFC_ASSERT( g_foobar2000_api != NULL ); return g_foobar2000_api->get_main_window(); @@ -79,43 +81,40 @@ namespace { class foobar2000_client_impl : public foobar2000_client, private foobar2000_component_globals { public: - t_uint32 get_version() {return FOOBAR2000_CLIENT_VERSION;} - pservice_factory_base get_service_list() {return service_factory_base::__internal__list;} + t_uint32 get_version() override {return FOOBAR2000_CLIENT_VERSION;} + pservice_factory_base get_service_list() override {return service_factory_base::__internal__list;} - void get_config(stream_writer * p_stream,abort_callback & p_abort) { + void get_config(stream_writer * p_stream,abort_callback & p_abort) override { #ifdef FOOBAR2000_HAVE_CFG_VAR_LEGACY cfg_var_legacy::cfg_var::config_write_file(p_stream,p_abort); #endif } - void set_config(stream_reader * p_stream,abort_callback & p_abort) { + void set_config(stream_reader * p_stream,abort_callback & p_abort) override { #ifdef FOOBAR2000_HAVE_CFG_VAR_LEGACY cfg_var_legacy::cfg_var::config_read_file(p_stream,p_abort); #endif } - void set_library_path(const char * path,const char * name) { + void set_library_path(const char * path,const char * name) override { g_full_path = path; g_name = name; } - void services_init(bool val) { + void services_init(bool val) override { if (val) g_initialized = true; g_services_available = val; } - bool is_debug() { -#ifdef _DEBUG - return true; -#else - return false; -#endif + bool is_debug() override { + return PFC_DEBUG != 0; } }; } static foobar2000_client_impl g_client; +#ifdef _WIN32 extern "C" { __declspec(dllexport) foobar2000_client * _cdecl foobar2000_get_interface(foobar2000_api * p_api,HINSTANCE hIns) @@ -126,3 +125,13 @@ extern "C" return &g_client; } } +#endif + +#ifdef __APPLE__ +extern "C" { + __attribute__ ((visibility ("default"))) foobar2000_client * foobar2000_get_interface(foobar2000_api * p_api, void * /*reserved*/) { + g_foobar2000_api = p_api; + return &g_client; + } +} +#endif diff --git a/sdk/foobar2000/foobar2000_component_client/foobar2000_component_client.xcodeproj/project.pbxproj b/sdk/foobar2000/foobar2000_component_client/foobar2000_component_client.xcodeproj/project.pbxproj new file mode 100644 index 0000000..14f285e --- /dev/null +++ b/sdk/foobar2000/foobar2000_component_client/foobar2000_component_client.xcodeproj/project.pbxproj @@ -0,0 +1,282 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 0F1FDDDC2AA0B33A00DE8967 /* component_client.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F1FDDDB2AA0B33A00DE8967 /* component_client.cpp */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 0F1FDDD42AA0B2FB00DE8967 /* libfoobar2000_component_client.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libfoobar2000_component_client.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 0F1FDDDB2AA0B33A00DE8967 /* component_client.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = component_client.cpp; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 0F1FDDD22AA0B2FB00DE8967 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 0F1FDDCB2AA0B2FB00DE8967 = { + isa = PBXGroup; + children = ( + 0F1FDDDB2AA0B33A00DE8967 /* component_client.cpp */, + 0F1FDDD52AA0B2FB00DE8967 /* Products */, + ); + sourceTree = ""; + }; + 0F1FDDD52AA0B2FB00DE8967 /* Products */ = { + isa = PBXGroup; + children = ( + 0F1FDDD42AA0B2FB00DE8967 /* libfoobar2000_component_client.a */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 0F1FDDD02AA0B2FB00DE8967 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 0F1FDDD32AA0B2FB00DE8967 /* foobar2000_component_client */ = { + isa = PBXNativeTarget; + buildConfigurationList = 0F1FDDD82AA0B2FB00DE8967 /* Build configuration list for PBXNativeTarget "foobar2000_component_client" */; + buildPhases = ( + 0F1FDDD02AA0B2FB00DE8967 /* Headers */, + 0F1FDDD12AA0B2FB00DE8967 /* Sources */, + 0F1FDDD22AA0B2FB00DE8967 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = foobar2000_component_client; + productName = foobar2000_component_client; + productReference = 0F1FDDD42AA0B2FB00DE8967 /* libfoobar2000_component_client.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 0F1FDDCC2AA0B2FB00DE8967 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastUpgradeCheck = 1430; + TargetAttributes = { + 0F1FDDD32AA0B2FB00DE8967 = { + CreatedOnToolsVersion = 14.3.1; + }; + }; + }; + buildConfigurationList = 0F1FDDCF2AA0B2FB00DE8967 /* Build configuration list for PBXProject "foobar2000_component_client" */; + compatibilityVersion = "Xcode 12.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 0F1FDDCB2AA0B2FB00DE8967; + productRefGroup = 0F1FDDD52AA0B2FB00DE8967 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 0F1FDDD32AA0B2FB00DE8967 /* foobar2000_component_client */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 0F1FDDD12AA0B2FB00DE8967 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0F1FDDDC2AA0B33A00DE8967 /* component_client.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 0F1FDDD62AA0B2FB00DE8967 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + .., + ../.., + ); + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + 0F1FDDD72AA0B2FB00DE8967 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + .., + ../.., + ); + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = macosx; + }; + name = Release; + }; + 0F1FDDD92AA0B2FB00DE8967 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 4S876G9VCD; + EXECUTABLE_PREFIX = lib; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 0F1FDDDA2AA0B2FB00DE8967 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 4S876G9VCD; + EXECUTABLE_PREFIX = lib; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 0F1FDDCF2AA0B2FB00DE8967 /* Build configuration list for PBXProject "foobar2000_component_client" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0F1FDDD62AA0B2FB00DE8967 /* Debug */, + 0F1FDDD72AA0B2FB00DE8967 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 0F1FDDD82AA0B2FB00DE8967 /* Build configuration list for PBXNativeTarget "foobar2000_component_client" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0F1FDDD92AA0B2FB00DE8967 /* Debug */, + 0F1FDDDA2AA0B2FB00DE8967 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 0F1FDDCC2AA0B2FB00DE8967 /* Project object */; +} diff --git a/sdk/foobar2000/helpers-mac/CFObject.h b/sdk/foobar2000/helpers-mac/CFObject.h new file mode 100644 index 0000000..0cc29b3 --- /dev/null +++ b/sdk/foobar2000/helpers-mac/CFObject.h @@ -0,0 +1,57 @@ +#pragma once + +#include + +template +class CFObject { +public: + typedef CFObject self_t; + type_t p = NULL; + + ~CFObject() { + if ( p ) CFRelease(p); + } + + void Retain(type_t * arg) { + if ( p ) CFRelease(p); + p = arg; + if ( p ) CFRetain(p); + } + + void Attach(type_t * arg) { + if ( p ) CFRelease(p); + p = arg; + } + + void operator=( self_t const & arg ) { + if ( p ) CFRelease(p); + p = arg.p; + if ( p ) CFRetain(p); + } + CFObject() {} + CFObject( self_t const & arg ) { + p = arg.p; + if ( p ) CFRetain(p); + } + + CFObject(self_t && arg ) { + p = arg.p; arg.p = NULL; + } + void operator=(self_t && arg) { + if ( p ) CFRelease(p); + p = arg.p; arg.p = NULL; + } + + operator bool() const { return p != NULL; } + operator type_t() const { return p;} + + + void reset() { + if ( p ) CFRelease(p); + p = NULL; + } + + void operator=(nullptr_t) { + reset(); + } +}; diff --git a/sdk/foobar2000/helpers-mac/NSAttributedString+ppaddons.h b/sdk/foobar2000/helpers-mac/NSAttributedString+ppaddons.h new file mode 100644 index 0000000..3a0170c --- /dev/null +++ b/sdk/foobar2000/helpers-mac/NSAttributedString+ppaddons.h @@ -0,0 +1,9 @@ +#import + +@interface NSAttributedString (ppaddons) ++ (NSAttributedString*) attributedStringWithImage: (NSImage*) img; ++ (NSAttributedString*) attributedStringWithImageNamed: (NSString*) name; ++ (NSAttributedString*) attributedStringWithImageNamed:(NSString *)name size: (NSSize) size; ++ (NSAttributedString*) attributedStringWithImageNamed:(NSString *)name squareSize: (CGFloat) size; ++ (NSAttributedString*) hyperlinkFromString:(NSString*)inString withURL:(NSURL*)aURL; +@end diff --git a/sdk/foobar2000/helpers-mac/NSAttributedString+ppaddons.m b/sdk/foobar2000/helpers-mac/NSAttributedString+ppaddons.m new file mode 100644 index 0000000..a01aaf2 --- /dev/null +++ b/sdk/foobar2000/helpers-mac/NSAttributedString+ppaddons.m @@ -0,0 +1,49 @@ +#import "NSAttributedString+ppaddons.h" +#import + +@implementation NSAttributedString (ppaddons) + ++ (NSAttributedString*) attributedStringWithImage: (NSImage*) img { + if (img == nil) return nil; + NSTextAttachment * attachment = [[NSTextAttachment alloc] init]; + NSTextAttachmentCell * cell = (NSTextAttachmentCell*) attachment.attachmentCell; + cell.image = img; + return [NSAttributedString attributedStringWithAttachment: attachment]; +} + ++ (NSAttributedString*) attributedStringWithImageNamed: (NSString*) name { + if (name == nil) return nil; + return [self attributedStringWithImage: [NSImage imageNamed: name]]; +} + ++ (NSAttributedString*) attributedStringWithImageNamed:(NSString *)name size: (NSSize) size { + NSImage * img = [NSImage imageNamed: name]; + if (img == nil) return nil; + img.size = size; + return [self attributedStringWithImage: img]; +} ++ (NSAttributedString*) attributedStringWithImageNamed:(NSString *)name squareSize: (CGFloat) size { + return [self attributedStringWithImageNamed: name size: NSMakeSize(size, size)]; +} + ++(NSAttributedString*)hyperlinkFromString:(NSString*)inString withURL:(NSURL*)aURL +{ + NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] initWithString: inString]; + NSRange range = NSMakeRange(0, [attrString length]); + + [attrString beginEditing]; + [attrString addAttribute:NSLinkAttributeName value:[aURL absoluteString] range:range]; + + // make the text appear in blue + [attrString addAttribute:NSForegroundColorAttributeName value:[NSColor linkColor] range:range]; + + // next make the text appear with an underline + [attrString addAttribute: + NSUnderlineStyleAttributeName value:[NSNumber numberWithInt:NSUnderlineStyleSingle] range:range]; + + [attrString endEditing]; + + return attrString; +} + +@end diff --git a/sdk/foobar2000/helpers-mac/NSButton+checked.h b/sdk/foobar2000/helpers-mac/NSButton+checked.h new file mode 100644 index 0000000..21dea56 --- /dev/null +++ b/sdk/foobar2000/helpers-mac/NSButton+checked.h @@ -0,0 +1,7 @@ +#import + +@interface NSButton (checked) + +@property BOOL checked; + +@end diff --git a/sdk/foobar2000/helpers-mac/NSButton+checked.m b/sdk/foobar2000/helpers-mac/NSButton+checked.m new file mode 100644 index 0000000..d6ade1c --- /dev/null +++ b/sdk/foobar2000/helpers-mac/NSButton+checked.m @@ -0,0 +1,13 @@ +#import "NSButton+checked.h" + +@implementation NSButton (checked) + +- (BOOL)checked { + return self.state == NSOnState; +} + +- (void)setChecked:(BOOL)checked { + self.state = checked ? NSOnState : NSOffState; +} + +@end diff --git a/sdk/foobar2000/helpers-mac/NSComboBox+fb2k.h b/sdk/foobar2000/helpers-mac/NSComboBox+fb2k.h new file mode 100644 index 0000000..589e7e4 --- /dev/null +++ b/sdk/foobar2000/helpers-mac/NSComboBox+fb2k.h @@ -0,0 +1,9 @@ +#import + +#import +#import + +@interface NSComboBox (fb2k) +- (void) setupHistory: (cfg_dropdown_history&) var; +- (void) addToHistory: (cfg_dropdown_history&) var; +@end diff --git a/sdk/foobar2000/helpers-mac/NSComboBox+fb2k.mm b/sdk/foobar2000/helpers-mac/NSComboBox+fb2k.mm new file mode 100644 index 0000000..b7a875f --- /dev/null +++ b/sdk/foobar2000/helpers-mac/NSComboBox+fb2k.mm @@ -0,0 +1,24 @@ +#import "NSComboBox+fb2k.h" +#import "NSMenu+ppaddons.h" + +@implementation NSComboBox (fb2k) +- (void) setupHistory: (cfg_dropdown_history&) var { + [self removeAllItems]; + pfc::string8 temp; var.get_state( temp ); + NSString * str = [NSString stringWithUTF8String: temp.c_str()]; + if ( str.length == 0 ) return; + NSArray * arr = [str componentsSeparatedByCharactersInSet: [NSCharacterSet newlineCharacterSet]]; + if ( arr.count == 0 ) return; + for( NSString * str in arr ) { + if ( str.length > 0 ) [self addItemWithObjectValue: str]; + } + self.stringValue = arr.firstObject; + + [self.menu addSeparator]; +} + +- (void)addToHistory:(cfg_dropdown_history &)var { + NSString * str = self.stringValue; + if ( str.length > 0 ) var.add_item( str.UTF8String ); +} +@end diff --git a/sdk/foobar2000/helpers-mac/NSEvent+ppstuff.h b/sdk/foobar2000/helpers-mac/NSEvent+ppstuff.h new file mode 100644 index 0000000..e713d29 --- /dev/null +++ b/sdk/foobar2000/helpers-mac/NSEvent+ppstuff.h @@ -0,0 +1,13 @@ +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface NSEvent (ppstuff) + +@property (readonly) BOOL isKeyDown; +@property (readonly) BOOL isCmdKeyDown; +@property (readonly) BOOL isShiftKeyDown; +@property (readonly) NSEventModifierFlags modifierFlagsDI; +@end + +NS_ASSUME_NONNULL_END diff --git a/sdk/foobar2000/helpers-mac/NSEvent+ppstuff.m b/sdk/foobar2000/helpers-mac/NSEvent+ppstuff.m new file mode 100644 index 0000000..cf4b6e0 --- /dev/null +++ b/sdk/foobar2000/helpers-mac/NSEvent+ppstuff.m @@ -0,0 +1,17 @@ +#import "NSEvent+ppstuff.h" + +@implementation NSEvent (ppstuff) + +- (BOOL)isKeyDown { + return self.type == NSEventTypeKeyDown; +} +- (BOOL)isCmdKeyDown { + return self.isKeyDown && self.modifierFlagsDI == NSEventModifierFlagCommand; +} +- (BOOL)isShiftKeyDown { + return self.isKeyDown && self.modifierFlagsDI == NSEventModifierFlagShift; +} +- (NSEventModifierFlags)modifierFlagsDI { + return self.modifierFlags & NSEventModifierFlagDeviceIndependentFlagsMask; +} +@end diff --git a/sdk/foobar2000/helpers-mac/NSMenu+ppaddons.h b/sdk/foobar2000/helpers-mac/NSMenu+ppaddons.h new file mode 100644 index 0000000..4383e31 --- /dev/null +++ b/sdk/foobar2000/helpers-mac/NSMenu+ppaddons.h @@ -0,0 +1,18 @@ +#import + +@interface NSMenu (ppaddons) + +- (NSMenuItem*) addItemWithTitle: (NSString*) title action: (SEL) action target: (id) target; +- (void) addSeparator; +- (NSMenuItem*) addSubMenu: (NSMenu*) menu withTitle: (NSString*) title; +- (void)popUpForView:(NSView *)view; + +- (void) textToSeparators: (NSString*) text; +- (void) textToSeparators; +@end + +@interface NSMenuItem (ppaddons) + +@property BOOL checked; + +@end diff --git a/sdk/foobar2000/helpers-mac/NSMenu+ppaddons.m b/sdk/foobar2000/helpers-mac/NSMenu+ppaddons.m new file mode 100644 index 0000000..d67e2b1 --- /dev/null +++ b/sdk/foobar2000/helpers-mac/NSMenu+ppaddons.m @@ -0,0 +1,63 @@ +#import "NSMenu+ppaddons.h" + +@implementation NSMenu (ppaddons) + +- (NSMenuItem*) addItemWithTitle: (NSString*) title action: (SEL) action target: (id) target { + NSMenuItem * item = [[NSMenuItem alloc] initWithTitle: title action: action keyEquivalent: @""]; + item.target = target; + [self addItem: item]; + return item; +} + +- (void) addSeparator { + [self addItem: [NSMenuItem separatorItem]]; +} + +- (NSMenuItem*) addSubMenu: (NSMenu*) menu withTitle: (NSString*) title { + NSMenuItem * item = [[NSMenuItem alloc] init]; + item.title = title; + item.submenu = menu; + [self addItem: item]; + return item; +} + +- (void)popUpForView:(NSView *)view { + BOOL pullsDown = YES; + NSMenu *popMenu = [self copy]; + NSRect frame = [view frame]; + frame.origin.x = 0.0; + frame.origin.y = 0.0; + + if (pullsDown) [popMenu insertItemWithTitle:@"" action:NULL keyEquivalent:@"" atIndex:0]; + + NSPopUpButtonCell *popUpButtonCell = [[NSPopUpButtonCell alloc] initTextCell:@"" pullsDown:pullsDown]; + [popUpButtonCell setMenu:popMenu]; + if (!pullsDown) [popUpButtonCell selectItem:nil]; + [popUpButtonCell performClickWithFrame:frame inView:view]; +} + +- (void)textToSeparators { + [self textToSeparators: @"-"]; +} + +- (void)textToSeparators:(NSString *)text { + for( size_t walk = 0; walk < self.numberOfItems; ++ walk ) { + NSMenuItem * fix = [self itemAtIndex: walk]; + if ( [fix.title isEqualToString: text] ) { + [self removeItemAtIndex: walk]; + [self insertItem: [NSMenuItem separatorItem] atIndex: walk]; + } + } +} + +@end + +@implementation NSMenuItem (ppaddons) + +- (void)setChecked:(BOOL)checked { + self.state = checked ? NSOnState : NSOffState; +} +- (BOOL)checked { + return self.state == NSOnState; +} +@end diff --git a/sdk/foobar2000/helpers-mac/NSTextField+grayed.h b/sdk/foobar2000/helpers-mac/NSTextField+grayed.h new file mode 100644 index 0000000..e3719de --- /dev/null +++ b/sdk/foobar2000/helpers-mac/NSTextField+grayed.h @@ -0,0 +1,7 @@ +#import + +@interface NSTextField (grayed) + +@property BOOL grayed; + +@end diff --git a/sdk/foobar2000/helpers-mac/NSTextField+grayed.m b/sdk/foobar2000/helpers-mac/NSTextField+grayed.m new file mode 100644 index 0000000..93f1482 --- /dev/null +++ b/sdk/foobar2000/helpers-mac/NSTextField+grayed.m @@ -0,0 +1,14 @@ +#import "NSTextField+grayed.h" + +@implementation NSTextField (grayed) + +- (void)setGrayed:(BOOL)grayed { + if (grayed) self.textColor = [NSColor disabledControlTextColor]; + else self.textColor = [NSColor labelColor]; +} + +- (BOOL)grayed { + return [self.textColor isEqualTo: [NSColor disabledControlTextColor]]; +} + +@end diff --git a/sdk/foobar2000/helpers-mac/NSView+embed.h b/sdk/foobar2000/helpers-mac/NSView+embed.h new file mode 100644 index 0000000..1a3c8e3 --- /dev/null +++ b/sdk/foobar2000/helpers-mac/NSView+embed.h @@ -0,0 +1,6 @@ +#import + +@interface NSView (embed) +- (void) embedInView: (NSView*) superview; +- (void) embedInViewV2: (NSView*) superview; // adds autolayout constraints +@end diff --git a/sdk/foobar2000/helpers-mac/NSView+embed.m b/sdk/foobar2000/helpers-mac/NSView+embed.m new file mode 100644 index 0000000..5393914 --- /dev/null +++ b/sdk/foobar2000/helpers-mac/NSView+embed.m @@ -0,0 +1,25 @@ +#import "NSView+embed.h" + +@implementation NSView (embed) + +- (void)embedInView:(NSView *)superview { + self.autoresizingMask = NSViewHeightSizable | NSViewWidthSizable; + self.frame = superview.bounds; + [superview addSubview: self]; +} + +- (void)embedInViewV2:(NSView *)superview { + + self.autoresizingMask = 0; + [superview addSubview: self]; + NSMutableArray * constraints = [NSMutableArray arrayWithCapacity: 4]; + static const NSLayoutAttribute params[4] = { NSLayoutAttributeLeft, NSLayoutAttributeRight, NSLayoutAttributeTop, NSLayoutAttributeBottom }; + for( unsigned i = 0; i < 4; ++ i) { + NSLayoutAttribute a = params[i]; + [constraints addObject: [NSLayoutConstraint constraintWithItem: self attribute:a relatedBy:NSLayoutRelationEqual toItem:superview attribute:a multiplier:1 constant:0]]; + } + + [superview addConstraints: constraints]; +} + +@end diff --git a/sdk/foobar2000/helpers-mac/NSView+ppsubviews.h b/sdk/foobar2000/helpers-mac/NSView+ppsubviews.h new file mode 100644 index 0000000..8fb9dc6 --- /dev/null +++ b/sdk/foobar2000/helpers-mac/NSView+ppsubviews.h @@ -0,0 +1,11 @@ +#import + +@interface NSView (ppsubviews) +- (NSView*) recurFindSubViewOfClass: (Class) cls identifier: (NSString*) identifier; +- (NSView*) findSubViewOfClass: (Class) cls identifier: (NSString*) identifier; +- (NSView*) findSubViewOfClass: (Class) cls; +- (NSButton*) findButton; +- (NSTextView*) findTextView; +- (NSTextField*) findTextField; +- (NSImageView*) findImageView; +@end diff --git a/sdk/foobar2000/helpers-mac/NSView+ppsubviews.m b/sdk/foobar2000/helpers-mac/NSView+ppsubviews.m new file mode 100644 index 0000000..bbfc49e --- /dev/null +++ b/sdk/foobar2000/helpers-mac/NSView+ppsubviews.m @@ -0,0 +1,52 @@ +#import "NSView+ppsubviews.h" + +@implementation NSView (ppsubviews) + +- (NSView*) recurFindSubViewOfClass: (Class) cls identifier: (NSString*) identifier { + @autoreleasepool { + NSMutableArray * arrAll = [NSMutableArray new]; + + [arrAll addObjectsFromArray: self.subviews]; + for ( NSUInteger w = 0; w < arrAll.count; ++ w ) { + NSView * thisView = [arrAll objectAtIndex: w]; + + if ( (cls == nil || [thisView isKindOfClass: cls]) && ( identifier == nil || [thisView.identifier isEqualToString: identifier] ) ) { + return thisView; + } + [arrAll addObjectsFromArray: thisView.subviews]; + + + if ( w >= 200 ) { + [arrAll removeObjectsInRange: NSMakeRange(0, w) ]; + w = 0; + } + } + return nil; + } +} + + +- (NSView*) findSubViewOfClass: (Class) cls identifier: (NSString*) identifier { + for (NSView * v in self.subviews) { + if ( (cls == nil || [v isKindOfClass: cls]) && ( identifier == nil || [ v.identifier isEqualToString: identifier ] ) ) { + return v; + } + } + return nil; +} +- (NSView *)findSubViewOfClass:(Class)cls { + return [self findSubViewOfClass: cls identifier: nil]; +} +- (NSButton *)findButton { + return (NSButton*) [self findSubViewOfClass: [NSButton class]]; +} +- (NSTextView *)findTextView { + return (NSTextView*) [self findSubViewOfClass: [NSTextView class]]; +} +- (NSTextField *) findTextField { + return (NSTextField*) [self findSubViewOfClass: [NSTextField class]]; +} +- (NSImageView*) findImageView { + return (NSImageView*) [self findSubViewOfClass: [NSImageView class]]; +} +@end diff --git a/sdk/foobar2000/helpers-mac/fb2k-platform.h b/sdk/foobar2000/helpers-mac/fb2k-platform.h new file mode 100644 index 0000000..f5a2ef1 --- /dev/null +++ b/sdk/foobar2000/helpers-mac/fb2k-platform.h @@ -0,0 +1,28 @@ +#pragma once + +#import +#import + +namespace fb2k { + NSString * strToPlatform( const char * ); + NSString * strToPlatform( const char * , size_t ); + NSString * strToPlatform( stringRef ); + stringRef strFromPlatform( NSString * ); + + stringRef urlFromPlatform( id url /* can be NSString or NSURL */ ); + + typedef NSImage* platformImage_t; + platformImage_t imageToPlatform( fb2k::objRef ); + + + // These two functions do the same, openWebBrowser() was added for compatiblity with fb2k mobile + void openWebBrowser(const char * URL); + void openURL( const char * URL); +} + +namespace pfc { + string8 strFromPlatform(NSString*); + NSString * strToPlatform( const char * ); + NSString * strToPlatform(string8 const&); + string8 strFromPlatform(CFStringRef); +} diff --git a/sdk/foobar2000/helpers-mac/fb2k-platform.mm b/sdk/foobar2000/helpers-mac/fb2k-platform.mm new file mode 100644 index 0000000..fd6604b --- /dev/null +++ b/sdk/foobar2000/helpers-mac/fb2k-platform.mm @@ -0,0 +1,68 @@ +#include "fb2k-platform.h" + +namespace fb2k { + NSString * strToPlatform( const char * s, size_t len ) { + pfc::string8 temp( s, len ); + return strToPlatform( temp ); + } + + NSString * strToPlatform( const char * s ) { + return [NSString stringWithUTF8String: s]; + } + NSString * strToPlatform( stringRef s ) { + if ( s.is_empty( ) ) return nil; + return strToPlatform( s->c_str() ); + } + stringRef strFromPlatform( NSString * s ) { + return makeString( s.UTF8String ); + } + + stringRef urlFromPlatform( id obj ) { + if ( [obj isKindOfClass: [NSURL class] ] ) { + NSURL * URL = obj; + obj = URL.absoluteString; + if ([obj hasPrefix:@"file://"]) + obj = URL.path; + } + if ( [obj respondsToSelector: @selector(UTF8String)]) { + pfc::string8 temp; + filesystem::g_get_canonical_path( [obj UTF8String], temp ); + return makeString( temp ); + } + return nullptr; + } + + void openURL( const char * URL ) { + @autoreleasepool { + [[NSWorkspace sharedWorkspace] openURL: [NSURL URLWithString: [NSString stringWithUTF8String: URL]]]; + } + } + void openWebBrowser( const char * URL) { + openURL(URL); + } + + NSImage * imageToPlatform( fb2k::objRef obj ) { + fb2k::image::ptr img; + if ( img &= obj ) { + return (__bridge NSImage *) img->getNative(); + } + return nil; + } +} + +namespace pfc { + string8 strFromPlatform(NSString* str) { + string8 ret; + if ( str ) ret = str.UTF8String; + return ret; + } + NSString * strToPlatform( const char * str) { + return fb2k::strToPlatform( str ); + } + NSString * strToPlatform(string8 const& str) { + return fb2k::strToPlatform( str.c_str() ); + } + string8 strFromPlatform(CFStringRef str) { + return strFromPlatform( (__bridge NSString*) str ); + } +} diff --git a/sdk/foobar2000/helpers-mac/fooDecibelFormatter.h b/sdk/foobar2000/helpers-mac/fooDecibelFormatter.h new file mode 100644 index 0000000..f428dbb --- /dev/null +++ b/sdk/foobar2000/helpers-mac/fooDecibelFormatter.h @@ -0,0 +1,8 @@ +#import + +@interface fooDecibelFormatter : NSFormatter + +@property (nonatomic) NSNumber * minValue; +@property (nonatomic) NSNumber * maxValue; +@property (nonatomic) BOOL showSignAlways; +@end diff --git a/sdk/foobar2000/helpers-mac/fooDecibelFormatter.m b/sdk/foobar2000/helpers-mac/fooDecibelFormatter.m new file mode 100644 index 0000000..06fb01f --- /dev/null +++ b/sdk/foobar2000/helpers-mac/fooDecibelFormatter.m @@ -0,0 +1,58 @@ +#import "fooDecibelFormatter.h" + +@implementation fooDecibelFormatter + +- (NSString*) formatNumber: (id) obj { + + double v = [ obj doubleValue ]; + + if ( self.showSignAlways ) { + if (v == 0) return [NSString stringWithUTF8String: "\xc2\xb1" "0"]; + if ( v > 0 ) { + if (v == (double) (int) v) return [NSString stringWithFormat: @"+%i", (int)v]; + else return [NSString stringWithFormat: @"+%.02f", v]; + } + } + + if (v == (double) (int) v) return [NSString stringWithFormat: @"%i", (int)v]; + else return [NSString stringWithFormat: @"%.02f", v]; +} + +- (NSString *)stringForObjectValue:(id)obj { + return [NSString stringWithFormat: @"%@ dB", [self formatNumber: obj]]; +} + +- (NSAttributedString *)attributedStringForObjectValue:(id)obj withDefaultAttributes:(NSDictionary *)attrs { + return nil; +} + +- (NSString *)editingStringForObjectValue:(id)obj { + return [self stringForObjectValue: obj]; + // return [self formatNumber: obj]; +} + +- (BOOL)getObjectValue:(out __autoreleasing id *)obj forString:(NSString *)string errorDescription:(out NSString *__autoreleasing *)error { + if (error) *error = nil; + + { + NSMutableCharacterSet * trimMe = [NSMutableCharacterSet whitespaceAndNewlineCharacterSet]; + [trimMe addCharactersInString: [NSString stringWithUTF8String: "+\xc2\xb1" ]]; + string = [ string.lowercaseString stringByTrimmingCharactersInSet: trimMe ]; + } + + if ( [string hasSuffix: @"db"]) { + string = [ [string substringToIndex: string.length-2] stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceCharacterSet] ]; + } + + double v = string.doubleValue; + if (self.minValue) { + if (v < self.minValue.doubleValue) v = self.minValue.doubleValue; + } + if (self.maxValue) { + if (v > self.maxValue.doubleValue) v = self.maxValue.doubleValue; + } + *obj = [NSNumber numberWithDouble: v]; + return YES; +} + +@end diff --git a/sdk/foobar2000/helpers-mac/fooGenericDialog.h b/sdk/foobar2000/helpers-mac/fooGenericDialog.h new file mode 100644 index 0000000..babba46 --- /dev/null +++ b/sdk/foobar2000/helpers-mac/fooGenericDialog.h @@ -0,0 +1,5 @@ +#import + +@interface fooGenericDialog : NSWindowController +@property (nonatomic) NSViewController * theContent; +@end diff --git a/sdk/foobar2000/helpers-mac/fooGenericDialog.mm b/sdk/foobar2000/helpers-mac/fooGenericDialog.mm new file mode 100644 index 0000000..20fd2da --- /dev/null +++ b/sdk/foobar2000/helpers-mac/fooGenericDialog.mm @@ -0,0 +1,31 @@ +#import "fooGenericDialog.h" + +@interface fooGenericDialog () + +@end + +@implementation fooGenericDialog { + __weak IBOutlet NSStackView *m_stack; +} + +- (instancetype)init { + return [self initWithWindowNibName:@"fooGenericDialog"]; +} +- (void)windowDidLoad { + [super windowDidLoad]; + + [m_stack setViews: @[_theContent.view] inGravity:NSStackViewGravityCenter]; +} +- (IBAction)onDone:(id)sender { + [self.window makeFirstResponder: self.window]; + [self endDialog: NSModalResponseOK]; +} +- (void)cancelOperation:(id)sender { + [self endDialog: NSModalResponseCancel]; +} + +- (void) endDialog: (NSModalResponse) response { + [self.window.sheetParent endSheet: self.window returnCode: response]; +} + +@end diff --git a/sdk/foobar2000/helpers-mac/fooGenericDialog.xib b/sdk/foobar2000/helpers-mac/fooGenericDialog.xib new file mode 100644 index 0000000..2daeb26 --- /dev/null +++ b/sdk/foobar2000/helpers-mac/fooGenericDialog.xib @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/foobar2000/helpers-mac/fooPreferencesCommon.h b/sdk/foobar2000/helpers-mac/fooPreferencesCommon.h new file mode 100644 index 0000000..ba9af3d --- /dev/null +++ b/sdk/foobar2000/helpers-mac/fooPreferencesCommon.h @@ -0,0 +1,12 @@ +#import +#import + +typedef NSViewController fooPreferencesCommon; + +template +class preferences_mac_common : public preferences_page_v4 { +public: + service_ptr instantiate() override { + return fb2k::wrapNSObject( [obj_t new] ); + } +}; diff --git a/sdk/foobar2000/helpers-mac/fooTimeFormatter.h b/sdk/foobar2000/helpers-mac/fooTimeFormatter.h new file mode 100644 index 0000000..2306605 --- /dev/null +++ b/sdk/foobar2000/helpers-mac/fooTimeFormatter.h @@ -0,0 +1,16 @@ +// +// fooTimeFormatter.h +// foo_abx +// +// Created by P on 06/09/2023. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface fooTimeFormatter : NSFormatter +@property (nonatomic) NSNumber * digits; +@end + +NS_ASSUME_NONNULL_END diff --git a/sdk/foobar2000/helpers-mac/fooTimeFormatter.mm b/sdk/foobar2000/helpers-mac/fooTimeFormatter.mm new file mode 100644 index 0000000..38e2981 --- /dev/null +++ b/sdk/foobar2000/helpers-mac/fooTimeFormatter.mm @@ -0,0 +1,37 @@ +// +// fooTimeFormatter.m +// foo_abx +// +// Created by P on 06/09/2023. +// + +#import "stdafx.h" +#import "fooTimeFormatter.h" + +@implementation fooTimeFormatter + +- (NSString *)stringForObjectValue:(id)obj { + double v = 0; + if ( [obj respondsToSelector: @selector(doubleValue)]) v = [obj doubleValue]; + else if ( [obj respondsToSelector: @selector(longValue)]) v = [obj longValue]; + else if ( [obj respondsToSelector: @selector(intValue)]) v = [obj intValue]; + + unsigned digits = 3; + if ( _digits ) digits = _digits.unsignedIntValue; + return [NSString stringWithUTF8String: pfc::format_time_ex(v, digits)]; +} + +- (NSString *)editingStringForObjectValue:(id)obj { + return [self stringForObjectValue: obj]; +} +- (BOOL)getObjectValue:(out id _Nullable __autoreleasing *)obj forString:(NSString *)string errorDescription:(out NSString * _Nullable __autoreleasing *)error { + if ( string == nil ) return NO; + try { + double v = pfc::parse_timecode( string.UTF8String ); + *obj = [NSNumber numberWithDouble: v]; + return YES; + } catch(...) { + return NO; + } +} +@end diff --git a/sdk/foobar2000/helpers-mac/fooWindowWithCancel.h b/sdk/foobar2000/helpers-mac/fooWindowWithCancel.h new file mode 100644 index 0000000..50de04d --- /dev/null +++ b/sdk/foobar2000/helpers-mac/fooWindowWithCancel.h @@ -0,0 +1,9 @@ +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface fooWindowWithCancel : NSWindow + +@end + +NS_ASSUME_NONNULL_END diff --git a/sdk/foobar2000/helpers-mac/fooWindowWithCancel.m b/sdk/foobar2000/helpers-mac/fooWindowWithCancel.m new file mode 100644 index 0000000..8c70d8f --- /dev/null +++ b/sdk/foobar2000/helpers-mac/fooWindowWithCancel.m @@ -0,0 +1,10 @@ +#import "fooWindowWithCancel.h" + +@implementation fooWindowWithCancel +- (void) cancelOperation: (id) sender { + id d = self.delegate; + if ( [d respondsToSelector: @selector(cancelOperation:)]) { + [d cancelOperation: sender]; + } +} +@end diff --git a/sdk/foobar2000/helpers/CListControlFb2kColors.h b/sdk/foobar2000/helpers/CListControlFb2kColors.h index d1f3290..a5175fb 100644 --- a/sdk/foobar2000/helpers/CListControlFb2kColors.h +++ b/sdk/foobar2000/helpers/CListControlFb2kColors.h @@ -3,6 +3,7 @@ // foobar2000 v2.0+ only #if FOOBAR2000_TARGET_VERSION >= 81 +// One-line fix for UI colors in CListControl, use CListControlFb2kColors< myCListControSubClass > to use fb2k colors template class CListControlFb2kColors : public parent_t, protected ui_config_callback_impl { public: @@ -22,3 +23,23 @@ class CListControlFb2kColors : public parent_t, protected ui_config_callback_imp }; #endif + +// For use in UI elements +// Not completely selfcontained, host must pass ui_element_instance_callback and call ui_colors_changed() +template +class CListControlFb2kColorsUIElem : public parent_t { +public: + template + CListControlFb2kColorsUIElem(ui_element_instance_callback::ptr callback, arg_t && ... args) : parent_t(std::forward(args) ...), m_callback(callback) { + this->SetDarkMode(m_callback->is_dark_mode()); + } + void ui_colors_changed() { // host must call this in response to notify() + this->SetDarkMode(m_callback->is_dark_mode()); + this->Invalidate(); + } +protected: + COLORREF GetSysColorHook(int colorIndex) const override { + return m_callback->getSysColor(colorIndex); + } + const ui_element_instance_callback_ptr m_callback; +}; diff --git a/sdk/foobar2000/helpers/atl-misc.h b/sdk/foobar2000/helpers/atl-misc.h index 62a26e9..01be5fa 100644 --- a/sdk/foobar2000/helpers/atl-misc.h +++ b/sdk/foobar2000/helpers/atl-misc.h @@ -1,8 +1,8 @@ #pragma once -#ifdef _WIN32 - #include "win32_misc.h" + +#ifdef _WIN32 #include #include #include diff --git a/sdk/foobar2000/helpers/cuesheet_index_list.cpp b/sdk/foobar2000/helpers/cuesheet_index_list.cpp index 5e77766..a851a51 100644 --- a/sdk/foobar2000/helpers/cuesheet_index_list.cpp +++ b/sdk/foobar2000/helpers/cuesheet_index_list.cpp @@ -34,7 +34,7 @@ void t_cuesheet_index_list::to_infos(file_info & p_out) const for(unsigned n=2;n 0) p_out.info_set(namebuffer,cuesheet_format_index_time(position)); @@ -63,7 +63,7 @@ bool t_cuesheet_index_list::from_infos(file_info const & p_in,double p_base) for(unsigned n=2;n 0) { out = m_contentType; return true; } else return false; + } + bool is_remote() override { return m_remote; } + void reopen(abort_callback&) override {} + void seek(t_filesize, abort_callback&) override { throw exception_io_object_not_seekable(); } + bool can_seek() override { return false; } + + pfc::string8 m_contentType; + bool m_remote = true; +}; diff --git a/sdk/foobar2000/helpers/filetimetools.cpp b/sdk/foobar2000/helpers/filetimetools.cpp index ec6ef44..21aec0a 100644 --- a/sdk/foobar2000/helpers/filetimetools.cpp +++ b/sdk/foobar2000/helpers/filetimetools.cpp @@ -2,323 +2,27 @@ #include "filetimetools.h" -#include +#include -typedef exception_io_data exception_time_error; - -#ifndef _WIN32 -namespace { - typedef uint16_t WORD; - - typedef struct _SYSTEMTIME { - WORD wYear; - WORD wMonth; - WORD wDayOfWeek; - WORD wDay; - WORD wHour; - WORD wMinute; - WORD wSecond; - WORD wMilliseconds; - } SYSTEMTIME, * PSYSTEMTIME, * LPSYSTEMTIME; - -} -static void SystemTimeToNix(const SYSTEMTIME& st, struct tm& Time) { - memset(&Time, 0, sizeof(Time)); - Time.tm_sec = st.wSecond; - Time.tm_min = st.wMinute; - Time.tm_hour = st.wHour; - Time.tm_mday = st.wDay; - Time.tm_mon = st.wMonth - 1; - Time.tm_year = st.wYear - 1900; -} - -static t_filetimestamp ExportSystemTime(const SYSTEMTIME& st) { - struct tm Time; - SystemTimeToNix(st, Time); - return pfc::fileTimeUtoW(mktime(&Time)); -} - -static t_filetimestamp ExportSystemTimeLocal(const SYSTEMTIME& st) { - struct tm Time, Local; - SystemTimeToNix(st, Time); - time_t t = mktime(&Time); - localtime_r(&t, &Local); - return pfc::fileTimeUtoW(mktime(&Local)); -} -static void SystemTimeFromNix(SYSTEMTIME& st, struct tm const& Time) { - memset(&st, 0, sizeof(st)); - st.wSecond = Time.tm_sec; - st.wMinute = Time.tm_min; - st.wHour = Time.tm_hour; - st.wDay = Time.tm_mday; - st.wDayOfWeek = Time.tm_wday; - st.wMonth = Time.tm_mon + 1; - st.wYear = Time.tm_year + 1900; -} - -static bool MakeSystemTime(SYSTEMTIME& st, t_filetimestamp ts) { - time_t t = (time_t)pfc::fileTimeWtoU(ts); - struct tm Time; - if (gmtime_r(&t, &Time) == NULL) return false; - SystemTimeFromNix(st, Time); - return true; -} - -static bool MakeSystemTimeLocal(SYSTEMTIME& st, t_filetimestamp ts) { - time_t t = (time_t)pfc::fileTimeWtoU(ts); - struct tm Time; - if (localtime_r(&t, &Time) == NULL) return false; - SystemTimeFromNix(st, Time); - return true; -} - -#else -static t_filetimestamp ExportSystemTime(const SYSTEMTIME& st) { - t_filetimestamp base; - if (!SystemTimeToFileTime(&st, (FILETIME*)&base)) throw exception_time_error(); - return base; -} -static t_filetimestamp ExportSystemTimeLocal(const SYSTEMTIME& st) { -#ifdef FOOBAR2000_DESKTOP_WINDOWS - t_filetimestamp base, out; - if (!SystemTimeToFileTime(&st, (FILETIME*)&base)) throw exception_time_error(); - if (!LocalFileTimeToFileTime((const FILETIME*)&base, (FILETIME*)&out)) throw exception_time_error(); - return out; -#else - SYSTEMTIME UTC; - if (!TzSpecificLocalTimeToSystemTime(NULL, &st, &UTC)) throw exception_time_error(); - return ExportSystemTime(UTC); -#endif -} -static bool MakeSystemTime(SYSTEMTIME& st, t_filetimestamp ts) { - if (ts == filetimestamp_invalid) return false; - return !!FileTimeToSystemTime((const FILETIME*)&ts, &st); - -} -static bool MakeSystemTimeLocal(SYSTEMTIME& st, t_filetimestamp ts) { - if (ts == filetimestamp_invalid) return false; -#ifdef FOOBAR2000_DESKTOP_WINDOWS - FILETIME ft; - if (FileTimeToLocalFileTime((FILETIME*)&ts, &ft)) { - if (FileTimeToSystemTime(&ft, &st)) { - return true; - } - } - return false; -#else - SYSTEMTIME UTC; - if (FileTimeToSystemTime((FILETIME*)&ts, &UTC)) { - if (SystemTimeToTzSpecificLocalTime(NULL, &UTC, &st)) return true; - } - return false; -#endif -} -#endif // _WIN32 - -static bool is_spacing(char c) { return c == ' ' || c == 10 || c == 13 || c == '\t'; } - -static unsigned ParseDateElem(const char* ptr, t_size len) { - unsigned ret = 0; - for (t_size walk = 0; walk < len; ++walk) { - const char c = ptr[walk]; - if (c < '0' || c > '9') throw exception_time_error(); - ret = ret * 10 + (unsigned)(c - '0'); - } - return ret; -} - -static bool st_sanity(SYSTEMTIME const& st) { - return st.wYear >= 1601 && st.wMonth >= 1 && st.wMonth <= 12 && st.wDay >= 1 && st.wDay <= 31 && st.wHour < 24 && st.wMinute < 60 && st.wSecond < 60 && st.wMilliseconds < 1000; -} -static t_filetimestamp filetimestamp_from_string_internal(const char* date, bool local) { - // Accepted format - // YYYY-MM-DD HH:MM:SS - try { - SYSTEMTIME st = {}; - st.wDay = 1; st.wMonth = 1; - - unsigned walk = 0; - auto worker = [&](unsigned n) { - auto ret = ParseDateElem(date + walk, n); - walk += n; - if (ret > UINT16_MAX) throw exception_time_error(); - return (WORD)ret;; - }; - - auto skip = [&](char c) { - if (date[walk] == c) ++walk; - }; - - auto skipSpacing = [&] { - while (is_spacing(date[walk])) ++walk; - }; - skipSpacing(); - st.wYear = worker(4); - skip('-'); - st.wMonth = worker(2); - skip('-'); - st.wDay = worker(2); - skipSpacing(); - st.wHour = worker(2); - skip(':'); - st.wMinute = worker(2); - skip(':'); - st.wSecond = worker(2); - if (date[walk] == '.') { - double v = pfc::string_to_float(date + walk); - st.wMilliseconds = (WORD)floor(v * 1000.f); // don't ever round up, don't want to handle ms of 1000 - } - - if (!st_sanity(st)) throw exception_time_error(); - - if (local) { - return ExportSystemTimeLocal(st); - } else { - return ExportSystemTime(st); - } - } catch (exception_time_error) { - return filetimestamp_invalid; - } -} +// Stub - functionality moved to PFC namespace foobar2000_io { - t_filetimestamp filetimestamp_from_string(const char* date) { - return filetimestamp_from_string_internal(date, true); - } - - t_filetimestamp filetimestamp_from_string_utc(const char* date) { - return filetimestamp_from_string_internal(date, false); - } - - static constexpr char g_invalidMsg[] = ""; - - pfc::string_formatter format_filetimestamp(t_filetimestamp p_timestamp) { - try { - SYSTEMTIME st; - if (MakeSystemTimeLocal(st, p_timestamp)) { - pfc::string_formatter buffer; - buffer - << pfc::format_uint(st.wYear, 4) << "-" << pfc::format_uint(st.wMonth, 2) << "-" << pfc::format_uint(st.wDay, 2) << " " - << pfc::format_uint(st.wHour, 2) << ":" << pfc::format_uint(st.wMinute, 2) << ":" << pfc::format_uint(st.wSecond, 2); - return buffer; - } - } catch (...) {} - return g_invalidMsg; - } - - pfc::string_formatter format_filetimestamp_ms(t_filetimestamp p_timestamp) { - try { - SYSTEMTIME st; - if (MakeSystemTimeLocal(st, p_timestamp)) { - pfc::string_formatter buffer; - buffer - << pfc::format_uint(st.wYear, 4) << "-" << pfc::format_uint(st.wMonth, 2) << "-" << pfc::format_uint(st.wDay, 2) << " " - << pfc::format_uint(st.wHour, 2) << ":" << pfc::format_uint(st.wMinute, 2) << ":" << pfc::format_uint(st.wSecond, 2) << "." << pfc::format_uint(st.wMilliseconds, 3); - return buffer; - } - } catch (...) {} - return g_invalidMsg; - } - - pfc::string_formatter format_filetimestamp_utc(t_filetimestamp p_timestamp) { - try { - SYSTEMTIME st; - if (MakeSystemTime(st, p_timestamp)) { - pfc::string_formatter buffer; - buffer - << pfc::format_uint(st.wYear, 4) << "-" << pfc::format_uint(st.wMonth, 2) << "-" << pfc::format_uint(st.wDay, 2) << " " - << pfc::format_uint(st.wHour, 2) << ":" << pfc::format_uint(st.wMinute, 2) << ":" << pfc::format_uint(st.wSecond, 2); - return buffer; - } - } catch (...) {} - return g_invalidMsg; - } - -} // namespace foobar2000_io - -namespace { - struct dateISO_t { - unsigned Y, M, D; - unsigned h, m, s; - double sfrac; - int tzdelta; - }; - - dateISO_t read_ISO_8601(const char* dateISO) { - dateISO_t ret = {}; - // 2022-01-26T13:44:51.200000Z - // 2010-02-19T14:54:23.031+08:00 - // 2022-01-27T11:01:49+00:00 - // 2022-01-27T11:01:49Z - // 20220127T110149Z - - unsigned walk = 0; - auto worker = [&](unsigned n) { - auto ret = ParseDateElem(dateISO + walk, n); - walk += n; - return ret; - }; - auto skip = [&](char c) { - if (dateISO[walk] == c) ++walk; - }; - auto expect = [&](char c) { - if (dateISO[walk] != c) throw exception_time_error(); - ++walk; - }; - ret.Y = worker(4); - skip('-'); - ret.M = worker(2); - skip('-'); - ret.D = worker(2); - expect('T'); - ret.h = worker(2); - skip(':'); - ret.m = worker(2); - skip(':'); - ret.s = worker(2); - if (dateISO[walk] == '.') { - unsigned base = walk; - ++walk; - while (pfc::char_is_numeric(dateISO[walk])) ++walk; - ret.sfrac = pfc::string_to_float(dateISO + base, walk - base); - } - if (dateISO[walk] == '+' || dateISO[walk] == '-') { - bool neg = dateISO[walk] == '-'; - ++walk; - unsigned tz_h = worker(2); - if (tz_h >= 24) throw exception_time_error(); - skip(':'); - unsigned tz_m = worker(2); - if (tz_m >= 60) throw exception_time_error(); - tz_m += tz_h * 60; - ret.tzdelta = neg ? (int)tz_m : -(int)tz_m; // reversed! it's a timezone offset, have to *add* it if timezone has a minus - } - return ret; - } -} - -t_filetimestamp foobar2000_io::filetimestamp_from_string_ISO_8601(const char* dateISO) { - try { - auto elems = read_ISO_8601(dateISO); - - SYSTEMTIME st = {}; - st.wDay = 1; st.wMonth = 1; - st.wYear = elems.Y; - st.wMonth = elems.M; - st.wDay = elems.D; - st.wHour = elems.h; - st.wMinute = elems.m; - st.wSecond = elems.s; - st.wMilliseconds = (WORD)floor(elems.sfrac * 1000.f); - - if (!st_sanity(st)) throw exception_time_error(); - - auto ret = ExportSystemTime(st); - - ret += filetimestamp_1second_increment * elems.tzdelta * 60; - - return ret; - } catch (...) { - return filetimestamp_invalid; - } + t_filetimestamp filetimestamp_from_string(const char* date) { + return pfc::filetimestamp_from_string( date ); + } + t_filetimestamp filetimestamp_from_string_utc(const char* date) { + return pfc::filetimestamp_from_string_utc( date ); + } + + pfc::string_formatter format_filetimestamp(t_filetimestamp p_timestamp) { + return pfc::format_filetimestamp( p_timestamp ); + } + + pfc::string_formatter format_filetimestamp_utc(t_filetimestamp p_timestamp) { + return pfc::format_filetimestamp_utc( p_timestamp ); + } + + pfc::string_formatter format_filetimestamp_ms(t_filetimestamp p_timestamp) { + return pfc::format_filetimestamp_ms( p_timestamp ); + } } diff --git a/sdk/foobar2000/helpers/filetimetools.h b/sdk/foobar2000/helpers/filetimetools.h index 041ea83..3be3676 100644 --- a/sdk/foobar2000/helpers/filetimetools.h +++ b/sdk/foobar2000/helpers/filetimetools.h @@ -3,8 +3,6 @@ namespace foobar2000_io { t_filetimestamp filetimestamp_from_string(const char * date); t_filetimestamp filetimestamp_from_string_utc(const char* date); - // From ISO 8601 time - t_filetimestamp filetimestamp_from_string_ISO_8601(const char* date); //! Warning: this formats according to system timezone settings, created strings should be used for display only, never for storage. pfc::string_formatter format_filetimestamp(t_filetimestamp p_timestamp); @@ -12,5 +10,4 @@ namespace foobar2000_io { pfc::string_formatter format_filetimestamp_utc(t_filetimestamp p_timestamp); //! Local timestamp with milliseconds pfc::string_formatter format_filetimestamp_ms(t_filetimestamp p_timestamp); - } diff --git a/sdk/foobar2000/helpers/foobar2000_SDK_helpers.xcodeproj/project.pbxproj b/sdk/foobar2000/helpers/foobar2000_SDK_helpers.xcodeproj/project.pbxproj new file mode 100644 index 0000000..51bf036 --- /dev/null +++ b/sdk/foobar2000/helpers/foobar2000_SDK_helpers.xcodeproj/project.pbxproj @@ -0,0 +1,819 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 0F75F5EA2A6B1DB200A45078 /* dialog_resize_helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5622A6B1DAE00A45078 /* dialog_resize_helper.h */; }; + 0F75F5EB2A6B1DB200A45078 /* input_logging.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5632A6B1DAE00A45078 /* input_logging.h */; }; + 0F75F5EC2A6B1DB200A45078 /* cfg_var_import.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F5642A6B1DAE00A45078 /* cfg_var_import.cpp */; }; + 0F75F5ED2A6B1DB200A45078 /* readers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F5652A6B1DAE00A45078 /* readers.cpp */; }; + 0F75F5EE2A6B1DB200A45078 /* text_file_loader_v2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F5662A6B1DAE00A45078 /* text_file_loader_v2.cpp */; }; + 0F75F5EF2A6B1DB200A45078 /* VisUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5672A6B1DAE00A45078 /* VisUtils.h */; }; + 0F75F5F02A6B1DB200A45078 /* file_move_helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5682A6B1DAE00A45078 /* file_move_helper.h */; }; + 0F75F5F12A6B1DB200A45078 /* filetimetools.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5692A6B1DAE00A45078 /* filetimetools.h */; }; + 0F75F5F22A6B1DB200A45078 /* create_directory_helper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F56A2A6B1DAE00A45078 /* create_directory_helper.cpp */; }; + 0F75F5F32A6B1DB200A45078 /* writer_wav.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F56B2A6B1DAE00A45078 /* writer_wav.h */; }; + 0F75F5F42A6B1DB200A45078 /* VisUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F56C2A6B1DAE00A45078 /* VisUtils.cpp */; }; + 0F75F5F52A6B1DB200A45078 /* COM_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F56D2A6B1DAE00A45078 /* COM_utils.h */; }; + 0F75F5F62A6B1DB200A45078 /* VolumeMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F56E2A6B1DAE00A45078 /* VolumeMap.h */; }; + 0F75F5F72A6B1DB200A45078 /* file_win32_wrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F56F2A6B1DAE00A45078 /* file_win32_wrapper.h */; }; + 0F75F5F82A6B1DB200A45078 /* foobar2000-lite+atl.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5702A6B1DAE00A45078 /* foobar2000-lite+atl.h */; }; + 0F75F5F92A6B1DB200A45078 /* metadb_handle_array.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5712A6B1DAE00A45078 /* metadb_handle_array.h */; }; + 0F75F5FA2A6B1DB200A45078 /* atl-misc.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5722A6B1DAE00A45078 /* atl-misc.h */; }; + 0F75F5FB2A6B1DB200A45078 /* CSingleThreadWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5732A6B1DAE00A45078 /* CSingleThreadWrapper.h */; }; + 0F75F5FC2A6B1DB200A45078 /* image_load_save.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5742A6B1DAE00A45078 /* image_load_save.h */; }; + 0F75F5FD2A6B1DB200A45078 /* reader_pretend_nonseekable.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5752A6B1DAF00A45078 /* reader_pretend_nonseekable.h */; }; + 0F75F5FF2A6B1DB200A45078 /* meta_table_builder.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5772A6B1DAF00A45078 /* meta_table_builder.h */; }; + 0F75F6002A6B1DB200A45078 /* fb2k_threads.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5782A6B1DAF00A45078 /* fb2k_threads.h */; }; + 0F75F6012A6B1DB200A45078 /* playlist_position_reference_tracker.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5792A6B1DAF00A45078 /* playlist_position_reference_tracker.h */; }; + 0F75F6022A6B1DB200A45078 /* file_list_helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F57A2A6B1DAF00A45078 /* file_list_helper.h */; }; + 0F75F6032A6B1DB200A45078 /* inplace_edit.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F57B2A6B1DAF00A45078 /* inplace_edit.h */; }; + 0F75F6042A6B1DB200A45078 /* album_art_helpers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F57C2A6B1DAF00A45078 /* album_art_helpers.cpp */; }; + 0F75F6052A6B1DB200A45078 /* AutoComplete.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F57D2A6B1DAF00A45078 /* AutoComplete.h */; }; + 0F75F6062A6B1DB200A45078 /* ProfileCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F57E2A6B1DAF00A45078 /* ProfileCache.h */; }; + 0F75F6072A6B1DB200A45078 /* fileReadAhead.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F57F2A6B1DAF00A45078 /* fileReadAhead.h */; }; + 0F75F6082A6B1DB200A45078 /* cfg_dsp_chain_config.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5802A6B1DAF00A45078 /* cfg_dsp_chain_config.h */; }; + 0F75F6092A6B1DB200A45078 /* metadb_io_callback_v2_data.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5812A6B1DAF00A45078 /* metadb_io_callback_v2_data.h */; }; + 0F75F60A2A6B1DB200A45078 /* cue_parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F5822A6B1DAF00A45078 /* cue_parser.cpp */; }; + 0F75F60C2A6B1DB200A45078 /* ui_element_helpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5842A6B1DAF00A45078 /* ui_element_helpers.h */; }; + 0F75F60D2A6B1DB200A45078 /* CListControlFb2kColors.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5852A6B1DAF00A45078 /* CListControlFb2kColors.h */; }; + 0F75F60E2A6B1DB200A45078 /* stream_buffer_helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5862A6B1DAF00A45078 /* stream_buffer_helper.h */; }; + 0F75F60F2A6B1DB200A45078 /* advconfig_runtime.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5872A6B1DAF00A45078 /* advconfig_runtime.h */; }; + 0F75F6102A6B1DB200A45078 /* readWriteLock.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5882A6B1DAF00A45078 /* readWriteLock.h */; }; + 0F75F6112A6B1DB200A45078 /* writer_wav.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F5892A6B1DAF00A45078 /* writer_wav.cpp */; }; + 0F75F6122A6B1DB200A45078 /* fb2kWorkerTool.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F58A2A6B1DAF00A45078 /* fb2kWorkerTool.h */; }; + 0F75F6132A6B1DB200A45078 /* cfg_objList.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F58B2A6B1DAF00A45078 /* cfg_objList.h */; }; + 0F75F6142A6B1DB200A45078 /* CDialogResizeHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F58C2A6B1DAF00A45078 /* CDialogResizeHelper.h */; }; + 0F75F6152A6B1DB200A45078 /* file_info_const_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F58D2A6B1DAF00A45078 /* file_info_const_impl.h */; }; + 0F75F6162A6B1DB200A45078 /* file_list_helper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F58E2A6B1DAF00A45078 /* file_list_helper.cpp */; }; + 0F75F6172A6B1DB200A45078 /* albumArtCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F58F2A6B1DAF00A45078 /* albumArtCache.h */; }; + 0F75F6182A6B1DB200A45078 /* rethrow.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5902A6B1DAF00A45078 /* rethrow.h */; }; + 0F75F6192A6B1DB200A45078 /* cfg_var_import.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5912A6B1DAF00A45078 /* cfg_var_import.h */; }; + 0F75F61A2A6B1DB200A45078 /* album_art_helpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5922A6B1DB000A45078 /* album_art_helpers.h */; }; + 0F75F61B2A6B1DB200A45078 /* create_directory_helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5932A6B1DB000A45078 /* create_directory_helper.h */; }; + 0F75F61C2A6B1DB200A45078 /* input_helpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5942A6B1DB000A45078 /* input_helpers.h */; }; + 0F75F61D2A6B1DB200A45078 /* notifyList.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5952A6B1DB000A45078 /* notifyList.h */; }; + 0F75F6202A6B1DB200A45078 /* win-MulDiv.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5982A6B1DB000A45078 /* win-MulDiv.h */; }; + 0F75F6212A6B1DB200A45078 /* metadb_info_container_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5992A6B1DB000A45078 /* metadb_info_container_impl.h */; }; + 0F75F6222A6B1DB200A45078 /* metadb_io_hintlist.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F59A2A6B1DB000A45078 /* metadb_io_hintlist.h */; }; + 0F75F6232A6B1DB200A45078 /* track_property_callback_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F59B2A6B1DB000A45078 /* track_property_callback_impl.h */; }; + 0F75F6242A6B1DB200A45078 /* filetimetools.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F59C2A6B1DB000A45078 /* filetimetools.cpp */; }; + 0F75F6252A6B1DB200A45078 /* ProcessUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F59D2A6B1DB000A45078 /* ProcessUtils.h */; }; + 0F75F6262A6B1DB200A45078 /* readers.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F59E2A6B1DB000A45078 /* readers.h */; }; + 0F75F6272A6B1DB200A45078 /* VolumeMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F59F2A6B1DB000A45078 /* VolumeMap.cpp */; }; + 0F75F6282A6B1DB200A45078 /* cfg_guidlist.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F5A02A6B1DB000A45078 /* cfg_guidlist.cpp */; }; + 0F75F6292A6B1DB200A45078 /* dropdown_helper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F5A12A6B1DB000A45078 /* dropdown_helper.cpp */; }; + 0F75F62A2A6B1DB200A45078 /* callback_merit.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5A22A6B1DB000A45078 /* callback_merit.h */; }; + 0F75F62B2A6B1DB200A45078 /* cue_creator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F5A32A6B1DB000A45078 /* cue_creator.cpp */; }; + 0F75F62C2A6B1DB200A45078 /* CPropVariant.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5A42A6B1DB000A45078 /* CPropVariant.h */; }; + 0F75F62D2A6B1DB200A45078 /* text_file_loader_v2.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5A52A6B1DB000A45078 /* text_file_loader_v2.h */; }; + 0F75F62E2A6B1DB200A45078 /* helpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5A62A6B1DB000A45078 /* helpers.h */; }; + 0F75F6302A6B1DB200A45078 /* dynamic_bitrate_helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5A82A6B1DB000A45078 /* dynamic_bitrate_helper.h */; }; + 0F75F6312A6B1DB200A45078 /* packet_decoder_mp3_common.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5A92A6B1DB000A45078 /* packet_decoder_mp3_common.h */; }; + 0F75F6322A6B1DB200A45078 /* foobar2000+atl.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5AA2A6B1DB000A45078 /* foobar2000+atl.h */; }; + 0F75F6332A6B1DB200A45078 /* CallForwarder.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5AB2A6B1DB000A45078 /* CallForwarder.h */; }; + 0F75F6342A6B1DB200A45078 /* StdAfx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F5AC2A6B1DB000A45078 /* StdAfx.cpp */; }; + 0F75F6352A6B1DB200A45078 /* CTableEditHelper-Legacy.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5AD2A6B1DB100A45078 /* CTableEditHelper-Legacy.h */; }; + 0F75F6362A6B1DB200A45078 /* window_placement_helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5AE2A6B1DB100A45078 /* window_placement_helper.h */; }; + 0F75F6372A6B1DB200A45078 /* input_helper_cue.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5AF2A6B1DB100A45078 /* input_helper_cue.h */; }; + 0F75F6382A6B1DB200A45078 /* cuesheet_index_list.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F5B02A6B1DB100A45078 /* cuesheet_index_list.cpp */; }; + 0F75F6392A6B1DB200A45078 /* win-systemtime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F5B12A6B1DB100A45078 /* win-systemtime.cpp */; }; + 0F75F63A2A6B1DB200A45078 /* dynamic_bitrate_helper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F5B22A6B1DB100A45078 /* dynamic_bitrate_helper.cpp */; }; + 0F75F63B2A6B1DB200A45078 /* bitreader_helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5B32A6B1DB100A45078 /* bitreader_helper.h */; }; + 0F75F63C2A6B1DB200A45078 /* StdAfx.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5B42A6B1DB100A45078 /* StdAfx.h */; }; + 0F75F63D2A6B1DB200A45078 /* packet_decoder_aac_common.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5B52A6B1DB100A45078 /* packet_decoder_aac_common.h */; }; + 0F75F63E2A6B1DB200A45078 /* CmdThread.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5B62A6B1DB100A45078 /* CmdThread.h */; }; + 0F75F63F2A6B1DB200A45078 /* readers_lite.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5B72A6B1DB100A45078 /* readers_lite.h */; }; + 0F75F6402A6B1DB200A45078 /* text_file_loader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F5B82A6B1DB100A45078 /* text_file_loader.cpp */; }; + 0F75F6412A6B1DB200A45078 /* cue_creator.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5B92A6B1DB100A45078 /* cue_creator.h */; }; + 0F75F6422A6B1DB200A45078 /* ThreadUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F5BA2A6B1DB100A45078 /* ThreadUtils.cpp */; }; + 0F75F6432A6B1DB200A45078 /* file_streamstub.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5BB2A6B1DB100A45078 /* file_streamstub.h */; }; + 0F75F6442A6B1DB200A45078 /* tag_write_callback_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5BC2A6B1DB100A45078 /* tag_write_callback_impl.h */; }; + 0F75F6452A6B1DB200A45078 /* win32_misc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F5BD2A6B1DB100A45078 /* win32_misc.cpp */; }; + 0F75F6462A6B1DB200A45078 /* WindowPositionUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5BE2A6B1DB100A45078 /* WindowPositionUtils.h */; }; + 0F75F6472A6B1DB200A45078 /* packet_decoder_mp3_common.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F5BF2A6B1DB100A45078 /* packet_decoder_mp3_common.cpp */; }; + 0F75F6492A6B1DB200A45078 /* duration_counter.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5C12A6B1DB100A45078 /* duration_counter.h */; }; + 0F75F64A2A6B1DB200A45078 /* cue_parser.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5C22A6B1DB100A45078 /* cue_parser.h */; }; + 0F75F64B2A6B1DB200A45078 /* dialog_resize_helper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F5C32A6B1DB100A45078 /* dialog_resize_helper.cpp */; }; + 0F75F64C2A6B1DB200A45078 /* seekabilizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F5C42A6B1DB100A45078 /* seekabilizer.cpp */; }; + 0F75F64D2A6B1DB200A45078 /* fullFileBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5C52A6B1DB100A45078 /* fullFileBuffer.h */; }; + 0F75F64E2A6B1DB200A45078 /* win32_dialog.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5C62A6B1DB100A45078 /* win32_dialog.h */; }; + 0F75F64F2A6B1DB200A45078 /* cuesheet_index_list.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5C72A6B1DB100A45078 /* cuesheet_index_list.h */; }; + 0F75F6502A6B1DB200A45078 /* callInMainThreadHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5C82A6B1DB100A45078 /* callInMainThreadHelper.h */; }; + 0F75F6512A6B1DB200A45078 /* icon_remapping_wildcard.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5C92A6B1DB100A45078 /* icon_remapping_wildcard.h */; }; + 0F75F6522A6B1DB200A45078 /* audio_render_float.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5CA2A6B1DB100A45078 /* audio_render_float.h */; }; + 0F75F6542A6B1DB200A45078 /* advconfig_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5CC2A6B1DB100A45078 /* advconfig_impl.h */; }; + 0F75F6552A6B1DB200A45078 /* input_fix_seeking.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5CD2A6B1DB100A45078 /* input_fix_seeking.h */; }; + 0F75F6562A6B1DB200A45078 /* win-systemtime.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5CE2A6B1DB100A45078 /* win-systemtime.h */; }; + 0F75F6572A6B1DB200A45078 /* stream_buffer_helper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F5CF2A6B1DB100A45078 /* stream_buffer_helper.cpp */; }; + 0F75F6582A6B1DB200A45078 /* dsp_dialog.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5D02A6B1DB100A45078 /* dsp_dialog.h */; }; + 0F75F6592A6B1DB200A45078 /* BumpableElem.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5D12A6B1DB100A45078 /* BumpableElem.h */; }; + 0F75F65A2A6B1DB200A45078 /* cfg_obj.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5D22A6B1DB100A45078 /* cfg_obj.h */; }; + 0F75F65B2A6B1DB200A45078 /* packet_decoder_aac_common.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F5D32A6B1DB200A45078 /* packet_decoder_aac_common.cpp */; }; + 0F75F65C2A6B1DB200A45078 /* mp3_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5D42A6B1DB200A45078 /* mp3_utils.h */; }; + 0F75F65D2A6B1DB200A45078 /* cue_parser_embedding.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F5D52A6B1DB200A45078 /* cue_parser_embedding.cpp */; }; + 0F75F65E2A6B1DB200A45078 /* input_helpers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F5D62A6B1DB200A45078 /* input_helpers.cpp */; }; + 0F75F65F2A6B1DB200A45078 /* ThreadUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5D72A6B1DB200A45078 /* ThreadUtils.h */; }; + 0F75F6602A6B1DB200A45078 /* track_property_callback_impl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F5D82A6B1DB200A45078 /* track_property_callback_impl.cpp */; }; + 0F75F6622A6B1DB200A45078 /* fb2k_wfx.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5DA2A6B1DB200A45078 /* fb2k_wfx.h */; }; + 0F75F6632A6B1DB200A45078 /* DarkMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5DB2A6B1DB200A45078 /* DarkMode.h */; }; + 0F75F6642A6B1DB200A45078 /* win32_misc.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5DC2A6B1DB200A45078 /* win32_misc.h */; }; + 0F75F6652A6B1DB200A45078 /* winmm-types.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5DD2A6B1DB200A45078 /* winmm-types.h */; }; + 0F75F6662A6B1DB200A45078 /* metadb_handle_set.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5DE2A6B1DB200A45078 /* metadb_handle_set.h */; }; + 0F75F6672A6B1DB200A45078 /* mp3_utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F5DF2A6B1DB200A45078 /* mp3_utils.cpp */; }; + 0F75F6682A6B1DB200A45078 /* file_win32_wrapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F5E02A6B1DB200A45078 /* file_win32_wrapper.cpp */; }; + 0F75F6692A6B1DB200A45078 /* seekabilizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5E12A6B1DB200A45078 /* seekabilizer.h */; }; + 0F75F66A2A6B1DB200A45078 /* file_move_helper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F5E22A6B1DB200A45078 /* file_move_helper.cpp */; }; + 0F75F66B2A6B1DB200A45078 /* cfg_guidlist.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5E32A6B1DB200A45078 /* cfg_guidlist.h */; }; + 0F75F66C2A6B1DB200A45078 /* input_helper_cue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F5E42A6B1DB200A45078 /* input_helper_cue.cpp */; }; + 0F75F66D2A6B1DB200A45078 /* text_file_loader.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5E52A6B1DB200A45078 /* text_file_loader.h */; }; + 0F75F66E2A6B1DB200A45078 /* file_cached.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5E62A6B1DB200A45078 /* file_cached.h */; }; + 0F75F66F2A6B1DB200A45078 /* input_stream_info_reader.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5E72A6B1DB200A45078 /* input_stream_info_reader.h */; }; + 0F75F6712A6B1DB200A45078 /* dropdown_helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F5E92A6B1DB200A45078 /* dropdown_helper.h */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 0F75F5622A6B1DAE00A45078 /* dialog_resize_helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dialog_resize_helper.h; sourceTree = ""; }; + 0F75F5632A6B1DAE00A45078 /* input_logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = input_logging.h; sourceTree = ""; }; + 0F75F5642A6B1DAE00A45078 /* cfg_var_import.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cfg_var_import.cpp; sourceTree = ""; }; + 0F75F5652A6B1DAE00A45078 /* readers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = readers.cpp; sourceTree = ""; }; + 0F75F5662A6B1DAE00A45078 /* text_file_loader_v2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = text_file_loader_v2.cpp; sourceTree = ""; }; + 0F75F5672A6B1DAE00A45078 /* VisUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VisUtils.h; sourceTree = ""; }; + 0F75F5682A6B1DAE00A45078 /* file_move_helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = file_move_helper.h; sourceTree = ""; }; + 0F75F5692A6B1DAE00A45078 /* filetimetools.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = filetimetools.h; sourceTree = ""; }; + 0F75F56A2A6B1DAE00A45078 /* create_directory_helper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = create_directory_helper.cpp; sourceTree = ""; }; + 0F75F56B2A6B1DAE00A45078 /* writer_wav.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = writer_wav.h; sourceTree = ""; }; + 0F75F56C2A6B1DAE00A45078 /* VisUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VisUtils.cpp; sourceTree = ""; }; + 0F75F56D2A6B1DAE00A45078 /* COM_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = COM_utils.h; sourceTree = ""; }; + 0F75F56E2A6B1DAE00A45078 /* VolumeMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VolumeMap.h; sourceTree = ""; }; + 0F75F56F2A6B1DAE00A45078 /* file_win32_wrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = file_win32_wrapper.h; sourceTree = ""; }; + 0F75F5702A6B1DAE00A45078 /* foobar2000-lite+atl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "foobar2000-lite+atl.h"; sourceTree = ""; }; + 0F75F5712A6B1DAE00A45078 /* metadb_handle_array.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = metadb_handle_array.h; sourceTree = ""; }; + 0F75F5722A6B1DAE00A45078 /* atl-misc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "atl-misc.h"; sourceTree = ""; }; + 0F75F5732A6B1DAE00A45078 /* CSingleThreadWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSingleThreadWrapper.h; sourceTree = ""; }; + 0F75F5742A6B1DAE00A45078 /* image_load_save.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = image_load_save.h; sourceTree = ""; }; + 0F75F5752A6B1DAF00A45078 /* reader_pretend_nonseekable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = reader_pretend_nonseekable.h; sourceTree = ""; }; + 0F75F5762A6B1DAF00A45078 /* window_placement_helper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = window_placement_helper.cpp; sourceTree = ""; }; + 0F75F5772A6B1DAF00A45078 /* meta_table_builder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = meta_table_builder.h; sourceTree = ""; }; + 0F75F5782A6B1DAF00A45078 /* fb2k_threads.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fb2k_threads.h; sourceTree = ""; }; + 0F75F5792A6B1DAF00A45078 /* playlist_position_reference_tracker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = playlist_position_reference_tracker.h; sourceTree = ""; }; + 0F75F57A2A6B1DAF00A45078 /* file_list_helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = file_list_helper.h; sourceTree = ""; }; + 0F75F57B2A6B1DAF00A45078 /* inplace_edit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = inplace_edit.h; sourceTree = ""; }; + 0F75F57C2A6B1DAF00A45078 /* album_art_helpers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = album_art_helpers.cpp; sourceTree = ""; }; + 0F75F57D2A6B1DAF00A45078 /* AutoComplete.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AutoComplete.h; sourceTree = ""; }; + 0F75F57E2A6B1DAF00A45078 /* ProfileCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProfileCache.h; sourceTree = ""; }; + 0F75F57F2A6B1DAF00A45078 /* fileReadAhead.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fileReadAhead.h; sourceTree = ""; }; + 0F75F5802A6B1DAF00A45078 /* cfg_dsp_chain_config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cfg_dsp_chain_config.h; sourceTree = ""; }; + 0F75F5812A6B1DAF00A45078 /* metadb_io_callback_v2_data.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = metadb_io_callback_v2_data.h; sourceTree = ""; }; + 0F75F5822A6B1DAF00A45078 /* cue_parser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cue_parser.cpp; sourceTree = ""; }; + 0F75F5832A6B1DAF00A45078 /* ui_element_helpers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ui_element_helpers.cpp; sourceTree = ""; }; + 0F75F5842A6B1DAF00A45078 /* ui_element_helpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ui_element_helpers.h; sourceTree = ""; }; + 0F75F5852A6B1DAF00A45078 /* CListControlFb2kColors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CListControlFb2kColors.h; sourceTree = ""; }; + 0F75F5862A6B1DAF00A45078 /* stream_buffer_helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stream_buffer_helper.h; sourceTree = ""; }; + 0F75F5872A6B1DAF00A45078 /* advconfig_runtime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = advconfig_runtime.h; sourceTree = ""; }; + 0F75F5882A6B1DAF00A45078 /* readWriteLock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = readWriteLock.h; sourceTree = ""; }; + 0F75F5892A6B1DAF00A45078 /* writer_wav.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = writer_wav.cpp; sourceTree = ""; }; + 0F75F58A2A6B1DAF00A45078 /* fb2kWorkerTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fb2kWorkerTool.h; sourceTree = ""; }; + 0F75F58B2A6B1DAF00A45078 /* cfg_objList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cfg_objList.h; sourceTree = ""; }; + 0F75F58C2A6B1DAF00A45078 /* CDialogResizeHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDialogResizeHelper.h; sourceTree = ""; }; + 0F75F58D2A6B1DAF00A45078 /* file_info_const_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = file_info_const_impl.h; sourceTree = ""; }; + 0F75F58E2A6B1DAF00A45078 /* file_list_helper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = file_list_helper.cpp; sourceTree = ""; }; + 0F75F58F2A6B1DAF00A45078 /* albumArtCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = albumArtCache.h; sourceTree = ""; }; + 0F75F5902A6B1DAF00A45078 /* rethrow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rethrow.h; sourceTree = ""; }; + 0F75F5912A6B1DAF00A45078 /* cfg_var_import.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cfg_var_import.h; sourceTree = ""; }; + 0F75F5922A6B1DB000A45078 /* album_art_helpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = album_art_helpers.h; sourceTree = ""; }; + 0F75F5932A6B1DB000A45078 /* create_directory_helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = create_directory_helper.h; sourceTree = ""; }; + 0F75F5942A6B1DB000A45078 /* input_helpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = input_helpers.h; sourceTree = ""; }; + 0F75F5952A6B1DB000A45078 /* notifyList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = notifyList.h; sourceTree = ""; }; + 0F75F5962A6B1DB000A45078 /* inplace_edit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = inplace_edit.cpp; sourceTree = ""; }; + 0F75F5972A6B1DB000A45078 /* image_load_save.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = image_load_save.cpp; sourceTree = ""; }; + 0F75F5982A6B1DB000A45078 /* win-MulDiv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "win-MulDiv.h"; sourceTree = ""; }; + 0F75F5992A6B1DB000A45078 /* metadb_info_container_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = metadb_info_container_impl.h; sourceTree = ""; }; + 0F75F59A2A6B1DB000A45078 /* metadb_io_hintlist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = metadb_io_hintlist.h; sourceTree = ""; }; + 0F75F59B2A6B1DB000A45078 /* track_property_callback_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = track_property_callback_impl.h; sourceTree = ""; }; + 0F75F59C2A6B1DB000A45078 /* filetimetools.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = filetimetools.cpp; sourceTree = ""; }; + 0F75F59D2A6B1DB000A45078 /* ProcessUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProcessUtils.h; sourceTree = ""; }; + 0F75F59E2A6B1DB000A45078 /* readers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = readers.h; sourceTree = ""; }; + 0F75F59F2A6B1DB000A45078 /* VolumeMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VolumeMap.cpp; sourceTree = ""; }; + 0F75F5A02A6B1DB000A45078 /* cfg_guidlist.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cfg_guidlist.cpp; sourceTree = ""; }; + 0F75F5A12A6B1DB000A45078 /* dropdown_helper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dropdown_helper.cpp; sourceTree = ""; }; + 0F75F5A22A6B1DB000A45078 /* callback_merit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = callback_merit.h; sourceTree = ""; }; + 0F75F5A32A6B1DB000A45078 /* cue_creator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cue_creator.cpp; sourceTree = ""; }; + 0F75F5A42A6B1DB000A45078 /* CPropVariant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CPropVariant.h; sourceTree = ""; }; + 0F75F5A52A6B1DB000A45078 /* text_file_loader_v2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = text_file_loader_v2.h; sourceTree = ""; }; + 0F75F5A62A6B1DB000A45078 /* helpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = helpers.h; sourceTree = ""; }; + 0F75F5A72A6B1DB000A45078 /* WindowPositionUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WindowPositionUtils.cpp; sourceTree = ""; }; + 0F75F5A82A6B1DB000A45078 /* dynamic_bitrate_helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dynamic_bitrate_helper.h; sourceTree = ""; }; + 0F75F5A92A6B1DB000A45078 /* packet_decoder_mp3_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = packet_decoder_mp3_common.h; sourceTree = ""; }; + 0F75F5AA2A6B1DB000A45078 /* foobar2000+atl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "foobar2000+atl.h"; sourceTree = ""; }; + 0F75F5AB2A6B1DB000A45078 /* CallForwarder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallForwarder.h; sourceTree = ""; }; + 0F75F5AC2A6B1DB000A45078 /* StdAfx.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StdAfx.cpp; sourceTree = ""; }; + 0F75F5AD2A6B1DB100A45078 /* CTableEditHelper-Legacy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CTableEditHelper-Legacy.h"; sourceTree = ""; }; + 0F75F5AE2A6B1DB100A45078 /* window_placement_helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = window_placement_helper.h; sourceTree = ""; }; + 0F75F5AF2A6B1DB100A45078 /* input_helper_cue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = input_helper_cue.h; sourceTree = ""; }; + 0F75F5B02A6B1DB100A45078 /* cuesheet_index_list.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cuesheet_index_list.cpp; sourceTree = ""; }; + 0F75F5B12A6B1DB100A45078 /* win-systemtime.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "win-systemtime.cpp"; sourceTree = ""; }; + 0F75F5B22A6B1DB100A45078 /* dynamic_bitrate_helper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dynamic_bitrate_helper.cpp; sourceTree = ""; }; + 0F75F5B32A6B1DB100A45078 /* bitreader_helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bitreader_helper.h; sourceTree = ""; }; + 0F75F5B42A6B1DB100A45078 /* StdAfx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StdAfx.h; sourceTree = ""; }; + 0F75F5B52A6B1DB100A45078 /* packet_decoder_aac_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = packet_decoder_aac_common.h; sourceTree = ""; }; + 0F75F5B62A6B1DB100A45078 /* CmdThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CmdThread.h; sourceTree = ""; }; + 0F75F5B72A6B1DB100A45078 /* readers_lite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = readers_lite.h; sourceTree = ""; }; + 0F75F5B82A6B1DB100A45078 /* text_file_loader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = text_file_loader.cpp; sourceTree = ""; }; + 0F75F5B92A6B1DB100A45078 /* cue_creator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cue_creator.h; sourceTree = ""; }; + 0F75F5BA2A6B1DB100A45078 /* ThreadUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ThreadUtils.cpp; sourceTree = ""; }; + 0F75F5BB2A6B1DB100A45078 /* file_streamstub.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = file_streamstub.h; sourceTree = ""; }; + 0F75F5BC2A6B1DB100A45078 /* tag_write_callback_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tag_write_callback_impl.h; sourceTree = ""; }; + 0F75F5BD2A6B1DB100A45078 /* win32_misc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = win32_misc.cpp; sourceTree = ""; }; + 0F75F5BE2A6B1DB100A45078 /* WindowPositionUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WindowPositionUtils.h; sourceTree = ""; }; + 0F75F5BF2A6B1DB100A45078 /* packet_decoder_mp3_common.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = packet_decoder_mp3_common.cpp; sourceTree = ""; }; + 0F75F5C02A6B1DB100A45078 /* CTableEditHelper-Legacy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "CTableEditHelper-Legacy.cpp"; sourceTree = ""; }; + 0F75F5C12A6B1DB100A45078 /* duration_counter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = duration_counter.h; sourceTree = ""; }; + 0F75F5C22A6B1DB100A45078 /* cue_parser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cue_parser.h; sourceTree = ""; }; + 0F75F5C32A6B1DB100A45078 /* dialog_resize_helper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dialog_resize_helper.cpp; sourceTree = ""; }; + 0F75F5C42A6B1DB100A45078 /* seekabilizer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = seekabilizer.cpp; sourceTree = ""; }; + 0F75F5C52A6B1DB100A45078 /* fullFileBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fullFileBuffer.h; sourceTree = ""; }; + 0F75F5C62A6B1DB100A45078 /* win32_dialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = win32_dialog.h; sourceTree = ""; }; + 0F75F5C72A6B1DB100A45078 /* cuesheet_index_list.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cuesheet_index_list.h; sourceTree = ""; }; + 0F75F5C82A6B1DB100A45078 /* callInMainThreadHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = callInMainThreadHelper.h; sourceTree = ""; }; + 0F75F5C92A6B1DB100A45078 /* icon_remapping_wildcard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = icon_remapping_wildcard.h; sourceTree = ""; }; + 0F75F5CA2A6B1DB100A45078 /* audio_render_float.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = audio_render_float.h; sourceTree = ""; }; + 0F75F5CB2A6B1DB100A45078 /* win32_dialog.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = win32_dialog.cpp; sourceTree = ""; }; + 0F75F5CC2A6B1DB100A45078 /* advconfig_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = advconfig_impl.h; sourceTree = ""; }; + 0F75F5CD2A6B1DB100A45078 /* input_fix_seeking.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = input_fix_seeking.h; sourceTree = ""; }; + 0F75F5CE2A6B1DB100A45078 /* win-systemtime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "win-systemtime.h"; sourceTree = ""; }; + 0F75F5CF2A6B1DB100A45078 /* stream_buffer_helper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = stream_buffer_helper.cpp; sourceTree = ""; }; + 0F75F5D02A6B1DB100A45078 /* dsp_dialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dsp_dialog.h; sourceTree = ""; }; + 0F75F5D12A6B1DB100A45078 /* BumpableElem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BumpableElem.h; sourceTree = ""; }; + 0F75F5D22A6B1DB100A45078 /* cfg_obj.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cfg_obj.h; sourceTree = ""; }; + 0F75F5D32A6B1DB200A45078 /* packet_decoder_aac_common.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = packet_decoder_aac_common.cpp; sourceTree = ""; }; + 0F75F5D42A6B1DB200A45078 /* mp3_utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mp3_utils.h; sourceTree = ""; }; + 0F75F5D52A6B1DB200A45078 /* cue_parser_embedding.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cue_parser_embedding.cpp; sourceTree = ""; }; + 0F75F5D62A6B1DB200A45078 /* input_helpers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = input_helpers.cpp; sourceTree = ""; }; + 0F75F5D72A6B1DB200A45078 /* ThreadUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThreadUtils.h; sourceTree = ""; }; + 0F75F5D82A6B1DB200A45078 /* track_property_callback_impl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = track_property_callback_impl.cpp; sourceTree = ""; }; + 0F75F5D92A6B1DB200A45078 /* AutoComplete.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AutoComplete.cpp; sourceTree = ""; }; + 0F75F5DA2A6B1DB200A45078 /* fb2k_wfx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fb2k_wfx.h; sourceTree = ""; }; + 0F75F5DB2A6B1DB200A45078 /* DarkMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DarkMode.h; sourceTree = ""; }; + 0F75F5DC2A6B1DB200A45078 /* win32_misc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = win32_misc.h; sourceTree = ""; }; + 0F75F5DD2A6B1DB200A45078 /* winmm-types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "winmm-types.h"; sourceTree = ""; }; + 0F75F5DE2A6B1DB200A45078 /* metadb_handle_set.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = metadb_handle_set.h; sourceTree = ""; }; + 0F75F5DF2A6B1DB200A45078 /* mp3_utils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mp3_utils.cpp; sourceTree = ""; }; + 0F75F5E02A6B1DB200A45078 /* file_win32_wrapper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = file_win32_wrapper.cpp; sourceTree = ""; }; + 0F75F5E12A6B1DB200A45078 /* seekabilizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = seekabilizer.h; sourceTree = ""; }; + 0F75F5E22A6B1DB200A45078 /* file_move_helper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = file_move_helper.cpp; sourceTree = ""; }; + 0F75F5E32A6B1DB200A45078 /* cfg_guidlist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cfg_guidlist.h; sourceTree = ""; }; + 0F75F5E42A6B1DB200A45078 /* input_helper_cue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = input_helper_cue.cpp; sourceTree = ""; }; + 0F75F5E52A6B1DB200A45078 /* text_file_loader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = text_file_loader.h; sourceTree = ""; }; + 0F75F5E62A6B1DB200A45078 /* file_cached.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = file_cached.h; sourceTree = ""; }; + 0F75F5E72A6B1DB200A45078 /* input_stream_info_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = input_stream_info_reader.h; sourceTree = ""; }; + 0F75F5E82A6B1DB200A45078 /* DarkMode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DarkMode.cpp; sourceTree = ""; }; + 0F75F5E92A6B1DB200A45078 /* dropdown_helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dropdown_helper.h; sourceTree = ""; }; + B12D1DB11991061A0087CEF3 /* libfoobar2000_SDK_helpers.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libfoobar2000_SDK_helpers.a; sourceTree = BUILT_PRODUCTS_DIR; }; + B166964A19ACC1560001728F /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + B166965819ACC1560001728F /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; + B166965B19ACC1560001728F /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + B12D1DAE1991061A0087CEF3 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + B12D1DA81991061A0087CEF3 = { + isa = PBXGroup; + children = ( + B12D1DBE1991063D0087CEF3 /* Source */, + B166964919ACC1560001728F /* Frameworks */, + B12D1DB21991061A0087CEF3 /* Products */, + ); + sourceTree = ""; + }; + B12D1DB21991061A0087CEF3 /* Products */ = { + isa = PBXGroup; + children = ( + B12D1DB11991061A0087CEF3 /* libfoobar2000_SDK_helpers.a */, + ); + name = Products; + sourceTree = ""; + }; + B12D1DBE1991063D0087CEF3 /* Source */ = { + isa = PBXGroup; + children = ( + 0F75F5CC2A6B1DB100A45078 /* advconfig_impl.h */, + 0F75F5872A6B1DAF00A45078 /* advconfig_runtime.h */, + 0F75F57C2A6B1DAF00A45078 /* album_art_helpers.cpp */, + 0F75F5922A6B1DB000A45078 /* album_art_helpers.h */, + 0F75F58F2A6B1DAF00A45078 /* albumArtCache.h */, + 0F75F5722A6B1DAE00A45078 /* atl-misc.h */, + 0F75F5CA2A6B1DB100A45078 /* audio_render_float.h */, + 0F75F5D92A6B1DB200A45078 /* AutoComplete.cpp */, + 0F75F57D2A6B1DAF00A45078 /* AutoComplete.h */, + 0F75F5B32A6B1DB100A45078 /* bitreader_helper.h */, + 0F75F5D12A6B1DB100A45078 /* BumpableElem.h */, + 0F75F5A22A6B1DB000A45078 /* callback_merit.h */, + 0F75F5AB2A6B1DB000A45078 /* CallForwarder.h */, + 0F75F5C82A6B1DB100A45078 /* callInMainThreadHelper.h */, + 0F75F58C2A6B1DAF00A45078 /* CDialogResizeHelper.h */, + 0F75F5802A6B1DAF00A45078 /* cfg_dsp_chain_config.h */, + 0F75F5A02A6B1DB000A45078 /* cfg_guidlist.cpp */, + 0F75F5E32A6B1DB200A45078 /* cfg_guidlist.h */, + 0F75F5D22A6B1DB100A45078 /* cfg_obj.h */, + 0F75F58B2A6B1DAF00A45078 /* cfg_objList.h */, + 0F75F5642A6B1DAE00A45078 /* cfg_var_import.cpp */, + 0F75F5912A6B1DAF00A45078 /* cfg_var_import.h */, + 0F75F5852A6B1DAF00A45078 /* CListControlFb2kColors.h */, + 0F75F5B62A6B1DB100A45078 /* CmdThread.h */, + 0F75F56D2A6B1DAE00A45078 /* COM_utils.h */, + 0F75F5A42A6B1DB000A45078 /* CPropVariant.h */, + 0F75F56A2A6B1DAE00A45078 /* create_directory_helper.cpp */, + 0F75F5932A6B1DB000A45078 /* create_directory_helper.h */, + 0F75F5732A6B1DAE00A45078 /* CSingleThreadWrapper.h */, + 0F75F5C02A6B1DB100A45078 /* CTableEditHelper-Legacy.cpp */, + 0F75F5AD2A6B1DB100A45078 /* CTableEditHelper-Legacy.h */, + 0F75F5A32A6B1DB000A45078 /* cue_creator.cpp */, + 0F75F5B92A6B1DB100A45078 /* cue_creator.h */, + 0F75F5D52A6B1DB200A45078 /* cue_parser_embedding.cpp */, + 0F75F5822A6B1DAF00A45078 /* cue_parser.cpp */, + 0F75F5C22A6B1DB100A45078 /* cue_parser.h */, + 0F75F5B02A6B1DB100A45078 /* cuesheet_index_list.cpp */, + 0F75F5C72A6B1DB100A45078 /* cuesheet_index_list.h */, + 0F75F5E82A6B1DB200A45078 /* DarkMode.cpp */, + 0F75F5DB2A6B1DB200A45078 /* DarkMode.h */, + 0F75F5C32A6B1DB100A45078 /* dialog_resize_helper.cpp */, + 0F75F5622A6B1DAE00A45078 /* dialog_resize_helper.h */, + 0F75F5A12A6B1DB000A45078 /* dropdown_helper.cpp */, + 0F75F5E92A6B1DB200A45078 /* dropdown_helper.h */, + 0F75F5D02A6B1DB100A45078 /* dsp_dialog.h */, + 0F75F5C12A6B1DB100A45078 /* duration_counter.h */, + 0F75F5B22A6B1DB100A45078 /* dynamic_bitrate_helper.cpp */, + 0F75F5A82A6B1DB000A45078 /* dynamic_bitrate_helper.h */, + 0F75F5782A6B1DAF00A45078 /* fb2k_threads.h */, + 0F75F5DA2A6B1DB200A45078 /* fb2k_wfx.h */, + 0F75F58A2A6B1DAF00A45078 /* fb2kWorkerTool.h */, + 0F75F5E62A6B1DB200A45078 /* file_cached.h */, + 0F75F58D2A6B1DAF00A45078 /* file_info_const_impl.h */, + 0F75F58E2A6B1DAF00A45078 /* file_list_helper.cpp */, + 0F75F57A2A6B1DAF00A45078 /* file_list_helper.h */, + 0F75F5E22A6B1DB200A45078 /* file_move_helper.cpp */, + 0F75F5682A6B1DAE00A45078 /* file_move_helper.h */, + 0F75F5BB2A6B1DB100A45078 /* file_streamstub.h */, + 0F75F5E02A6B1DB200A45078 /* file_win32_wrapper.cpp */, + 0F75F56F2A6B1DAE00A45078 /* file_win32_wrapper.h */, + 0F75F57F2A6B1DAF00A45078 /* fileReadAhead.h */, + 0F75F59C2A6B1DB000A45078 /* filetimetools.cpp */, + 0F75F5692A6B1DAE00A45078 /* filetimetools.h */, + 0F75F5702A6B1DAE00A45078 /* foobar2000-lite+atl.h */, + 0F75F5AA2A6B1DB000A45078 /* foobar2000+atl.h */, + 0F75F5C52A6B1DB100A45078 /* fullFileBuffer.h */, + 0F75F5A62A6B1DB000A45078 /* helpers.h */, + 0F75F5C92A6B1DB100A45078 /* icon_remapping_wildcard.h */, + 0F75F5972A6B1DB000A45078 /* image_load_save.cpp */, + 0F75F5742A6B1DAE00A45078 /* image_load_save.h */, + 0F75F5962A6B1DB000A45078 /* inplace_edit.cpp */, + 0F75F57B2A6B1DAF00A45078 /* inplace_edit.h */, + 0F75F5CD2A6B1DB100A45078 /* input_fix_seeking.h */, + 0F75F5E42A6B1DB200A45078 /* input_helper_cue.cpp */, + 0F75F5AF2A6B1DB100A45078 /* input_helper_cue.h */, + 0F75F5D62A6B1DB200A45078 /* input_helpers.cpp */, + 0F75F5942A6B1DB000A45078 /* input_helpers.h */, + 0F75F5632A6B1DAE00A45078 /* input_logging.h */, + 0F75F5E72A6B1DB200A45078 /* input_stream_info_reader.h */, + 0F75F5772A6B1DAF00A45078 /* meta_table_builder.h */, + 0F75F5712A6B1DAE00A45078 /* metadb_handle_array.h */, + 0F75F5DE2A6B1DB200A45078 /* metadb_handle_set.h */, + 0F75F5992A6B1DB000A45078 /* metadb_info_container_impl.h */, + 0F75F5812A6B1DAF00A45078 /* metadb_io_callback_v2_data.h */, + 0F75F59A2A6B1DB000A45078 /* metadb_io_hintlist.h */, + 0F75F5DF2A6B1DB200A45078 /* mp3_utils.cpp */, + 0F75F5D42A6B1DB200A45078 /* mp3_utils.h */, + 0F75F5952A6B1DB000A45078 /* notifyList.h */, + 0F75F5D32A6B1DB200A45078 /* packet_decoder_aac_common.cpp */, + 0F75F5B52A6B1DB100A45078 /* packet_decoder_aac_common.h */, + 0F75F5BF2A6B1DB100A45078 /* packet_decoder_mp3_common.cpp */, + 0F75F5A92A6B1DB000A45078 /* packet_decoder_mp3_common.h */, + 0F75F5792A6B1DAF00A45078 /* playlist_position_reference_tracker.h */, + 0F75F59D2A6B1DB000A45078 /* ProcessUtils.h */, + 0F75F57E2A6B1DAF00A45078 /* ProfileCache.h */, + 0F75F5752A6B1DAF00A45078 /* reader_pretend_nonseekable.h */, + 0F75F5B72A6B1DB100A45078 /* readers_lite.h */, + 0F75F5652A6B1DAE00A45078 /* readers.cpp */, + 0F75F59E2A6B1DB000A45078 /* readers.h */, + 0F75F5882A6B1DAF00A45078 /* readWriteLock.h */, + 0F75F5902A6B1DAF00A45078 /* rethrow.h */, + 0F75F5C42A6B1DB100A45078 /* seekabilizer.cpp */, + 0F75F5E12A6B1DB200A45078 /* seekabilizer.h */, + 0F75F5AC2A6B1DB000A45078 /* StdAfx.cpp */, + 0F75F5B42A6B1DB100A45078 /* StdAfx.h */, + 0F75F5CF2A6B1DB100A45078 /* stream_buffer_helper.cpp */, + 0F75F5862A6B1DAF00A45078 /* stream_buffer_helper.h */, + 0F75F5BC2A6B1DB100A45078 /* tag_write_callback_impl.h */, + 0F75F5662A6B1DAE00A45078 /* text_file_loader_v2.cpp */, + 0F75F5A52A6B1DB000A45078 /* text_file_loader_v2.h */, + 0F75F5B82A6B1DB100A45078 /* text_file_loader.cpp */, + 0F75F5E52A6B1DB200A45078 /* text_file_loader.h */, + 0F75F5BA2A6B1DB100A45078 /* ThreadUtils.cpp */, + 0F75F5D72A6B1DB200A45078 /* ThreadUtils.h */, + 0F75F5D82A6B1DB200A45078 /* track_property_callback_impl.cpp */, + 0F75F59B2A6B1DB000A45078 /* track_property_callback_impl.h */, + 0F75F5832A6B1DAF00A45078 /* ui_element_helpers.cpp */, + 0F75F5842A6B1DAF00A45078 /* ui_element_helpers.h */, + 0F75F56C2A6B1DAE00A45078 /* VisUtils.cpp */, + 0F75F5672A6B1DAE00A45078 /* VisUtils.h */, + 0F75F59F2A6B1DB000A45078 /* VolumeMap.cpp */, + 0F75F56E2A6B1DAE00A45078 /* VolumeMap.h */, + 0F75F5982A6B1DB000A45078 /* win-MulDiv.h */, + 0F75F5B12A6B1DB100A45078 /* win-systemtime.cpp */, + 0F75F5CE2A6B1DB100A45078 /* win-systemtime.h */, + 0F75F5CB2A6B1DB100A45078 /* win32_dialog.cpp */, + 0F75F5C62A6B1DB100A45078 /* win32_dialog.h */, + 0F75F5BD2A6B1DB100A45078 /* win32_misc.cpp */, + 0F75F5DC2A6B1DB200A45078 /* win32_misc.h */, + 0F75F5762A6B1DAF00A45078 /* window_placement_helper.cpp */, + 0F75F5AE2A6B1DB100A45078 /* window_placement_helper.h */, + 0F75F5A72A6B1DB000A45078 /* WindowPositionUtils.cpp */, + 0F75F5BE2A6B1DB100A45078 /* WindowPositionUtils.h */, + 0F75F5DD2A6B1DB200A45078 /* winmm-types.h */, + 0F75F5892A6B1DAF00A45078 /* writer_wav.cpp */, + 0F75F56B2A6B1DAE00A45078 /* writer_wav.h */, + ); + name = Source; + sourceTree = ""; + }; + B166964919ACC1560001728F /* Frameworks */ = { + isa = PBXGroup; + children = ( + B166964A19ACC1560001728F /* Foundation.framework */, + B166965819ACC1560001728F /* XCTest.framework */, + B166965B19ACC1560001728F /* UIKit.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + B12D1DAF1991061A0087CEF3 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 0F75F6092A6B1DB200A45078 /* metadb_io_callback_v2_data.h in Headers */, + 0F75F62E2A6B1DB200A45078 /* helpers.h in Headers */, + 0F75F5F52A6B1DB200A45078 /* COM_utils.h in Headers */, + 0F75F6122A6B1DB200A45078 /* fb2kWorkerTool.h in Headers */, + 0F75F6082A6B1DB200A45078 /* cfg_dsp_chain_config.h in Headers */, + 0F75F6362A6B1DB200A45078 /* window_placement_helper.h in Headers */, + 0F75F61B2A6B1DB200A45078 /* create_directory_helper.h in Headers */, + 0F75F5FC2A6B1DB200A45078 /* image_load_save.h in Headers */, + 0F75F5F82A6B1DB200A45078 /* foobar2000-lite+atl.h in Headers */, + 0F75F61C2A6B1DB200A45078 /* input_helpers.h in Headers */, + 0F75F62D2A6B1DB200A45078 /* text_file_loader_v2.h in Headers */, + 0F75F6352A6B1DB200A45078 /* CTableEditHelper-Legacy.h in Headers */, + 0F75F6442A6B1DB200A45078 /* tag_write_callback_impl.h in Headers */, + 0F75F61A2A6B1DB200A45078 /* album_art_helpers.h in Headers */, + 0F75F6322A6B1DB200A45078 /* foobar2000+atl.h in Headers */, + 0F75F65F2A6B1DB200A45078 /* ThreadUtils.h in Headers */, + 0F75F6592A6B1DB200A45078 /* BumpableElem.h in Headers */, + 0F75F64D2A6B1DB200A45078 /* fullFileBuffer.h in Headers */, + 0F75F60C2A6B1DB200A45078 /* ui_element_helpers.h in Headers */, + 0F75F6252A6B1DB200A45078 /* ProcessUtils.h in Headers */, + 0F75F66D2A6B1DB200A45078 /* text_file_loader.h in Headers */, + 0F75F6072A6B1DB200A45078 /* fileReadAhead.h in Headers */, + 0F75F60D2A6B1DB200A45078 /* CListControlFb2kColors.h in Headers */, + 0F75F6132A6B1DB200A45078 /* cfg_objList.h in Headers */, + 0F75F6692A6B1DB200A45078 /* seekabilizer.h in Headers */, + 0F75F6562A6B1DB200A45078 /* win-systemtime.h in Headers */, + 0F75F6312A6B1DB200A45078 /* packet_decoder_mp3_common.h in Headers */, + 0F75F64A2A6B1DB200A45078 /* cue_parser.h in Headers */, + 0F75F6502A6B1DB200A45078 /* callInMainThreadHelper.h in Headers */, + 0F75F6652A6B1DB200A45078 /* winmm-types.h in Headers */, + 0F75F6662A6B1DB200A45078 /* metadb_handle_set.h in Headers */, + 0F75F6522A6B1DB200A45078 /* audio_render_float.h in Headers */, + 0F75F65A2A6B1DB200A45078 /* cfg_obj.h in Headers */, + 0F75F6182A6B1DB200A45078 /* rethrow.h in Headers */, + 0F75F5EA2A6B1DB200A45078 /* dialog_resize_helper.h in Headers */, + 0F75F6232A6B1DB200A45078 /* track_property_callback_impl.h in Headers */, + 0F75F6372A6B1DB200A45078 /* input_helper_cue.h in Headers */, + 0F75F6552A6B1DB200A45078 /* input_fix_seeking.h in Headers */, + 0F75F64F2A6B1DB200A45078 /* cuesheet_index_list.h in Headers */, + 0F75F5F02A6B1DB200A45078 /* file_move_helper.h in Headers */, + 0F75F6222A6B1DB200A45078 /* metadb_io_hintlist.h in Headers */, + 0F75F5F32A6B1DB200A45078 /* writer_wav.h in Headers */, + 0F75F6582A6B1DB200A45078 /* dsp_dialog.h in Headers */, + 0F75F6102A6B1DB200A45078 /* readWriteLock.h in Headers */, + 0F75F63C2A6B1DB200A45078 /* StdAfx.h in Headers */, + 0F75F6002A6B1DB200A45078 /* fb2k_threads.h in Headers */, + 0F75F65C2A6B1DB200A45078 /* mp3_utils.h in Headers */, + 0F75F66B2A6B1DB200A45078 /* cfg_guidlist.h in Headers */, + 0F75F6142A6B1DB200A45078 /* CDialogResizeHelper.h in Headers */, + 0F75F63E2A6B1DB200A45078 /* CmdThread.h in Headers */, + 0F75F5FB2A6B1DB200A45078 /* CSingleThreadWrapper.h in Headers */, + 0F75F6632A6B1DB200A45078 /* DarkMode.h in Headers */, + 0F75F5EF2A6B1DB200A45078 /* VisUtils.h in Headers */, + 0F75F6542A6B1DB200A45078 /* advconfig_impl.h in Headers */, + 0F75F6262A6B1DB200A45078 /* readers.h in Headers */, + 0F75F6032A6B1DB200A45078 /* inplace_edit.h in Headers */, + 0F75F5EB2A6B1DB200A45078 /* input_logging.h in Headers */, + 0F75F6202A6B1DB200A45078 /* win-MulDiv.h in Headers */, + 0F75F6062A6B1DB200A45078 /* ProfileCache.h in Headers */, + 0F75F6302A6B1DB200A45078 /* dynamic_bitrate_helper.h in Headers */, + 0F75F61D2A6B1DB200A45078 /* notifyList.h in Headers */, + 0F75F5FD2A6B1DB200A45078 /* reader_pretend_nonseekable.h in Headers */, + 0F75F6512A6B1DB200A45078 /* icon_remapping_wildcard.h in Headers */, + 0F75F5F12A6B1DB200A45078 /* filetimetools.h in Headers */, + 0F75F63B2A6B1DB200A45078 /* bitreader_helper.h in Headers */, + 0F75F6012A6B1DB200A45078 /* playlist_position_reference_tracker.h in Headers */, + 0F75F62C2A6B1DB200A45078 /* CPropVariant.h in Headers */, + 0F75F6622A6B1DB200A45078 /* fb2k_wfx.h in Headers */, + 0F75F60E2A6B1DB200A45078 /* stream_buffer_helper.h in Headers */, + 0F75F6462A6B1DB200A45078 /* WindowPositionUtils.h in Headers */, + 0F75F6412A6B1DB200A45078 /* cue_creator.h in Headers */, + 0F75F62A2A6B1DB200A45078 /* callback_merit.h in Headers */, + 0F75F6212A6B1DB200A45078 /* metadb_info_container_impl.h in Headers */, + 0F75F6172A6B1DB200A45078 /* albumArtCache.h in Headers */, + 0F75F66E2A6B1DB200A45078 /* file_cached.h in Headers */, + 0F75F6712A6B1DB200A45078 /* dropdown_helper.h in Headers */, + 0F75F5F92A6B1DB200A45078 /* metadb_handle_array.h in Headers */, + 0F75F63D2A6B1DB200A45078 /* packet_decoder_aac_common.h in Headers */, + 0F75F66F2A6B1DB200A45078 /* input_stream_info_reader.h in Headers */, + 0F75F6332A6B1DB200A45078 /* CallForwarder.h in Headers */, + 0F75F6642A6B1DB200A45078 /* win32_misc.h in Headers */, + 0F75F6192A6B1DB200A45078 /* cfg_var_import.h in Headers */, + 0F75F6052A6B1DB200A45078 /* AutoComplete.h in Headers */, + 0F75F64E2A6B1DB200A45078 /* win32_dialog.h in Headers */, + 0F75F5F62A6B1DB200A45078 /* VolumeMap.h in Headers */, + 0F75F5FA2A6B1DB200A45078 /* atl-misc.h in Headers */, + 0F75F60F2A6B1DB200A45078 /* advconfig_runtime.h in Headers */, + 0F75F6152A6B1DB200A45078 /* file_info_const_impl.h in Headers */, + 0F75F63F2A6B1DB200A45078 /* readers_lite.h in Headers */, + 0F75F6022A6B1DB200A45078 /* file_list_helper.h in Headers */, + 0F75F6432A6B1DB200A45078 /* file_streamstub.h in Headers */, + 0F75F6492A6B1DB200A45078 /* duration_counter.h in Headers */, + 0F75F5FF2A6B1DB200A45078 /* meta_table_builder.h in Headers */, + 0F75F5F72A6B1DB200A45078 /* file_win32_wrapper.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + B12D1DB01991061A0087CEF3 /* foobar2000_SDK_helpers */ = { + isa = PBXNativeTarget; + buildConfigurationList = B12D1DB51991061A0087CEF3 /* Build configuration list for PBXNativeTarget "foobar2000_SDK_helpers" */; + buildPhases = ( + B12D1DAD1991061A0087CEF3 /* Sources */, + B12D1DAE1991061A0087CEF3 /* Frameworks */, + B12D1DAF1991061A0087CEF3 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = foobar2000_SDK_helpers; + productName = foobar2000_SDK_helpers; + productReference = B12D1DB11991061A0087CEF3 /* libfoobar2000_SDK_helpers.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + B12D1DA91991061A0087CEF3 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1250; + ORGANIZATIONNAME = "___FULLUSERNAME___"; + }; + buildConfigurationList = B12D1DAC1991061A0087CEF3 /* Build configuration list for PBXProject "foobar2000_SDK_helpers" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = B12D1DA81991061A0087CEF3; + productRefGroup = B12D1DB21991061A0087CEF3 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + B12D1DB01991061A0087CEF3 /* foobar2000_SDK_helpers */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + B12D1DAD1991061A0087CEF3 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0F75F6672A6B1DB200A45078 /* mp3_utils.cpp in Sources */, + 0F75F63A2A6B1DB200A45078 /* dynamic_bitrate_helper.cpp in Sources */, + 0F75F62B2A6B1DB200A45078 /* cue_creator.cpp in Sources */, + 0F75F6292A6B1DB200A45078 /* dropdown_helper.cpp in Sources */, + 0F75F60A2A6B1DB200A45078 /* cue_parser.cpp in Sources */, + 0F75F6472A6B1DB200A45078 /* packet_decoder_mp3_common.cpp in Sources */, + 0F75F6422A6B1DB200A45078 /* ThreadUtils.cpp in Sources */, + 0F75F64B2A6B1DB200A45078 /* dialog_resize_helper.cpp in Sources */, + 0F75F6272A6B1DB200A45078 /* VolumeMap.cpp in Sources */, + 0F75F65E2A6B1DB200A45078 /* input_helpers.cpp in Sources */, + 0F75F6392A6B1DB200A45078 /* win-systemtime.cpp in Sources */, + 0F75F6112A6B1DB200A45078 /* writer_wav.cpp in Sources */, + 0F75F6682A6B1DB200A45078 /* file_win32_wrapper.cpp in Sources */, + 0F75F5ED2A6B1DB200A45078 /* readers.cpp in Sources */, + 0F75F5EC2A6B1DB200A45078 /* cfg_var_import.cpp in Sources */, + 0F75F6572A6B1DB200A45078 /* stream_buffer_helper.cpp in Sources */, + 0F75F6282A6B1DB200A45078 /* cfg_guidlist.cpp in Sources */, + 0F75F5F42A6B1DB200A45078 /* VisUtils.cpp in Sources */, + 0F75F5EE2A6B1DB200A45078 /* text_file_loader_v2.cpp in Sources */, + 0F75F6042A6B1DB200A45078 /* album_art_helpers.cpp in Sources */, + 0F75F6602A6B1DB200A45078 /* track_property_callback_impl.cpp in Sources */, + 0F75F64C2A6B1DB200A45078 /* seekabilizer.cpp in Sources */, + 0F75F65D2A6B1DB200A45078 /* cue_parser_embedding.cpp in Sources */, + 0F75F66C2A6B1DB200A45078 /* input_helper_cue.cpp in Sources */, + 0F75F6402A6B1DB200A45078 /* text_file_loader.cpp in Sources */, + 0F75F6242A6B1DB200A45078 /* filetimetools.cpp in Sources */, + 0F75F6382A6B1DB200A45078 /* cuesheet_index_list.cpp in Sources */, + 0F75F5F22A6B1DB200A45078 /* create_directory_helper.cpp in Sources */, + 0F75F66A2A6B1DB200A45078 /* file_move_helper.cpp in Sources */, + 0F75F6342A6B1DB200A45078 /* StdAfx.cpp in Sources */, + 0F75F6162A6B1DB200A45078 /* file_list_helper.cpp in Sources */, + 0F75F65B2A6B1DB200A45078 /* packet_decoder_aac_common.cpp in Sources */, + 0F75F6452A6B1DB200A45078 /* win32_misc.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + B12D1DB31991061A0087CEF3 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = StdAfx.h; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + ../.., + .., + ); + IPHONEOS_DEPLOYMENT_TARGET = 12.1; + MACOSX_DEPLOYMENT_TARGET = 10.13; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + B12D1DB41991061A0087CEF3 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = StdAfx.h; + GCC_PREPROCESSOR_DEFINITIONS = "NDEBUG=1"; + GCC_SYMBOLS_PRIVATE_EXTERN = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + ../.., + .., + ); + IPHONEOS_DEPLOYMENT_TARGET = 12.1; + MACOSX_DEPLOYMENT_TARGET = 10.13; + SDKROOT = macosx; + SKIP_INSTALL = YES; + }; + name = Release; + }; + B12D1DB61991061A0087CEF3 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + EXECUTABLE_PREFIX = lib; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + B12D1DB71991061A0087CEF3 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + EXECUTABLE_PREFIX = lib; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + B12D1DAC1991061A0087CEF3 /* Build configuration list for PBXProject "foobar2000_SDK_helpers" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B12D1DB31991061A0087CEF3 /* Debug */, + B12D1DB41991061A0087CEF3 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B12D1DB51991061A0087CEF3 /* Build configuration list for PBXNativeTarget "foobar2000_SDK_helpers" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B12D1DB61991061A0087CEF3 /* Debug */, + B12D1DB71991061A0087CEF3 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = B12D1DA91991061A0087CEF3 /* Project object */; +} diff --git a/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj b/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj index 8e8712f..2e38ddd 100644 --- a/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj +++ b/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj @@ -525,6 +525,7 @@ + diff --git a/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj.filters b/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj.filters index 912c4e9..5e32b96 100644 --- a/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj.filters +++ b/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj.filters @@ -415,5 +415,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/sdk/foobar2000/helpers/input_helpers.cpp b/sdk/foobar2000/helpers/input_helpers.cpp index 42f4028..62d237b 100644 --- a/sdk/foobar2000/helpers/input_helpers.cpp +++ b/sdk/foobar2000/helpers/input_helpers.cpp @@ -5,15 +5,19 @@ #include "file_list_helper.h" #include "fileReadAhead.h" #include +#include "readers_lite.h" - -input_helper::ioFilter_t input_helper::ioFilter_full_buffer(t_filesize val ) { +input_helper::ioFilter_t input_helper::ioFilter_full_buffer(t_filesize val) { if (val == 0) return nullptr; return [val] ( file_ptr & f, const char * path, abort_callback & aborter) { if (!filesystem::g_is_remote_or_unrecognized(path)) { - fullFileBuffer a; - f = a.open(path, aborter, f, val); - return true; + if (f.is_empty()) filesystem::g_open_read(f, path, aborter); + if (!f->is_in_memory() && !f->is_remote() && f->can_seek() && f->get_size(aborter) <= val) { + try { + f = createFileMemMirrorAsync(f, nullptr, aborter); + return true; + } catch (std::bad_alloc) {} // keep orig file object + } } return false; }; @@ -81,8 +85,7 @@ bool input_helper::test_if_lockless(abort_callback& a) { return false; } void input_helper::fileOpenTools(service_ptr_t & p_file,const char * p_path,input_helper::ioFilters_t const & filters, abort_callback & p_abort) { - for( auto walk = filters.begin(); walk != filters.end(); ++ walk ) { - auto f = *walk; + for( auto & f : filters ) { if (f) { if (f(p_file, p_path, p_abort)) break; } diff --git a/sdk/foobar2000/helpers/readers.cpp b/sdk/foobar2000/helpers/readers.cpp index 39fa6ad..dc54aad 100644 --- a/sdk/foobar2000/helpers/readers.cpp +++ b/sdk/foobar2000/helpers/readers.cpp @@ -5,6 +5,7 @@ #include "fileReadAhead.h" #include #include +#include t_size reader_membuffer_base::read(void * p_buffer, t_size p_bytes, abort_callback & p_abort) { p_abort.check_e(); @@ -86,7 +87,7 @@ namespace { }; typedef std::shared_ptr readAheadInstanceRef; static const t_filesize seek_reopen = (filesize_invalid-1); - class fileReadAhead : public file_readonly_t< service_multi_inherit > { + class fileReadAhead : public file_readonly_t< service_multi_inherit< service_multi_inherit, stream_receive > > { service_ptr m_metadata; public: readAheadInstanceRef m_instance; @@ -133,11 +134,17 @@ namespace { worker(*i); } ); } - t_size read(void * p_buffer,t_size p_bytes,abort_callback & p_abort) override { + t_size receive(void* p_buffer, t_size p_bytes, abort_callback& p_abort) override { + return read_internal(p_buffer, p_bytes, p_abort, true); + } + t_size read(void* p_buffer, t_size p_bytes, abort_callback& p_abort) override { + return read_internal(p_buffer, p_bytes, p_abort, false); + } + t_size read_internal(void * p_buffer,t_size p_bytes,abort_callback & p_abort, bool bReceive) { auto & i = * m_instance; size_t done = 0; bool initial = true; - while( done < p_bytes ) { + while( bReceive ? done == 0 : done < p_bytes ) { if ( !initial ) { // Do not invoke waiting with common case read with lots of data in the buffer pfc::event::g_twoEventWait( i.m_canRead.get_handle(), p_abort.get_abort_event(), -1); @@ -315,7 +322,7 @@ namespace { dynInfoEntry_t dynInfo; if ( readHowMuch > 0 ) { - readHowMuch = i.m_file->read( bufptr + readOffset, readHowMuch, i.m_abort ); + readHowMuch = i.m_file->receive( bufptr + readOffset, readHowMuch, i.m_abort ); if ( readHowMuch == 0 ) atEOF = true; @@ -443,3 +450,146 @@ file::ptr createFileMemMirror(file::ptr source, abort_callback& abort) { if (!reader_membuffer_mirror::g_create(ret, source, abort)) ret = source; return ret; } + +namespace { + class file_memMirrorAsync : public file_readonly_t< file_v2 > { + struct shared_t { + abort_callback_impl m_abort; + size_t m_size; + pfc::mutex m_sync; + file::ptr m_file; + + pfc::bigmem m_data; + size_t m_dataAvailable = 0; + + size_t m_triggerOffset = SIZE_MAX; + pfc::event m_trigger; + }; + shared_t m_shared; + + static void worker(shared_t& s) { + + constexpr size_t tempSize = 256 * 1024; + auto temp = std::make_unique(tempSize); + + while (s.m_dataAvailable < s.m_size) { + size_t got = s.m_file->receive(temp.get(), tempSize, s.m_abort); + if (got == 0) break; + + PFC_INSYNC(s.m_sync); + s.m_data.write(temp.get(), got, s.m_dataAvailable); + + auto before = s.m_dataAvailable; + s.m_dataAvailable += got; + if (before < s.m_triggerOffset && s.m_dataAvailable >= s.m_triggerOffset) { + s.m_trigger.set_state(true); + } + } + } + t_filestats2 m_stats; + bool m_is_remote = false; + pfc::string8 m_contentType; + service_ptr m_metadata; + t_filesize m_position = 0; + fb2k::thread m_thread; + public: + ~file_memMirrorAsync() { + m_shared.m_abort.set(); + m_thread.waitTillDone(); + } + void open(file::ptr chain, completion_notify::ptr onDone, abort_callback& a) { + if ( chain->get_position(a) > 0 ) chain->reopen(a); + m_stats = chain->get_stats2_(stats2_all, a); + if (m_stats.m_size > SIZE_MAX) throw pfc::exception_overflow(); + m_is_remote = chain->is_remote(); + m_contentType = chain->get_content_type(); + m_metadata = chain->get_metadata_(a); + m_shared.m_size = (size_t)m_stats.m_size; + m_shared.m_file = chain; + m_shared.m_data.resize(m_shared.m_size); + auto work = [this, onDone] { + try { + worker(this->m_shared); + } catch (...) {} + this->m_shared.m_file.release(); + if (onDone.is_valid()) onDone->on_completion(this->m_shared.m_size == this->m_shared.m_dataAvailable ? 1 : 0); + }; + m_thread.startHere(work); + } + + + service_ptr get_metadata(abort_callback& a) override { + a.check(); + return m_metadata; + } + + t_filestats2 get_stats2(uint32_t, abort_callback& a) override { + a.check(); + return m_stats; + } + + t_filesize get_position(abort_callback& p_abort) override { + p_abort.check(); + return m_position; + } + + void seek(t_filesize p_position, abort_callback& p_abort) override { + if (p_position > get_size(p_abort)) throw exception_io_seek_out_of_range(); + m_position = p_position; + } + + bool can_seek() override { return true; } + + bool get_content_type(pfc::string_base& p_out) override { + bool rv = m_contentType.length() > 0; + if (rv) p_out = m_contentType; + return rv; + } + + void reopen(abort_callback& p_abort) override { seek(0, p_abort); } + + bool is_remote() override { return m_is_remote; } + + t_size read(void* p_buffer, t_size p_bytes, abort_callback& p_abort) override { + auto limit = get_size(p_abort); + auto left = limit - m_position; + if (p_bytes > left) p_bytes = (size_t)left; + + const auto upper = m_position + p_bytes; + + auto& shared = m_shared; + + { + PFC_INSYNC(shared.m_sync); + if (shared.m_dataAvailable >= upper) { + shared.m_data.read(p_buffer, p_bytes, m_position); + m_position += p_bytes; + return p_bytes; + } + shared.m_trigger.set_state(false); + shared.m_triggerOffset = upper; + } + p_abort.waitForEvent(shared.m_trigger); + + PFC_INSYNC(shared.m_sync); + PFC_ASSERT(shared.m_dataAvailable >= upper); + shared.m_data.read(p_buffer, p_bytes, m_position); + m_position += p_bytes; + return p_bytes; + } + t_filesize skip(t_filesize p_bytes, abort_callback& p_abort) override { + auto total = get_size(p_abort); + PFC_ASSERT(total >= m_position ); + auto left = total - m_position; + if (p_bytes > left) p_bytes = left; + m_position += p_bytes; + return p_bytes; + } + }; +} + +file::ptr createFileMemMirrorAsync(file::ptr source, completion_notify::ptr onDone, abort_callback & a) { + auto ret = fb2k::service_new(); + ret->open(source, onDone, a); + return ret; +} diff --git a/sdk/foobar2000/helpers/readers_lite.h b/sdk/foobar2000/helpers/readers_lite.h index 7e3634a..2db93e0 100644 --- a/sdk/foobar2000/helpers/readers_lite.h +++ b/sdk/foobar2000/helpers/readers_lite.h @@ -4,3 +4,4 @@ file::ptr createFileWithMemBlock(fb2k::memBlock::ptr mem, t_filestats stats = fi file::ptr createFileLimited(file::ptr base, t_filesize offset, t_filesize size, abort_callback& abort); file::ptr createFileBigMemMirror(file::ptr source, abort_callback& abort); file::ptr createFileMemMirror(file::ptr source, abort_callback& abort); +file::ptr createFileMemMirrorAsync(file::ptr source, completion_notify::ptr optionalDoneReading, abort_callback & a); diff --git a/sdk/foobar2000/helpers/win32_dialog.cpp b/sdk/foobar2000/helpers/win32_dialog.cpp index 2516388..ab811f3 100644 --- a/sdk/foobar2000/helpers/win32_dialog.cpp +++ b/sdk/foobar2000/helpers/win32_dialog.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "StdAfx.h" #ifdef FOOBAR2000_DESKTOP_WINDOWS diff --git a/sdk/foobar2000/helpers/win32_misc.cpp b/sdk/foobar2000/helpers/win32_misc.cpp index d2d24cf..e36170b 100644 --- a/sdk/foobar2000/helpers/win32_misc.cpp +++ b/sdk/foobar2000/helpers/win32_misc.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "StdAfx.h" #include "win32_misc.h" #ifdef FOOBAR2000_MOBILE_WINDOWS diff --git a/sdk/foobar2000/helpers/window_placement_helper.cpp b/sdk/foobar2000/helpers/window_placement_helper.cpp index d905254..f516e5a 100644 --- a/sdk/foobar2000/helpers/window_placement_helper.cpp +++ b/sdk/foobar2000/helpers/window_placement_helper.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "StdAfx.h" #ifdef FOOBAR2000_DESKTOP_WINDOWS diff --git a/sdk/foobar2000/shared/Utility.cpp b/sdk/foobar2000/shared/Utility.cpp new file mode 100644 index 0000000..842bc2d --- /dev/null +++ b/sdk/foobar2000/shared/Utility.cpp @@ -0,0 +1,138 @@ +#include "shared.h" + +#include + +static std::once_flag g_infinitWaitInit; +static HANDLE g_infinitWaitEvent = NULL; + +HANDLE SHARED_EXPORT GetInfiniteWaitEvent() { + std::call_once(g_infinitWaitInit, [] { + g_infinitWaitEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + } ); + return g_infinitWaitEvent; +} + +struct createFileRequest { + TCHAR * lpFileName; + DWORD dwDesiredAccess; + DWORD dwShareMode; + LPSECURITY_ATTRIBUTES lpSecurityAttributes; + DWORD dwCreationDisposition; + DWORD dwFlagsAndAttributes; + + HANDLE hResultHandle; + + DWORD dwErrorCode; + + volatile LONG refCounter; + + void Delete() { + free(lpFileName); + if (hResultHandle != INVALID_HANDLE_VALUE) CloseHandle(hResultHandle); + delete this; + } + + void Release() { + if (InterlockedDecrement(&refCounter) == 0) { + Delete(); + } + } +}; + +static unsigned CALLBACK createFileThread(void* p) { + createFileRequest * req = reinterpret_cast(p); + + SetLastError(0); + req->hResultHandle = CreateFile(req->lpFileName, req->dwDesiredAccess, req->dwShareMode, req->lpSecurityAttributes, req->dwCreationDisposition, req->dwFlagsAndAttributes, NULL); + req->dwErrorCode = GetLastError(); + + req->Release(); + return 0; +} + + +typedef BOOL (WINAPI * pCancelSynchronousIo_t)(HANDLE hThread); +static BOOL myCancelSynchronousIo(HANDLE hThread) { + pCancelSynchronousIo_t pCancelSynchronousIo = (pCancelSynchronousIo_t) GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "CancelSynchronousIo"); + if (pCancelSynchronousIo == NULL) {SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE;} + return pCancelSynchronousIo(hThread); +} + +HANDLE SHARED_EXPORT CreateFileAbortable( __in LPCWSTR lpFileName, + __in DWORD dwDesiredAccess, + __in DWORD dwShareMode, + __in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes, + __in DWORD dwCreationDisposition, + __in DWORD dwFlagsAndAttributes, + __in_opt HANDLE hAborter + ) { + if (hAborter == NULL || hAborter == GetInfiniteWaitEvent()) { + return CreateFile(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, NULL); + } + switch(WaitForSingleObject(hAborter, 0)) { + case WAIT_TIMEOUT: + break; + case WAIT_OBJECT_0: + SetLastError(ERROR_OPERATION_ABORTED); + return INVALID_HANDLE_VALUE; + default: + return INVALID_HANDLE_VALUE; + } + + createFileRequest * req = new createFileRequest(); + req->lpFileName = _tcsdup(lpFileName); + req->dwDesiredAccess = dwDesiredAccess; + req->dwShareMode = dwShareMode; + req->lpSecurityAttributes = lpSecurityAttributes; + req->dwCreationDisposition = dwCreationDisposition; + req->dwFlagsAndAttributes = dwFlagsAndAttributes; + req->hResultHandle = INVALID_HANDLE_VALUE; + req->dwErrorCode = 0; + req->refCounter = 2; + + HANDLE hThread = (HANDLE) _beginthreadex(NULL, 0, createFileThread, req, CREATE_SUSPENDED, NULL); + if (hThread == NULL) { + req->Delete(); + return INVALID_HANDLE_VALUE; + } + SetThreadPriority(hThread, GetThreadPriority(GetCurrentThread())); + ResumeThread(hThread); + + DWORD waitStatus; + { + HANDLE waits[2] = {hThread, hAborter}; + waitStatus = WaitForMultipleObjects(2, waits, FALSE, INFINITE); + } + HANDLE hRetVal = INVALID_HANDLE_VALUE; + DWORD dwErrorCode = 0; + switch(waitStatus) { + case WAIT_OBJECT_0: // thread completed + hRetVal = req->hResultHandle; + req->hResultHandle = INVALID_HANDLE_VALUE; + dwErrorCode = req->dwErrorCode; + break; + case WAIT_OBJECT_0 + 1: // aborted + dwErrorCode = ERROR_OPERATION_ABORTED; + myCancelSynchronousIo(hThread); + break; + default: // unexpected, use last-error code from WFMO + dwErrorCode = GetLastError(); + myCancelSynchronousIo(hThread); + break; + } + req->Release(); + CloseHandle(hThread); + SetLastError(dwErrorCode); + return hRetVal; +} + +namespace pfc { + BOOL winFormatSystemErrorMessageImpl(pfc::string_base & p_out, DWORD p_code); + BOOL winFormatSystemErrorMessageHook(pfc::string_base & p_out, DWORD p_code) { + return winFormatSystemErrorMessageImpl(p_out, p_code); + } + + void crashHook() { + uBugCheck(); + } +} diff --git a/sdk/foobar2000/shared/audio_math.cpp b/sdk/foobar2000/shared/audio_math.cpp new file mode 100644 index 0000000..a9ad99a --- /dev/null +++ b/sdk/foobar2000/shared/audio_math.cpp @@ -0,0 +1,137 @@ +#include "shared.h" + +//#define AUDIO_MATH_NOASM + +// NOTE: SSE4.1 int16 ops code determined MUCH SLOWER than SSE2 on Sandy Bridge era Xeon and therefore disabled for now +// #define SUPPORT_SSE41 + +#ifdef SUPPORT_SSE41 +static const bool g_have_sse41 = pfc::query_cpu_feature_set(pfc::CPU_HAVE_SSE41); + +inline static void convert_from_int16_noopt(const t_int16 * p_source,t_size p_count,audio_sample * p_output,float p_scale) +{ + t_size num = p_count; + for(;num;num--) + *(p_output++) = (audio_sample)*(p_source++) * p_scale; +} + +__declspec(naked) static void __fastcall convert_from_int16_sse41_8word(const t_int16 * p_source,t_size p_count,audio_sample * p_output,float p_scale) { + __asm { + // ecx = source, edx = count, [esp + 4] = output, [esp + 8] = scale + movss xmm7, [esp + 8] + test edx, edx + mov eax, [esp + 4] + pshufd xmm7, xmm7, 0 + jz loopend +loopbegin: + PMOVSXWD xmm0, mmword ptr [ecx] + PMOVSXWD xmm1, mmword ptr [ecx+8] + CVTDQ2PS xmm0, xmm0 + CVTDQ2PS xmm1, xmm1 + add ecx, 16 + mulps xmm0, xmm7 + mulps xmm1, xmm7 + dec edx + movups [eax], xmm0 + movups [eax + 16], xmm1 + lea eax, [eax + 32] + jnz loopbegin +loopend: + ret 8 + } +} + + +__declspec(naked) static void __fastcall convert_from_int16_sse41_8word_aligned(const t_int16 * p_source,t_size p_count,audio_sample * p_output,float p_scale) { + __asm { + // ecx = source, edx = count, [esp + 4] = output, [esp + 8] = scale + movss xmm7, [esp + 8] + test edx, edx + mov eax, [esp + 4] + pshufd xmm7, xmm7, 0 + jz loopend +loopbegin: + PMOVSXWD xmm0, mmword ptr [ecx] + PMOVSXWD xmm1, mmword ptr [ecx+8] + CVTDQ2PS xmm0, xmm0 + CVTDQ2PS xmm1, xmm1 + add ecx, 16 + mulps xmm0, xmm7 + mulps xmm1, xmm7 + dec edx + movaps [eax], xmm0 + movaps [eax + 16], xmm1 + lea eax, [eax + 32] + jnz loopbegin +loopend: + ret 8 + } +} +#endif + + + +#ifdef audio_math +#undef audio_math +#endif +namespace audio_math { + + void SHARED_EXPORT scale(const audio_sample * p_source,t_size p_count,audio_sample * p_output,audio_sample p_scale) + { + ::pfc::audio_math::scale(p_source, p_count, p_output, p_scale); + } + + void SHARED_EXPORT convert_to_int16(const audio_sample * p_source,t_size p_count,t_int16 * p_output,audio_sample p_scale) + { + ::pfc::audio_math::convert_to_int16(p_source, p_count, p_output, p_scale); + } + + audio_sample SHARED_EXPORT convert_to_int16_calculate_peak(const audio_sample * p_source,t_size p_count,t_int16 * p_output,audio_sample p_scale) + { + convert_to_int16(p_source,p_count,p_output,p_scale); + return p_scale * calculate_peak(p_source,p_count); + } + + void SHARED_EXPORT convert_from_int16(const t_int16 * p_source,t_size p_count,audio_sample * p_output,audio_sample p_scale) + { +#ifdef SUPPORT_SSE41 + if (g_have_sse41) { + audio_sample scale = (audio_sample)(p_scale / (double)0x8000); + convert_from_int16_sse41_8word(p_source, p_count >> 3, p_output, scale); + convert_from_int16_noopt(p_source + (p_count & ~7), p_count & 7, p_output + (p_count & ~7), scale); + return; + } +#endif + ::pfc::audio_math::convert_from_int16(p_source, p_count, p_output, p_scale); + } + + void SHARED_EXPORT convert_to_int32(const audio_sample * p_source,t_size p_count,t_int32 * p_output,audio_sample p_scale) + { + return ::pfc::audio_math::convert_to_int32(p_source, p_count, p_output, p_scale); + } + + audio_sample SHARED_EXPORT convert_to_int32_calculate_peak(const audio_sample * p_source,t_size p_count,t_int32 * p_output,audio_sample p_scale) + { + convert_to_int32(p_source,p_count,p_output,p_scale); + return p_scale * calculate_peak(p_source,p_count); + } + + void SHARED_EXPORT convert_from_int32(const t_int32 * p_source,t_size p_count,audio_sample * p_output,audio_sample p_scale) + { + ::pfc::audio_math::convert_from_int32(p_source, p_count, p_output, p_scale); + } + + + audio_sample SHARED_EXPORT calculate_peak(const audio_sample * p_source,t_size p_count) { + return ::pfc::audio_math::calculate_peak(p_source, p_count); + } + + void SHARED_EXPORT kill_denormal(audio_sample * p_buffer,t_size p_count) { + ::pfc::audio_math::remove_denormals(p_buffer, p_count); + } + + void SHARED_EXPORT add_offset(audio_sample * p_buffer,audio_sample p_delta,t_size p_count) { + ::pfc::audio_math::add_offset(p_buffer, p_delta, p_count); + } + +} diff --git a/sdk/foobar2000/shared/crash_info.cpp b/sdk/foobar2000/shared/crash_info.cpp new file mode 100644 index 0000000..e01f3ab --- /dev/null +++ b/sdk/foobar2000/shared/crash_info.cpp @@ -0,0 +1,651 @@ +#include "shared.h" +#include +#include + +#if SIZE_MAX == UINT32_MAX +#define STACKSPEC "%08X" +#define PTRSPEC "%08Xh" +#define OFFSETSPEC "%Xh" +#elif SIZE_MAX == UINT64_MAX +#define STACKSPEC "%016llX" +#define PTRSPEC "%016llXh" +#define OFFSETSPEC "%llXh" +#else +#error WTF? +#endif + + +static volatile bool g_didSuppress = false; +static critical_section g_panicHandlersSync; +static std::forward_list g_panicHandlers; + +static void callPanicHandlers() { + insync(g_panicHandlersSync); + for( auto i = g_panicHandlers.begin(); i != g_panicHandlers.end(); ++ i ) { + try { + (*i)->onPanic(); + } catch(...) {} + } +} + +void SHARED_EXPORT uAddPanicHandler(fb2k::panicHandler* p) { + insync(g_panicHandlersSync); + g_panicHandlers.push_front(p); +} + +void SHARED_EXPORT uRemovePanicHandler(fb2k::panicHandler* p) { + insync(g_panicHandlersSync); + g_panicHandlers.remove(p); +} + + +enum { EXCEPTION_BUG_CHECK = 0xaa67913c }; + +#if FB2K_SUPPORT_CRASH_LOGS + +static const unsigned char utf8_header[3] = {0xEF,0xBB,0xBF}; + +static __declspec(thread) char g_thread_call_stack[1024]; +static __declspec(thread) t_size g_thread_call_stack_length; + +static critical_section g_lastEventsSync; +static pfc::chain_list_v2_t g_lastEvents; +static constexpr t_size KLastEventCount = 200; + +static pfc::string8 version_string; + +static pfc::array_t DumpPathBuffer; + +static long crash_no = 0; + +// Debug timer: GetTickCount() diff since app startup. +// Intentionally kept as dumb as possible (originally meant to format system time nicely). +// Do not want to do expensive preformat of every event that in >99% of scenarios isn't logged. +// Cannot do formatting & system calls in crash handler. +// So we just write amount of MS since app startup. +static const uint64_t debugTimerInit = GetTickCount64(); +static pfc::format_int_t queryDebugTimer() { return pfc::format_int( GetTickCount64() - debugTimerInit ); } + +static pfc::string8 g_components; + +static void WriteFileString_internal(HANDLE hFile,const char * ptr,t_size len) +{ + DWORD bah; + WriteFile(hFile,ptr,(DWORD)len,&bah,0); +} + +static HANDLE create_failure_log() +{ + bool rv = false; + if (DumpPathBuffer.get_size() == 0) return INVALID_HANDLE_VALUE; + + TCHAR * path = DumpPathBuffer.get_ptr(); + + t_size lenWalk = _tcslen(path); + + if (lenWalk == 0 || path[lenWalk-1] != '\\') {path[lenWalk++] = '\\';} + + _tcscpy(path + lenWalk, _T("crash reports")); + lenWalk += _tcslen(path + lenWalk); + + SetLastError(NO_ERROR); + if (!CreateDirectory(path, NULL)) { + if (GetLastError() != ERROR_ALREADY_EXISTS) return INVALID_HANDLE_VALUE; + } + path[lenWalk++] = '\\'; + + TCHAR * fn_out = path + lenWalk; + HANDLE hFile = INVALID_HANDLE_VALUE; + unsigned attempts = 0; + for(;;) { + wsprintf(fn_out,TEXT("failure_%08u.txt"),++attempts); + hFile = CreateFile(path,GENERIC_WRITE,0,0,CREATE_NEW,0,0); + if (hFile!=INVALID_HANDLE_VALUE) break; + if (attempts > 1000) break; + } + if (hFile!=INVALID_HANDLE_VALUE) WriteFileString_internal(hFile, (const char*)utf8_header, sizeof(utf8_header)); + return hFile; +} + + +static void WriteFileString(HANDLE hFile,const char * str) +{ + const char * ptr = str; + for(;;) + { + const char * start = ptr; + ptr = strchr(ptr,'\n'); + if (ptr) + { + if (ptr>start) { + t_size len = ptr-start; + if (ptr[-1] == '\r') --len; + WriteFileString_internal(hFile,start,len); + } + WriteFileString_internal(hFile,"\r\n",2); + ptr++; + } + else + { + WriteFileString_internal(hFile,start,strlen(start)); + break; + } + } +} + +static void WriteEvent(HANDLE hFile,const char * str) { + bool haveText = false; + const char * ptr = str; + bool isLineBreak = false; + while(*ptr) { + const char * base = ptr; + while(*ptr && *ptr != '\r' && *ptr != '\n') ++ptr; + if (ptr > base) { + if (isLineBreak) WriteFileString_internal(hFile,"\r\n",2); + WriteFileString_internal(hFile,base,ptr-base); + isLineBreak = false; haveText = true; + } + for(;;) { + if (*ptr == '\n') isLineBreak = haveText; + else if (*ptr != '\r') break; + ++ptr; + } + } + if (haveText) WriteFileString_internal(hFile,"\r\n",2); +} + +static bool read_int(t_size src, t_size* out) +{ + __try + { + *out = *(t_size*)src; + return true; + } __except (1) { return false; } +} + +static bool hexdump8(char * out,size_t address,const char * msg,int from,int to) +{ + unsigned max = (to-from)*16; + if (IsBadReadPtr((const void*)(address+(from*16)),max)) return false; + out += sprintf(out,"\n%s (" PTRSPEC "):",msg,address); + unsigned n; + const unsigned char * src = (const unsigned char*)(address)+(from*16); + + for(n=0;n(rptr); + t_size walk = 0; + for (; walk < 255; ++walk) { + char c = ptr[walk]; + if (c == 0) break; + if (c < 0x20) c = ' '; + temp[walk] = c; + } + temp[walk] = 0; + return true; + } __except (1) { return false; } +} + +static void DumpCPPExceptionData(HANDLE hFile, const ULONG_PTR* params, char* temp) { + t_size strPtr; + if (read_int(params[1] + sizeof(void*), &strPtr)) { + if (SalvageString(strPtr, temp)) { + WriteFileString(hFile, "Message: "); + WriteFileString(hFile, temp); + WriteFileString(hFile, "\n"); + } + } +} + +static void writeFailureTxt(LPEXCEPTION_POINTERS param, HANDLE hFile, DWORD lastError) { + char temp[2048]; + { + t_size address = (t_size)param->ExceptionRecord->ExceptionAddress; + sprintf(temp, "Illegal operation:\nCode: %08Xh, flags: %08Xh, address: " PTRSPEC "\n", param->ExceptionRecord->ExceptionCode, param->ExceptionRecord->ExceptionFlags, address); + WriteFileString(hFile, temp); + + if (param->ExceptionRecord->ExceptionCode == EXCEPTION_BUG_CHECK) { + WriteFileString(hFile, "Bug check\n"); + } else if (param->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION && param->ExceptionRecord->NumberParameters >= 2) { + sprintf(temp, "Access violation, operation: %s, address: " PTRSPEC "\n", param->ExceptionRecord->ExceptionInformation[0] ? "write" : "read", param->ExceptionRecord->ExceptionInformation[1]); + WriteFileString(hFile, temp); + } else if (param->ExceptionRecord->NumberParameters > 0) { + WriteFileString(hFile, "Additional parameters:"); + for (DWORD walk = 0; walk < param->ExceptionRecord->NumberParameters; ++walk) { + sprintf(temp, " " PTRSPEC, param->ExceptionRecord->ExceptionInformation[walk]); + WriteFileString(hFile, temp); + } + WriteFileString(hFile, "\n"); + } + + if (param->ExceptionRecord->ExceptionCode == 0xE06D7363 && param->ExceptionRecord->NumberParameters >= 3) { //C++ exception + DumpCPPExceptionData(hFile, param->ExceptionRecord->ExceptionInformation, temp); + } + + if (lastError) { + sprintf(temp, "Last win32 error: %u\n", lastError); + WriteFileString(hFile, temp); + } + + if (g_thread_call_stack[0] != 0) { + WriteFileString(hFile, "\nCall path:\n"); + WriteFileString(hFile, g_thread_call_stack); + WriteFileString(hFile, "\n"); + } else { + WriteFileString(hFile, "\nCall path not available.\n"); + } + + + if (hexdump8(temp, address, "Code bytes", -4, +4)) WriteFileString(hFile, temp); +#ifdef _M_IX86 + if (hexdump_stack(temp, param->ContextRecord->Esp, "Stack", -2, +18)) WriteFileString(hFile, temp); + sprintf(temp, "\nRegisters:\nEAX: %08X, EBX: %08X, ECX: %08X, EDX: %08X\nESI: %08X, EDI: %08X, EBP: %08X, ESP: %08X\n", param->ContextRecord->Eax, param->ContextRecord->Ebx, param->ContextRecord->Ecx, param->ContextRecord->Edx, param->ContextRecord->Esi, param->ContextRecord->Edi, param->ContextRecord->Ebp, param->ContextRecord->Esp); + WriteFileString(hFile, temp); +#endif + +#ifdef _M_X64 + if (hexdump_stack(temp, param->ContextRecord->Rsp, "Stack", -2, +18)) WriteFileString(hFile, temp); + sprintf(temp, "\nRegisters:\nRAX: %016llX, RBX: %016llX, RCX: %016llX, RDX: %016llX\nRSI: %016llX, RDI: %016llX, RBP: %016llX, RSP: %016llX\n", param->ContextRecord->Rax, param->ContextRecord->Rbx, param->ContextRecord->Rcx, param->ContextRecord->Rdx, param->ContextRecord->Rsi, param->ContextRecord->Rdi, param->ContextRecord->Rbp, param->ContextRecord->Rsp); + WriteFileString(hFile, temp); +#endif + +#ifdef _M_ARM64 + if (hexdump_stack(temp, param->ContextRecord->Sp, "Stack", -2, +18)) WriteFileString(hFile, temp); +#endif + + WriteFileString(hFile, "\nTimestamp:\n"); + WriteFileString(hFile, queryDebugTimer() ); + WriteFileString(hFile, "ms\n"); + + { + const HANDLE hProcess = GetCurrentProcess(); + if (SymInitialize(hProcess, NULL, TRUE)) + { + { + IMAGEHLP_MODULE mod = {}; + mod.SizeOfStruct = sizeof(mod); + if (!IsBadCodePtr((FARPROC)address) && SymGetModuleInfo(hProcess, address, &mod)) + { + sprintf(temp, "\nCrash location:\nModule: %s\nOffset: " OFFSETSPEC "\n", mod.ModuleName, address - mod.BaseOfImage); + WriteFileString(hFile, temp); + } else + { + sprintf(temp, "\nUnable to identify crash location!\n"); + WriteFileString(hFile, temp); + } + } + + { + union + { + char buffer[128]; + IMAGEHLP_SYMBOL symbol; + }; + memset(buffer, 0, sizeof(buffer)); + symbol.SizeOfStruct = sizeof(symbol); + symbol.MaxNameLength = (DWORD)(buffer + sizeof(buffer) - symbol.Name); + DWORD_PTR offset = 0; + if (SymGetSymFromAddr(hProcess, address, &offset, &symbol)) + { + buffer[PFC_TABSIZE(buffer) - 1] = 0; + if (symbol.Name[0]) + { + sprintf(temp, "Symbol: \"%s\" (+" OFFSETSPEC ")\n", symbol.Name, offset); + WriteFileString(hFile, temp); + } + } + } + + WriteFileString(hFile, "\nLoaded modules:\n"); + SymEnumerateModules(hProcess, EnumModulesCallback, hFile); + +#ifdef _M_IX86 + call_stack_parse(param->ContextRecord->Esp, hFile, temp, hProcess); +#endif + +#ifdef _M_X64 + call_stack_parse(param->ContextRecord->Rsp, hFile, temp, hProcess); +#endif + + SymCleanup(hProcess); + } else { + WriteFileString(hFile, "\nFailed to get module/symbol info.\n"); + } + } + + WriteFileString(hFile, "\nEnvironment:\n"); + WriteFileString(hFile, version_string); + + WriteFileString(hFile, "\n"); + + if (!g_components.is_empty()) { + WriteFileString(hFile, "\nComponents:\n"); + WriteFileString(hFile, g_components); + } + + { + insync(g_lastEventsSync); + if (g_lastEvents.get_count() > 0) { + WriteFileString(hFile, "\nRecent events:\n"); + for( auto & walk : g_lastEvents) WriteEvent(hFile, walk); + } + } + } +} + +static bool GrabOSVersion(char * out) { + OSVERSIONINFO ver = {}; ver.dwOSVersionInfoSize = sizeof(ver); + if (!GetVersionEx(&ver)) return false; + *out = 0; + char temp[16]; + strcat(out,"Windows "); + _itoa(ver.dwMajorVersion,temp,10); strcat(out,temp); + strcat(out,"."); + _itoa(ver.dwMinorVersion,temp,10); strcat(out,temp); + return true; +} + +static void OnLogFileWritten() { + TCHAR exePath[MAX_PATH + 1] = {}; + TCHAR params[1024]; + GetModuleFileName(NULL, exePath, MAX_PATH); + exePath[MAX_PATH] = 0; + //unsafe... + wsprintf(params, _T("/crashed \"%s\""), DumpPathBuffer.get_ptr()); + ShellExecute(NULL, NULL, exePath, params, NULL, SW_SHOW); +} + +BOOL WriteMiniDumpHelper(HANDLE, LPEXCEPTION_POINTERS); //minidump.cpp + + +void SHARED_EXPORT uDumpCrashInfo(LPEXCEPTION_POINTERS param) +{ + if (g_didSuppress) return; + const DWORD lastError = GetLastError(); + if (InterlockedIncrement(&crash_no) > 1) {Sleep(10000);return;} + HANDLE hFile = create_failure_log(); + if (hFile == INVALID_HANDLE_VALUE) return; + + { + _tcscpy(_tcsrchr(DumpPathBuffer.get_ptr(), '.'), _T(".dmp")); + HANDLE hDump = CreateFile(DumpPathBuffer.get_ptr(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); + if (hDump != INVALID_HANDLE_VALUE) { + const BOOL written = WriteMiniDumpHelper(hDump, param); + CloseHandle(hDump); + if (!written) { //don't bother proceeding if we don't have a valid minidump + DeleteFile(DumpPathBuffer.get_ptr()); + CloseHandle(hFile); + _tcscpy(_tcsrchr(DumpPathBuffer.get_ptr(), '.'), _T(".txt")); + DeleteFile(DumpPathBuffer.get_ptr()); + return; + } + } + _tcscpy(_tcsrchr(DumpPathBuffer.get_ptr(), '.'), _T(".txt")); + } + + writeFailureTxt(param, hFile, lastError); + + CloseHandle(hFile); + + OnLogFileWritten(); +} + +//No longer used. +size_t SHARED_EXPORT uPrintCrashInfo(LPEXCEPTION_POINTERS param,const char * extra_info,char * outbase) { + *outbase = 0; + return 0; +} + + +LONG SHARED_EXPORT uExceptFilterProc(LPEXCEPTION_POINTERS param) { + if (g_didSuppress) return UnhandledExceptionFilter(param); + callPanicHandlers(); + if (IsDebuggerPresent()) { + return UnhandledExceptionFilter(param); + } else { + if ( param->ExceptionRecord->ExceptionCode == STATUS_STACK_OVERFLOW ) { + pfc::thread2 trd; + trd.startHere( [param] { + uDumpCrashInfo(param); + } ); + trd.waitTillDone(); + } else { + uDumpCrashInfo(param); + } + TerminateProcess(GetCurrentProcess(), 0); + return 0;// never reached + } +} + +void SHARED_EXPORT uPrintCrashInfo_Init(const char * name)//called only by exe on startup +{ + version_string = pfc::format( "App: ", name, "\nArch: ", pfc::cpuArch()); + + SetUnhandledExceptionFilter(uExceptFilterProc); +} +void SHARED_EXPORT uPrintCrashInfo_Suppress() { + g_didSuppress = true; +} + +void SHARED_EXPORT uPrintCrashInfo_AddEnvironmentInfo(const char * p_info) { + version_string << "\n" << p_info; +} + +void SHARED_EXPORT uPrintCrashInfo_SetComponentList(const char * p_info) { + g_components = p_info; +} + +void SHARED_EXPORT uPrintCrashInfo_SetDumpPath(const char * p_path) { + pfc::stringcvt::string_os_from_utf8 temp(p_path); + DumpPathBuffer.set_size(temp.length() + 256); + _tcscpy(DumpPathBuffer.get_ptr(), temp.get_ptr()); +} + +static HANDLE hLogFile = INVALID_HANDLE_VALUE; + +static void logEvent(const char* message) { + if ( hLogFile != INVALID_HANDLE_VALUE ) { + DWORD wrote = 0; + WriteFile(hLogFile, message, (DWORD) strlen(message), &wrote, NULL ); + WriteFile(hLogFile, "\r\n", 2, &wrote, NULL); + } +} + +void SHARED_EXPORT uPrintCrashInfo_StartLogging(const char * path) { + insync(g_lastEventsSync); + PFC_ASSERT(hLogFile == INVALID_HANDLE_VALUE); + hLogFile = CreateFile( pfc::stringcvt::string_wide_from_utf8(path), GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL); + PFC_ASSERT(hLogFile != INVALID_HANDLE_VALUE); + + for( auto & walk : g_lastEvents ) { + logEvent( walk.c_str() ); + } +} + +void SHARED_EXPORT uPrintCrashInfo_OnEvent(const char * message, t_size length) { + + pfc::string8 msg = pfc::format("[", queryDebugTimer(), "ms] "); + msg.add_string( message, length ); + + insync(g_lastEventsSync); + logEvent(msg); + while(g_lastEvents.get_count() >= KLastEventCount) g_lastEvents.remove(g_lastEvents.first()); + g_lastEvents.insert_last( std::move(msg) ); +} + +static void callstack_add(const char * param) +{ + enum { MAX = PFC_TABSIZE(g_thread_call_stack) - 1} ; + t_size len = strlen(param); + if (g_thread_call_stack_length + len > MAX) len = MAX - g_thread_call_stack_length; + if (len>0) + { + memcpy(g_thread_call_stack+g_thread_call_stack_length,param,len); + g_thread_call_stack_length += len; + g_thread_call_stack[g_thread_call_stack_length]=0; + } +} + +uCallStackTracker::uCallStackTracker(const char * name) +{ + param = g_thread_call_stack_length; + if (g_thread_call_stack_length>0) callstack_add("=>"); + callstack_add(name); +} + +uCallStackTracker::~uCallStackTracker() +{ + g_thread_call_stack_length = param; + g_thread_call_stack[param]=0; + +} + +extern "C" {LPCSTR SHARED_EXPORT uGetCallStackPath() {return g_thread_call_stack;} } + +#ifdef _DEBUG +extern "C" { + void SHARED_EXPORT fb2kDebugSelfTest() { + auto ptr = SetUnhandledExceptionFilter(NULL); + PFC_ASSERT( ptr == uExceptFilterProc ); + SetUnhandledExceptionFilter(ptr); + } +} +#endif + +#else + +void SHARED_EXPORT uDumpCrashInfo(LPEXCEPTION_POINTERS param) {} +void SHARED_EXPORT uPrintCrashInfo_OnEvent(const char * message, t_size length) {} +LONG SHARED_EXPORT uExceptFilterProc(LPEXCEPTION_POINTERS param) { + return UnhandledExceptionFilter(param); +} +uCallStackTracker::uCallStackTracker(const char * name) {} +uCallStackTracker::~uCallStackTracker() {} +extern "C" { + LPCSTR SHARED_EXPORT uGetCallStackPath() { return ""; } + void SHARED_EXPORT fb2kDebugSelfTest() {} +} +#endif + +PFC_NORETURN void SHARED_EXPORT uBugCheck() { + fb2k_instacrash_scope(RaiseException(EXCEPTION_BUG_CHECK, EXCEPTION_NONCONTINUABLE, 0, NULL); ); +} diff --git a/sdk/foobar2000/shared/filedialogs.cpp b/sdk/foobar2000/shared/filedialogs.cpp new file mode 100644 index 0000000..9629ac8 --- /dev/null +++ b/sdk/foobar2000/shared/filedialogs.cpp @@ -0,0 +1,317 @@ +#include "shared.h" +#include "filedialogs.h" +#include + +#define dTEXT(X) pfc::stringcvt::string_os_from_utf8(X) + +static UINT_PTR CALLBACK uGetOpenFileName_Hook(HWND wnd,UINT msg,WPARAM wp,LPARAM lp) +{ + switch(msg) { + case WM_INITDIALOG: + { + OPENFILENAME * ofn = reinterpret_cast(lp); + reinterpret_cast(ofn->lCustData)->initialize(FindOwningPopup(wnd)); + } + return 0; + default: + return 0; + } +} + +static void ImportExtMask(pfc::array_t & out, const char * in) { + { + pfc::stringcvt::string_os_from_utf8 temp(in); + out.set_size(temp.length()+2); + out.fill_null(); + pfc::memcpy_t(out.get_ptr(),temp.get_ptr(),temp.length()); + } + + for(t_size walk = 0; walk < out.get_size(); ++walk) { + if (out[walk] == '|') out[walk] = 0; + } +} + +BOOL Vista_GetOpenFileName(HWND parent,const char * p_ext_mask,unsigned def_ext_mask,const char * p_def_ext,const char * p_title,const char * p_directory,pfc::string_base & p_filename,BOOL b_save); +BOOL Vista_GetOpenFileNameMulti(HWND parent,const char * p_ext_mask,unsigned def_ext_mask,const char * p_def_ext,const char * p_title,const char * p_directory,pfc::ptrholder_t & out); +BOOL Vista_BrowseForFolder(HWND parent, const char * p_title, pfc::string_base & path); +puGetOpenFileNameMultiResult Vista_BrowseForFolderEx(HWND parent,const char * title, const char * initPath); + +static bool UseVistaDialogs() { +#if FB2K_TARGET_MICROSOFT_STORE || _WIN32_WINNT >= 0x600 + return true; +#else + return GetWindowsVersionCode() >= 0x600; +#endif +} + +BOOL SHARED_EXPORT uGetOpenFileName(HWND parent,const char * p_ext_mask,unsigned def_ext_mask,const char * p_def_ext,const char * p_title,const char * p_directory,pfc::string_base & p_filename,BOOL b_save) { + TRACK_CALL_TEXT("uGetOpenFileName"); + try { + if (UseVistaDialogs()) return Vista_GetOpenFileName(parent, p_ext_mask, def_ext_mask, p_def_ext, p_title, p_directory, p_filename, b_save); + } catch(pfc::exception_not_implemented) {} + + modal_dialog_scope scope; + + pfc::array_t ext_mask; + ImportExtMask(ext_mask,p_ext_mask); + + TCHAR buffer[4096]; + + pfc::stringToBuffer(buffer,pfc::stringcvt::string_os_from_utf8(p_filename)); + + pfc::stringcvt::string_os_from_utf8 def_ext(p_def_ext ? p_def_ext : ""),title(p_title ? p_title : ""), + directory(p_directory ? p_directory : ""); + + OPENFILENAME ofn = {}; + + ofn.lStructSize=sizeof(ofn); + ofn.hwndOwner = parent; + ofn.lpstrFilter = ext_mask.get_ptr(); + ofn.nFilterIndex = def_ext_mask + 1; + ofn.lpstrFile = buffer; + ofn.lpstrInitialDir = directory; + ofn.nMaxFile = _countof(buffer); + ofn.Flags = b_save ? OFN_NOCHANGEDIR|OFN_EXPLORER|OFN_HIDEREADONLY|OFN_PATHMUSTEXIST|OFN_OVERWRITEPROMPT|OFN_ENABLEHOOK|OFN_ENABLESIZING : OFN_NOCHANGEDIR|OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_PATHMUSTEXIST|OFN_ENABLEHOOK|OFN_ENABLESIZING; + ofn.lpstrDefExt = *(const TCHAR*)def_ext ? (const TCHAR*)def_ext : 0; + ofn.lpstrTitle = *(const TCHAR*)title ? (const TCHAR*)title : 0; + ofn.lCustData = reinterpret_cast(&scope); + ofn.lpfnHook = uGetOpenFileName_Hook; + if (b_save ? GetSaveFileName(&ofn) : GetOpenFileName(&ofn)) + { + buffer[_countof(buffer)-1]=0; + + { + t_size ptr = _tcslen(buffer); + while(ptr>0 && buffer[ptr-1]==' ') buffer[--ptr] = 0; + } + + p_filename = pfc::stringcvt::string_utf8_from_os(buffer,_countof(buffer)); + return TRUE; + } + else return FALSE; +} + + +puGetOpenFileNameMultiResult SHARED_EXPORT uGetOpenFileNameMulti(HWND parent,const char * p_ext_mask,unsigned def_ext_mask,const char * p_def_ext,const char * p_title,const char * p_directory) { + TRACK_CALL_TEXT("uGetOpenFileNameMulti"); + try { + if (UseVistaDialogs()) { + pfc::ptrholder_t result; + if (!Vista_GetOpenFileNameMulti(parent,p_ext_mask,def_ext_mask,p_def_ext,p_title,p_directory,result)) return NULL; + return result.detach(); + } + } catch(pfc::exception_not_implemented) {} + + modal_dialog_scope scope; + + pfc::array_t ext_mask; + ImportExtMask(ext_mask,p_ext_mask); + + TCHAR buffer[0x4000]; + buffer[0]=0; + + pfc::stringcvt::string_os_from_utf8 def_ext(p_def_ext ? p_def_ext : ""),title(p_title ? p_title : ""), + directory(p_directory ? p_directory : ""); + + OPENFILENAME ofn = {}; + + ofn.lStructSize=sizeof(ofn); + ofn.hwndOwner = parent; + ofn.lpstrFilter = ext_mask.get_ptr(); + ofn.nFilterIndex = def_ext_mask + 1; + ofn.lpstrFile = buffer; + ofn.lpstrInitialDir = directory; + ofn.nMaxFile = _countof(buffer); + ofn.Flags = OFN_NOCHANGEDIR|OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_PATHMUSTEXIST|OFN_ALLOWMULTISELECT|OFN_ENABLEHOOK|OFN_ENABLESIZING; + ofn.lpstrDefExt = *(const TCHAR*)def_ext ? (const TCHAR*)def_ext : 0; + ofn.lpstrTitle = *(const TCHAR*)title ? (const TCHAR*)title : 0; + ofn.lCustData = reinterpret_cast(&scope); + ofn.lpfnHook = uGetOpenFileName_Hook; + if (GetOpenFileName(&ofn)) + { + buffer[_countof(buffer)-1]=0; + buffer[_countof(buffer)-2]=0; + + pfc::ptrholder_t result = new uGetOpenFileNameMultiResult_impl; + + TCHAR * p=buffer; + while(*p) p++; + p++; + if (!*p) + { + { + t_size ptr = _tcslen(buffer); + while(ptr>0 && buffer[ptr-1]==' ') buffer[--ptr] = 0; + } + + result->AddItem(pfc::stringcvt::string_utf8_from_os(buffer)); + } + else + { + pfc::string_formatter s = (const char*) pfc::stringcvt::string_utf8_from_os(buffer,_countof(buffer)); + t_size ofs = s.length(); + if (ofs>0 && s[ofs-1]!='\\') {s.add_char('\\');ofs++;} + while(*p) + { + s.truncate(ofs); + s += pfc::stringcvt::string_utf8_from_os(p); + s.skip_trailing_char(' '); + result->AddItem(s); + while(*p) p++; + p++; + } + } + return result.detach(); + } + else return 0; +} + + + + + +struct browse_for_dir_struct +{ + const TCHAR * m_initval; + const TCHAR * m_tofind; + + modal_dialog_scope m_scope; +}; + +static bool file_exists(const TCHAR * p_path) +{ + DWORD val = GetFileAttributes(p_path); + if (val == (-1) || (val & FILE_ATTRIBUTE_DIRECTORY)) return false; + return true; +} + +static void browse_proc_check_okbutton(HWND wnd,const browse_for_dir_struct * p_struct,const TCHAR * p_path) +{ + TCHAR temp[MAX_PATH+1]; + pfc::stringToBuffer(temp, p_path); + + t_size len = _tcslen(temp); + if (len < MAX_PATH && len > 0) + { + if (temp[len-1] != '\\') + temp[len++] = '\\'; + } + t_size idx = 0; + while(p_struct->m_tofind[idx] && idx+len < MAX_PATH) + { + temp[len+idx] = p_struct->m_tofind[idx]; + idx++; + } + temp[len+idx] = 0; + + SendMessage(wnd,BFFM_ENABLEOK,0,!!file_exists(temp)); + +} + +static int _stdcall browse_proc(HWND wnd,UINT msg,LPARAM lp,LPARAM dat) +{ + browse_for_dir_struct * p_struct = reinterpret_cast(dat); + switch(msg) + { + case BFFM_INITIALIZED: + p_struct->m_scope.initialize(wnd); + SendMessage(wnd,BFFM_SETSELECTION,1,(LPARAM)p_struct->m_initval); + if (p_struct->m_tofind) browse_proc_check_okbutton(wnd,p_struct,p_struct->m_initval); + break; + case BFFM_SELCHANGED: + if (p_struct->m_tofind) + { + if (lp != 0) + { + TCHAR temp[MAX_PATH+1]; + if (SHGetPathFromIDList(reinterpret_cast(lp),temp)) + { + temp[MAX_PATH] = 0; + browse_proc_check_okbutton(wnd,p_struct,temp); + } + else + SendMessage(wnd,BFFM_ENABLEOK,0,FALSE); + } + else SendMessage(wnd,BFFM_ENABLEOK,0,FALSE); + } + break; + } + return 0; +} + +static BOOL BrowseForFolderHelper(HWND p_parent,const TCHAR * p_title,TCHAR (&p_out)[MAX_PATH],const TCHAR * p_file_to_find) +{ + pfc::com_ptr_t mallocptr; + + if (FAILED(SHGetMalloc(mallocptr.receive_ptr()))) return FALSE; + if (mallocptr.is_empty()) return FALSE; + + browse_for_dir_struct data; + data.m_initval = p_out; + data.m_tofind = p_file_to_find; + + + BROWSEINFO bi= + { + p_parent, + 0, + 0, + p_title, + BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE | BIF_EDITBOX, + browse_proc, + reinterpret_cast(&data), + 0 + }; + + LPITEMIDLIST li = SHBrowseForFolder(&bi); + if (li == NULL) return FALSE; + BOOL state = SHGetPathFromIDList(li,p_out); + mallocptr->Free(li); + return state; +} + +BOOL SHARED_EXPORT uBrowseForFolder(HWND parent,const char * p_title,pfc::string_base & out) { + TRACK_CALL_TEXT("uBrowseForFolder"); + try { + if (UseVistaDialogs()) { + return Vista_BrowseForFolder(parent,p_title,out); + } + } catch(pfc::exception_not_implemented) {} + + TCHAR temp[MAX_PATH]; + pfc::stringToBuffer(temp,dTEXT(out)); + BOOL rv = BrowseForFolderHelper(parent,dTEXT(p_title),temp,0); + if (rv) { + out = pfc::stringcvt::string_utf8_from_os(temp,_countof(temp)); + } + return rv; +} + +BOOL SHARED_EXPORT uBrowseForFolderWithFile(HWND parent,const char * title,pfc::string_base & out,const char * p_file_to_find) +{ + TRACK_CALL_TEXT("uBrowseForFolderWithFile"); + TCHAR temp[MAX_PATH]; + pfc::stringToBuffer(temp,dTEXT(out)); + BOOL rv = BrowseForFolderHelper(parent,dTEXT(title),temp,dTEXT(p_file_to_find)); + if (rv) { + out = pfc::stringcvt::string_utf8_from_os(temp,_countof(temp)); + } + return rv; +} + + +puGetOpenFileNameMultiResult SHARED_EXPORT uBrowseForFolderEx(HWND parent,const char * title, const char * initPath) { + TRACK_CALL_TEXT("uBrowseForFolderEx"); + try { + if (UseVistaDialogs()) { + return Vista_BrowseForFolderEx(parent,title, initPath); + } + } catch(pfc::exception_not_implemented) {} + + pfc::string8 temp; + if (initPath) temp = initPath; + if (!uBrowseForFolder(parent, title, temp)) return NULL; + pfc::ptrholder_t result = new uGetOpenFileNameMultiResult_impl; + result->AddItem(temp); + return result.detach(); +} diff --git a/sdk/foobar2000/shared/filedialogs_vista.cpp b/sdk/foobar2000/shared/filedialogs_vista.cpp new file mode 100644 index 0000000..a1b7976 --- /dev/null +++ b/sdk/foobar2000/shared/filedialogs_vista.cpp @@ -0,0 +1,497 @@ +#include "shared.h" +#include "filedialogs.h" +#include +#include +#include +#include +#include + +#define dTEXT(X) pfc::stringcvt::string_os_from_utf8(X) + +class FilterSpec { +public: + void clear() { + m_types.set_size(0); m_strings.remove_all(); + } + void Sanity() { + if ( GetCount() > 200 ) SetAllFiles(); + } + void SetAllFiles() { + FromString( "All files|*.*" ); + } + void FromString(const char * in) { + clear(); + if (in == NULL) return; + pfc::chain_list_v2_t types; + + for(t_size inWalk = 0; ; ) { + + t_size base1 = inWalk; + t_size delta1 = ScanForSeparator(in+base1); + t_size base2 = base1 + delta1; + if (in[base2] == 0) break; + ++base2; + t_size delta2 = ScanForSeparator(in+base2); + if (delta1 > 0 && delta2 > 0) { + COMDLG_FILTERSPEC spec; + spec.pszName = MakeString(in+base1,delta1); + spec.pszSpec = MakeString(in+base2,delta2); + types.add_item(spec); + } + inWalk = base2 + delta2; + if (in[inWalk] == 0) break; + ++inWalk; + } + + pfc::list_to_array(m_types,types); + } + + t_size GetCount() const {return m_types.get_count();} + const COMDLG_FILTERSPEC * GetPtr() const {return m_types.get_ptr();} +private: + static t_size ScanForSeparator(const char * in) { + for(t_size walk = 0; ; ++walk) { + if (in[walk] == 0 || in[walk] == '|') return walk; + } + } + WCHAR * MakeString(const char * in, t_size inLen) { + t_size len = pfc::stringcvt::estimate_utf8_to_wide(in,inLen); + WCHAR* str = AllocString(len); + pfc::stringcvt::convert_utf8_to_wide(str,len,in,inLen); + return str; + } + WCHAR * AllocString(t_size size) { + auto iter = m_strings.insert_last(); + iter->set_size(size); + return iter->get_ptr(); + } + pfc::chain_list_v2_t > m_strings; + pfc::array_t m_types; +}; + +static HRESULT AddOptionsHelper(pfc::com_ptr_t dlg, DWORD opts) { + DWORD options; + HRESULT state; + if (FAILED(state = dlg->GetOptions(&options))) return state; + options |= opts; + if (FAILED(state = dlg->SetOptions( options ))) return state; + return S_OK; +} + +namespace { + + // SPECIAL + // Deal with slow or nonworking net shares, do not lockup the calling thread in such cases, just split away + // Particularly relevant to net shares referred by raw IP, these get us stuck for a long time + class PDNArg_t : public pfc::refcounted_object_root { + public: + CoTaskMemObject m_idList; + pfc::string8 m_path; + HRESULT m_result; + }; + + static unsigned CALLBACK PDNProc(void * arg) { + pfc::refcounted_object_ptr_t ptr; ptr.attach( reinterpret_cast( arg ) ); + CoInitialize(0); + + SFGAOF dummy; + ptr->m_result = SHParseDisplayName(dTEXT(ptr->m_path),NULL,&ptr->m_idList.m_ptr,0,&dummy); + + CoUninitialize(); + + return 0; + } +} + +static HRESULT SetFolderHelper(pfc::com_ptr_t dlg, const char * folderPath) { + CoTaskMemObject idList; + + // Do SHParseDisplayName() off-thread as it is known to lock up on bad net share references + pfc::refcounted_object_ptr_t ptr = new PDNArg_t(); + ptr->m_path = folderPath; + ptr->m_result = E_FAIL; + HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, PDNProc, reinterpret_cast(ptr._duplicate_ptr()), 0, NULL); + DWORD status = WaitForSingleObject( hThread, 3000 ); + CloseHandle(hThread); + if (status != WAIT_OBJECT_0) return E_FAIL; + if (FAILED(ptr->m_result)) return ptr->m_result; + + pfc::com_ptr_t item; + HRESULT state; + if (FAILED(state = SHCreateShellItem(NULL,NULL,ptr->m_idList.m_ptr,item.receive_ptr()))) return state; + return dlg->SetFolder(item.get_ptr()); +} + +namespace { + class _EH { + public: + void operator<<(HRESULT hr) { + if (FAILED(hr)) throw exception_com(hr); + } + }; + static _EH EH; +}; + +BOOL Vista_GetOpenFileName(HWND parent,const char * p_ext_mask,unsigned def_ext_mask,const char * p_def_ext,const char * p_title,const char * p_directory,pfc::string_base & p_filename,BOOL b_save) { + modal_dialog_scope modalScope(parent); + + pfc::com_ptr_t dlg; + + if (b_save) { + if (FAILED(CoCreateInstance(__uuidof(FileSaveDialog), NULL, CLSCTX_ALL, IID_IFileSaveDialog, (void**) dlg.receive_ptr()))) throw pfc::exception_not_implemented(); + } else { + if (FAILED(CoCreateInstance(__uuidof(FileOpenDialog), NULL, CLSCTX_ALL, IID_IFileOpenDialog, (void**) dlg.receive_ptr()))) throw pfc::exception_not_implemented(); + } + + { + FilterSpec spec; spec.FromString(p_ext_mask); + spec.Sanity(); + if (FAILED(dlg->SetFileTypes((UINT)spec.GetCount(),spec.GetPtr()))) return FALSE; + if (def_ext_mask < spec.GetCount()) { + if (FAILED(dlg->SetFileTypeIndex(def_ext_mask + 1))) return FALSE; + } + } + if (p_def_ext != NULL) { + if (FAILED(dlg->SetDefaultExtension(dTEXT(p_def_ext)))) return FALSE; + } + if (p_title != NULL) { + if (FAILED(dlg->SetTitle(dTEXT(p_title)))) return FALSE; + } + + if (!p_filename.is_empty()) { + pfc::string path(p_filename); + pfc::string fn = pfc::io::path::getFileName(path); + pfc::string parent = pfc::io::path::getParent(path); + if (!parent.isEmpty()) SetFolderHelper(dlg,parent.ptr()); + dlg->SetFileName(dTEXT(fn.ptr())); + } else if (p_directory != NULL) { + SetFolderHelper(dlg,p_directory); + } + + if (FAILED(AddOptionsHelper(dlg, FOS_FORCEFILESYSTEM))) return FALSE; + + if (FAILED( dlg->Show(parent) ) ) return FALSE; + + { + pfc::com_ptr_t result; + if (FAILED(dlg->GetResult(result.receive_ptr()))) return FALSE; + + CoTaskMemObject nameBuf; + if (FAILED(result->GetDisplayName(SIGDN_FILESYSPATH,&nameBuf.m_ptr))) return FALSE; + + p_filename = pfc::stringcvt::string_utf8_from_os_ex( nameBuf.m_ptr ); + } + return TRUE; +} + +BOOL Vista_GetOpenFileNameMulti(HWND parent,const char * p_ext_mask,unsigned def_ext_mask,const char * p_def_ext,const char * p_title,const char * p_directory,pfc::ptrholder_t & out) { + modal_dialog_scope modalScope(parent); + + pfc::com_ptr_t dlg; + if (FAILED(CoCreateInstance(__uuidof(FileOpenDialog), NULL, CLSCTX_ALL, IID_IFileOpenDialog, (void**) dlg.receive_ptr()))) throw pfc::exception_not_implemented(); + + { + FilterSpec spec; spec.FromString(p_ext_mask); + spec.Sanity(); + if (FAILED(dlg->SetFileTypes((UINT)spec.GetCount(),spec.GetPtr()))) return FALSE; + if (def_ext_mask < spec.GetCount()) { + if (FAILED(dlg->SetFileTypeIndex(def_ext_mask + 1))) return FALSE; + } + } + if (p_def_ext != NULL) { + if (FAILED(dlg->SetDefaultExtension(dTEXT(p_def_ext)))) return FALSE; + } + if (p_title != NULL) { + if (FAILED(dlg->SetTitle(dTEXT(p_title)))) return FALSE; + } + + if (p_directory != NULL) { + SetFolderHelper(dlg,p_directory); + } + + if (FAILED(AddOptionsHelper(dlg, FOS_ALLOWMULTISELECT | FOS_FORCEFILESYSTEM))) return FALSE; + + if (FAILED( dlg->Show(parent) ) ) return FALSE; + + { + pfc::ptrholder_t result = new uGetOpenFileNameMultiResult_impl; + pfc::com_ptr_t results; + if (FAILED(dlg->GetResults(results.receive_ptr()))) return FALSE; + DWORD total; + if (FAILED(results->GetCount(&total))) return FALSE; + for(DWORD itemWalk = 0; itemWalk < total; ++itemWalk) { + pfc::com_ptr_t item; + if (SUCCEEDED(results->GetItemAt(itemWalk,item.receive_ptr()))) { + CoTaskMemObject nameBuf; + if (FAILED(item->GetDisplayName(SIGDN_FILESYSPATH,&nameBuf.m_ptr))) return FALSE; + + result->AddItem(pfc::stringcvt::string_utf8_from_os_ex( nameBuf.m_ptr ) ); + + } + } + + if (result->get_count() == 0) return FALSE; + + out = result.detach(); + } + + return TRUE; +} +#if 0 +namespace { + class CFileDialogEvents_LocateFile : public IFileDialogEvents { + public: + CFileDialogEvents_LocateFile(pfc::stringp tofind) : m_tofind(tofind) {} + HRESULT STDMETHODCALLTYPE OnFileOk(IFileDialog *pfd) {return S_OK;} + + HRESULT STDMETHODCALLTYPE OnFolderChanging( IFileDialog *pfd, IShellItem *psiFolder) {return S_OK;} + + HRESULT STDMETHODCALLTYPE OnFolderChange( IFileDialog *pfd ) { + //pfd->GetFolder(); + return S_OK; + } + + HRESULT STDMETHODCALLTYPE OnSelectionChange( IFileDialog *pfd ) {return S_OK;} + + HRESULT STDMETHODCALLTYPE OnShareViolation( IFileDialog *pfd, IShellItem *psi, FDE_SHAREVIOLATION_RESPONSE *pResponse) { return S_OK; } + + HRESULT STDMETHODCALLTYPE OnTypeChange( IFileDialog *pfd ) {return S_OK; } + + HRESULT STDMETHODCALLTYPE OnOverwrite( IFileDialog *pfd, IShellItem *psi, FDE_OVERWRITE_RESPONSE *pResponse) {return S_OK; } + + private: + const pfc::string m_tofind; + }; + +} +#endif +BOOL Vista_BrowseForFolder(HWND parent, const char * p_title, pfc::string_base & path) { + modal_dialog_scope modalScope(parent); + pfc::com_ptr_t dlg; + if (FAILED(CoCreateInstance(__uuidof(FileOpenDialog), NULL, CLSCTX_ALL, IID_IFileOpenDialog, (void**) dlg.receive_ptr()))) throw pfc::exception_not_implemented(); + + if (p_title != NULL) { + if (FAILED(dlg->SetTitle(dTEXT(p_title)))) return FALSE; + } + + if (FAILED(AddOptionsHelper(dlg, FOS_PICKFOLDERS | FOS_FORCEFILESYSTEM))) return FALSE; + + if (!path.is_empty()) { + SetFolderHelper(dlg,path); + } + + if (FAILED( dlg->Show(parent) ) ) return FALSE; + + { + pfc::com_ptr_t result; + if (FAILED(dlg->GetResult(result.receive_ptr()))) return FALSE; + + CoTaskMemObject nameBuf; + if (FAILED(result->GetDisplayName(SIGDN_FILESYSPATH,&nameBuf.m_ptr))) return FALSE; + + path = pfc::stringcvt::string_utf8_from_os_ex( nameBuf.m_ptr ); + } + return TRUE; +} + + +__inline HRESULT mySHLoadLibraryFromItem( + __in IShellItem *psiLibrary, + __in DWORD grfMode, + __in REFIID riid, + __deref_out void **ppv +) +{ + *ppv = NULL; + IShellLibrary *plib; + + HRESULT hr = CoCreateInstance( + CLSID_ShellLibrary, + NULL, + CLSCTX_INPROC_SERVER, + IID_PPV_ARGS(&plib)); + + if (SUCCEEDED(hr)) + { + hr = plib->LoadLibraryFromItem (psiLibrary, grfMode); + if (SUCCEEDED(hr)) + { + hr = plib->QueryInterface (riid, ppv); + } + plib->Release(); + } + return hr; +} + +// +// from shobjidl.h +// +__inline HRESULT mySHLoadLibraryFromKnownFolder( + __in REFKNOWNFOLDERID kfidLibrary, + __in DWORD grfMode, + __in REFIID riid, + __deref_out void **ppv) +{ + *ppv = NULL; + IShellLibrary *plib; + HRESULT hr = CoCreateInstance( + CLSID_ShellLibrary, + NULL, + CLSCTX_INPROC_SERVER, + IID_PPV_ARGS(&plib)); + if (SUCCEEDED(hr)) + { + hr = plib->LoadLibraryFromKnownFolder(kfidLibrary, grfMode); + if (SUCCEEDED(hr)) + { + hr = plib->QueryInterface(riid, ppv); + } + plib->Release(); + } + return hr; +} + +puGetOpenFileNameMultiResult Vista_BrowseForFolderEx(HWND parent,const char * p_title, const char * initPath) { + try { + modal_dialog_scope modalScope(parent); + pfc::com_ptr_t dlg; + if (FAILED(CoCreateInstance(__uuidof(FileOpenDialog), NULL, CLSCTX_ALL, IID_IFileOpenDialog, (void**) dlg.receive_ptr()))) throw pfc::exception_not_implemented(); + + if (p_title != NULL) { + EH << dlg->SetTitle(dTEXT(p_title)); + } + + EH << AddOptionsHelper(dlg, FOS_ALLOWMULTISELECT | FOS_PICKFOLDERS); + + if (initPath && *initPath) { + SetFolderHelper(dlg,initPath); + } + + EH << dlg->Show(parent); + + pfc::ptrholder_t result = new uGetOpenFileNameMultiResult_impl; + pfc::com_ptr_t results; + EH << dlg->GetResults(results.receive_ptr()); + DWORD total; + EH << results->GetCount(&total); + CoTaskMemObject nameBuf; + for(DWORD itemWalk = 0; itemWalk < total; ++itemWalk) { + pfc::com_ptr_t item; + EH << results->GetItemAt(itemWalk,item.receive_ptr()); + if (SUCCEEDED(item->GetDisplayName(SIGDN_FILESYSPATH,nameBuf.Receive()))) { + result->AddItem(pfc::stringcvt::string_utf8_from_os_ex( nameBuf.m_ptr ) ); + } else { + pfc::com_ptr_t library; + if (SUCCEEDED(mySHLoadLibraryFromItem(item.get_ptr(), STGM_READ, IID_IShellLibrary, (void**)library.receive_ptr()))) { + pfc::com_ptr_t subFolders; + EH << library->GetFolders(LFF_FORCEFILESYSTEM, IID_IShellItemArray, (void**)subFolders.receive_ptr()); + DWORD subTotal; + EH << subFolders->GetCount(&subTotal); + for(DWORD subWalk = 0; subWalk < subTotal; ++subWalk) { + pfc::com_ptr_t subItem; + EH << subFolders->GetItemAt(subWalk,subItem.receive_ptr()); + EH << subItem->GetDisplayName(SIGDN_FILESYSPATH,nameBuf.Receive()); + result->AddItem(pfc::stringcvt::string_utf8_from_os_ex( nameBuf.m_ptr ) ); + } + } + } + } + if (result->GetCount() == 0) return NULL; + return result.detach(); + } catch(exception_com) { + return NULL; + } +} + +static bool GetLegacyKnownFolder(int & out, REFKNOWNFOLDERID id) { + if (id == FOLDERID_Music) { + out = CSIDL_MYMUSIC; + return true; + } else if (id == FOLDERID_Pictures) { + out = CSIDL_MYPICTURES; + return true; + } else if (id == FOLDERID_Videos) { + out = CSIDL_MYVIDEO; + return true; + } else if (id == FOLDERID_Documents) { + out = CSIDL_MYDOCUMENTS; + return true; + } else if (id == FOLDERID_Desktop) { + out = CSIDL_DESKTOP; + return true; + } else { + return false; + } +} + +puGetOpenFileNameMultiResult SHARED_EXPORT uEvalKnownFolder(REFKNOWNFOLDERID id) { + try { + pfc::com_ptr_t library; + EH << mySHLoadLibraryFromKnownFolder(id, STGM_READ, IID_IShellLibrary, (void**)library.receive_ptr()); + + pfc::com_ptr_t subFolders; + EH << library->GetFolders(LFF_FORCEFILESYSTEM, IID_IShellItemArray, (void**)subFolders.receive_ptr()); + + pfc::ptrholder_t result = new uGetOpenFileNameMultiResult_impl; + + DWORD subTotal; + EH << subFolders->GetCount(&subTotal); + CoTaskMemObject nameBuf; + for(DWORD subWalk = 0; subWalk < subTotal; ++subWalk) { + pfc::com_ptr_t subItem; + EH << subFolders->GetItemAt(subWalk,subItem.receive_ptr()); + EH << subItem->GetDisplayName(SIGDN_FILESYSPATH,nameBuf.Receive()); + result->AddItem(pfc::stringcvt::string_utf8_from_os_ex( nameBuf.m_ptr ) ); + } + if (result->get_count() == 0) return NULL; + return result.detach(); + } catch(exception_com) { + //failed + } + + + try { + CComPtr mgr; CComPtr folder; CoTaskMemObject path; + EH << CoCreateInstance(__uuidof(KnownFolderManager), nullptr, CLSCTX_ALL, IID_IKnownFolderManager, (void**)&mgr.p); + EH << mgr->GetFolder(id, &folder.p); + EH << folder->GetPath(0, &path.m_ptr); + + pfc::ptrholder_t result = new uGetOpenFileNameMultiResult_impl; + result->AddItem(pfc::stringcvt::string_utf8_from_os(path.m_ptr)); + return result.detach(); + } catch (exception_com) { + + } + + //FALLBACK + + + + { + int legacyID; + if (GetLegacyKnownFolder(legacyID, id)) { + try { + TCHAR path[MAX_PATH+16] = {}; + EH << SHGetFolderPath(NULL, legacyID, NULL, SHGFP_TYPE_CURRENT, path); + path[_countof(path)-1] = 0; + pfc::ptrholder_t result = new uGetOpenFileNameMultiResult_impl; + result->AddItem(pfc::stringcvt::string_utf8_from_os_ex( path ) ); + return result.detach(); + } catch(exception_com) { + //failed; + } + } + } +#if 0 // Vista code path - uninteresting, XP shit still needs to be supported, SHGetKnownFolderPath() does not exist on XP + try { + pfc::ptrholder_t result = new uGetOpenFileNameMultiResult_impl; + CoTaskMemObject nameBuf; + EH << SHGetKnownFolderPath(id, 0, NULL, nameBuf.Receive()); + result->AddItem(pfc::stringcvt::string_utf8_from_os_ex( nameBuf.m_ptr ) ); + return result.detach(); + } catch(exception_com) { + //failed + } +#endif + return NULL; //failure +} diff --git a/sdk/foobar2000/shared/font_description.cpp b/sdk/foobar2000/shared/font_description.cpp new file mode 100644 index 0000000..440930c --- /dev/null +++ b/sdk/foobar2000/shared/font_description.cpp @@ -0,0 +1,126 @@ +#include "shared.h" + + +static unsigned query_dpi() +{ + unsigned ret; + HDC dc = GetDC(0); + ret = GetDeviceCaps(dc,LOGPIXELSY); + ReleaseDC(0,dc); + return ret; +} + + +#if 0 +struct t_font_description +{ + enum {m_facename_length = LF_FACESIZE*2}; + + t_uint32 m_height; + t_uint32 m_weight; + t_uint8 m_italic; + t_uint8 m_charset; + char m_facename[m_facename_length]; +} +#endif + +static void make_logfont(LOGFONT & p_logfont,const t_font_description & p_desc) +{ + p_logfont.lfHeight = - MulDiv(p_desc.m_height, query_dpi(), t_font_description::m_height_dpi); + p_logfont.lfWidth = 0; + p_logfont.lfEscapement = 0; + p_logfont.lfOrientation = 0; + p_logfont.lfWeight = p_desc.m_weight; + p_logfont.lfItalic = p_desc.m_italic; + p_logfont.lfUnderline = 0; + p_logfont.lfStrikeOut = 0; + p_logfont.lfCharSet = p_desc.m_charset; + p_logfont.lfOutPrecision = 3; + p_logfont.lfClipPrecision = 2; + p_logfont.lfQuality = 1; + p_logfont.lfPitchAndFamily = 34; + pfc::stringToBuffer(p_logfont.lfFaceName,pfc::stringcvt::string_os_from_utf8(p_desc.m_facename,tabsize(p_desc.m_facename))); +} + +static void make_description(t_font_description & p_desc,const LOGFONT & p_logfont) +{ + p_desc.m_height = MulDiv(pfc::abs_t(p_logfont.lfHeight), t_font_description::m_height_dpi, query_dpi()); + p_desc.m_weight = p_logfont.lfWeight; + p_desc.m_italic = p_logfont.lfItalic; + p_desc.m_charset = p_logfont.lfCharSet; + pfc::stringToBuffer(p_desc.m_facename,pfc::stringcvt::string_utf8_from_os(p_logfont.lfFaceName,tabsize(p_logfont.lfFaceName))); +} + +HFONT SHARED_EXPORT t_font_description::create() const +{ + LOGFONT temp; + make_logfont(temp,*this); + return CreateFontIndirect(&temp); +} + +static UINT_PTR CALLBACK choose_font_hook(HWND wnd,UINT msg,WPARAM wp,LPARAM lp) +{ + switch(msg) + { + case WM_INITDIALOG: + { + CHOOSEFONT * cf = reinterpret_cast(lp); + reinterpret_cast(cf->lCustData)->initialize(FindOwningPopup(wnd)); + } + return 0; + default: + return 0; + } +} + +bool SHARED_EXPORT t_font_description::popup_dialog(HWND p_parent) +{ + modal_dialog_scope scope; + + LOGFONT logfont; + make_logfont(logfont,*this); + + CHOOSEFONT cf = {}; + cf.lStructSize = sizeof(cf); + cf.hwndOwner = p_parent; + cf.lpLogFont = &logfont; + cf.Flags = CF_SCREENFONTS|CF_FORCEFONTEXIST|CF_INITTOLOGFONTSTRUCT|CF_ENABLEHOOK; + cf.nFontType = SCREEN_FONTTYPE; + cf.lCustData = reinterpret_cast(&scope); + cf.lpfnHook = choose_font_hook; + if (ChooseFont(&cf)) + { + make_description(*this,logfont); + return true; + } + else return false; +} + + +void SHARED_EXPORT t_font_description::from_font(HFONT p_font) +{ + LOGFONT logfont; + PFC_ASSERT_SUCCESS( GetObject((HGDIOBJ) p_font, sizeof(logfont), &logfont) != 0 ); + make_description(*this,logfont); +} + +t_font_description SHARED_EXPORT t_font_description::g_from_font(HFONT p_font) +{ + t_font_description temp; + temp.from_font(p_font); + return temp; +} + + +t_font_description SHARED_EXPORT t_font_description::g_from_logfont(LOGFONT const & lf) { + t_font_description ret; make_description(ret, lf); return ret; +} + +t_font_description SHARED_EXPORT t_font_description::g_from_system(int id) { + LOGFONT lf; + if (FAILED( GetThemeSysFont(NULL, id, &lf) ) ) { + PFC_ASSERT(!"Should not get here!"); + return g_from_font( (HFONT) GetStockObject(DEFAULT_GUI_FONT) ); + } + return g_from_logfont(lf); +} diff --git a/sdk/foobar2000/shared/minidump.cpp b/sdk/foobar2000/shared/minidump.cpp new file mode 100644 index 0000000..eec6d14 --- /dev/null +++ b/sdk/foobar2000/shared/minidump.cpp @@ -0,0 +1,251 @@ +#include "shared.h" +#include + +#ifdef _M_ARM64EC +typedef ARM64EC_NT_CONTEXT myCONTEXT; +#else +typedef CONTEXT myCONTEXT; +#endif +struct DumpState { + int state; + myCONTEXT*context; +}; + +__declspec(noinline) static bool safeRead(volatile const void* addr, size_t& dest) +{ + __try { + dest = *(const volatile size_t*)addr; + return true; + } + __except (1) { + return false; + } +} + +__declspec(noinline) static bool safeTestReadAccess(volatile const void* addr) +{ + size_t dummy; + return safeRead(addr, dummy); +} + +#if defined(_M_ARM64) || defined(_M_ARM64EC) + +BOOL WINAPI MiniDumpCallback(PVOID CallbackParam, + const PMINIDUMP_CALLBACK_INPUT CallbackInput, + PMINIDUMP_CALLBACK_OUTPUT CallbackOutput) +{ + static const unsigned STACK_SEARCH_SIZE = 0x400; + static const unsigned MEM_BLOCK_SIZE = 0x400; + + if (CallbackInput->CallbackType == MemoryCallback) { + // Called to get user defined blocks of memory to write until + // callback returns FALSE or CallbackOutput->MemorySize == 0. + + DumpState* ds = (DumpState*)CallbackParam; + switch (ds->state) { + // Save memory referenced by registers. + case 0: CallbackOutput->MemoryBase = ds->context->X0; ds->state++; break; + case 1: CallbackOutput->MemoryBase = ds->context->X1; ds->state++; break; + case 2: CallbackOutput->MemoryBase = ds->context->X2; ds->state++; break; + case 3: CallbackOutput->MemoryBase = ds->context->X3; ds->state++; break; + case 4: CallbackOutput->MemoryBase = ds->context->X4; ds->state++; break; + case 5: CallbackOutput->MemoryBase = ds->context->X5; ds->state++; break; + case 6: CallbackOutput->MemoryBase = ds->context->X6; ds->state++; break; + case 7: CallbackOutput->MemoryBase = ds->context->X7; ds->state++; break; + case 8: CallbackOutput->MemoryBase = ds->context->X8; ds->state++; break; + case 9: CallbackOutput->MemoryBase = ds->context->X9; ds->state++; break; + case 10: CallbackOutput->MemoryBase = ds->context->X10; ds->state++; break; + case 11: CallbackOutput->MemoryBase = ds->context->X11; ds->state++; break; + case 12: CallbackOutput->MemoryBase = ds->context->X12; ds->state++; break; +#ifndef _M_ARM64EC + case 13: CallbackOutput->MemoryBase = ds->context->X13; ds->state++; break; + case 14: CallbackOutput->MemoryBase = ds->context->X14; ds->state++; break; + case 15: CallbackOutput->MemoryBase = ds->context->X15; ds->state++; break; + case 16: CallbackOutput->MemoryBase = ds->context->X16; ds->state++; break; + case 17: CallbackOutput->MemoryBase = ds->context->X17; ds->state++; break; + case 18: CallbackOutput->MemoryBase = ds->context->X18; ds->state++; break; + case 19: CallbackOutput->MemoryBase = ds->context->X19; ds->state++; break; + case 20: CallbackOutput->MemoryBase = ds->context->X20; ds->state++; break; + case 21: CallbackOutput->MemoryBase = ds->context->X21; ds->state++; break; + case 22: CallbackOutput->MemoryBase = ds->context->X22; ds->state++; break; + case 23: CallbackOutput->MemoryBase = ds->context->X23; ds->state++; break; + case 24: CallbackOutput->MemoryBase = ds->context->X24; ds->state++; break; + case 25: CallbackOutput->MemoryBase = ds->context->X25; ds->state++; break; + case 26: CallbackOutput->MemoryBase = ds->context->X26; ds->state++; break; + case 27: CallbackOutput->MemoryBase = ds->context->X27; ds->state++; break; + case 28: CallbackOutput->MemoryBase = ds->context->X28; ds->state++; break; +#endif + + // Save memory referenced by values in stack. + default: + if (ds->state < 0x1000) + ds->state = 0x1000; + + size_t addr; + do { + if (ds->state > 0x1000 + STACK_SEARCH_SIZE) + return FALSE; + + if (!safeRead((void*)((ds->context->Sp & ~7) + ds->state - 0x1000), addr)) + return FALSE; + + ds->state += 4; + } while (addr < 0x1000 || !safeTestReadAccess((void*)addr)); + + CallbackOutput->MemoryBase = addr; + break; + } + + if (CallbackOutput->MemoryBase >= MEM_BLOCK_SIZE / 2) + CallbackOutput->MemoryBase -= MEM_BLOCK_SIZE / 2; + CallbackOutput->MemorySize = MEM_BLOCK_SIZE; + + // No need to perform additional checks here, the minidump engine + // safely clips the addresses to valid memory pages only. + // Also seems to apply for overlapped areas etc. + } + + return TRUE; +} + +#elif defined(_M_IX86) + +BOOL WINAPI MiniDumpCallback(PVOID CallbackParam, + const PMINIDUMP_CALLBACK_INPUT CallbackInput, + PMINIDUMP_CALLBACK_OUTPUT CallbackOutput) +{ + static const unsigned STACK_SEARCH_SIZE = 0x400; + static const unsigned MEM_BLOCK_SIZE = 0x400; + + if (CallbackInput->CallbackType == MemoryCallback) { + // Called to get user defined blocks of memory to write until + // callback returns FALSE or CallbackOutput->MemorySize == 0. + + DumpState* ds = (DumpState*)CallbackParam; + switch (ds->state) { + // Save memory referenced by registers. + case 0: CallbackOutput->MemoryBase = ds->context->Eax; ds->state++; break; + case 1: CallbackOutput->MemoryBase = ds->context->Ebx; ds->state++; break; + case 2: CallbackOutput->MemoryBase = ds->context->Ecx; ds->state++; break; + case 3: CallbackOutput->MemoryBase = ds->context->Edx; ds->state++; break; + case 4: CallbackOutput->MemoryBase = ds->context->Esi; ds->state++; break; + case 5: CallbackOutput->MemoryBase = ds->context->Edi; ds->state++; break; + case 6: CallbackOutput->MemoryBase = ds->context->Ebp; ds->state++; break; + case 7: CallbackOutput->MemoryBase = ds->context->Esp; ds->state++; break; + case 8: CallbackOutput->MemoryBase = ds->context->Eip; ds->state++; break; + + // Save memory referenced by values in stack. + default: + if (ds->state < 0x1000) + ds->state = 0x1000; + + size_t addr; + do { + if (ds->state > 0x1000 + STACK_SEARCH_SIZE) + return FALSE; + + if (!safeRead((void*)((ds->context->Esp & ~3) + ds->state - 0x1000), addr)) + return FALSE; + + ds->state += 4; + } while (addr < 0x1000 || !safeTestReadAccess((void*)addr)); + + CallbackOutput->MemoryBase = addr; + break; + } + + if (CallbackOutput->MemoryBase >= MEM_BLOCK_SIZE / 2) + CallbackOutput->MemoryBase -= MEM_BLOCK_SIZE / 2; + CallbackOutput->MemorySize = MEM_BLOCK_SIZE; + + // No need to perform additional checks here, the minidump engine + // safely clips the addresses to valid memory pages only. + // Also seems to apply for overlapped areas etc. + } + + return TRUE; +} + +#elif defined(_M_X64) + +BOOL WINAPI MiniDumpCallback(PVOID CallbackParam, + const PMINIDUMP_CALLBACK_INPUT CallbackInput, + PMINIDUMP_CALLBACK_OUTPUT CallbackOutput) +{ + static const unsigned STACK_SEARCH_SIZE = 0x400; + static const unsigned MEM_BLOCK_SIZE = 0x400; + + if (CallbackInput->CallbackType == MemoryCallback) { + // Called to get user defined blocks of memory to write until + // callback returns FALSE or CallbackOutput->MemorySize == 0. + + DumpState* ds = (DumpState*)CallbackParam; + switch (ds->state) { + // Save memory referenced by registers. + case 0: CallbackOutput->MemoryBase = ds->context->Rax; ds->state++; break; + case 1: CallbackOutput->MemoryBase = ds->context->Rbx; ds->state++; break; + case 2: CallbackOutput->MemoryBase = ds->context->Rcx; ds->state++; break; + case 3: CallbackOutput->MemoryBase = ds->context->Rdx; ds->state++; break; + case 4: CallbackOutput->MemoryBase = ds->context->Rsi; ds->state++; break; + case 5: CallbackOutput->MemoryBase = ds->context->Rdi; ds->state++; break; + case 6: CallbackOutput->MemoryBase = ds->context->Rsp; ds->state++; break; + case 7: CallbackOutput->MemoryBase = ds->context->Rbp; ds->state++; break; + case 8: CallbackOutput->MemoryBase = ds->context->R8; ds->state++; break; + case 9: CallbackOutput->MemoryBase = ds->context->R9; ds->state++; break; + case 10: CallbackOutput->MemoryBase = ds->context->R10; ds->state++; break; + case 11: CallbackOutput->MemoryBase = ds->context->R11; ds->state++; break; + case 12: CallbackOutput->MemoryBase = ds->context->R12; ds->state++; break; + case 13: CallbackOutput->MemoryBase = ds->context->R13; ds->state++; break; + case 14: CallbackOutput->MemoryBase = ds->context->R14; ds->state++; break; + case 15: CallbackOutput->MemoryBase = ds->context->R15; ds->state++; break; + + // Save memory referenced by values in stack. + default: + if (ds->state < 0x1000) + ds->state = 0x1000; + + size_t addr; + do { + if (ds->state > 0x1000 + STACK_SEARCH_SIZE) + return FALSE; + + if (!safeRead((void*)((ds->context->Rsp & ~7) + ds->state - 0x1000), addr)) + return FALSE; + + ds->state += 4; + } while (addr < 0x1000 || !safeTestReadAccess((void*)addr)); + + CallbackOutput->MemoryBase = addr; + break; + } + + if (CallbackOutput->MemoryBase >= MEM_BLOCK_SIZE / 2) + CallbackOutput->MemoryBase -= MEM_BLOCK_SIZE / 2; + CallbackOutput->MemorySize = MEM_BLOCK_SIZE; + + // No need to perform additional checks here, the minidump engine + // safely clips the addresses to valid memory pages only. + // Also seems to apply for overlapped areas etc. + } + + return TRUE; +} + +#endif // _M_X64 + + + + +BOOL WriteMiniDumpHelper(HANDLE hDump, LPEXCEPTION_POINTERS param) { + MINIDUMP_EXCEPTION_INFORMATION exception = {}; + exception.ThreadId = GetCurrentThreadId(); + exception.ExceptionPointers = param; + exception.ClientPointers = FALSE; + DumpState ds; + ds.state = 0; + ds.context = reinterpret_cast(param->ContextRecord); + MINIDUMP_CALLBACK_INFORMATION mci; + mci.CallbackRoutine = &MiniDumpCallback; + mci.CallbackParam = (void*)&ds; + return MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDump, (MINIDUMP_TYPE)(MiniDumpWithUnloadedModules), &exception, NULL, &mci); +} diff --git a/sdk/foobar2000/shared/modal_dialog.cpp b/sdk/foobar2000/shared/modal_dialog.cpp new file mode 100644 index 0000000..8478579 --- /dev/null +++ b/sdk/foobar2000/shared/modal_dialog.cpp @@ -0,0 +1,66 @@ +#include "shared.h" + +static DWORD g_main_thread = GetCurrentThreadId(); + +static t_modal_dialog_entry g_status = {0,false}; + +static bool TestMainThread() +{ + if (GetCurrentThreadId() == g_main_thread) return true; + OutputDebugString(TEXT("This function can be called only from main thread.\n")); + return false; +} + +HWND SHARED_EXPORT FindOwningPopup(HWND p_wnd) +{ + return pfc::findOwningPopup(p_wnd); +} + +void SHARED_EXPORT PokeWindow(HWND p_wnd) +{ + p_wnd = FindOwningPopup(p_wnd); + if (IsWindowEnabled(p_wnd)) + { +// SetForegroundWindow(p_wnd); + SetActiveWindow(p_wnd); + FlashWindow(p_wnd,FALSE); + } + else + { + HWND child = GetWindow(p_wnd,GW_ENABLEDPOPUP); + if (child != 0) + { +// SetForegroundWindow(child); + SetActiveWindow(child); + FlashWindow(child,FALSE); + } + } +} + +extern "C" { + void SHARED_EXPORT ModalDialog_Switch(t_modal_dialog_entry & p_entry) + { + if (TestMainThread()) + pfc::swap_t(p_entry,g_status); + } + + void SHARED_EXPORT ModalDialog_PokeExisting() + { + if (TestMainThread()) + { + if (g_status.m_in_use && g_status.m_wnd_to_poke != 0) + { + PokeWindow(g_status.m_wnd_to_poke); + MessageBeep(0); + } + } + } + + bool SHARED_EXPORT ModalDialog_CanCreateNew() + { + if (TestMainThread()) + return !g_status.m_in_use; + else + return false; + } +} \ No newline at end of file diff --git a/sdk/foobar2000/shared/shared-apple.mm b/sdk/foobar2000/shared/shared-apple.mm new file mode 100644 index 0000000..6223656 --- /dev/null +++ b/sdk/foobar2000/shared/shared-apple.mm @@ -0,0 +1,31 @@ +#include "shared.h" +#include "shared-apple.h" + +#import + +bool uSetClipboardString(const char * str) { + @autoreleasepool { + @try { + NSPasteboard * pb = [NSPasteboard generalPasteboard]; + [pb clearContents]; + [pb setString: [NSString stringWithUTF8String: str] forType:NSPasteboardTypeString]; + return true; + } @catch (NSException *) { + + } + } + return false; +} + +bool uGetClipboardString(pfc::string_base & out) { + bool rv = false; + @autoreleasepool { + NSPasteboard * pb = [NSPasteboard generalPasteboard]; + NSString * str = [pb stringForType: NSPasteboardTypeString]; + if ( str != nil ) { + out = str.UTF8String; + rv = true; + } + } + return rv; +} diff --git a/sdk/foobar2000/shared/shared-nix.cpp b/sdk/foobar2000/shared/shared-nix.cpp new file mode 100644 index 0000000..e13f114 --- /dev/null +++ b/sdk/foobar2000/shared/shared-nix.cpp @@ -0,0 +1,195 @@ +#include "shared.h" +#include +#include + +// foobar2000 SDK project method... bah +namespace foobar2000_io { + PFC_NORETURN void nix_io_op_fail(); +} +using namespace foobar2000_io; + +namespace { + class uFindFileImpl : public uFindFile { + public: + uFindFileImpl ( DIR * dir ) : m_dir(dir) {} + bool FindNext() override { + m_entry = readdir(m_dir); + return m_entry != NULL; + } + const char * GetFileName() override { + return m_entry->d_name; + } + bool IsDirectory() override { + return m_entry->d_type == DT_DIR; + } + ~uFindFileImpl() { + closedir(m_dir); + } + private: + dirent * m_entry; + + DIR * m_dir; + }; + + class uFindFileFiltered : public uFindFile { + public: + uFindFileFiltered( DIR * dir, const char * wc ) : m_impl(dir), m_wc(wc) {} + bool FindNext() override { + for( ;; ) { + if (!m_impl.FindNext()) return false; + if ( testWC() ) return true; + } + } + const char * GetFileName() override { + return m_impl.GetFileName(); + } + bool IsDirectory() override { + return m_impl.IsDirectory(); + } + bool testWC() { + return wildcard_helper::test(GetFileName(), m_wc); + } + + uFindFileImpl m_impl; + const pfc::string8 m_wc; + }; +} + +puFindFile uFindFirstFile(const char * path) { + + if ( wildcard_helper::has_wildcards( path ) ) { + size_t idx = pfc::scan_filename(path); + + try { + DIR * dir = opendir( pfc::string8(path, idx) ); + if (dir == NULL) nix_io_op_fail(); + try { + uFindFile * ff; + try { + ff = new uFindFileFiltered(dir, path + idx); + } catch(...) { closedir( dir ); throw; } + if (ff->FindNext()) return ff; + delete ff; + return NULL; + } catch(...) { closedir( dir ); throw; } + } catch(...) {return NULL;} + + } + + try { + DIR * dir = opendir( path ); + if (dir == NULL) nix_io_op_fail(); + try { + uFindFile * ff; + try { + ff = new uFindFileImpl(dir); + } catch(...) { closedir( dir ); throw; } + if (ff->FindNext()) return ff; + delete ff; + return NULL; + } catch(...) { closedir( dir ); throw; } + } catch(...) {return NULL;} +} + +pfc::string8 uStringPrintf(const char * fmt, ...) { + pfc::string8 ret; + va_list list; + va_start(list,fmt); + uPrintfV(ret,fmt,list); + va_end(list); + return ret; +} + +void uPrintfV(pfc::string_base & out,const char * fmt,va_list arglist) { + pfc::string_printf_here_va(out, fmt, arglist); +} + +void uPrintf(pfc::string_base & out,const char * fmt,...) { + va_list list;va_start(list,fmt);uPrintfV(out,fmt,list);va_end(list); +} + + +static int makeInfiniteWaitEvent() { + int fdPipe[2]; + pfc::createPipe(fdPipe); + return fdPipe[0]; // leak the other end +} + +int GetInfiniteWaitEvent() { + static int obj = makeInfiniteWaitEvent(); + return obj; +} + + +// DUMMY +void SHARED_EXPORT uAddPanicHandler(fb2k::panicHandler*) { + +} +void SHARED_EXPORT uRemovePanicHandler(fb2k::panicHandler*) { + +} + +void SHARED_EXPORT uOutputDebugString(const char * msg) { + // UGLY: underlying APIs want whole lines, calling code feeds lines terminated with \n or \r\n because Windows + pfc::string8 temp ( msg ); + if ( temp.endsWith('\n') ) temp.truncate( temp.length() - 1) ; + if ( temp.endsWith('\r') ) temp.truncate( temp.length() - 1) ; + pfc::outputDebugLine(temp); +} +namespace pfc { PFC_NORETURN void crashImpl(); } +PFC_NORETURN void SHARED_EXPORT uBugCheck() { + pfc::crashImpl(); +} + +int SHARED_EXPORT uStringCompare(const char * elem1, const char * elem2) { + return pfc::naturalSortCompareI(elem1, elem2); +} + +void fb2kDebugSelfTest() { + +} + +bool uGetTempPath(pfc::string_base & out) { + auto var = getenv("TMPDIR"); + if ( var == nullptr ) uBugCheck(); + out = var; + return true; +} +bool uGetTempFileName(const char * path_name,const char * prefix,unsigned unique,pfc::string_base & out) { +#if 0 // sample use + pfc::string8 temp_path, temp_file; + uGetTempPath(temp_path); + uGetTempFileName(temp_path, "img", 0, temp_file); +#endif + pfc::string8 ret; + if ( path_name == nullptr ) uGetTempPath( ret ); + else ret = path_name; + + pfc::chain_list_v2_t segments; + if ( prefix ) segments += prefix; + if ( unique ) segments += pfc::format(unique); + segments += pfc::print_guid(pfc::createGUID()); + + pfc::string8 fn; + for( auto & seg : segments ) { + if (seg.length() == 0) continue; + if ( fn.length() > 0 ) fn += "-"; + fn += seg; + } + + ret.add_filename( fn ); + out = ret; + return true; +} + +pfc::string8 uGetTempFileName() { + pfc::string8 ret; + uGetTempFileName(nullptr, nullptr, 0, ret); + return ret; +} + + +void fb2k::crashWithMessage [[noreturn]] ( const char * msg_ ) { + // there used to be code throwing Objective-C exceptions, but those were of no use, + pfc::crashWithMessageOnStack(msg_); +} diff --git a/sdk/foobar2000/shared/shared.h b/sdk/foobar2000/shared/shared.h index 2600ccb..b0b2494 100644 --- a/sdk/foobar2000/shared/shared.h +++ b/sdk/foobar2000/shared/shared.h @@ -568,7 +568,7 @@ typedef HICON hicon_t; typedef HMENU hmenu_t; typedef HFONT hfont_t; #else -typedef void* hwnd_t; +typedef void* hwnd_t; // Mac: bridged NSObject, context specific (NSWindow, NSView, NSViewController) typedef void* hicon_t; typedef void* hmenu_t; typedef void* hfont_t; diff --git a/sdk/foobar2000/shared/shared.vcxproj b/sdk/foobar2000/shared/shared.vcxproj new file mode 100644 index 0000000..db8b677 --- /dev/null +++ b/sdk/foobar2000/shared/shared.vcxproj @@ -0,0 +1,420 @@ + + + + + Debug + ARM64 + + + Debug + ARM64EC + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM64 + + + Release + ARM64EC + + + Release + Win32 + + + Release + x64 + + + + {054C606B-17BF-4540-AC4E-A9A7243628B8} + shared + Win32Proj + + + + DynamicLibrary + Unicode + true + v143 + + + DynamicLibrary + Unicode + true + v143 + + + DynamicLibrary + Unicode + true + v143 + + + DynamicLibrary + Unicode + true + v143 + + + DynamicLibrary + Unicode + v143 + + + DynamicLibrary + Unicode + v143 + + + DynamicLibrary + Unicode + v143 + + + DynamicLibrary + Unicode + v143 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + true + true + true + true + $(SolutionDir)$(Configuration)\ + $(Configuration)\ + false + false + false + false + + + + Disabled + EnableFastChecks + Use + shared.h + Level3 + ProgramDatabase + MultiThreadedDebugDLL + 4715 + Fast + _CRT_SECURE_NO_WARNINGS;SHARED_EXPORTS;_WINDLL;%(PreprocessorDefinitions) + true + stdcpp20 + + + comctl32.lib;imagehlp.lib;uxtheme.lib;dbghelp.lib;%(AdditionalDependencies) + true + $(OutDir)shared.pdb + Windows + + + $(OutDir)shared.lib + MachineX86 + + + + + Disabled + EnableFastChecks + Use + shared.h + Level3 + ProgramDatabase + MultiThreadedDebugDLL + 4715 + Fast + _CRT_SECURE_NO_WARNINGS;SHARED_EXPORTS;_WINDLL;%(PreprocessorDefinitions) + true + stdcpp20 + + + comctl32.lib;imagehlp.lib;uxtheme.lib;dbghelp.lib;%(AdditionalDependencies) + true + $(OutDir)shared.pdb + Windows + + + $(OutDir)shared.lib + + + + + Disabled + EnableFastChecks + Use + shared.h + Level3 + ProgramDatabase + MultiThreadedDebugDLL + 4715 + Fast + _CRT_SECURE_NO_WARNINGS;SHARED_EXPORTS;_WINDLL;%(PreprocessorDefinitions) + true + stdcpp20 + + + comctl32.lib;imagehlp.lib;uxtheme.lib;dbghelp.lib;%(AdditionalDependencies) + true + $(OutDir)shared.pdb + Windows + + + $(OutDir)shared.lib + + + + + Disabled + EnableFastChecks + Use + shared.h + Level3 + ProgramDatabase + MultiThreadedDebugDLL + 4715 + Fast + _CRT_SECURE_NO_WARNINGS;SHARED_EXPORTS;_WINDLL;%(PreprocessorDefinitions) + true + stdcpp20 + + + comctl32.lib;imagehlp.lib;uxtheme.lib;dbghelp.lib;%(AdditionalDependencies) + true + $(OutDir)shared.pdb + Windows + + + $(OutDir)shared.lib + + + + + Full + true + false + Fast + false + Use + shared.h + Level3 + ProgramDatabase + MultiThreadedDLL + /d2notypeopt %(AdditionalOptions) + 4715 + true + _CRT_SECURE_NO_WARNINGS;SHARED_EXPORTS;_WINDLL;NDEBUG;%(PreprocessorDefinitions) + true + stdcpp20 + + + comctl32.lib;imagehlp.lib;uxtheme.lib;dbghelp.lib;%(AdditionalDependencies) + true + Windows + true + true + + + $(OutDir)shared.lib + MachineX86 + + + copy "$(OutDir)shared.lib" "$(ProjectDir)shared-$(Platform).lib" + + + + + Full + true + false + Fast + false + Use + shared.h + Level3 + ProgramDatabase + MultiThreadedDLL + /d2notypeopt %(AdditionalOptions) + 4715 + true + _CRT_SECURE_NO_WARNINGS;SHARED_EXPORTS;_WINDLL;NDEBUG;%(PreprocessorDefinitions) + true + stdcpp20 + + + comctl32.lib;imagehlp.lib;uxtheme.lib;dbghelp.lib;%(AdditionalDependencies) + true + Windows + true + true + + + $(OutDir)shared.lib + + + copy "$(OutDir)shared.lib" "$(ProjectDir)shared-$(Platform).lib" + + + + + Full + true + false + Fast + false + Use + shared.h + Level3 + ProgramDatabase + MultiThreadedDLL + /d2notypeopt %(AdditionalOptions) + 4715 + true + _CRT_SECURE_NO_WARNINGS;SHARED_EXPORTS;_WINDLL;NDEBUG;%(PreprocessorDefinitions) + true + stdcpp20 + + + comctl32.lib;imagehlp.lib;uxtheme.lib;dbghelp.lib;%(AdditionalDependencies) + true + Windows + true + true + + + $(OutDir)shared.lib + + + copy "$(OutDir)shared.lib" "$(ProjectDir)shared-$(Platform).lib" + + + + + Full + true + false + Fast + false + Use + shared.h + Level3 + ProgramDatabase + MultiThreadedDLL + /d2notypeopt %(AdditionalOptions) + 4715 + true + _CRT_SECURE_NO_WARNINGS;SHARED_EXPORTS;_WINDLL;NDEBUG;%(PreprocessorDefinitions) + true + stdcpp20 + + + comctl32.lib;imagehlp.lib;uxtheme.lib;dbghelp.lib;%(AdditionalDependencies) + true + Windows + true + true + + + $(OutDir)shared.lib + + + copy "$(OutDir)shared.lib" "$(ProjectDir)shared-$(Platform).lib" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + Create + Create + Create + Create + + + + + + + + + + + + + + + + + {ebfffb4e-261d-44d3-b89c-957b31a0bf9c} + + + + + + \ No newline at end of file diff --git a/sdk/foobar2000/shared/shared.vcxproj.filters b/sdk/foobar2000/shared/shared.vcxproj.filters new file mode 100644 index 0000000..0bad1ee --- /dev/null +++ b/sdk/foobar2000/shared/shared.vcxproj.filters @@ -0,0 +1,75 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/sdk/foobar2000/shared/shared.xcodeproj/project.pbxproj b/sdk/foobar2000/shared/shared.xcodeproj/project.pbxproj new file mode 100644 index 0000000..3eb996b --- /dev/null +++ b/sdk/foobar2000/shared/shared.xcodeproj/project.pbxproj @@ -0,0 +1,352 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 0F75F3A72A6B1A8C00A45078 /* stdafx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F3932A6B1A8C00A45078 /* stdafx.cpp */; }; + 0F75F3AB2A6B1A8C00A45078 /* shared-apple.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F39A2A6B1A8C00A45078 /* shared-apple.mm */; }; + 0F75F3AC2A6B1A8C00A45078 /* utf8.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F39B2A6B1A8C00A45078 /* utf8.cpp */; }; + 0F75F3AE2A6B1A8C00A45078 /* shared-nix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F39E2A6B1A8C00A45078 /* shared-nix.cpp */; }; + 0F75F3B02A6B1A8C00A45078 /* audio_math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F3A02A6B1A8C00A45078 /* audio_math.cpp */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 0F75F3772A6B1A3900A45078 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "include/$(PRODUCT_NAME)"; + dstSubfolderSpec = 16; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 0F75F3792A6B1A3900A45078 /* libshared.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libshared.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 0F75F38C2A6B1A8C00A45078 /* modal_dialog.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = modal_dialog.cpp; sourceTree = ""; }; + 0F75F38D2A6B1A8C00A45078 /* minidump.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = minidump.cpp; sourceTree = ""; }; + 0F75F38E2A6B1A8C00A45078 /* font_description.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = font_description.cpp; sourceTree = ""; }; + 0F75F38F2A6B1A8C00A45078 /* filedialogs_vista.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = filedialogs_vista.cpp; sourceTree = ""; }; + 0F75F3902A6B1A8C00A45078 /* audio_math.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = audio_math.h; sourceTree = ""; }; + 0F75F3912A6B1A8C00A45078 /* text_drawing.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = text_drawing.cpp; sourceTree = ""; }; + 0F75F3922A6B1A8C00A45078 /* filedialogs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = filedialogs.h; sourceTree = ""; }; + 0F75F3932A6B1A8C00A45078 /* stdafx.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = stdafx.cpp; sourceTree = ""; }; + 0F75F3942A6B1A8C00A45078 /* crash_info.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = crash_info.cpp; sourceTree = ""; }; + 0F75F3952A6B1A8C00A45078 /* fb2kdebug.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fb2kdebug.h; sourceTree = ""; }; + 0F75F3962A6B1A8C00A45078 /* systray.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = systray.cpp; sourceTree = ""; }; + 0F75F3972A6B1A8C00A45078 /* win32_misc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = win32_misc.h; sourceTree = ""; }; + 0F75F3982A6B1A8C00A45078 /* shared-nix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "shared-nix.h"; sourceTree = ""; }; + 0F75F3992A6B1A8C00A45078 /* filedialogs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = filedialogs.cpp; sourceTree = ""; }; + 0F75F39A2A6B1A8C00A45078 /* shared-apple.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "shared-apple.mm"; sourceTree = ""; }; + 0F75F39B2A6B1A8C00A45078 /* utf8.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = utf8.cpp; sourceTree = ""; }; + 0F75F39C2A6B1A8C00A45078 /* utf8api.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = utf8api.cpp; sourceTree = ""; }; + 0F75F39D2A6B1A8C00A45078 /* shared.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = shared.h; sourceTree = ""; }; + 0F75F39E2A6B1A8C00A45078 /* shared-nix.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "shared-nix.cpp"; sourceTree = ""; }; + 0F75F39F2A6B1A8C00A45078 /* Utility.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Utility.cpp; sourceTree = ""; }; + 0F75F3A02A6B1A8C00A45078 /* audio_math.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = audio_math.cpp; sourceTree = ""; }; + 0F75F3A12A6B1A8C00A45078 /* shared-apple.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "shared-apple.h"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 0F75F3762A6B1A3900A45078 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 0F75F3702A6B1A3900A45078 = { + isa = PBXGroup; + children = ( + 0F75F38B2A6B1A7D00A45078 /* Source */, + 0F75F37A2A6B1A3900A45078 /* Products */, + ); + sourceTree = ""; + }; + 0F75F37A2A6B1A3900A45078 /* Products */ = { + isa = PBXGroup; + children = ( + 0F75F3792A6B1A3900A45078 /* libshared.a */, + ); + name = Products; + sourceTree = ""; + }; + 0F75F38B2A6B1A7D00A45078 /* Source */ = { + isa = PBXGroup; + children = ( + 0F75F3A02A6B1A8C00A45078 /* audio_math.cpp */, + 0F75F3902A6B1A8C00A45078 /* audio_math.h */, + 0F75F3942A6B1A8C00A45078 /* crash_info.cpp */, + 0F75F3952A6B1A8C00A45078 /* fb2kdebug.h */, + 0F75F38F2A6B1A8C00A45078 /* filedialogs_vista.cpp */, + 0F75F3992A6B1A8C00A45078 /* filedialogs.cpp */, + 0F75F3922A6B1A8C00A45078 /* filedialogs.h */, + 0F75F38E2A6B1A8C00A45078 /* font_description.cpp */, + 0F75F38D2A6B1A8C00A45078 /* minidump.cpp */, + 0F75F38C2A6B1A8C00A45078 /* modal_dialog.cpp */, + 0F75F3A12A6B1A8C00A45078 /* shared-apple.h */, + 0F75F39A2A6B1A8C00A45078 /* shared-apple.mm */, + 0F75F39E2A6B1A8C00A45078 /* shared-nix.cpp */, + 0F75F3982A6B1A8C00A45078 /* shared-nix.h */, + 0F75F39D2A6B1A8C00A45078 /* shared.h */, + 0F75F3932A6B1A8C00A45078 /* stdafx.cpp */, + 0F75F3962A6B1A8C00A45078 /* systray.cpp */, + 0F75F3912A6B1A8C00A45078 /* text_drawing.cpp */, + 0F75F39B2A6B1A8C00A45078 /* utf8.cpp */, + 0F75F39C2A6B1A8C00A45078 /* utf8api.cpp */, + 0F75F39F2A6B1A8C00A45078 /* Utility.cpp */, + 0F75F3972A6B1A8C00A45078 /* win32_misc.h */, + ); + name = Source; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 0F75F3782A6B1A3900A45078 /* shared */ = { + isa = PBXNativeTarget; + buildConfigurationList = 0F75F3822A6B1A3900A45078 /* Build configuration list for PBXNativeTarget "shared" */; + buildPhases = ( + 0F75F3752A6B1A3900A45078 /* Sources */, + 0F75F3762A6B1A3900A45078 /* Frameworks */, + 0F75F3772A6B1A3900A45078 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = shared; + productName = shared; + productReference = 0F75F3792A6B1A3900A45078 /* libshared.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 0F75F3712A6B1A3900A45078 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1250; + TargetAttributes = { + 0F75F3782A6B1A3900A45078 = { + CreatedOnToolsVersion = 12.5.1; + }; + }; + }; + buildConfigurationList = 0F75F3742A6B1A3900A45078 /* Build configuration list for PBXProject "shared" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 0F75F3702A6B1A3900A45078; + productRefGroup = 0F75F37A2A6B1A3900A45078 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 0F75F3782A6B1A3900A45078 /* shared */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 0F75F3752A6B1A3900A45078 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0F75F3B02A6B1A8C00A45078 /* audio_math.cpp in Sources */, + 0F75F3AE2A6B1A8C00A45078 /* shared-nix.cpp in Sources */, + 0F75F3AB2A6B1A8C00A45078 /* shared-apple.mm in Sources */, + 0F75F3A72A6B1A8C00A45078 /* stdafx.cpp in Sources */, + 0F75F3AC2A6B1A8C00A45078 /* utf8.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 0F75F3802A6B1A3900A45078 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = shared.h; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + ../.., + .., + ); + IPHONEOS_DEPLOYMENT_TARGET = 14.5; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + 0F75F3812A6B1A3900A45078 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = shared.h; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + ../.., + .., + ); + IPHONEOS_DEPLOYMENT_TARGET = 14.5; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = macosx; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 0F75F3832A6B1A3900A45078 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 4S876G9VCD; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 0F75F3842A6B1A3900A45078 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 4S876G9VCD; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 0F75F3742A6B1A3900A45078 /* Build configuration list for PBXProject "shared" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0F75F3802A6B1A3900A45078 /* Debug */, + 0F75F3812A6B1A3900A45078 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 0F75F3822A6B1A3900A45078 /* Build configuration list for PBXNativeTarget "shared" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0F75F3832A6B1A3900A45078 /* Debug */, + 0F75F3842A6B1A3900A45078 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 0F75F3712A6B1A3900A45078 /* Project object */; +} diff --git a/sdk/foobar2000/shared/stdafx.cpp b/sdk/foobar2000/shared/stdafx.cpp new file mode 100644 index 0000000..a036ba6 --- /dev/null +++ b/sdk/foobar2000/shared/stdafx.cpp @@ -0,0 +1 @@ +#include "shared.h" \ No newline at end of file diff --git a/sdk/foobar2000/shared/systray.cpp b/sdk/foobar2000/shared/systray.cpp new file mode 100644 index 0000000..3c5e047 --- /dev/null +++ b/sdk/foobar2000/shared/systray.cpp @@ -0,0 +1,108 @@ +#include "shared.h" +#include + +void SHARED_EXPORT uFixAmpersandChars(const char * src,pfc::string_base & out) +{ + out.reset(); + while(*src) + { + if (*src=='&') + { + out.add_string("&&&"); + src++; + while(*src=='&') + { + out.add_string("&&"); + src++; + } + } + else out.add_byte(*(src++)); + } +} + +void SHARED_EXPORT uFixAmpersandChars_v2(const char * src,pfc::string_base & out) +{ + out.reset(); + while(*src) + { + if (*src=='&') + { + out.add_string("&&"); + src++; + } + else out.add_byte(*(src++)); + } +} + +static BOOL run_action(DWORD action,NOTIFYICONDATA * data) +{ + if (Shell_NotifyIcon(action,data)) return TRUE; + if (action==NIM_MODIFY) + { + if (Shell_NotifyIcon(NIM_ADD,data)) return TRUE; + } + return FALSE; +} + +extern "C" +{ + + BOOL SHARED_EXPORT uShellNotifyIcon(DWORD action,HWND wnd,UINT id,UINT callbackmsg,HICON icon,const char * tip) + { + NOTIFYICONDATA nid = {}; + nid.cbSize = sizeof(nid); + nid.hWnd = wnd; + nid.uID = id; + nid.uFlags = 0; + if (callbackmsg) + { + nid.uFlags |= NIF_MESSAGE; + nid.uCallbackMessage = callbackmsg; + } + if (icon) + { + nid.uFlags |= NIF_ICON; + nid.hIcon = icon; + } + if (tip) + { + nid.uFlags |= NIF_TIP; + pfc::stringToBuffer(nid.szTip,pfc::stringcvt::string_os_from_utf8(tip)); + } + + return run_action(action,&nid); + } + + BOOL SHARED_EXPORT uShellNotifyIconEx(DWORD action,HWND wnd,UINT id,UINT callbackmsg,HICON icon,const char * tip,const char * balloon_title,const char * balloon_msg) + { + NOTIFYICONDATA nid = {}; + nid.cbSize = sizeof(nid); + nid.hWnd = wnd; + nid.uID = id; + if (callbackmsg) + { + nid.uFlags |= NIF_MESSAGE; + nid.uCallbackMessage = callbackmsg; + } + if (icon) + { + nid.uFlags |= NIF_ICON; + nid.hIcon = icon; + } + if (tip) + { + nid.uFlags |= NIF_TIP; + pfc::stringToBuffer(nid.szTip,pfc::stringcvt::string_os_from_utf8(tip)); + } + + nid.dwInfoFlags = NIIF_INFO | NIIF_NOSOUND; + //if (balloon_title || balloon_msg) + { + nid.uFlags |= NIF_INFO; + if (balloon_title) pfc::stringToBuffer(nid.szInfoTitle,pfc::stringcvt::string_os_from_utf8(balloon_title)); + if (balloon_msg) pfc::stringToBuffer(nid.szInfo,pfc::stringcvt::string_os_from_utf8(balloon_msg)); + } + return run_action(action,&nid); + } + +}//extern "C" diff --git a/sdk/foobar2000/shared/text_drawing.cpp b/sdk/foobar2000/shared/text_drawing.cpp new file mode 100644 index 0000000..a728614 --- /dev/null +++ b/sdk/foobar2000/shared/text_drawing.cpp @@ -0,0 +1,230 @@ +#include "shared.h" + + +static bool is_rect_null(const RECT * r) +{ + return r->right <= r->left || r->bottom <= r->top; +} + +UINT SHARED_EXPORT uGetTextHeight(HDC dc) +{ + TEXTMETRIC tm; + POINT pt[2]; + GetTextMetrics(dc,&tm); + pt[0].x = 0; + pt[0].y = tm.tmHeight; + pt[1].x = 0; + pt[1].y = 0; + LPtoDP(dc,pt,2); + + int ret = pt[0].y - pt[1].y; + return ret > 1 ? (unsigned)ret : 1; +} + +static int get_text_width(HDC dc,const TCHAR * src,int len) +{ + if (len<=0) return 0; + else + { + SIZE goatse; + GetTextExtentPoint32(dc,src,len,&goatse); + return goatse.cx; + } +} + +//GetTextExtentPoint32 wrapper, removes color marks +static int get_text_width_color(HDC dc,const TCHAR * src,int len) +{ + int ptr = 0; + int start = 0; + int rv = 0; + if (len<0) len = (int) _tcslen(src); + while(ptrright<=pos_x || clip->bottom<=pos_y) return TRUE; + } + SetTextAlign(dc,TA_LEFT); + SetBkMode(dc,TRANSPARENT); + SetTextColor(dc,selected ? 0xFFFFFF - default_color : default_color); + + int title_ptr = 0; + int textout_start = 0; + int position = pos_x;//item.left+BORDER; + + for(;;) + { + if (title_ptr>=len || src[title_ptr]==3) + { + if (title_ptr>textout_start) + { + int width = get_text_width(dc,src+textout_start,title_ptr-textout_start); + ExtTextOut(dc,position,pos_y,clip ? ETO_CLIPPED : 0,clip,src+textout_start,title_ptr-textout_start,0); + position += width; + textout_start = title_ptr; + } + if (title_ptr>=len) break; + } + if (src[title_ptr]==3) + { + DWORD new_color; + DWORD new_inverted; + bool have_inverted = false; + + if (src[title_ptr+1]==3) {new_color=default_color;title_ptr+=2;} + else + { + title_ptr++; + new_color = _tcstoul(src+title_ptr,0,16); + while(title_ptrtop + (item->bottom-item->top - (int)uGetTextHeight(dc)) / 2; + + int n_tabs = 0; + int total_width = 0; + { + int start = 0; + int n; + for(n=0;nright - item->left; + if (!columns) tab_total -= total_width; + int ptr = display_len; + int tab_ptr = 0; + int written = 0; + int clip_x = item->right; + do + { + int ptr_end = ptr; + while(ptr>0 && display[ptr-1]!='\t') ptr--; + const TCHAR * t_string = display + ptr; + int t_length = ptr_end - ptr; + if (t_length>0) + { + int t_width = get_text_width_color(dc,t_string,t_length) + border*2; + + int pos_x; + int pos_x_right; + + if (!columns) + { + pos_x_right = item->right - MulDiv(tab_ptr,tab_total,n_tabs) - written; + } + else + { + if (tab_ptr==0) pos_x_right = item->right; + else pos_x_right = item->right - MulDiv(tab_ptr,tab_total,n_tabs) + t_width; + } + + if (ptr==0) + { + pos_x = item->left; + } + else + { + pos_x = pos_x_right - t_width ; + if (pos_xleft) pos_x = item->left; + } + + RECT t_clip = clip; + + if (t_clip.right > clip_x) t_clip.right = clip_x; + + text_out_colors(dc,t_string,t_length,pos_x+border,pos_y,&t_clip,selected,default_color); + + if (clip_x>pos_x) clip_x = pos_x; + + written += t_width; + } + + if (ptr>0) + { + ptr--;//tab char + tab_ptr++; + } + } + while(ptr>0); + + return TRUE; +} + +extern "C" { + +BOOL SHARED_EXPORT uTextOutColors(HDC dc,const char * p_text,UINT len,int x,int y,const RECT * clip,BOOL is_selected,DWORD default_color) +{ + try { + pfc::stringcvt::string_os_from_utf8 temp(p_text); + return text_out_colors(dc,temp,pfc::downcast_guarded(temp.length()),x,y,clip,!!is_selected,default_color); + } catch(...) {return FALSE;} +} + +BOOL SHARED_EXPORT uTextOutColorsTabbed(HDC dc,const char * p_text,UINT len,const RECT * item,int border,const RECT * clip,BOOL selected,DWORD default_color,BOOL use_columns) +{ + try { + pfc::stringcvt::string_os_from_utf8 temp(p_text); + return text_out_colors_tab(dc,temp,pfc::downcast_guarded(temp.length()),item,border,clip,!!selected,default_color,!!use_columns); + } catch(...) {return FALSE;} +} + +} \ No newline at end of file diff --git a/sdk/foobar2000/shared/utf8.cpp b/sdk/foobar2000/shared/utf8.cpp new file mode 100644 index 0000000..18f8793 --- /dev/null +++ b/sdk/foobar2000/shared/utf8.cpp @@ -0,0 +1,226 @@ +#include "shared.h" + +#include + +using namespace pfc; + +extern "C" { + +#if 0 +inline static unsigned q_tolower(unsigned c) +{ + if (c>='A' && c<='Z') c += 'a' - 'A'; + return c; +} +#else +static const t_uint8 ascii_tolower_table[128] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x5B,0x5C,0x5D,0x5E,0x5F,0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F}; +#define q_tolower(c) ascii_tolower_table[(unsigned)c] +#endif + + +unsigned SHARED_EXPORT uCharLower(unsigned param) +{ + return pfc::charLower(param); +} + +unsigned SHARED_EXPORT uCharUpper(unsigned param) +{ + return pfc::charUpper(param); +} + +static inline int compare_wchar(unsigned c1,unsigned c2) throw() +{ + if (c1==c2) return 0; + c1 = pfc::charLower(c1); + c2 = pfc::charLower(c2); + if (c1c2) return 1; + else return 0; +} + + +int SHARED_EXPORT stricmp_utf8(const char * p1,const char * p2) throw() +{ + for(;;) + { + if (*p1>=0 && *p2>=0)//signed char + { + unsigned c1 = q_tolower(*p1), c2 = q_tolower(*p2); + if (c1c2) return 1; + else if (c1 == 0) return 0; + else + { + p1++; + p2++; + } + } + else + { + unsigned w1,w2; t_size d1,d2; + d1 = utf8_decode_char(p1,w1); + d2 = utf8_decode_char(p2,w2); + if (d1 == 0 && d2 == 0) return 0; + else if (d1==0) return -1; + else if (d2==0) return 1; + int rv = compare_wchar(w1,w2); + if (rv) return rv; + p1 += d1; + p2 += d2; + } + } +} + +int SHARED_EXPORT stricmp_utf8_stringtoblock(const char * p1,const char * p2,t_size p2_bytes) throw() +{ + return stricmp_utf8_ex(p1,-1,p2,p2_bytes); +} + +int SHARED_EXPORT stricmp_utf8_partial(const char * p1,const char * p2,t_size num) throw() +{ + for(;num;) + { + unsigned w1,w2; t_size d1,d2; + d1 = utf8_decode_char(p1,w1); + d2 = utf8_decode_char(p2,w2); + if (w2==0 || d2==0) return 0; + int rv = compare_wchar(w1,w2); + if (rv) return rv; + p1 += d1; + p2 += d2; + num--; + } + return 0; +} + +int SHARED_EXPORT stricmp_utf8_max(const char * p1,const char * p2,t_size p1_bytes) throw() +{ + return stricmp_utf8_ex(p1,p1_bytes,p2,-1); +} + +namespace { + typedef bool (*t_replace_test)(const char * src,const char * test,t_size len); + + static bool replace_test_i(const char * src,const char * test,t_size len) + { + return stricmp_utf8_max(src,test,len)==0; + } + + static bool replace_test(const char * src,const char * test,t_size len) + { + t_size ptr; + bool rv = true; + for(ptr=0;ptr0) + { + t_size ptr = 0; + while(ptr+len1<=len) + { + if (testfunc(src+ptr,s1,len1)) + { + count++; + out.add_string(s2,len2); + ptr += len1; + } + else out.add_byte(src[ptr++]); + } + if (ptr0); + assert(c2>0); + char s1[8],s2[8]; + t_size len1,len2; + len1 = utf8_encode_char(c1,s1); + len2 = utf8_encode_char(c2,s2); + return uReplaceString(out,src,src_len,s1,len1,s2,len2,casesens); +} + + +void SHARED_EXPORT uAddStringLower(string_base & out,const char * src,t_size len) +{ + while(len && *src) + { + unsigned c; t_size d; + d = utf8_decode_char(src,c,len); + if (d==0 || d>len) break; + out.add_char(uCharLower(c)); + src+=d; + len-=d; + } +} + +void SHARED_EXPORT uAddStringUpper(string_base & out,const char * src,t_size len) +{ + while(len && *src) + { + unsigned c; t_size d; + d = utf8_decode_char(src,c,len); + if (d==0 || d>len) break; + out.add_char(uCharUpper(c)); + src+=d; + len-=d; + } +} + +int SHARED_EXPORT stricmp_utf8_ex(const char * p1,t_size p1_bytes,const char * p2,t_size p2_bytes) throw() +{ + p1_bytes = strlen_max(p1,p1_bytes); + p2_bytes = strlen_max(p2,p2_bytes); + for(;;) + { + if (p1_bytes == 0 && p2_bytes == 0) return 0; + else if (p1_bytes == 0) return -1; + else if (p2_bytes == 0) return 1; + else if (*p1>0 && *p2>0)//signed char + { + unsigned c1 = q_tolower(*p1), c2 = q_tolower(*p2); + if (c1c2) return 1; + else + { + p1++; + p2++; + p1_bytes--; + p2_bytes--; + } + } + else + { + unsigned w1,w2; + auto d1 = utf8_decode_char(p1,w1,p1_bytes); + auto d2 = utf8_decode_char(p2,w2,p2_bytes); + if (d1==0) return -1; + if (d2==0) return 1; + int rv = compare_wchar(w1,w2); + if (rv) return rv; + p1 += d1; + p2 += d2; + p1_bytes -= d1; + p2_bytes -= d2; + } + } +} + +} diff --git a/sdk/foobar2000/shared/utf8api.cpp b/sdk/foobar2000/shared/utf8api.cpp new file mode 100644 index 0000000..2471b87 --- /dev/null +++ b/sdk/foobar2000/shared/utf8api.cpp @@ -0,0 +1,1186 @@ +#include "shared.h" + + +#include + +#ifndef BIF_NEWDIALOGSTYLE +#define BIF_NEWDIALOGSTYLE 0x0040 +#endif + +using namespace pfc; + +class param_os_from_utf8 +{ + bool m_is_null; + WORD m_low_word; + stringcvt::string_os_from_utf8 m_cvt; +public: + param_os_from_utf8(const char * p) : + m_is_null(p==NULL), + m_low_word( ((t_size)p & ~0xFFFF) == 0 ? (WORD)((t_size)p & 0xFFFF) : 0), + m_cvt( p != NULL && ((t_size)p & ~0xFFFF) != 0 ? p : "") + {} + operator const TCHAR *() + { + return get_ptr(); + } + const TCHAR * get_ptr() + { + return m_low_word ? (const TCHAR*)(t_size)m_low_word : m_is_null ? 0 : m_cvt.get_ptr(); + } + +}; + + + +extern "C" { + +LRESULT SHARED_EXPORT uSendMessageText(HWND wnd,UINT msg,WPARAM wp,const char * p_text) +{ + if (p_text == NULL) + return SendMessage(wnd,msg,wp,0); + else { + stringcvt::string_os_from_utf8 temp; + temp.convert(p_text); + return SendMessage(wnd,msg,wp,(LPARAM)temp.get_ptr()); + } +} + +LRESULT SHARED_EXPORT uSendDlgItemMessageText(HWND wnd,UINT id,UINT msg,WPARAM wp,const char * text) +{ + return uSendMessageText(uGetDlgItem(wnd,id),msg,wp,text);//SendDlgItemMessage(wnd,id,msg,wp,(long)(const TCHAR*)string_os_from_utf8(text)); +} + +BOOL SHARED_EXPORT uGetWindowText(HWND wnd,string_base & out) +{ + PFC_ASSERT( wnd != NULL ); + int len = GetWindowTextLength(wnd); + if (len>0) + { + len++; + pfc::array_t temp; + temp.set_size(len); + temp[0]=0; + if (GetWindowText(wnd,temp.get_ptr(),len)>0) + { + out = stringcvt::string_utf8_from_os(temp.get_ptr(),len); + return TRUE; + } + else return FALSE; + } + else + { + out.reset(); + return TRUE; + } +} + +BOOL SHARED_EXPORT uSetWindowTextEx(HWND wnd,const char * p_text,size_t p_text_length) +{ + return SetWindowText(wnd,stringcvt::string_os_from_utf8(p_text, p_text_length)); +} + + +BOOL SHARED_EXPORT uGetDlgItemText(HWND wnd,UINT id,string_base & out) +{ + return uGetWindowText(GetDlgItem(wnd,id),out); +} + +BOOL SHARED_EXPORT uSetDlgItemTextEx(HWND wnd,UINT id,const char * p_text,size_t p_text_length) +{ + return SetDlgItemText(wnd,id,stringcvt::string_os_from_utf8(p_text,p_text_length)); +} + +int SHARED_EXPORT uMessageBox(HWND wnd,const char * text,const char * caption,UINT type) +{ + modal_dialog_scope scope(wnd); + return MessageBox(wnd,param_os_from_utf8(text),param_os_from_utf8(caption),type); +} + +void SHARED_EXPORT uOutputDebugString(const char * msg) {OutputDebugString(stringcvt::string_os_from_utf8(msg));} + +BOOL SHARED_EXPORT uAppendMenu(HMENU menu,UINT flags,UINT_PTR id,const char * content) +{ + return AppendMenu(menu,flags,id,param_os_from_utf8(content)); +} + +BOOL SHARED_EXPORT uInsertMenu(HMENU menu,UINT position,UINT flags,UINT_PTR id,const char * content) +{ + return InsertMenu(menu,position,flags,id,param_os_from_utf8(content)); +} + +int SHARED_EXPORT uCharCompare(t_uint32 p_char1,t_uint32 p_char2) { +#ifdef UNICODE + wchar_t temp1[4],temp2[4]; + temp1[utf16_encode_char(p_char1,temp1)]=0; + temp2[utf16_encode_char(p_char2,temp2)]=0; + return lstrcmpiW(temp1,temp2); +#else + wchar_t temp1[4],temp2[4]; + char ctemp1[20],ctemp2[20]; + temp1[utf16_encode_char(p_char1,temp1)]=0; + temp2[utf16_encode_char(p_char2,temp2)]=0; + WideCharToMultiByte(CP_ACP,0,temp1,-1,ctemp1,_countof(ctemp1),0,0); + WideCharToMultiByte(CP_ACP,0,temp2,-1,ctemp2,_countof(ctemp2),0,0); + return lstrcmpiA(ctemp1,ctemp2); +#endif +} + +int SHARED_EXPORT uStringCompare(const char * elem1, const char * elem2) { + for(;;) { + unsigned c1,c2; t_size l1,l2; + l1 = utf8_decode_char(elem1,c1); + l2 = utf8_decode_char(elem2,c2); + if (l1==0 && l2==0) return 0; + if (c1!=c2) { + int test = uCharCompare(c1,c2); + if (test) return test; + } + elem1 += l1; + elem2 += l2; + } +} + +int SHARED_EXPORT uStringCompare_ConvertNumbers(const char * elem1,const char * elem2) { + for(;;) { + if (pfc::char_is_numeric(*elem1) && pfc::char_is_numeric(*elem2)) { + t_size delta1 = 1, delta2 = 1; + while(pfc::char_is_numeric(elem1[delta1])) delta1++; + while(pfc::char_is_numeric(elem2[delta2])) delta2++; + int test = pfc::compare_t(pfc::atoui64_ex(elem1,delta1),pfc::atoui64_ex(elem2,delta2)); + if (test != 0) return test; + elem1 += delta1; + elem2 += delta2; + } else { + unsigned c1,c2; t_size l1,l2; + l1 = utf8_decode_char(elem1,c1); + l2 = utf8_decode_char(elem2,c2); + if (l1==0 && l2==0) return 0; + if (c1!=c2) { + int test = uCharCompare(c1,c2); + if (test) return test; + } + elem1 += l1; + elem2 += l2; + } + } +} + +HINSTANCE SHARED_EXPORT uLoadLibrary(const char * name) +{ + return LoadLibrary(param_os_from_utf8(name)); +} + +HANDLE SHARED_EXPORT uCreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes,BOOL bManualReset,BOOL bInitialState, const char * lpName) +{ + return CreateEvent(lpEventAttributes,bManualReset,bInitialState, param_os_from_utf8(lpName)); +} + +DWORD SHARED_EXPORT uGetModuleFileName(HMODULE hMod,string_base & out) +{ + try { + pfc::array_t buffer; buffer.set_size(256); + for(;;) { + DWORD ret = GetModuleFileName(hMod,buffer.get_ptr(), (DWORD)buffer.get_size()); + if (ret == 0) return 0; + if (ret < buffer.get_size()) break; + buffer.set_size(buffer.get_size() * 2); + } + out = stringcvt::string_utf8_from_os(buffer.get_ptr(),buffer.get_size()); + return (DWORD) out.length(); + } catch(...) { + return 0; + } +} + +BOOL SHARED_EXPORT uSetClipboardRawData(UINT format,const void * ptr,t_size size) { + try { + HANDLE buffer = GlobalAlloc(GMEM_DDESHARE,size); + if (buffer == NULL) throw std::bad_alloc(); + try { + CGlobalLockScope lock(buffer); + PFC_ASSERT(lock.GetSize() == size); + memcpy(lock.GetPtr(),ptr,size); + } catch(...) { + GlobalFree(buffer); throw; + } + + if (SetClipboardData(format,buffer) == NULL) throw pfc::exception_bug_check(); + return TRUE; + } catch(...) { + return FALSE; + } +} +BOOL SHARED_EXPORT uSetClipboardString(const char * ptr) +{ + try { + CClipboardOpenScope scope; + if (!scope.Open(NULL)) return FALSE; + EmptyClipboard(); + stringcvt::string_os_from_utf8 temp(ptr); + return uSetClipboardRawData( + #ifdef UNICODE + CF_UNICODETEXT + #else + CF_TEXT + #endif + ,temp.get_ptr(), (temp.length() + 1) * sizeof(TCHAR)); + } catch(...) { + return FALSE; + } +} + +BOOL SHARED_EXPORT uGetClipboardString(pfc::string_base & p_out) { + try { + CClipboardOpenScope scope; + if (!scope.Open(NULL)) return FALSE; + HANDLE data = GetClipboardData( + #ifdef UNICODE + CF_UNICODETEXT + #else + CF_TEXT + #endif + ); + if (data == NULL) return FALSE; + + CGlobalLockScope lock(data); + p_out = pfc::stringcvt::string_utf8_from_os( (const TCHAR*) lock.GetPtr(), lock.GetSize() / sizeof(TCHAR) ); + return TRUE; + } catch(...) { + return FALSE; + } +} + + +BOOL SHARED_EXPORT uGetClassName(HWND wnd,string_base & out) +{ + TCHAR temp[512]; + temp[0]=0; + if (GetClassName(wnd,temp,_countof(temp))>0) + { + out = stringcvt::string_utf8_from_os(temp,_countof(temp)); + return TRUE; + } + else return FALSE; +} + +t_size SHARED_EXPORT uCharLength(const char * src) {return utf8_char_len(src);} + +BOOL SHARED_EXPORT uDragQueryFile(HDROP hDrop,UINT idx,string_base & out) +{ + UINT len = DragQueryFile(hDrop,idx,0,0); + if (len>0 && len!=(UINT)(~0)) + { + len++; + array_t temp; + temp.set_size(len); + temp[0] =0 ; + if (DragQueryFile(hDrop,idx,temp.get_ptr(),len)>0) + { + out = stringcvt::string_utf8_from_os(temp.get_ptr(),len); + return TRUE; + } + } + return FALSE; +} + +UINT SHARED_EXPORT uDragQueryFileCount(HDROP hDrop) +{ + return DragQueryFile(hDrop,-1,0,0); +} + + + +BOOL SHARED_EXPORT uGetTextExtentPoint32(HDC dc,const char * text,UINT cb,LPSIZE size) +{ + stringcvt::string_os_from_utf8 temp(text,cb); + return GetTextExtentPoint32(dc,temp,pfc::downcast_guarded(temp.length()),size); +} + +BOOL SHARED_EXPORT uExtTextOut(HDC dc,int x,int y,UINT flags,const RECT * rect,const char * text,UINT cb,const int * lpdx) +{ + stringcvt::string_os_from_utf8 temp(text,cb); + return ExtTextOut(dc,x,y,flags,rect,temp,pfc::downcast_guarded(_tcslen(temp)),lpdx); +} + +static UINT_PTR CALLBACK choose_color_hook(HWND wnd,UINT msg,WPARAM wp,LPARAM lp) +{ + switch(msg) + { + case WM_INITDIALOG: + { + CHOOSECOLOR * cc = reinterpret_cast(lp); + reinterpret_cast(cc->lCustData)->initialize(FindOwningPopup(wnd)); + } + return 0; + default: + return 0; + } +} + +BOOL SHARED_EXPORT uChooseColor(DWORD * p_color,HWND parent,DWORD * p_custom_colors) +{ + modal_dialog_scope scope; + + CHOOSECOLOR cc = {}; + cc.lStructSize = sizeof(cc); + cc.hwndOwner = parent; + cc.rgbResult = *p_color; + cc.lpCustColors = p_custom_colors; + cc.Flags = CC_ANYCOLOR|CC_FULLOPEN|CC_RGBINIT|CC_ENABLEHOOK; + cc.lpfnHook = choose_color_hook; + cc.lCustData = reinterpret_cast(&scope); + BOOL rv = ChooseColor(&cc); + if (rv) + { + *p_color = cc.rgbResult; + return TRUE; + } + else return FALSE; +} + +HCURSOR SHARED_EXPORT uLoadCursor(HINSTANCE hIns,const char * name) +{ + return LoadCursor(hIns,param_os_from_utf8(name)); +} + +HICON SHARED_EXPORT uLoadIcon(HINSTANCE hIns,const char * name) +{ + return LoadIcon(hIns,param_os_from_utf8(name)); +} + +HMENU SHARED_EXPORT uLoadMenu(HINSTANCE hIns,const char * name) +{ + return LoadMenu(hIns,param_os_from_utf8(name)); +} + + + +BOOL SHARED_EXPORT uGetEnvironmentVariable(const char * name,string_base & out) +{ + stringcvt::string_os_from_utf8 name_t(name); + DWORD size = GetEnvironmentVariable(name_t,0,0); + if (size>0) + { + size++; + array_t temp; + temp.set_size(size); + temp[0]=0; + if (GetEnvironmentVariable(name_t,temp.get_ptr(),size)>0) + { + out = stringcvt::string_utf8_from_os(temp.get_ptr(),size); + return TRUE; + } + } + return FALSE; +} + +HMODULE SHARED_EXPORT uGetModuleHandle(const char * name) +{ + return GetModuleHandle(param_os_from_utf8(name)); +} + +UINT SHARED_EXPORT uRegisterWindowMessage(const char * name) +{ + return RegisterWindowMessage(stringcvt::string_os_from_utf8(name)); +} + +BOOL SHARED_EXPORT uMoveFile(const char * src,const char * dst) +{ + return MoveFile(stringcvt::string_os_from_utf8(src),stringcvt::string_os_from_utf8(dst)); +} + +BOOL SHARED_EXPORT uDeleteFile(const char * fn) +{ + return DeleteFile(stringcvt::string_os_from_utf8(fn)); +} + +DWORD SHARED_EXPORT uGetFileAttributes(const char * fn) +{ + PFC_ASSERT( ! pfc::string_has_prefix_i( fn, "file://" ) ); + return GetFileAttributes(stringcvt::string_os_from_utf8(fn)); +} + +BOOL SHARED_EXPORT uRemoveDirectory(const char * fn) +{ + return RemoveDirectory(stringcvt::string_os_from_utf8(fn)); +} + +HANDLE SHARED_EXPORT uCreateFile(const char * fn,DWORD access,DWORD share,LPSECURITY_ATTRIBUTES blah,DWORD creat,DWORD flags,HANDLE tmpl) +{ + return CreateFile(stringcvt::string_os_from_utf8(fn),access,share,blah,creat,flags,tmpl); +} + +BOOL SHARED_EXPORT uCreateDirectory(const char * fn,LPSECURITY_ATTRIBUTES blah) +{ + return CreateDirectory(stringcvt::string_os_from_utf8(fn),blah); +} + +HANDLE SHARED_EXPORT uCreateMutex(LPSECURITY_ATTRIBUTES blah,BOOL bInitialOwner,const char * name) +{ + return name ? CreateMutex(blah,bInitialOwner,stringcvt::string_os_from_utf8(name)) : CreateMutex(blah,bInitialOwner,0); +} + +BOOL SHARED_EXPORT uGetFullPathName(const char * name,string_base & out) +{ + stringcvt::string_os_from_utf8 name_os(name); + unsigned len = GetFullPathName(name_os,0,0,0); + if (len==0) return FALSE; + array_t temp; + temp.set_size(len+1); + TCHAR * blah; + if (GetFullPathName(name_os,len+1,temp.get_ptr(),&blah)==0) return FALSE; + out = stringcvt::string_utf8_from_os(temp.get_ptr(),len); + return TRUE; +} + +BOOL SHARED_EXPORT uGetLongPathName(const char * name,string_base & out) +{ + TCHAR temp[4096]; + temp[0]=0; + BOOL state = GetLongPathName(stringcvt::string_os_from_utf8(name),temp,_countof(temp)); + if (state) out = stringcvt::string_utf8_from_os(temp,_countof(temp)); + return state; +} + +void SHARED_EXPORT uGetCommandLine(string_base & out) +{ + out = stringcvt::string_utf8_from_os(GetCommandLine()); +} + +BOOL SHARED_EXPORT uGetTempPath(string_base & out) +{ + TCHAR temp[MAX_PATH+1]; + temp[0]=0; + if (GetTempPath(_countof(temp),temp)) + { + out = stringcvt::string_utf8_from_os(temp,_countof(temp)); + return TRUE; + } + return FALSE; + +} +BOOL SHARED_EXPORT uGetTempFileName(const char * path_name,const char * prefix,UINT unique,string_base & out) +{ + if (path_name==0 || prefix==0) return FALSE; + TCHAR temp[MAX_PATH+1]; + temp[0]=0; + if (GetTempFileName(stringcvt::string_os_from_utf8(path_name),stringcvt::string_os_from_utf8(prefix),unique,temp)) + { + out = stringcvt::string_utf8_from_os(temp,_countof(temp)); + return TRUE; + } + return FALSE; +} + +class uFindFile_i : public uFindFile +{ + string8 fn; + WIN32_FIND_DATA fd; + HANDLE hFF; +public: + uFindFile_i() {hFF = INVALID_HANDLE_VALUE;} + bool FindFirst(const char * path) + { + hFF = FindFirstFile(stringcvt::string_os_from_utf8(path),&fd); + if (hFF==INVALID_HANDLE_VALUE) return false; + fn = stringcvt::string_utf8_from_os(fd.cFileName,_countof(fd.cFileName)); + return true; + } + virtual BOOL FindNext() + { + if (hFF==INVALID_HANDLE_VALUE) return FALSE; + BOOL rv = FindNextFile(hFF,&fd); + if (rv) fn = stringcvt::string_utf8_from_os(fd.cFileName,_countof(fd.cFileName)); + return rv; + } + + virtual const char * GetFileName() + { + return fn; + } + + virtual t_uint64 GetFileSize() + { + union + { + t_uint64 val64; + struct + { + DWORD lo,hi; + }; + } ret; + + ret.hi = fd.nFileSizeHigh; + ret.lo = fd.nFileSizeLow; + return ret.val64; + + } + virtual DWORD GetAttributes() + { + return fd.dwFileAttributes; + } + + virtual FILETIME GetCreationTime() + { + return fd.ftCreationTime; + } + virtual FILETIME GetLastAccessTime() + { + return fd.ftLastAccessTime; + } + virtual FILETIME GetLastWriteTime() + { + return fd.ftLastWriteTime; + } + virtual ~uFindFile_i() + { + if (hFF!=INVALID_HANDLE_VALUE) FindClose(hFF); + } +}; + +puFindFile SHARED_EXPORT uFindFirstFile(const char * path) +{ + pfc::ptrholder_t ptr = new uFindFile_i; + if (!ptr->FindFirst(path)) { + ptr.release(); + return NULL; + } else { + return ptr.detach(); + } +} + +HINSTANCE SHARED_EXPORT uShellExecute(HWND wnd,const char * oper,const char * file,const char * params,const char * dir,int cmd) +{ + modal_dialog_scope modal; // IDIOCY - ShellExecute may spawn a modal dialog + if (wnd) modal.initialize(wnd); + return ShellExecute(wnd,param_os_from_utf8(oper),param_os_from_utf8(file),param_os_from_utf8(params),param_os_from_utf8(dir),cmd); +} + +HWND SHARED_EXPORT uCreateStatusWindow(LONG style,const char * text,HWND parent,UINT id) +{ + return CreateStatusWindow(style,param_os_from_utf8(text),parent,id); +} + +HWND SHARED_EXPORT uCreateWindowEx(DWORD dwExStyle,const char * lpClassName,const char * lpWindowName,DWORD dwStyle,int x,int y,int nWidth,int nHeight,HWND hWndParent,HMENU hMenu,HINSTANCE hInstance,LPVOID lpParam) +{ + return CreateWindowEx(dwExStyle,param_os_from_utf8(lpClassName),param_os_from_utf8(lpWindowName),dwStyle,x,y,nWidth,nHeight,hWndParent,hMenu,hInstance,lpParam); +} + +HANDLE SHARED_EXPORT uLoadImage(HINSTANCE hIns,const char * name,UINT type,int x,int y,UINT flags) +{ + return LoadImage(hIns,param_os_from_utf8(name),type,x,y,flags); +} + +BOOL SHARED_EXPORT uGetSystemDirectory(string_base & out) +{ + UINT len = GetSystemDirectory(0,0); + if (len==0) len = MAX_PATH; + len++; + array_t temp; + temp.set_size(len); + if (GetSystemDirectory(temp.get_ptr(),len)==0) return FALSE; + out = stringcvt::string_utf8_from_os(temp.get_ptr(),len); + return TRUE; +} + +BOOL SHARED_EXPORT uGetWindowsDirectory(string_base & out) +{ + UINT len = GetWindowsDirectory(0,0); + if (len==0) len = MAX_PATH; + len++; + array_t temp; + temp.set_size(len); + if (GetWindowsDirectory(temp.get_ptr(),len)==0) return FALSE; + out = stringcvt::string_utf8_from_os(temp.get_ptr(),len); + return TRUE; +} + +BOOL SHARED_EXPORT uSetCurrentDirectory(const char * path) +{ + return SetCurrentDirectory(stringcvt::string_os_from_utf8(path)); +} + +BOOL SHARED_EXPORT uGetCurrentDirectory(string_base & out) +{ + UINT len = GetCurrentDirectory(0,0); + if (len==0) len = MAX_PATH; + len++; + array_t temp; + temp.set_size(len); + if (GetCurrentDirectory(len,temp.get_ptr())==0) return FALSE; + out = stringcvt::string_utf8_from_os(temp.get_ptr(),len); + return TRUE; +} + +BOOL SHARED_EXPORT uExpandEnvironmentStrings(const char * src,string_base & out) +{ + stringcvt::string_os_from_utf8 src_os(src); + UINT len = ExpandEnvironmentStrings(src_os,0,0); + if (len==0) len = 256; + len++; + array_t temp; + temp.set_size(len); + if (ExpandEnvironmentStrings(src_os,temp.get_ptr(),len)==0) return FALSE; + out = stringcvt::string_utf8_from_os(temp.get_ptr(),len); + return TRUE; +} + +BOOL SHARED_EXPORT uGetUserName(string_base & out) +{ + TCHAR temp[UNLEN+1]; + DWORD len = _countof(temp); + if (GetUserName(temp,&len)) + { + out = stringcvt::string_utf8_from_os(temp,_countof(temp)); + return TRUE; + } + else return FALSE; +} + +BOOL SHARED_EXPORT uGetShortPathName(const char * src,string_base & out) +{ + stringcvt::string_os_from_utf8 src_os(src); + UINT len = GetShortPathName(src_os,0,0); + if (len==0) len = MAX_PATH; + len++; + array_t temp; temp.set_size(len); + if (GetShortPathName(src_os,temp.get_ptr(),len)) + { + out = stringcvt::string_utf8_from_os(temp.get_ptr(),len); + return TRUE; + } + else return FALSE; +} + + +#ifdef UNICODE +#define DDE_CODEPAGE CP_WINUNICODE +#else +#define DDE_CODEPAGE CP_WINANSI +#endif + + +HSZ SHARED_EXPORT uDdeCreateStringHandle(DWORD ins,const char * src) +{ + return DdeCreateStringHandle(ins,stringcvt::string_os_from_utf8(src),DDE_CODEPAGE); +} + +BOOL SHARED_EXPORT uDdeQueryString(DWORD ins,HSZ hsz,string_base & out) +{ + array_t temp; + UINT len = DdeQueryString(ins,hsz,0,0,DDE_CODEPAGE); + if (len==0) len = MAX_PATH; + len++; + temp.set_size(len); + if (DdeQueryString(ins,hsz,temp.get_ptr(),len,DDE_CODEPAGE)) + { + out = stringcvt::string_utf8_from_os(temp.get_ptr(),len); + return TRUE; + } + else return FALSE; +} + +UINT SHARED_EXPORT uDdeInitialize(LPDWORD pidInst,PFNCALLBACK pfnCallback,DWORD afCmd,DWORD ulRes) +{ + return DdeInitialize(pidInst,pfnCallback,afCmd,ulRes); +} + +BOOL SHARED_EXPORT uDdeAccessData_Text(HDDEDATA data,string_base & out) +{ + const TCHAR * ptr = (const TCHAR*) DdeAccessData(data,0); + if (ptr) + { + out = stringcvt::string_utf8_from_os(ptr); + return TRUE; + } + else return FALSE; +} + +uSortString_t SHARED_EXPORT uSortStringCreate(const char * src) { + t_size lenEst = pfc::stringcvt::estimate_utf8_to_wide(src,SIZE_MAX); + TCHAR * ret = pfc::__raw_malloc_t(lenEst); + pfc::stringcvt::convert_utf8_to_wide(ret,lenEst,src,SIZE_MAX); + return reinterpret_cast( ret ); +} + +int SHARED_EXPORT uSortStringCompareEx(uSortString_t string1, uSortString_t string2,uint32_t flags) { + return CompareString(LOCALE_USER_DEFAULT,flags,reinterpret_cast(string1),-1,reinterpret_cast(string2),-1); +} + +int SHARED_EXPORT uSortStringCompare(uSortString_t string1, uSortString_t string2) { + return lstrcmpi(reinterpret_cast(string1),reinterpret_cast(string2)); +} + +void SHARED_EXPORT uSortStringFree(uSortString_t string) { + pfc::__raw_free_t(reinterpret_cast(string)); +} + +HTREEITEM SHARED_EXPORT uTreeView_InsertItem(HWND wnd,const uTVINSERTSTRUCT * param) +{ + stringcvt::string_os_from_utf8 temp; + temp.convert(param->item.pszText); + + + TVINSERTSTRUCT l_param = {}; + l_param.hParent = param->hParent; + l_param.hInsertAfter = param->hInsertAfter; + l_param.item.mask = param->item.mask; + l_param.item.hItem = param->item.hItem; + l_param.item.state = param->item.state; + l_param.item.stateMask = param->item.stateMask; + l_param.item.pszText = const_cast(temp.get_ptr()); + l_param.item.cchTextMax = 0; + l_param.item.iImage = param->item.iImage; + l_param.item.iSelectedImage = param->item.iImage; + l_param.item.cChildren = param->item.cChildren; + l_param.item.lParam = param->item.lParam; + if (param->item.mask & TVIF_INTEGRAL) + { + l_param.itemex.iIntegral = param->itemex.iIntegral; + } + + return (HTREEITEM) uSendMessage(wnd,TVM_INSERTITEM,0,(LPARAM)&l_param); +} + +UINT SHARED_EXPORT uGetFontHeight(HFONT font) +{ + UINT ret; + HDC dc = CreateCompatibleDC(0); + SelectObject(dc,font); + ret = uGetTextHeight(dc); + DeleteDC(dc); + return ret; +} + + +HIMAGELIST SHARED_EXPORT uImageList_LoadImage(HINSTANCE hi, const char * lpbmp, int cx, int cGrow, COLORREF crMask, UINT uType, UINT uFlags) +{ + return ImageList_LoadImage(hi,param_os_from_utf8(lpbmp),cx,cGrow,crMask,uType,uFlags); +} + +int SHARED_EXPORT uTabCtrl_InsertItem(HWND wnd,t_size idx,const uTCITEM * item) +{ + param_os_from_utf8 text((item->mask & TCIF_TEXT) ? item->pszText : 0); + TCITEM l_item; + assert(sizeof(l_item)==sizeof(*item));//meh lazy + memcpy(&l_item,item,sizeof(l_item)); + l_item.pszText = const_cast(text.get_ptr()); + l_item.cchTextMax = 0; + return TabCtrl_InsertItem(wnd,idx,&l_item); +} + +int SHARED_EXPORT uTabCtrl_SetItem(HWND wnd,t_size idx,const uTCITEM * item) +{ + param_os_from_utf8 text((item->mask & TCIF_TEXT) ? item->pszText : 0); + TCITEM l_item; + PFC_STATIC_ASSERT(sizeof(l_item)==sizeof(*item));//meh lazy + memcpy(&l_item,item,sizeof(l_item)); + l_item.pszText = const_cast(text.get_ptr()); + l_item.cchTextMax = 0; + return TabCtrl_SetItem(wnd,idx,&l_item); +} + +int SHARED_EXPORT uGetKeyNameText(LONG lparam,string_base & out) +{ + TCHAR temp[256]; + temp[0]=0; + if (!GetKeyNameText(lparam,temp,_countof(temp))) return 0; + out = stringcvt::string_utf8_from_os(temp,_countof(temp)); + return 1; +} + +HANDLE SHARED_EXPORT uCreateFileMapping(HANDLE hFile,LPSECURITY_ATTRIBUTES lpFileMappingAttributes,DWORD flProtect,DWORD dwMaximumSizeHigh,DWORD dwMaximumSizeLow,const char * lpName) +{ + return CreateFileMapping(hFile,lpFileMappingAttributes,flProtect,dwMaximumSizeHigh,dwMaximumSizeLow,param_os_from_utf8(lpName)); +} + +BOOL SHARED_EXPORT uListBox_GetText(HWND listbox,UINT index,string_base & out) +{ + t_size len = uSendMessage(listbox,LB_GETTEXTLEN,index,0); + if (len==LB_ERR || len>16*1024*1024) return FALSE; + if (len==0) {out.reset();return TRUE;} + + array_t temp; temp.set_size(len+1); + pfc::memset_t(temp,(TCHAR)0); + len = uSendMessage(listbox,LB_GETTEXT,index,(LPARAM)temp.get_ptr()); + if (len==LB_ERR) return false; + out = stringcvt::string_utf8_from_os(temp.get_ptr()); + return TRUE; +} +/* +void SHARED_EXPORT uPrintf(string_base & out,const char * fmt,...) +{ + va_list list; + va_start(list,fmt); + uPrintfV(out,fmt,list); + va_end(list); +} +*/ +void SHARED_EXPORT uPrintfV(string_base & out,const char * fmt,va_list arglist) +{ + pfc::string_printf_here_va(out, fmt, arglist); +} + +int SHARED_EXPORT uCompareString(DWORD flags,const char * str1,size_t len1,const char * str2,size_t len2) +{ + return CompareString(LOCALE_USER_DEFAULT,flags,stringcvt::string_os_from_utf8(str1,len1),-1,stringcvt::string_os_from_utf8(str2,len2),-1); +} + +class uResource_i : public uResource +{ + unsigned size; + const void * ptr; +public: + inline uResource_i(const void * p_ptr,unsigned p_size) : ptr(p_ptr), size(p_size) + { + } + virtual const void * GetPointer() + { + return ptr; + } + virtual unsigned GetSize() + { + return size; + } + virtual ~uResource_i() + { + } +}; + +puResource SHARED_EXPORT uLoadResource(HMODULE hMod,const char * name,const char * type,WORD wLang) +{ + HRSRC res = uFindResource(hMod,name,type,wLang); + if (res==0) return 0; + HGLOBAL hglob = LoadResource(hMod,res); + if (hglob) + { + void * ptr = LockResource(hglob); + if (ptr) + { + return new uResource_i(ptr,SizeofResource(hMod,res)); + } + else return 0; + } + else return 0; +} + +puResource SHARED_EXPORT LoadResourceEx(HMODULE hMod,const TCHAR * name,const TCHAR * type,WORD wLang) +{ + HRSRC res = wLang ? FindResourceEx(hMod,type,name,wLang) : FindResource(hMod,name,type); + if (res==0) return 0; + HGLOBAL hglob = LoadResource(hMod,res); + if (hglob) + { + void * ptr = LockResource(hglob); + if (ptr) + { + return new uResource_i(ptr,SizeofResource(hMod,res)); + } + else return 0; + } + else return 0; +} + +HRSRC SHARED_EXPORT uFindResource(HMODULE hMod,const char * name,const char * type,WORD wLang) +{ + return wLang ? FindResourceEx(hMod,param_os_from_utf8(type),param_os_from_utf8(name),wLang) : FindResource(hMod,param_os_from_utf8(name),param_os_from_utf8(type)); +} + +BOOL SHARED_EXPORT uLoadString(HINSTANCE ins,UINT id,string_base & out) +{ + BOOL rv = FALSE; + uResource * res = uLoadResource(ins,uMAKEINTRESOURCE(id),(const char*)(RT_STRING)); + if (res) + { + unsigned size = res->GetSize(); + const WCHAR * ptr = (const WCHAR*)res->GetPointer(); + if (size>=4) + { + unsigned len = *(const WORD*)(ptr+1); + if (len * 2 + 4 <= size) + { + out = stringcvt::string_utf8_from_wide(ptr+2,len); + } + } + + delete res; + rv = TRUE; + } + return rv; +} + +BOOL SHARED_EXPORT uGetMenuString(HMENU menu,UINT id,string_base & out,UINT flag) +{ + unsigned len = GetMenuString(menu,id,0,0,flag); + if (len==0) + { + out.reset(); + return FALSE; + } + array_t temp; + temp.set_size(len+1); + if (GetMenuString(menu,id,temp.get_ptr(),len+1,flag)==0) { + out.reset(); + return FALSE; + } + out = stringcvt::string_utf8_from_os(temp.get_ptr()); + return TRUE; +} + +BOOL SHARED_EXPORT uModifyMenu(HMENU menu,UINT id,UINT flags,UINT newitem,const char * data) +{ + return ModifyMenu(menu,id,flags,newitem,param_os_from_utf8(data)); +} + +UINT SHARED_EXPORT uGetMenuItemType(HMENU menu,UINT position) +{ + MENUITEMINFO info = {}; + info.cbSize = sizeof(info); + info.fMask = MIIM_TYPE; + if (!GetMenuItemInfo(menu,position,TRUE,&info)) + return 0; + return info.fType; +} + +static inline bool i_is_path_separator(unsigned c) +{ + return c=='\\' || c=='/' || c=='|' || c==':'; +} + +int SHARED_EXPORT uSortPathCompare(HANDLE string1,HANDLE string2) +{ + const TCHAR * s1 = reinterpret_cast(string1); + const TCHAR * s2 = reinterpret_cast(string2); + const TCHAR * p1, * p2; + + while (*s1 || *s2) + { + if (*s1 == *s2) + { + s1++; + s2++; + continue; + } + + p1 = s1; while (*p1 && !i_is_path_separator(*p1)) p1++; + p2 = s2; while (*p2 && !i_is_path_separator(*p2)) p2++; + + if ((!*p1 && !*p2) || (*p1 && *p2)) + { + int test = CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE | NORM_IGNOREKANATYPE | NORM_IGNOREWIDTH, s1, pfc::downcast_guarded(p1 - s1), s2, pfc::downcast_guarded(p2 - s2)); + if (test && test != 2) return test - 2; + if (!*p1) return 0; + } + else + { + if (*p1) return -1; + else return 1; + } + + s1 = p1 + 1; + s2 = p2 + 1; + } + + return 0; +} + +UINT SHARED_EXPORT uRegisterClipboardFormat(const char * name) +{ + return RegisterClipboardFormat(stringcvt::string_os_from_utf8(name)); +} + +BOOL SHARED_EXPORT uGetClipboardFormatName(UINT format,string_base & out) +{ + TCHAR temp[1024]; + if (!GetClipboardFormatName(format,temp,_countof(temp))) return FALSE; + out = stringcvt::string_utf8_from_os(temp,_countof(temp)); + return TRUE; +} + +}//extern "C" + +BOOL SHARED_EXPORT uSearchPath(const char * path, const char * filename, const char * extension, string_base & p_out) +{ + enum {temp_size = 1024}; + param_os_from_utf8 path_os(path), filename_os(filename), extension_os(extension); + array_t temp; temp.set_size(temp_size); + LPTSTR dummy; + unsigned len; + + len = SearchPath(path_os,filename_os,extension_os,temp_size,temp.get_ptr(),&dummy); + if (len == 0) return FALSE; + if (len >= temp_size) + { + unsigned len2; + temp.set_size(len + 1); + len2 = SearchPath(path_os,filename_os,extension_os,len+1,temp.get_ptr(),&dummy); + if (len2 == 0 || len2 > len) return FALSE; + len = len2; + } + + p_out = stringcvt::string_utf8_from_os(temp.get_ptr(),len); + + return TRUE; + +} + +static bool is_ascii_alpha(char c) +{ + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); +} + +static char ascii_upper(char c) +{ + if (c >= 'a' && c <= 'z') c += 'A' - 'a'; + return c; +} + +static BOOL uFixPathCaps_Internal(const char * path,string_base & p_out, bool bQuick) { + pfc::string8_fastalloc temp, prependbuffer; + if (path[0] == '\\' && path[1] == '\\') + { + unsigned index = 2; + while(path[index] != '\\') + { + if (path[index] == 0) return FALSE; + index++; + } + index++; + if (path[index] == '\\' || path[index] == 0) return FALSE; + while(path[index] != '\\') + { + if (path[index] == 0) { + // \\host\share + uStringLower(p_out,path); + return TRUE; + } + index++; + } + index++; + if (path[index] == '\\') return FALSE; + uAddStringLower(temp,path,index); + path += index; + } + else if (is_ascii_alpha(path[0]) && path[1] == ':' && path[2] == '\\') + { + temp.add_char(ascii_upper(path[0])); + temp.add_string(":\\"); + path += 3; + } + else return FALSE; + + for(;;) + { + t_size truncat = temp.length(); + t_size delta = 0; + while(path[delta]!=0 && path[delta]!='\\') delta++; + if (delta == 0) break; + temp.add_string_nc(path,delta); + + bool found = false; + if (!bQuick) { +#ifdef UNICODE + pfc::winPrefixPath( prependbuffer, temp ); + pfc::ptrholder_t ff = uFindFirstFile(prependbuffer); +#else + pfc::ptrholder_t ff = uFindFirstFile(temp); +#endif + if (ff.is_valid()) { + do { + const char * fn = ff->GetFileName(); + if (!stricmp_utf8_ex(path,delta,fn,strlen(fn))) + { + found = true; + temp.truncate(truncat); + temp.add_string(fn); + break; + } + } while(ff->FindNext()); + } + } + if (!found) + { + temp.add_string(path + delta); + break; + } + path += delta; + if (*path == 0) break; + path ++; + temp.add_char('\\'); + } + + + p_out = temp; + + return TRUE; +} +/*BOOL SHARED_EXPORT uFixPathCapsQuick(const char * path,string_base & p_out) { + return uFixPathCaps_Internal(path, p_out, true); +}*/ +BOOL SHARED_EXPORT uFixPathCaps(const char * path,string_base & p_out) { + return uFixPathCaps_Internal(path, p_out, false); +} + +LPARAM SHARED_EXPORT uTreeView_GetUserData(HWND p_tree,HTREEITEM p_item) +{ + TVITEM item = {}; + item.mask = TVIF_PARAM; + item.hItem = p_item; + if (uSendMessage(p_tree,TVM_GETITEM,0,(LPARAM)&item)) + return item.lParam; + return 0; +} + +bool SHARED_EXPORT uTreeView_GetText(HWND p_tree,HTREEITEM p_item,string_base & p_out) +{ + TCHAR temp[1024];//changeme ? + TVITEM item = {}; + item.mask = TVIF_TEXT; + item.hItem = p_item; + item.pszText = temp; + item.cchTextMax = _countof(temp); + if (uSendMessage(p_tree,TVM_GETITEM,0,(LPARAM)&item)) + { + p_out = stringcvt::string_utf8_from_os(temp,_countof(temp)); + return true; + } + else return false; +} + +BOOL SHARED_EXPORT uSetWindowText(HWND wnd,const char * p_text) +{ + PFC_ASSERT( wnd != NULL ); + return SetWindowText(wnd,stringcvt::string_os_from_utf8(p_text)); +} + +BOOL SHARED_EXPORT uSetDlgItemText(HWND wnd,UINT id,const char * p_text) +{ + PFC_ASSERT( wnd != NULL ); + return SetDlgItemText(wnd, id, stringcvt::string_os_from_utf8(p_text)); +} + +BOOL SHARED_EXPORT uFileExists(const char * fn) +{ + DWORD attrib = uGetFileAttributes(fn); + if (attrib == 0xFFFFFFFF || (attrib & FILE_ATTRIBUTE_DIRECTORY)) return FALSE; + return TRUE; +} + +BOOL SHARED_EXPORT uFormatSystemErrorMessage(string_base & p_out,DWORD p_code) { + return pfc::winFormatSystemErrorMessage(p_out, p_code); +} + +HMODULE SHARED_EXPORT LoadSystemLibrary(const TCHAR * name) { + pfc::array_t buffer; buffer.set_size( MAX_PATH + _tcslen(name) + 2 ); + TCHAR * bufptr = buffer.get_ptr(); + if (GetSystemDirectory(bufptr, MAX_PATH) == 0) return NULL; + bufptr[MAX_PATH] = 0; + + size_t idx = _tcslen(bufptr); + if (idx > 0 && bufptr[idx-1] != '\\') bufptr[idx++] = '\\'; + + pfc::strcpy_t(bufptr+idx, name); + + return LoadLibrary(bufptr); +} \ No newline at end of file diff --git a/sdk/libPPUI/CDialogResizeHelper.h b/sdk/libPPUI/CDialogResizeHelper.h index 91932e2..1fe80d0 100644 --- a/sdk/libPPUI/CDialogResizeHelper.h +++ b/sdk/libPPUI/CDialogResizeHelper.h @@ -3,6 +3,17 @@ #include "CDialogResizeHelperCompat.h" #include +// ========================================================== +// CDialogResizeHelper +// ========================================================== +// Usage: +// Put CDialogResizeHelper member in your dialog class +// Initialize with controls sizing info table, array of CDialogResizeHelper::Param +// Put CHAIN_MSG_MAP_MEMBER(m_resizer) before your dialog message handlers +// CDialogResizeHelper will do its own message handling without marking messages as handled, that is, your handlers of the same messages will be allowed to run. +// CRect minMaxRange specifies allowed size min (left&top) and max (right&bottom) values, in DLU not pixels. +// ========================================================== + class CDialogResizeHelper : public CMessageMap { public: diff --git a/sdk/libPPUI/CEditWithButtons.cpp b/sdk/libPPUI/CEditWithButtons.cpp index bd6d728..d119e5c 100644 --- a/sdk/libPPUI/CEditWithButtons.cpp +++ b/sdk/libPPUI/CEditWithButtons.cpp @@ -171,7 +171,26 @@ void CEditWithButtons::Layout(CSize size, CFontHandle fontSetMe) { } unsigned CEditWithButtons::MeasureButton(Button_t const & button) { + if (m_fixedWidthAuto && m_fixedWidth == 0) { + CWindowDC dc(*this); + SelectObjectScope fontScope(dc, GetFont()); + SIZE sz = {}; + WIN32_OP_D( dc.GetTextExtent(L"#", 1, &sz) ); + m_fixedWidth = MulDiv(sz.cx, 3, 2); + } if (m_fixedWidth != 0) return m_fixedWidth; return button.wnd.Measure(); } + +void CEditWithButtons::OnSetFont(CFontHandle font, BOOL bRedraw) { + (void)bRedraw; + + if ( m_fixedWidthAuto ) m_fixedWidth = 0; // require re-calculation + + DefWindowProc(); + CRect rc; + if (GetClientRect(&rc)) { + Layout(rc.Size(), font); + } +} diff --git a/sdk/libPPUI/CEditWithButtons.h b/sdk/libPPUI/CEditWithButtons.h index c2df276..1646bd7 100644 --- a/sdk/libPPUI/CEditWithButtons.h +++ b/sdk/libPPUI/CEditWithButtons.h @@ -47,9 +47,12 @@ class CEditWithButtons : public CEditPPHooks { void AddClearButton( const wchar_t * clearVal = L"", bool bHandleEsc = false); void AddButton( const wchar_t * str, handler_t handler, condition_t condition = nullptr, const wchar_t * drawAlternateText = nullptr ); - static unsigned DefaultFixedWidth() {return GetSystemMetrics(SM_CXVSCROLL) * 3 / 4;} - void SetFixedWidth(unsigned fw = DefaultFixedWidth() ) { - m_fixedWidth = fw; + void SetFixedWidth(unsigned fw) { + m_fixedWidth = fw; m_fixedWidthAuto = false; + RefreshButtons(); + } + void SetFixedWidth() { + m_fixedWidth = 0; m_fixedWidthAuto = true; RefreshButtons(); } CRect RectOfButton( const wchar_t * text ); @@ -168,14 +171,8 @@ class CEditWithButtons : public CEditPPHooks { bool visible; condition_t condition; }; - void OnSetFont(CFontHandle font, BOOL bRedraw) { - (void)bRedraw; - CRect rc; - if (GetClientRect(&rc)) { - Layout(rc.Size(), font); - } - SetMsgHandled(FALSE); - } + + void OnSetFont(CFontHandle font, BOOL bRedraw); void RefreshButtons() { if ( m_hWnd != NULL && m_buttons.size() > 0 ) { @@ -208,6 +205,7 @@ class CEditWithButtons : public CEditPPHooks { unsigned MeasureButton(Button_t const & button ); unsigned m_fixedWidth = 0; + bool m_fixedWidthAuto = false; std::list< Button_t > m_buttons; bool m_hasAutoComplete = false; }; diff --git a/sdk/libPPUI/CListControl.h b/sdk/libPPUI/CListControl.h index 878f119..2b8b6f8 100644 --- a/sdk/libPPUI/CListControl.h +++ b/sdk/libPPUI/CListControl.h @@ -282,7 +282,7 @@ class CListControlImpl : public CWindowImpl #include "Controls.h" #include "PaintUtils.h" +#include "HyperLinkCtrl.h" void CStaticSeparator::OnPaint(CDCHandle) { PaintUtils::PaintSeparatorControl(*this); @@ -49,4 +50,33 @@ void CStaticThemed::OnPaint(CDCHandle) { PFC_ASSERT(SUCCEEDED(retval)); } } -#endif \ No newline at end of file +#endif + + +#include "DarkMode-CHyperLink.h" +#include "windowLifetime.h" + +void PP::createHyperLink(HWND wndReplaceMe) { + auto obj = PP::subclassThisWindow(wndReplaceMe); + obj->SetHyperLinkExtendedStyle(HLINK_NOTIFYBUTTON); +} + +namespace { + class CHyperLinkLambda : public DarkMode::CHyperLinkImpl { + public: + std::function f; + bool Navigate() { + f(); + return true; + } + }; +} +void PP::createHyperLink(HWND wndReplaceMe, std::function handler) { + auto obj = PP::subclassThisWindow(wndReplaceMe); + obj->f = handler; +} + +void PP::createHyperLink(HWND wndReplaceMe, const wchar_t* openURL) { + auto obj = PP::subclassThisWindow(wndReplaceMe); + obj->SetHyperLink(openURL); +} diff --git a/sdk/libPPUI/DarkMode-CHyperLink.h b/sdk/libPPUI/DarkMode-CHyperLink.h index 534a0b0..66f8635 100644 --- a/sdk/libPPUI/DarkMode-CHyperLink.h +++ b/sdk/libPPUI/DarkMode-CHyperLink.h @@ -3,6 +3,8 @@ #include "DarkMode.h" namespace DarkMode { + static constexpr COLORREF colorHyperLink = 0xCC6600; // taken from screenshot of syslink + template class CHyperLinkImpl : public ::CHyperLinkImpl { public: BEGIN_MSG_MAP_EX(CDarkHyperLinkImpl) @@ -16,8 +18,8 @@ namespace DarkMode { if (bDark != m_isDark) { m_isDark = bDark; - m_clrLink = bDark ? DarkMode::GetSysColor(COLOR_HOTLIGHT) : m_clrLinkBackup; - Invalidate(); + this->m_clrLink = bDark ? colorHyperLink : m_clrLinkBackup; + this->Invalidate(); } return 1; diff --git a/sdk/libPPUI/DarkMode.cpp b/sdk/libPPUI/DarkMode.cpp index 2fd774d..97f5830 100644 --- a/sdk/libPPUI/DarkMode.cpp +++ b/sdk/libPPUI/DarkMode.cpp @@ -109,9 +109,10 @@ Full custom draw SetWindowTheme(wnd, L"", L""); works but not 100% pretty, disabled text ugly in particular Full custom draw preferred -== Group box +== Group box === SetWindowTheme(wnd, L"", L""); works but not 100% pretty, disabled text ugly in particular -Full custom draw preferred +Full custom draw preferred (we don't do this). +Avoid disabling groupboxes / use something else. ==== NOTES ==== AllowDarkModeForWindow() needs SetPreferredAppMode() to take effect, hence we implicitly call it @@ -270,6 +271,7 @@ namespace DarkMode { } void ApplyDarkThemeCtrl(HWND ctrl, bool bDark, const wchar_t* ThemeID) { + if ( ctrl == NULL ) return; // Both ways work // DarkMode_Theme approach doesn't require evil undocumented MS API calls though AllowDarkModeForWindow(ctrl, bDark); @@ -378,17 +380,13 @@ namespace DarkMode { return false; } - static bool IsHighContrastImpl() - { + bool IsHighContrast() { HIGHCONTRASTW highContrast = { sizeof(highContrast) }; if (SystemParametersInfoW(SPI_GETHIGHCONTRAST, sizeof(highContrast), &highContrast, FALSE)) - return highContrast.dwFlags & HCF_HIGHCONTRASTON; + return (highContrast.dwFlags & HCF_HIGHCONTRASTON) != 0; return false; } - bool IsHighContrast() { - static bool v = IsHighContrastImpl(); - return v; - } + static void DrawTab(CTabCtrl& tabs, CDCHandle dc, int iTab, bool selected, bool focused, const RECT * rcPaint) { (void)focused; PFC_ASSERT((tabs.GetStyle() & TCS_VERTICAL) == 0); @@ -510,7 +508,7 @@ namespace DarkMode { class CToolbarHook { bool m_dark = false; const bool m_explorerTheme; - CWindow m_wnd; + CToolBarCtrl m_wnd; public: CToolbarHook(HWND wnd, bool initial, bool bExplorerTheme) : m_wnd(wnd), m_explorerTheme(bExplorerTheme) { SetDark(initial); @@ -527,6 +525,8 @@ namespace DarkMode { if (m_explorerTheme) ::SetWindowTheme(m_wnd, L"Explorer", NULL); } m_wnd.Invalidate(); + + ApplyDarkThemeCtrl(m_wnd.GetToolTips(), v); } ~CToolbarHook() { if (m_dark) lstDark_clear(m_wnd); @@ -580,6 +580,8 @@ namespace DarkMode { void CTabsHook::SetDark(bool v) { m_dark = v; if (m_hWnd != NULL) Invalidate(); + + ApplyDarkThemeCtrl(GetToolTips(), v); } class CTreeViewHook : public CWindowImpl { @@ -616,6 +618,8 @@ namespace DarkMode { COLORREF tx = m_dark ? GetSysColor(COLOR_WINDOWTEXT) : (COLORREF)(-1); this->SetTextColor(tx); this->SetLineColor(tx); this->SetBkColor(bk); + + ApplyDarkThemeCtrl(GetToolTips(), m_dark); } void SubclassWindow(HWND wnd) { @@ -1046,7 +1050,8 @@ namespace DarkMode { GetParent().SendMessage(WM_CTLCOLORBTN, (WPARAM)dc.m_hDC, (LPARAM)m_hWnd); if (bDisabled) dc.SetTextColor(DarkMode::GetSysColor(COLOR_GRAYTEXT)); // override WM_CTLCOLORBTN - const DWORD btnType = GetStyle() & BS_TYPEMASK; + const DWORD btnStyle = GetStyle(); + const DWORD btnType = btnStyle & BS_TYPEMASK; const bool bRadio = (btnType == BS_RADIOBUTTON || btnType == BS_AUTORADIOBUTTON); const int part = bRadio ? BP_RADIOBUTTON : BP_CHECKBOX; @@ -1117,7 +1122,12 @@ namespace DarkMode { if (!text.IsEmpty()) { CRect rcText = rcClient; rcText.left += margin; - UINT dtFlags = DT_VCENTER | DT_END_ELLIPSIS | DT_SINGLELINE; + UINT dtFlags = DT_VCENTER; + if (btnStyle & BS_MULTILINE) { + dtFlags |= DT_WORDBREAK; + } else { + dtFlags |= DT_END_ELLIPSIS | DT_SINGLELINE; + } dc.DrawText(text, text.GetLength(), rcText, dtFlags); if (bFocus) { dc.DrawText(text, text.GetLength(), rcText, DT_CALCRECT | dtFlags); diff --git a/sdk/libPPUI/HyperLinkCtrl.h b/sdk/libPPUI/HyperLinkCtrl.h new file mode 100644 index 0000000..383c1ac --- /dev/null +++ b/sdk/libPPUI/HyperLinkCtrl.h @@ -0,0 +1,8 @@ +#pragma once +#include +namespace PP { + // One-line method to turn static control to hyperlink firing WM_NOTIFY + void createHyperLink(HWND wndReplaceMe); + void createHyperLink(HWND wndReplaceMe, std::function handler); + void createHyperLink(HWND wndReplaceMe, const wchar_t * openURL); +} \ No newline at end of file diff --git a/sdk/libPPUI/libPPUI.vcxproj b/sdk/libPPUI/libPPUI.vcxproj index 60361f9..0420ed3 100644 --- a/sdk/libPPUI/libPPUI.vcxproj +++ b/sdk/libPPUI/libPPUI.vcxproj @@ -362,6 +362,7 @@ + diff --git a/sdk/libPPUI/libPPUI.vcxproj.filters b/sdk/libPPUI/libPPUI.vcxproj.filters index 16f4b4d..3128d60 100644 --- a/sdk/libPPUI/libPPUI.vcxproj.filters +++ b/sdk/libPPUI/libPPUI.vcxproj.filters @@ -200,6 +200,9 @@ Header Files + + Header Files + diff --git a/sdk/pfc/audio_math.cpp b/sdk/pfc/audio_math.cpp index 63fcf80..46faaf3 100644 --- a/sdk/pfc/audio_math.cpp +++ b/sdk/pfc/audio_math.cpp @@ -28,13 +28,19 @@ static const bool haveAVX = pfc::query_cpu_feature_set(pfc::CPU_HAVE_AVX); #endif -#if defined( __aarch64__ ) || defined( __ARM_NEON__ ) || defined( _M_ARM64) || defined( _M_ARM64EC ) +#if defined( __aarch64__ ) || defined( _M_ARM64) || defined( _M_ARM64EC ) +#define AUDIO_MATH_ARM64 +#endif + +#if defined( AUDIO_MATH_ARM64 ) || defined( __ARM_NEON__ ) #define AUDIO_MATH_NEON #include #endif -#if defined( __aarch64__ ) || defined( _M_ARM64) || defined( _M_ARM64EC ) -#define AUDIO_MATH_ARM64 + +#if defined( AUDIO_MATH_ARM64 ) && !defined( __ANDROID__ ) +// Don't do Neon float64 on Android, crashes clang from NDK 25 +#define AUDIO_MATH_NEON_FLOAT64 #endif template inline static float_t noopt_calculate_peak(const float_t *p_src, t_size p_num) @@ -99,9 +105,9 @@ inline static void noopt_convert(const in_t* in, out_t* out, size_t count) { for (size_t walk = 0; walk < count; ++walk) out[walk] = (out_t)in[walk]; } -#if defined(AUDIO_MATH_NEON) +#ifdef AUDIO_MATH_NEON -#if defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC) +#ifdef AUDIO_MATH_ARM64 #define _vmaxvq_f32_wrap vmaxvq_f32 #else inline float _vmaxvq_f32_wrap( float32x4_t arg ) { @@ -233,7 +239,7 @@ inline static void neon_convert_from_int16(const t_int16 * __restrict p_source,t noopt_convert_from_int16( p_source, rem, p_output, p_scale ); } -#ifdef AUDIO_MATH_ARM64 +#ifdef AUDIO_MATH_NEON_FLOAT64 inline static void neon_convert_to_int16(const double* __restrict p_source, t_size p_count, int16_t* __restrict p_output, double p_scale) { size_t num = p_count / 4; @@ -284,7 +290,7 @@ inline static void neon_convert_from_int16(const t_int16* __restrict p_source, t noopt_convert_from_int16(p_source, rem, p_output, p_scale); } -#endif // AUDIO_MATH_ARM64 +#endif // AUDIO_MATH_NEON_FLOAT64 #endif // AUDIO_MATH_NEON @@ -782,7 +788,7 @@ namespace pfc { { convert_to_16bit_sse2(p_source, p_count, p_output, scale); } -#elif defined( AUDIO_MATH_ARM64 ) +#elif defined( AUDIO_MATH_NEON_FLOAT64 ) neon_convert_to_int16(p_source, p_count, p_output, scale); #else noopt_convert_to_16bit(p_source, p_count, p_output, scale); @@ -813,7 +819,7 @@ namespace pfc { { convert_from_int16_sse2(p_source, p_count, p_output, scale); } -#elif defined( AUDIO_MATH_ARM64 ) +#elif defined( AUDIO_MATH_NEON_FLOAT64 ) neon_convert_from_int16(p_source, p_count, p_output, scale); #else noopt_convert_from_int16(p_source, p_count, p_output, scale); diff --git a/sdk/pfc/bigmem.cpp b/sdk/pfc/bigmem.cpp index d7e79ae..a9ebc17 100644 --- a/sdk/pfc/bigmem.cpp +++ b/sdk/pfc/bigmem.cpp @@ -23,7 +23,7 @@ namespace pfc { m_data.set_size(0); m_size = 0; } - void bigmem::read(void* ptrOut, size_t bytes, size_t offset) { + void bigmem::read(void* ptrOut, size_t bytes, size_t offset) const { PFC_ASSERT(offset + bytes <= size()); uint8_t* outWalk = (uint8_t*)ptrOut; while (bytes > 0) { diff --git a/sdk/pfc/bigmem.h b/sdk/pfc/bigmem.h index 58d9481..ff2392b 100644 --- a/sdk/pfc/bigmem.h +++ b/sdk/pfc/bigmem.h @@ -12,7 +12,7 @@ namespace pfc { void resize(size_t newSize); size_t size() const {return m_size;} void clear(); - void read(void * ptrOut, size_t bytes, size_t offset); + void read(void * ptrOut, size_t bytes, size_t offset) const; void write(const void * ptrIn, size_t bytes, size_t offset); uint8_t * _slicePtr(size_t which); size_t _sliceCount(); diff --git a/sdk/pfc/filetimetools.cpp b/sdk/pfc/filetimetools.cpp new file mode 100644 index 0000000..810d737 --- /dev/null +++ b/sdk/pfc/filetimetools.cpp @@ -0,0 +1,330 @@ +#include "pfc-lite.h" + +#include "filetimetools.h" + +#include "timers.h" + +#include + +namespace { + class exception_time_error {}; +} + +using namespace pfc; + +#ifndef _WIN32 +namespace { + typedef uint16_t WORD; + + typedef struct _SYSTEMTIME { + WORD wYear; + WORD wMonth; + WORD wDayOfWeek; + WORD wDay; + WORD wHour; + WORD wMinute; + WORD wSecond; + WORD wMilliseconds; + } SYSTEMTIME, * PSYSTEMTIME, * LPSYSTEMTIME; + +} +static void SystemTimeToNix(const SYSTEMTIME& st, struct tm& Time) { + memset(&Time, 0, sizeof(Time)); + Time.tm_sec = st.wSecond; + Time.tm_min = st.wMinute; + Time.tm_hour = st.wHour; + Time.tm_mday = st.wDay; + Time.tm_mon = st.wMonth - 1; + Time.tm_year = st.wYear - 1900; +} + +static t_filetimestamp ExportSystemTime(const SYSTEMTIME& st) { + struct tm Time; + SystemTimeToNix(st, Time); + return pfc::fileTimeUtoW(mktime(&Time)); +} + +static t_filetimestamp ExportSystemTimeLocal(const SYSTEMTIME& st) { + struct tm Time, Local; + SystemTimeToNix(st, Time); + time_t t = mktime(&Time); + localtime_r(&t, &Local); + return pfc::fileTimeUtoW(mktime(&Local)); +} +static void SystemTimeFromNix(SYSTEMTIME& st, struct tm const& Time) { + memset(&st, 0, sizeof(st)); + st.wSecond = Time.tm_sec; + st.wMinute = Time.tm_min; + st.wHour = Time.tm_hour; + st.wDay = Time.tm_mday; + st.wDayOfWeek = Time.tm_wday; + st.wMonth = Time.tm_mon + 1; + st.wYear = Time.tm_year + 1900; +} + +static bool MakeSystemTime(SYSTEMTIME& st, t_filetimestamp ts) { + time_t t = (time_t)pfc::fileTimeWtoU(ts); + struct tm Time; + if (gmtime_r(&t, &Time) == NULL) return false; + SystemTimeFromNix(st, Time); + return true; +} + +static bool MakeSystemTimeLocal(SYSTEMTIME& st, t_filetimestamp ts) { + time_t t = (time_t)pfc::fileTimeWtoU(ts); + struct tm Time; + if (localtime_r(&t, &Time) == NULL) return false; + SystemTimeFromNix(st, Time); + return true; +} + +#else +static t_filetimestamp ExportSystemTime(const SYSTEMTIME& st) { + t_filetimestamp base; + if (!SystemTimeToFileTime(&st, (FILETIME*)&base)) throw exception_time_error(); + return base; +} +static t_filetimestamp ExportSystemTimeLocal(const SYSTEMTIME& st) { +#ifdef FOOBAR2000_DESKTOP_WINDOWS + t_filetimestamp base, out; + if (!SystemTimeToFileTime(&st, (FILETIME*)&base)) throw exception_time_error(); + if (!LocalFileTimeToFileTime((const FILETIME*)&base, (FILETIME*)&out)) throw exception_time_error(); + return out; +#else + SYSTEMTIME UTC; + if (!TzSpecificLocalTimeToSystemTime(NULL, &st, &UTC)) throw exception_time_error(); + return ExportSystemTime(UTC); +#endif +} +static bool MakeSystemTime(SYSTEMTIME& st, t_filetimestamp ts) { + if (ts == filetimestamp_invalid) return false; + return !!FileTimeToSystemTime((const FILETIME*)&ts, &st); + +} +static bool MakeSystemTimeLocal(SYSTEMTIME& st, t_filetimestamp ts) { + if (ts == filetimestamp_invalid) return false; +#ifdef FOOBAR2000_DESKTOP_WINDOWS + FILETIME ft; + if (FileTimeToLocalFileTime((FILETIME*)&ts, &ft)) { + if (FileTimeToSystemTime(&ft, &st)) { + return true; + } + } + return false; +#else + SYSTEMTIME UTC; + if (FileTimeToSystemTime((FILETIME*)&ts, &UTC)) { + if (SystemTimeToTzSpecificLocalTime(NULL, &UTC, &st)) return true; + } + return false; +#endif +} +#endif // _WIN32 + +static bool is_spacing(char c) { return c == ' ' || c == 10 || c == 13 || c == '\t'; } + +static unsigned ParseDateElem(const char* ptr, t_size len) { + unsigned ret = 0; + for (t_size walk = 0; walk < len; ++walk) { + const char c = ptr[walk]; + if (c < '0' || c > '9') throw exception_time_error(); + ret = ret * 10 + (unsigned)(c - '0'); + } + return ret; +} + +static bool st_sanity(SYSTEMTIME const& st) { + return st.wYear >= 1601 && st.wMonth >= 1 && st.wMonth <= 12 && st.wDay >= 1 && st.wDay <= 31 && st.wHour < 24 && st.wMinute < 60 && st.wSecond < 60 && st.wMilliseconds < 1000; +} +static t_filetimestamp filetimestamp_from_string_internal(const char* date, bool local) { + // Accepted format + // YYYY-MM-DD HH:MM:SS + try { + SYSTEMTIME st = {}; + st.wDay = 1; st.wMonth = 1; + + unsigned walk = 0; + auto worker = [&](unsigned n) { + auto ret = ParseDateElem(date + walk, n); + walk += n; + if (ret > UINT16_MAX) throw exception_time_error(); + return (WORD)ret;; + }; + + auto skip = [&](char c) { + if (date[walk] == c) ++walk; + }; + + auto skipSpacing = [&] { + while (is_spacing(date[walk])) ++walk; + }; + skipSpacing(); + st.wYear = worker(4); + skip('-'); + st.wMonth = worker(2); + skip('-'); + st.wDay = worker(2); + skipSpacing(); + st.wHour = worker(2); + skip(':'); + st.wMinute = worker(2); + skip(':'); + st.wSecond = worker(2); + if (date[walk] == '.') { + double v = pfc::string_to_float(date + walk); + st.wMilliseconds = (WORD)floor(v * 1000.f); // don't ever round up, don't want to handle ms of 1000 + } + + if (!st_sanity(st)) throw exception_time_error(); + + if (local) { + return ExportSystemTimeLocal(st); + } else { + return ExportSystemTime(st); + } + } catch (exception_time_error) { + return filetimestamp_invalid; + } +} + +namespace pfc { + t_filetimestamp filetimestamp_from_string(const char* date) { + return filetimestamp_from_string_internal(date, true); + } + + t_filetimestamp filetimestamp_from_string_utc(const char* date) { + return filetimestamp_from_string_internal(date, false); + } + + static constexpr char g_invalidMsg[] = ""; + + pfc::string_formatter format_filetimestamp(t_filetimestamp p_timestamp) { + try { + SYSTEMTIME st; + if (MakeSystemTimeLocal(st, p_timestamp)) { + pfc::string_formatter buffer; + buffer + << pfc::format_uint(st.wYear, 4) << "-" << pfc::format_uint(st.wMonth, 2) << "-" << pfc::format_uint(st.wDay, 2) << " " + << pfc::format_uint(st.wHour, 2) << ":" << pfc::format_uint(st.wMinute, 2) << ":" << pfc::format_uint(st.wSecond, 2); + return buffer; + } + } catch (...) {} + return g_invalidMsg; + } + + pfc::string_formatter format_filetimestamp_ms(t_filetimestamp p_timestamp) { + try { + SYSTEMTIME st; + if (MakeSystemTimeLocal(st, p_timestamp)) { + pfc::string_formatter buffer; + buffer + << pfc::format_uint(st.wYear, 4) << "-" << pfc::format_uint(st.wMonth, 2) << "-" << pfc::format_uint(st.wDay, 2) << " " + << pfc::format_uint(st.wHour, 2) << ":" << pfc::format_uint(st.wMinute, 2) << ":" << pfc::format_uint(st.wSecond, 2) << "." << pfc::format_uint(st.wMilliseconds, 3); + return buffer; + } + } catch (...) {} + return g_invalidMsg; + } + + pfc::string_formatter format_filetimestamp_utc(t_filetimestamp p_timestamp) { + try { + SYSTEMTIME st; + if (MakeSystemTime(st, p_timestamp)) { + pfc::string_formatter buffer; + buffer + << pfc::format_uint(st.wYear, 4) << "-" << pfc::format_uint(st.wMonth, 2) << "-" << pfc::format_uint(st.wDay, 2) << " " + << pfc::format_uint(st.wHour, 2) << ":" << pfc::format_uint(st.wMinute, 2) << ":" << pfc::format_uint(st.wSecond, 2); + return buffer; + } + } catch (...) {} + return g_invalidMsg; + } + +} // namespace foobar2000_io + +namespace { + struct dateISO_t { + unsigned Y, M, D; + unsigned h, m, s; + double sfrac; + int tzdelta; + }; + + dateISO_t read_ISO_8601(const char* dateISO) { + dateISO_t ret = {}; + // 2022-01-26T13:44:51.200000Z + // 2010-02-19T14:54:23.031+08:00 + // 2022-01-27T11:01:49+00:00 + // 2022-01-27T11:01:49Z + // 20220127T110149Z + + unsigned walk = 0; + auto worker = [&](unsigned n) { + auto ret = ParseDateElem(dateISO + walk, n); + walk += n; + return ret; + }; + auto skip = [&](char c) { + if (dateISO[walk] == c) ++walk; + }; + auto expect = [&](char c) { + if (dateISO[walk] != c) throw exception_time_error(); + ++walk; + }; + ret.Y = worker(4); + skip('-'); + ret.M = worker(2); + skip('-'); + ret.D = worker(2); + expect('T'); + ret.h = worker(2); + skip(':'); + ret.m = worker(2); + skip(':'); + ret.s = worker(2); + if (dateISO[walk] == '.') { + unsigned base = walk; + ++walk; + while (pfc::char_is_numeric(dateISO[walk])) ++walk; + ret.sfrac = pfc::string_to_float(dateISO + base, walk - base); + } + if (dateISO[walk] == '+' || dateISO[walk] == '-') { + bool neg = dateISO[walk] == '-'; + ++walk; + unsigned tz_h = worker(2); + if (tz_h >= 24) throw exception_time_error(); + skip(':'); + unsigned tz_m = worker(2); + if (tz_m >= 60) throw exception_time_error(); + tz_m += tz_h * 60; + ret.tzdelta = neg ? (int)tz_m : -(int)tz_m; // reversed! it's a timezone offset, have to *add* it if timezone has a minus + } + return ret; + } +} + +t_filetimestamp pfc::filetimestamp_from_string_ISO_8601(const char* dateISO) { + try { + auto elems = read_ISO_8601(dateISO); + + SYSTEMTIME st = {}; + st.wDay = 1; st.wMonth = 1; + st.wYear = elems.Y; + st.wMonth = elems.M; + st.wDay = elems.D; + st.wHour = elems.h; + st.wMinute = elems.m; + st.wSecond = elems.s; + st.wMilliseconds = (WORD)floor(elems.sfrac * 1000.f); + + if (!st_sanity(st)) throw exception_time_error(); + + auto ret = ExportSystemTime(st); + + ret += filetimestamp_1second_increment * elems.tzdelta * 60; + + return ret; + } catch (...) { + return filetimestamp_invalid; + } +} diff --git a/sdk/pfc/filetimetools.h b/sdk/pfc/filetimetools.h new file mode 100644 index 0000000..c7af5aa --- /dev/null +++ b/sdk/pfc/filetimetools.h @@ -0,0 +1,20 @@ +#pragma once + +namespace pfc { + typedef uint64_t t_filetimestamp; + static constexpr t_filetimestamp filetimestamp_invalid = 0; + static constexpr t_filetimestamp filetimestamp_1second_increment = 10000000; + + t_filetimestamp filetimestamp_from_string(const char * date); + t_filetimestamp filetimestamp_from_string_utc(const char* date); + // From ISO 8601 time + t_filetimestamp filetimestamp_from_string_ISO_8601(const char* date); + + //! Warning: this formats according to system timezone settings, created strings should be used for display only, never for storage. + pfc::string_formatter format_filetimestamp(t_filetimestamp p_timestamp); + //! UTC timestamp + pfc::string_formatter format_filetimestamp_utc(t_filetimestamp p_timestamp); + //! Local timestamp with milliseconds + pfc::string_formatter format_filetimestamp_ms(t_filetimestamp p_timestamp); + +} diff --git a/sdk/pfc/obj-c.mm b/sdk/pfc/obj-c.mm index a1ca504..529041f 100644 --- a/sdk/pfc/obj-c.mm +++ b/sdk/pfc/obj-c.mm @@ -31,21 +31,21 @@ bool isShiftKeyPressed() { #if TARGET_OS_MAC && !TARGET_OS_IPHONE - return ( [NSEvent modifierFlags] & NSShiftKeyMask ) != 0; + return ( [NSEvent modifierFlags] & NSEventModifierFlagShift ) != 0; #else return false; #endif } bool isCtrlKeyPressed() { #if TARGET_OS_MAC && !TARGET_OS_IPHONE - return ( [NSEvent modifierFlags] & NSControlKeyMask ) != 0; + return ( [NSEvent modifierFlags] & NSEventModifierFlagControl ) != 0; #else return false; #endif } bool isAltKeyPressed() { #if TARGET_OS_MAC && !TARGET_OS_IPHONE - return ( [NSEvent modifierFlags] & NSAlternateKeyMask ) != 0; + return ( [NSEvent modifierFlags] & NSEventModifierFlagOption ) != 0; #else return false; #endif @@ -104,5 +104,21 @@ void appleSetThreadDescription( const char * str ) { return ret; } } + + int appleNaturalSortCompare(const char* s1, const char* s2) { + @autoreleasepool { + NSString * str1 = [NSString stringWithUTF8String: s1]; + NSString * str2 = [NSString stringWithUTF8String: s2]; + return (int) [str1 localizedCompare: str2]; + } + } + int appleNaturalSortCompareI(const char* s1, const char* s2) { + @autoreleasepool { + NSString * str1 = [NSString stringWithUTF8String: s1]; + NSString * str2 = [NSString stringWithUTF8String: s2]; + return (int) [str1 localizedCaseInsensitiveCompare: str2]; + } + } + } #endif diff --git a/sdk/pfc/pfc.vcxproj b/sdk/pfc/pfc.vcxproj index e8541b2..082eab7 100644 --- a/sdk/pfc/pfc.vcxproj +++ b/sdk/pfc/pfc.vcxproj @@ -666,6 +666,7 @@ + @@ -701,6 +702,7 @@ + @@ -772,6 +774,7 @@ + Disabled Disabled diff --git a/sdk/pfc/pfc.vcxproj.filters b/sdk/pfc/pfc.vcxproj.filters index 9ad3218..d1a820d 100644 --- a/sdk/pfc/pfc.vcxproj.filters +++ b/sdk/pfc/pfc.vcxproj.filters @@ -97,6 +97,9 @@ Source Files + + Source Files + @@ -348,6 +351,12 @@ Header Files + + Header Files + + + Header Files + diff --git a/sdk/pfc/pfc.xcodeproj/project.pbxproj b/sdk/pfc/pfc.xcodeproj/project.pbxproj new file mode 100644 index 0000000..04e2313 --- /dev/null +++ b/sdk/pfc/pfc.xcodeproj/project.pbxproj @@ -0,0 +1,885 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 0F0794D427C90AA4006BAD7F /* fixed_map.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0794CF27C90AA4006BAD7F /* fixed_map.h */; }; + 0F0794D527C90AA4006BAD7F /* charDownConvert.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0794D027C90AA4006BAD7F /* charDownConvert.h */; }; + 0F0794D627C90AA4006BAD7F /* SmartStrStr-table.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0794D127C90AA4006BAD7F /* SmartStrStr-table.h */; }; + 0F0794D727C90AA4006BAD7F /* charDownConvert.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F0794D227C90AA4006BAD7F /* charDownConvert.cpp */; }; + 0F0794D827C90AA4006BAD7F /* SmartStrStr-twoCharMappings.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F0794D327C90AA4006BAD7F /* SmartStrStr-twoCharMappings.h */; }; + 0F0794D927C90AA8006BAD7F /* charDownConvert.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F0794D227C90AA4006BAD7F /* charDownConvert.cpp */; }; + 0F14904D242E44C300D0BD81 /* notifyList.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F14904C242E44C300D0BD81 /* notifyList.h */; }; + 0F14904F242E44ED00D0BD81 /* autoref.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F14904E242E44ED00D0BD81 /* autoref.h */; }; + 0F149051242E454C00D0BD81 /* weakRef.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F149050242E454C00D0BD81 /* weakRef.h */; }; + 0F2F4BF7250BFF660014812D /* pfc-fb2k-hooks.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2F4BEF250BFF660014812D /* pfc-fb2k-hooks.h */; }; + 0F2F4BF8250BFF660014812D /* killswitch.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2F4BF0250BFF660014812D /* killswitch.h */; }; + 0F2F4BF9250BFF660014812D /* pfc-fb2k-hooks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2F4BF1250BFF660014812D /* pfc-fb2k-hooks.cpp */; }; + 0F2F4BFA250BFF660014812D /* pfc-fb2k-hooks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2F4BF1250BFF660014812D /* pfc-fb2k-hooks.cpp */; }; + 0F2F4BFB250BFF660014812D /* stdsort.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2F4BF2250BFF660014812D /* stdsort.h */; }; + 0F2F4BFC250BFF660014812D /* suppress_fb2k_hooks.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2F4BF3250BFF660014812D /* suppress_fb2k_hooks.h */; }; + 0F2F4BFD250BFF660014812D /* platform-objects.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2F4BF4250BFF660014812D /* platform-objects.h */; }; + 0F2F4BFE250BFF660014812D /* pocket_char_ops.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2F4BF5250BFF660014812D /* pocket_char_ops.h */; }; + 0F2F4BFF250BFF660014812D /* cmd_thread.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2F4BF6250BFF660014812D /* cmd_thread.h */; }; + 0F54079726C2964500A118C8 /* splitString2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FB717E126C295370040D7FE /* splitString2.cpp */; }; + 0F643510253A250600D6335A /* string-conv-lite.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F64350D253A250600D6335A /* string-conv-lite.h */; }; + 0F643511253A250600D6335A /* pp-winapi.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F64350E253A250600D6335A /* pp-winapi.h */; }; + 0F643512253A250600D6335A /* string-conv-lite.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F64350F253A250600D6335A /* string-conv-lite.cpp */; }; + 0F643513253A250600D6335A /* string-conv-lite.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F64350F253A250600D6335A /* string-conv-lite.cpp */; }; + 0F65005525122FD5001B03BA /* string-compare.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F65005125122FD5001B03BA /* string-compare.cpp */; }; + 0F65005625122FD5001B03BA /* string-compare.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F65005125122FD5001B03BA /* string-compare.cpp */; }; + 0F65005725122FD5001B03BA /* string-compare.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F65005225122FD5001B03BA /* string-compare.h */; }; + 0F65005825122FD5001B03BA /* string-part.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F65005325122FD5001B03BA /* string-part.h */; }; + 0F65005925122FD5001B03BA /* string-lite.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F65005425122FD5001B03BA /* string-lite.cpp */; }; + 0F65005A25122FD5001B03BA /* string-lite.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F65005425122FD5001B03BA /* string-lite.cpp */; }; + 0F7A1B6A2A692C88004F89FB /* filetimetools.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F7A1B682A692C88004F89FB /* filetimetools.cpp */; }; + 0F7A1B6B2A692C88004F89FB /* filetimetools.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F7A1B682A692C88004F89FB /* filetimetools.cpp */; }; + 0F7A1B6C2A692C88004F89FB /* filetimetools.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F7A1B692A692C88004F89FB /* filetimetools.h */; }; + 0F7EDDAA27FAFDA5000996AA /* unicode-normalize.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F7EDDA827FAFDA5000996AA /* unicode-normalize.cpp */; }; + 0F7EDDAB27FAFDA5000996AA /* unicode-normalize.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F7EDDA827FAFDA5000996AA /* unicode-normalize.cpp */; }; + 0F7EDDAC27FAFDA5000996AA /* unicode-normalize.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F7EDDA927FAFDA5000996AA /* unicode-normalize.h */; }; + 0FAC031727C8EC6500BA9E97 /* SmartStrStr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FAC031527C8EC6500BA9E97 /* SmartStrStr.cpp */; }; + 0FAC031827C8EC6500BA9E97 /* SmartStrStr.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FAC031627C8EC6500BA9E97 /* SmartStrStr.h */; }; + 0FAC031927C8EC6A00BA9E97 /* SmartStrStr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FAC031527C8EC6500BA9E97 /* SmartStrStr.cpp */; }; + 0FB717E226C295370040D7FE /* splitString2.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB717E026C295370040D7FE /* splitString2.h */; }; + 0FB717E326C295370040D7FE /* splitString2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FB717E126C295370040D7FE /* splitString2.cpp */; }; + 0FFFAEAE23C9C9580023328B /* crashWithMessage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FFFAEAD23C9C9580023328B /* crashWithMessage.cpp */; }; + 0FFFAEAF23C9DB640023328B /* crashWithMessage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FFFAEAD23C9C9580023328B /* crashWithMessage.cpp */; }; + B10D405B19ADFADB004D2596 /* audio_math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8A0CD198FB83D00A23435 /* audio_math.cpp */; }; + B10D405C19ADFADB004D2596 /* audio_sample.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8A0CE198FB83D00A23435 /* audio_sample.cpp */; }; + B10D405D19ADFADB004D2596 /* base64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD35C6198A702E00EF7043 /* base64.cpp */; }; + B10D405E19ADFADB004D2596 /* bit_array.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD35CB198A702E00EF7043 /* bit_array.cpp */; }; + B10D405F19ADFADB004D2596 /* bsearch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD35CE198A702E00EF7043 /* bsearch.cpp */; }; + B10D406019ADFADB004D2596 /* cpuid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD35D3198A702E00EF7043 /* cpuid.cpp */; }; + B10D406119ADFADB004D2596 /* filehandle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1C37D7E19922EF500EE6ABC /* filehandle.cpp */; }; + B10D406219ADFADB004D2596 /* guid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD35D6198A702E00EF7043 /* guid.cpp */; }; + B10D406319ADFADB004D2596 /* nix-objects.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD35DF198A702E00EF7043 /* nix-objects.cpp */; }; + B10D406419ADFADB004D2596 /* other.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD35E3198A702E00EF7043 /* other.cpp */; }; + B10D406519ADFADB004D2596 /* pathUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD35E5198A702E00EF7043 /* pathUtils.cpp */; }; + B10D406619ADFADB004D2596 /* printf.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD35EA198A702E00EF7043 /* printf.cpp */; }; + B10D406719ADFADB004D2596 /* selftest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD35F0198A702E00EF7043 /* selftest.cpp */; }; + B10D406819ADFADB004D2596 /* sort.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD35F1198A702E00EF7043 /* sort.cpp */; }; + B10D406919ADFADB004D2596 /* stdafx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD35F3198A702E00EF7043 /* stdafx.cpp */; }; + B10D406A19ADFADB004D2596 /* string_base.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD35F7198A702E00EF7043 /* string_base.cpp */; }; + B10D406B19ADFADB004D2596 /* string_conv.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD35F4198A702E00EF7043 /* string_conv.cpp */; }; + B10D406D19ADFADB004D2596 /* synchro_nix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD35FD198A702E00EF7043 /* synchro_nix.cpp */; }; + B10D406E19ADFADB004D2596 /* threads.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD3600198A702E00EF7043 /* threads.cpp */; }; + B10D406F19ADFADB004D2596 /* timers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD35EB198A702E00EF7043 /* timers.cpp */; }; + B10D407019ADFADB004D2596 /* utf8.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD3603198A702E00EF7043 /* utf8.cpp */; }; + B10D407119ADFADB004D2596 /* wildcard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1B502D3198FF75000525EAF /* wildcard.cpp */; }; + B10D407219ADFADB004D2596 /* win-objects.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD3604198A702E00EF7043 /* win-objects.cpp */; }; + B10D407319ADFE52004D2596 /* obj-c.mm in Sources */ = {isa = PBXBuildFile; fileRef = B1DD35E1198A702E00EF7043 /* obj-c.mm */; }; + B125C8AD1F46D9A900ADB97B /* once.h in Headers */ = {isa = PBXBuildFile; fileRef = B125C8AC1F46D9A900ADB97B /* once.h */; }; + B12CBBC81BD4D96A00952805 /* bigmem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B12CBBC61BD4D96A00952805 /* bigmem.cpp */; }; + B12CBBC91BD4D96A00952805 /* bigmem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B12CBBC61BD4D96A00952805 /* bigmem.cpp */; }; + B12CBBCA1BD4D96A00952805 /* bigmem.h in Headers */ = {isa = PBXBuildFile; fileRef = B12CBBC71BD4D96A00952805 /* bigmem.h */; }; + B16695F719ACC12A0001728F /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B16695F619ACC12A0001728F /* Foundation.framework */; }; + B17EB26E1E85358D0057E2A4 /* pool.h in Headers */ = {isa = PBXBuildFile; fileRef = B17EB26B1E85358D0057E2A4 /* pool.h */; }; + B17EB26F1E85358D0057E2A4 /* splitString.h in Headers */ = {isa = PBXBuildFile; fileRef = B17EB26C1E85358D0057E2A4 /* splitString.h */; }; + B17EB2701E85358D0057E2A4 /* wait_queue.h in Headers */ = {isa = PBXBuildFile; fileRef = B17EB26D1E85358D0057E2A4 /* wait_queue.h */; }; + B1B502D5198FF75000525EAF /* wildcard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1B502D3198FF75000525EAF /* wildcard.cpp */; }; + B1B502D6198FF75000525EAF /* wildcard.h in Headers */ = {isa = PBXBuildFile; fileRef = B1B502D4198FF75000525EAF /* wildcard.h */; }; + B1C37D7F19922EF500EE6ABC /* filehandle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1C37D7E19922EF500EE6ABC /* filehandle.cpp */; }; + B1CF88B71BD6657F00F42F87 /* fpu.h in Headers */ = {isa = PBXBuildFile; fileRef = B1CF88B41BD6657F00F42F87 /* fpu.h */; }; + B1CF88B81BD6657F00F42F87 /* mem_block.h in Headers */ = {isa = PBXBuildFile; fileRef = B1CF88B51BD6657F00F42F87 /* mem_block.h */; }; + B1CF88B91BD6657F00F42F87 /* string-lite.h in Headers */ = {isa = PBXBuildFile; fileRef = B1CF88B61BD6657F00F42F87 /* string-lite.h */; }; + B1D8A0D0198FB83D00A23435 /* audio_math.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8A0CD198FB83D00A23435 /* audio_math.cpp */; }; + B1D8A0D1198FB83D00A23435 /* audio_sample.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1D8A0CE198FB83D00A23435 /* audio_sample.cpp */; }; + B1D8A0D2198FB83D00A23435 /* audio_sample.h in Headers */ = {isa = PBXBuildFile; fileRef = B1D8A0CF198FB83D00A23435 /* audio_sample.h */; }; + B1DD3606198A702E00EF7043 /* alloc.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35C3198A702E00EF7043 /* alloc.h */; }; + B1DD3607198A702E00EF7043 /* array.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35C4198A702E00EF7043 /* array.h */; }; + B1DD3608198A702E00EF7043 /* avltree.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35C5198A702E00EF7043 /* avltree.h */; }; + B1DD3609198A702E00EF7043 /* base64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD35C6198A702E00EF7043 /* base64.cpp */; }; + B1DD360A198A702E00EF7043 /* base64.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35C7198A702E00EF7043 /* base64.h */; }; + B1DD360B198A702E00EF7043 /* binary_search.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35C8198A702E00EF7043 /* binary_search.h */; }; + B1DD360C198A702E00EF7043 /* bit_array_impl_part2.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35C9198A702E00EF7043 /* bit_array_impl_part2.h */; }; + B1DD360D198A702E00EF7043 /* bit_array_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35CA198A702E00EF7043 /* bit_array_impl.h */; }; + B1DD360E198A702E00EF7043 /* bit_array.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD35CB198A702E00EF7043 /* bit_array.cpp */; }; + B1DD360F198A702E00EF7043 /* bit_array.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35CC198A702E00EF7043 /* bit_array.h */; }; + B1DD3610198A702E00EF7043 /* bsearch_inline.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35CD198A702E00EF7043 /* bsearch_inline.h */; }; + B1DD3611198A702E00EF7043 /* bsearch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD35CE198A702E00EF7043 /* bsearch.cpp */; }; + B1DD3612198A702E00EF7043 /* bsearch.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35CF198A702E00EF7043 /* bsearch.h */; }; + B1DD3613198A702E00EF7043 /* byte_order.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35D0198A702E00EF7043 /* byte_order.h */; }; + B1DD3614198A702E00EF7043 /* chain_list_v2.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35D1198A702E00EF7043 /* chain_list_v2.h */; }; + B1DD3615198A702E00EF7043 /* com_ptr_t.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35D2198A702E00EF7043 /* com_ptr_t.h */; }; + B1DD3616198A702E00EF7043 /* cpuid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD35D3198A702E00EF7043 /* cpuid.cpp */; }; + B1DD3617198A702E00EF7043 /* cpuid.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35D4198A702E00EF7043 /* cpuid.h */; }; + B1DD3618198A702E00EF7043 /* event.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35D5198A702E00EF7043 /* event.h */; }; + B1DD3619198A702E00EF7043 /* guid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD35D6198A702E00EF7043 /* guid.cpp */; }; + B1DD361A198A702E00EF7043 /* guid.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35D7198A702E00EF7043 /* guid.h */; }; + B1DD361C198A702E00EF7043 /* int_types.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35D9198A702E00EF7043 /* int_types.h */; }; + B1DD361D198A702E00EF7043 /* iterators.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35DA198A702E00EF7043 /* iterators.h */; }; + B1DD361E198A702E00EF7043 /* list.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35DB198A702E00EF7043 /* list.h */; }; + B1DD361F198A702E00EF7043 /* map.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35DC198A702E00EF7043 /* map.h */; }; + B1DD3621198A702E00EF7043 /* memalign.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35DE198A702E00EF7043 /* memalign.h */; }; + B1DD3622198A702E00EF7043 /* nix-objects.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD35DF198A702E00EF7043 /* nix-objects.cpp */; }; + B1DD3623198A702E00EF7043 /* nix-objects.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35E0198A702E00EF7043 /* nix-objects.h */; }; + B1DD3624198A702E00EF7043 /* obj-c.mm in Sources */ = {isa = PBXBuildFile; fileRef = B1DD35E1198A702E00EF7043 /* obj-c.mm */; }; + B1DD3625198A702E00EF7043 /* order_helper.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35E2198A702E00EF7043 /* order_helper.h */; }; + B1DD3626198A702E00EF7043 /* other.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD35E3198A702E00EF7043 /* other.cpp */; }; + B1DD3627198A702E00EF7043 /* other.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35E4198A702E00EF7043 /* other.h */; }; + B1DD3628198A702E00EF7043 /* pathUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD35E5198A702E00EF7043 /* pathUtils.cpp */; }; + B1DD3629198A702E00EF7043 /* pathUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35E6198A702E00EF7043 /* pathUtils.h */; }; + B1DD362A198A702E00EF7043 /* pfc.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35E7198A702E00EF7043 /* pfc.h */; }; + B1DD362B198A702E00EF7043 /* primitives_part2.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35E8198A702E00EF7043 /* primitives_part2.h */; }; + B1DD362C198A702E00EF7043 /* primitives.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35E9198A702E00EF7043 /* primitives.h */; }; + B1DD362D198A702E00EF7043 /* printf.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD35EA198A702E00EF7043 /* printf.cpp */; }; + B1DD362E198A702E00EF7043 /* timers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD35EB198A702E00EF7043 /* timers.cpp */; }; + B1DD362F198A702E00EF7043 /* timers.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35EC198A702E00EF7043 /* timers.h */; }; + B1DD3630198A702E00EF7043 /* ptr_list.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35ED198A702E00EF7043 /* ptr_list.h */; }; + B1DD3631198A702E00EF7043 /* rcptr.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35EE198A702E00EF7043 /* rcptr.h */; }; + B1DD3632198A702E00EF7043 /* ref_counter.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35EF198A702E00EF7043 /* ref_counter.h */; }; + B1DD3633198A702E00EF7043 /* selftest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD35F0198A702E00EF7043 /* selftest.cpp */; }; + B1DD3634198A702E00EF7043 /* sort.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD35F1198A702E00EF7043 /* sort.cpp */; }; + B1DD3635198A702E00EF7043 /* sort.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35F2198A702E00EF7043 /* sort.h */; }; + B1DD3636198A702E00EF7043 /* stdafx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD35F3198A702E00EF7043 /* stdafx.cpp */; }; + B1DD3637198A702E00EF7043 /* string_conv.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD35F4198A702E00EF7043 /* string_conv.cpp */; }; + B1DD3638198A702E00EF7043 /* string_conv.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35F5198A702E00EF7043 /* string_conv.h */; }; + B1DD3639198A702E00EF7043 /* string_list.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35F6198A702E00EF7043 /* string_list.h */; }; + B1DD363A198A702E00EF7043 /* string_base.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD35F7198A702E00EF7043 /* string_base.cpp */; }; + B1DD363B198A702E00EF7043 /* string_base.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35F8198A702E00EF7043 /* string_base.h */; }; + B1DD363F198A702E00EF7043 /* syncd_storage.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35FC198A702E00EF7043 /* syncd_storage.h */; }; + B1DD3640198A702E00EF7043 /* synchro_nix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD35FD198A702E00EF7043 /* synchro_nix.cpp */; }; + B1DD3641198A702E00EF7043 /* synchro_nix.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35FE198A702E00EF7043 /* synchro_nix.h */; }; + B1DD3642198A702E00EF7043 /* synchro_win.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD35FF198A702E00EF7043 /* synchro_win.h */; }; + B1DD3643198A702E00EF7043 /* threads.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD3600198A702E00EF7043 /* threads.cpp */; }; + B1DD3644198A702E00EF7043 /* threads.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD3601198A702E00EF7043 /* threads.h */; }; + B1DD3645198A702E00EF7043 /* traits.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD3602198A702E00EF7043 /* traits.h */; }; + B1DD3646198A702E00EF7043 /* utf8.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD3603198A702E00EF7043 /* utf8.cpp */; }; + B1DD3647198A702E00EF7043 /* win-objects.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B1DD3604198A702E00EF7043 /* win-objects.cpp */; }; + B1DD3648198A702E00EF7043 /* win-objects.h in Headers */ = {isa = PBXBuildFile; fileRef = B1DD3605198A702E00EF7043 /* win-objects.h */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + B16695F219ACC12A0001728F /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "include/$(PRODUCT_NAME)"; + dstSubfolderSpec = 16; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 0F0794CF27C90AA4006BAD7F /* fixed_map.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fixed_map.h; sourceTree = ""; }; + 0F0794D027C90AA4006BAD7F /* charDownConvert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = charDownConvert.h; sourceTree = ""; }; + 0F0794D127C90AA4006BAD7F /* SmartStrStr-table.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SmartStrStr-table.h"; sourceTree = ""; }; + 0F0794D227C90AA4006BAD7F /* charDownConvert.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = charDownConvert.cpp; sourceTree = ""; }; + 0F0794D327C90AA4006BAD7F /* SmartStrStr-twoCharMappings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SmartStrStr-twoCharMappings.h"; sourceTree = ""; }; + 0F14904C242E44C300D0BD81 /* notifyList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = notifyList.h; sourceTree = ""; }; + 0F14904E242E44ED00D0BD81 /* autoref.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = autoref.h; sourceTree = ""; }; + 0F149050242E454C00D0BD81 /* weakRef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = weakRef.h; sourceTree = ""; }; + 0F2F4BEF250BFF660014812D /* pfc-fb2k-hooks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "pfc-fb2k-hooks.h"; sourceTree = ""; }; + 0F2F4BF0250BFF660014812D /* killswitch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = killswitch.h; sourceTree = ""; }; + 0F2F4BF1250BFF660014812D /* pfc-fb2k-hooks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "pfc-fb2k-hooks.cpp"; sourceTree = ""; }; + 0F2F4BF2250BFF660014812D /* stdsort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stdsort.h; sourceTree = ""; }; + 0F2F4BF3250BFF660014812D /* suppress_fb2k_hooks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = suppress_fb2k_hooks.h; sourceTree = ""; }; + 0F2F4BF4250BFF660014812D /* platform-objects.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "platform-objects.h"; sourceTree = ""; }; + 0F2F4BF5250BFF660014812D /* pocket_char_ops.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pocket_char_ops.h; sourceTree = ""; }; + 0F2F4BF6250BFF660014812D /* cmd_thread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cmd_thread.h; sourceTree = ""; }; + 0F64350D253A250600D6335A /* string-conv-lite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "string-conv-lite.h"; sourceTree = ""; }; + 0F64350E253A250600D6335A /* pp-winapi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "pp-winapi.h"; sourceTree = ""; }; + 0F64350F253A250600D6335A /* string-conv-lite.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "string-conv-lite.cpp"; sourceTree = ""; }; + 0F65005125122FD5001B03BA /* string-compare.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "string-compare.cpp"; sourceTree = ""; }; + 0F65005225122FD5001B03BA /* string-compare.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "string-compare.h"; sourceTree = ""; }; + 0F65005325122FD5001B03BA /* string-part.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "string-part.h"; sourceTree = ""; }; + 0F65005425122FD5001B03BA /* string-lite.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "string-lite.cpp"; sourceTree = ""; }; + 0F7A1B682A692C88004F89FB /* filetimetools.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = filetimetools.cpp; sourceTree = ""; }; + 0F7A1B692A692C88004F89FB /* filetimetools.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = filetimetools.h; sourceTree = ""; }; + 0F7EDDA827FAFDA5000996AA /* unicode-normalize.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = "unicode-normalize.cpp"; sourceTree = ""; }; + 0F7EDDA927FAFDA5000996AA /* unicode-normalize.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "unicode-normalize.h"; sourceTree = ""; }; + 0FAC031527C8EC6500BA9E97 /* SmartStrStr.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SmartStrStr.cpp; sourceTree = ""; }; + 0FAC031627C8EC6500BA9E97 /* SmartStrStr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SmartStrStr.h; sourceTree = ""; }; + 0FB717E026C295370040D7FE /* splitString2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = splitString2.h; sourceTree = ""; }; + 0FB717E126C295370040D7FE /* splitString2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = splitString2.cpp; sourceTree = ""; }; + 0FFFAEAD23C9C9580023328B /* crashWithMessage.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = crashWithMessage.cpp; sourceTree = ""; }; + B125C8AC1F46D9A900ADB97B /* once.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = once.h; sourceTree = ""; }; + B12CBBB61BD3F08800952805 /* pfc-lite.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "pfc-lite.h"; sourceTree = ""; }; + B12CBBB71BD3F0D100952805 /* string-interface.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "string-interface.h"; sourceTree = ""; }; + B12CBBB91BD4A01400952805 /* debug.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = debug.h; sourceTree = ""; }; + B12CBBC61BD4D96A00952805 /* bigmem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bigmem.cpp; sourceTree = ""; }; + B12CBBC71BD4D96A00952805 /* bigmem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bigmem.h; sourceTree = ""; }; + B12CBBD01BD4DD4600952805 /* ptrholder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ptrholder.h; sourceTree = ""; }; + B12CBBD11BD4DE8100952805 /* synchro.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = synchro.h; sourceTree = ""; }; + B16695F419ACC12A0001728F /* libpfc-iOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libpfc-iOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + B16695F619ACC12A0001728F /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + B166960419ACC12A0001728F /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; + B166960719ACC12A0001728F /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; }; + B17EB26B1E85358D0057E2A4 /* pool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pool.h; sourceTree = ""; }; + B17EB26C1E85358D0057E2A4 /* splitString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = splitString.h; sourceTree = ""; }; + B17EB26D1E85358D0057E2A4 /* wait_queue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wait_queue.h; sourceTree = ""; }; + B1B502D3198FF75000525EAF /* wildcard.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wildcard.cpp; sourceTree = ""; }; + B1B502D4198FF75000525EAF /* wildcard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wildcard.h; sourceTree = ""; }; + B1C37D7D19922EEB00EE6ABC /* filehandle.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = filehandle.h; sourceTree = ""; }; + B1C37D7E19922EF500EE6ABC /* filehandle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = filehandle.cpp; sourceTree = ""; }; + B1CF88B41BD6657F00F42F87 /* fpu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fpu.h; sourceTree = ""; }; + B1CF88B51BD6657F00F42F87 /* mem_block.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mem_block.h; sourceTree = ""; }; + B1CF88B61BD6657F00F42F87 /* string-lite.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "string-lite.h"; sourceTree = ""; }; + B1D8A0CD198FB83D00A23435 /* audio_math.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = audio_math.cpp; sourceTree = ""; }; + B1D8A0CE198FB83D00A23435 /* audio_sample.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = audio_sample.cpp; sourceTree = ""; }; + B1D8A0CF198FB83D00A23435 /* audio_sample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = audio_sample.h; sourceTree = ""; }; + B1DD35AF198A6FAA00EF7043 /* libpfc-Mac.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libpfc-Mac.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + B1DD35C3198A702E00EF7043 /* alloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = alloc.h; sourceTree = ""; }; + B1DD35C4198A702E00EF7043 /* array.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = array.h; sourceTree = ""; }; + B1DD35C5198A702E00EF7043 /* avltree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = avltree.h; sourceTree = ""; }; + B1DD35C6198A702E00EF7043 /* base64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = base64.cpp; sourceTree = ""; }; + B1DD35C7198A702E00EF7043 /* base64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = base64.h; sourceTree = ""; }; + B1DD35C8198A702E00EF7043 /* binary_search.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = binary_search.h; sourceTree = ""; }; + B1DD35C9198A702E00EF7043 /* bit_array_impl_part2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bit_array_impl_part2.h; sourceTree = ""; }; + B1DD35CA198A702E00EF7043 /* bit_array_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bit_array_impl.h; sourceTree = ""; }; + B1DD35CB198A702E00EF7043 /* bit_array.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bit_array.cpp; sourceTree = ""; }; + B1DD35CC198A702E00EF7043 /* bit_array.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bit_array.h; sourceTree = ""; }; + B1DD35CD198A702E00EF7043 /* bsearch_inline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bsearch_inline.h; sourceTree = ""; }; + B1DD35CE198A702E00EF7043 /* bsearch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = bsearch.cpp; sourceTree = ""; }; + B1DD35CF198A702E00EF7043 /* bsearch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bsearch.h; sourceTree = ""; }; + B1DD35D0198A702E00EF7043 /* byte_order.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = byte_order.h; sourceTree = ""; }; + B1DD35D1198A702E00EF7043 /* chain_list_v2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = chain_list_v2.h; sourceTree = ""; }; + B1DD35D2198A702E00EF7043 /* com_ptr_t.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = com_ptr_t.h; sourceTree = ""; }; + B1DD35D3198A702E00EF7043 /* cpuid.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cpuid.cpp; sourceTree = ""; }; + B1DD35D4198A702E00EF7043 /* cpuid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cpuid.h; sourceTree = ""; }; + B1DD35D5198A702E00EF7043 /* event.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = event.h; sourceTree = ""; }; + B1DD35D6198A702E00EF7043 /* guid.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = guid.cpp; sourceTree = ""; }; + B1DD35D7198A702E00EF7043 /* guid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = guid.h; sourceTree = ""; }; + B1DD35D9198A702E00EF7043 /* int_types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = int_types.h; sourceTree = ""; }; + B1DD35DA198A702E00EF7043 /* iterators.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iterators.h; sourceTree = ""; }; + B1DD35DB198A702E00EF7043 /* list.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = list.h; sourceTree = ""; }; + B1DD35DC198A702E00EF7043 /* map.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = map.h; sourceTree = ""; }; + B1DD35DE198A702E00EF7043 /* memalign.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = memalign.h; sourceTree = ""; }; + B1DD35DF198A702E00EF7043 /* nix-objects.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "nix-objects.cpp"; sourceTree = ""; }; + B1DD35E0198A702E00EF7043 /* nix-objects.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "nix-objects.h"; sourceTree = ""; }; + B1DD35E1198A702E00EF7043 /* obj-c.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "obj-c.mm"; sourceTree = ""; }; + B1DD35E2198A702E00EF7043 /* order_helper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = order_helper.h; sourceTree = ""; }; + B1DD35E3198A702E00EF7043 /* other.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = other.cpp; sourceTree = ""; }; + B1DD35E4198A702E00EF7043 /* other.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = other.h; sourceTree = ""; }; + B1DD35E5198A702E00EF7043 /* pathUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pathUtils.cpp; sourceTree = ""; }; + B1DD35E6198A702E00EF7043 /* pathUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pathUtils.h; sourceTree = ""; }; + B1DD35E7198A702E00EF7043 /* pfc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pfc.h; sourceTree = ""; }; + B1DD35E8198A702E00EF7043 /* primitives_part2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = primitives_part2.h; sourceTree = ""; }; + B1DD35E9198A702E00EF7043 /* primitives.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = primitives.h; sourceTree = ""; }; + B1DD35EA198A702E00EF7043 /* printf.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = printf.cpp; sourceTree = ""; }; + B1DD35EB198A702E00EF7043 /* timers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = timers.cpp; sourceTree = ""; }; + B1DD35EC198A702E00EF7043 /* timers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = timers.h; sourceTree = ""; }; + B1DD35ED198A702E00EF7043 /* ptr_list.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ptr_list.h; sourceTree = ""; }; + B1DD35EE198A702E00EF7043 /* rcptr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rcptr.h; sourceTree = ""; }; + B1DD35EF198A702E00EF7043 /* ref_counter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ref_counter.h; sourceTree = ""; }; + B1DD35F0198A702E00EF7043 /* selftest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = selftest.cpp; sourceTree = ""; }; + B1DD35F1198A702E00EF7043 /* sort.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sort.cpp; sourceTree = ""; }; + B1DD35F2198A702E00EF7043 /* sort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sort.h; sourceTree = ""; }; + B1DD35F3198A702E00EF7043 /* stdafx.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = stdafx.cpp; sourceTree = ""; }; + B1DD35F4198A702E00EF7043 /* string_conv.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = string_conv.cpp; sourceTree = ""; }; + B1DD35F5198A702E00EF7043 /* string_conv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = string_conv.h; sourceTree = ""; }; + B1DD35F6198A702E00EF7043 /* string_list.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = string_list.h; sourceTree = ""; }; + B1DD35F7198A702E00EF7043 /* string_base.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = string_base.cpp; sourceTree = ""; }; + B1DD35F8198A702E00EF7043 /* string_base.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = string_base.h; sourceTree = ""; }; + B1DD35FC198A702E00EF7043 /* syncd_storage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = syncd_storage.h; sourceTree = ""; }; + B1DD35FD198A702E00EF7043 /* synchro_nix.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = synchro_nix.cpp; sourceTree = ""; }; + B1DD35FE198A702E00EF7043 /* synchro_nix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = synchro_nix.h; sourceTree = ""; }; + B1DD35FF198A702E00EF7043 /* synchro_win.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = synchro_win.h; sourceTree = ""; }; + B1DD3600198A702E00EF7043 /* threads.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = threads.cpp; sourceTree = ""; }; + B1DD3601198A702E00EF7043 /* threads.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = threads.h; sourceTree = ""; }; + B1DD3602198A702E00EF7043 /* traits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = traits.h; sourceTree = ""; }; + B1DD3603198A702E00EF7043 /* utf8.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = utf8.cpp; sourceTree = ""; }; + B1DD3604198A702E00EF7043 /* win-objects.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "win-objects.cpp"; sourceTree = ""; }; + B1DD3605198A702E00EF7043 /* win-objects.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "win-objects.h"; sourceTree = ""; }; + B1EFBAC51B90658600C2CE84 /* lockless.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = lockless.h; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + B16695F119ACC12A0001728F /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + B16695F719ACC12A0001728F /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B1DD35AC198A6FAA00EF7043 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + B16695F519ACC12A0001728F /* Frameworks */ = { + isa = PBXGroup; + children = ( + B16695F619ACC12A0001728F /* Foundation.framework */, + B166960419ACC12A0001728F /* XCTest.framework */, + B166960719ACC12A0001728F /* UIKit.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + B1DD35A6198A6FAA00EF7043 = { + isa = PBXGroup; + children = ( + B1DD35C2198A701100EF7043 /* Source */, + B16695F519ACC12A0001728F /* Frameworks */, + B1DD35B0198A6FAA00EF7043 /* Products */, + ); + sourceTree = ""; + }; + B1DD35B0198A6FAA00EF7043 /* Products */ = { + isa = PBXGroup; + children = ( + B1DD35AF198A6FAA00EF7043 /* libpfc-Mac.a */, + B16695F419ACC12A0001728F /* libpfc-iOS.a */, + ); + name = Products; + sourceTree = ""; + }; + B1DD35C2198A701100EF7043 /* Source */ = { + isa = PBXGroup; + children = ( + 0F7A1B682A692C88004F89FB /* filetimetools.cpp */, + 0F7A1B692A692C88004F89FB /* filetimetools.h */, + 0F0794D227C90AA4006BAD7F /* charDownConvert.cpp */, + 0F0794D027C90AA4006BAD7F /* charDownConvert.h */, + 0F0794CF27C90AA4006BAD7F /* fixed_map.h */, + 0F0794D127C90AA4006BAD7F /* SmartStrStr-table.h */, + 0F0794D327C90AA4006BAD7F /* SmartStrStr-twoCharMappings.h */, + 0FAC031527C8EC6500BA9E97 /* SmartStrStr.cpp */, + 0FAC031627C8EC6500BA9E97 /* SmartStrStr.h */, + B1DD35C3198A702E00EF7043 /* alloc.h */, + B1DD35C4198A702E00EF7043 /* array.h */, + B1D8A0CD198FB83D00A23435 /* audio_math.cpp */, + B1D8A0CE198FB83D00A23435 /* audio_sample.cpp */, + B1D8A0CF198FB83D00A23435 /* audio_sample.h */, + 0F14904E242E44ED00D0BD81 /* autoref.h */, + B1DD35C5198A702E00EF7043 /* avltree.h */, + B1DD35C6198A702E00EF7043 /* base64.cpp */, + B1DD35C7198A702E00EF7043 /* base64.h */, + B12CBBC61BD4D96A00952805 /* bigmem.cpp */, + B12CBBC71BD4D96A00952805 /* bigmem.h */, + B1DD35C8198A702E00EF7043 /* binary_search.h */, + B1DD35C9198A702E00EF7043 /* bit_array_impl_part2.h */, + B1DD35CA198A702E00EF7043 /* bit_array_impl.h */, + B1DD35CB198A702E00EF7043 /* bit_array.cpp */, + B1DD35CC198A702E00EF7043 /* bit_array.h */, + B1DD35CD198A702E00EF7043 /* bsearch_inline.h */, + B1DD35CE198A702E00EF7043 /* bsearch.cpp */, + B1DD35CF198A702E00EF7043 /* bsearch.h */, + B1DD35D0198A702E00EF7043 /* byte_order.h */, + B1DD35D1198A702E00EF7043 /* chain_list_v2.h */, + 0F2F4BF6250BFF660014812D /* cmd_thread.h */, + B1DD35D2198A702E00EF7043 /* com_ptr_t.h */, + B1DD35D3198A702E00EF7043 /* cpuid.cpp */, + B1DD35D4198A702E00EF7043 /* cpuid.h */, + 0FFFAEAD23C9C9580023328B /* crashWithMessage.cpp */, + B12CBBB91BD4A01400952805 /* debug.h */, + B1DD35D5198A702E00EF7043 /* event.h */, + B1C37D7E19922EF500EE6ABC /* filehandle.cpp */, + B1C37D7D19922EEB00EE6ABC /* filehandle.h */, + B1CF88B41BD6657F00F42F87 /* fpu.h */, + B1DD35D6198A702E00EF7043 /* guid.cpp */, + B1DD35D7198A702E00EF7043 /* guid.h */, + B1DD35D9198A702E00EF7043 /* int_types.h */, + B1DD35DA198A702E00EF7043 /* iterators.h */, + 0F2F4BF0250BFF660014812D /* killswitch.h */, + B1DD35DB198A702E00EF7043 /* list.h */, + B1EFBAC51B90658600C2CE84 /* lockless.h */, + B1DD35DC198A702E00EF7043 /* map.h */, + B1CF88B51BD6657F00F42F87 /* mem_block.h */, + B1DD35DE198A702E00EF7043 /* memalign.h */, + B1DD35DF198A702E00EF7043 /* nix-objects.cpp */, + B1DD35E0198A702E00EF7043 /* nix-objects.h */, + 0F14904C242E44C300D0BD81 /* notifyList.h */, + B1DD35E1198A702E00EF7043 /* obj-c.mm */, + B125C8AC1F46D9A900ADB97B /* once.h */, + B1DD35E2198A702E00EF7043 /* order_helper.h */, + B1DD35E3198A702E00EF7043 /* other.cpp */, + B1DD35E4198A702E00EF7043 /* other.h */, + B1DD35E5198A702E00EF7043 /* pathUtils.cpp */, + B1DD35E6198A702E00EF7043 /* pathUtils.h */, + 0F2F4BF1250BFF660014812D /* pfc-fb2k-hooks.cpp */, + 0F2F4BEF250BFF660014812D /* pfc-fb2k-hooks.h */, + B12CBBB61BD3F08800952805 /* pfc-lite.h */, + B1DD35E7198A702E00EF7043 /* pfc.h */, + 0F2F4BF4250BFF660014812D /* platform-objects.h */, + 0F2F4BF5250BFF660014812D /* pocket_char_ops.h */, + B17EB26B1E85358D0057E2A4 /* pool.h */, + 0F64350E253A250600D6335A /* pp-winapi.h */, + B1DD35E8198A702E00EF7043 /* primitives_part2.h */, + B1DD35E9198A702E00EF7043 /* primitives.h */, + B1DD35EA198A702E00EF7043 /* printf.cpp */, + B1DD35ED198A702E00EF7043 /* ptr_list.h */, + B12CBBD01BD4DD4600952805 /* ptrholder.h */, + B1DD35EE198A702E00EF7043 /* rcptr.h */, + B1DD35EF198A702E00EF7043 /* ref_counter.h */, + B1DD35F0198A702E00EF7043 /* selftest.cpp */, + B1DD35F1198A702E00EF7043 /* sort.cpp */, + B1DD35F2198A702E00EF7043 /* sort.h */, + B17EB26C1E85358D0057E2A4 /* splitString.h */, + 0FB717E126C295370040D7FE /* splitString2.cpp */, + 0FB717E026C295370040D7FE /* splitString2.h */, + B1DD35F3198A702E00EF7043 /* stdafx.cpp */, + 0F2F4BF2250BFF660014812D /* stdsort.h */, + B1DD35F7198A702E00EF7043 /* string_base.cpp */, + B1DD35F8198A702E00EF7043 /* string_base.h */, + B1DD35F4198A702E00EF7043 /* string_conv.cpp */, + B1DD35F5198A702E00EF7043 /* string_conv.h */, + B1DD35F6198A702E00EF7043 /* string_list.h */, + 0F65005125122FD5001B03BA /* string-compare.cpp */, + 0F65005225122FD5001B03BA /* string-compare.h */, + 0F64350F253A250600D6335A /* string-conv-lite.cpp */, + 0F64350D253A250600D6335A /* string-conv-lite.h */, + B12CBBB71BD3F0D100952805 /* string-interface.h */, + 0F65005425122FD5001B03BA /* string-lite.cpp */, + B1CF88B61BD6657F00F42F87 /* string-lite.h */, + 0F65005325122FD5001B03BA /* string-part.h */, + 0F2F4BF3250BFF660014812D /* suppress_fb2k_hooks.h */, + B1DD35FC198A702E00EF7043 /* syncd_storage.h */, + B1DD35FD198A702E00EF7043 /* synchro_nix.cpp */, + B1DD35FE198A702E00EF7043 /* synchro_nix.h */, + B1DD35FF198A702E00EF7043 /* synchro_win.h */, + B12CBBD11BD4DE8100952805 /* synchro.h */, + B1DD3600198A702E00EF7043 /* threads.cpp */, + B1DD3601198A702E00EF7043 /* threads.h */, + B1DD35EB198A702E00EF7043 /* timers.cpp */, + B1DD35EC198A702E00EF7043 /* timers.h */, + B1DD3602198A702E00EF7043 /* traits.h */, + B1DD3603198A702E00EF7043 /* utf8.cpp */, + B17EB26D1E85358D0057E2A4 /* wait_queue.h */, + 0F149050242E454C00D0BD81 /* weakRef.h */, + B1B502D3198FF75000525EAF /* wildcard.cpp */, + B1B502D4198FF75000525EAF /* wildcard.h */, + B1DD3604198A702E00EF7043 /* win-objects.cpp */, + B1DD3605198A702E00EF7043 /* win-objects.h */, + 0F7EDDA827FAFDA5000996AA /* unicode-normalize.cpp */, + 0F7EDDA927FAFDA5000996AA /* unicode-normalize.h */, + ); + name = Source; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + B1DD35AD198A6FAA00EF7043 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + B1DD361E198A702E00EF7043 /* list.h in Headers */, + 0F2F4BF7250BFF660014812D /* pfc-fb2k-hooks.h in Headers */, + B12CBBCA1BD4D96A00952805 /* bigmem.h in Headers */, + B1DD3629198A702E00EF7043 /* pathUtils.h in Headers */, + B1DD3615198A702E00EF7043 /* com_ptr_t.h in Headers */, + B1DD360D198A702E00EF7043 /* bit_array_impl.h in Headers */, + 0F7EDDAC27FAFDA5000996AA /* unicode-normalize.h in Headers */, + B1DD3617198A702E00EF7043 /* cpuid.h in Headers */, + 0F643510253A250600D6335A /* string-conv-lite.h in Headers */, + B1DD3635198A702E00EF7043 /* sort.h in Headers */, + B1DD3648198A702E00EF7043 /* win-objects.h in Headers */, + B1DD3607198A702E00EF7043 /* array.h in Headers */, + B1DD360B198A702E00EF7043 /* binary_search.h in Headers */, + B1DD3621198A702E00EF7043 /* memalign.h in Headers */, + B1B502D6198FF75000525EAF /* wildcard.h in Headers */, + B1DD361A198A702E00EF7043 /* guid.h in Headers */, + B1DD362F198A702E00EF7043 /* timers.h in Headers */, + 0F0794D827C90AA4006BAD7F /* SmartStrStr-twoCharMappings.h in Headers */, + B1DD3638198A702E00EF7043 /* string_conv.h in Headers */, + B1DD3610198A702E00EF7043 /* bsearch_inline.h in Headers */, + 0F65005725122FD5001B03BA /* string-compare.h in Headers */, + 0F14904F242E44ED00D0BD81 /* autoref.h in Headers */, + 0F0794D527C90AA4006BAD7F /* charDownConvert.h in Headers */, + 0FAC031827C8EC6500BA9E97 /* SmartStrStr.h in Headers */, + B1DD3641198A702E00EF7043 /* synchro_nix.h in Headers */, + B1CF88B91BD6657F00F42F87 /* string-lite.h in Headers */, + B1DD360C198A702E00EF7043 /* bit_array_impl_part2.h in Headers */, + B1DD3645198A702E00EF7043 /* traits.h in Headers */, + 0F2F4BFB250BFF660014812D /* stdsort.h in Headers */, + B1DD361F198A702E00EF7043 /* map.h in Headers */, + 0F2F4BF8250BFF660014812D /* killswitch.h in Headers */, + B1DD3612198A702E00EF7043 /* bsearch.h in Headers */, + 0F2F4BFE250BFF660014812D /* pocket_char_ops.h in Headers */, + 0F149051242E454C00D0BD81 /* weakRef.h in Headers */, + B1CF88B81BD6657F00F42F87 /* mem_block.h in Headers */, + B1DD3614198A702E00EF7043 /* chain_list_v2.h in Headers */, + 0F0794D627C90AA4006BAD7F /* SmartStrStr-table.h in Headers */, + B1DD3627198A702E00EF7043 /* other.h in Headers */, + 0F2F4BFC250BFF660014812D /* suppress_fb2k_hooks.h in Headers */, + B17EB26E1E85358D0057E2A4 /* pool.h in Headers */, + B17EB26F1E85358D0057E2A4 /* splitString.h in Headers */, + 0F2F4BFF250BFF660014812D /* cmd_thread.h in Headers */, + B1DD362B198A702E00EF7043 /* primitives_part2.h in Headers */, + 0F2F4BFD250BFF660014812D /* platform-objects.h in Headers */, + B1DD3632198A702E00EF7043 /* ref_counter.h in Headers */, + B1DD3630198A702E00EF7043 /* ptr_list.h in Headers */, + B17EB2701E85358D0057E2A4 /* wait_queue.h in Headers */, + B1DD362C198A702E00EF7043 /* primitives.h in Headers */, + B1DD3639198A702E00EF7043 /* string_list.h in Headers */, + B1DD361C198A702E00EF7043 /* int_types.h in Headers */, + B1DD3618198A702E00EF7043 /* event.h in Headers */, + 0F7A1B6C2A692C88004F89FB /* filetimetools.h in Headers */, + B1DD3608198A702E00EF7043 /* avltree.h in Headers */, + B1DD3606198A702E00EF7043 /* alloc.h in Headers */, + 0F14904D242E44C300D0BD81 /* notifyList.h in Headers */, + B1DD3644198A702E00EF7043 /* threads.h in Headers */, + 0F65005825122FD5001B03BA /* string-part.h in Headers */, + B1DD3623198A702E00EF7043 /* nix-objects.h in Headers */, + B1DD363F198A702E00EF7043 /* syncd_storage.h in Headers */, + B1DD362A198A702E00EF7043 /* pfc.h in Headers */, + B1DD3613198A702E00EF7043 /* byte_order.h in Headers */, + B1DD3631198A702E00EF7043 /* rcptr.h in Headers */, + 0F0794D427C90AA4006BAD7F /* fixed_map.h in Headers */, + B1DD3642198A702E00EF7043 /* synchro_win.h in Headers */, + 0F643511253A250600D6335A /* pp-winapi.h in Headers */, + B1DD360F198A702E00EF7043 /* bit_array.h in Headers */, + B1DD360A198A702E00EF7043 /* base64.h in Headers */, + B1D8A0D2198FB83D00A23435 /* audio_sample.h in Headers */, + B125C8AD1F46D9A900ADB97B /* once.h in Headers */, + B1DD363B198A702E00EF7043 /* string_base.h in Headers */, + B1DD361D198A702E00EF7043 /* iterators.h in Headers */, + 0FB717E226C295370040D7FE /* splitString2.h in Headers */, + B1DD3625198A702E00EF7043 /* order_helper.h in Headers */, + B1CF88B71BD6657F00F42F87 /* fpu.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + B16695F319ACC12A0001728F /* pfc-iOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = B166961819ACC12A0001728F /* Build configuration list for PBXNativeTarget "pfc-iOS" */; + buildPhases = ( + B16695F019ACC12A0001728F /* Sources */, + B16695F119ACC12A0001728F /* Frameworks */, + B16695F219ACC12A0001728F /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "pfc-iOS"; + productName = "pfc-iOS"; + productReference = B16695F419ACC12A0001728F /* libpfc-iOS.a */; + productType = "com.apple.product-type.library.static"; + }; + B1DD35AE198A6FAA00EF7043 /* pfc-Mac */ = { + isa = PBXNativeTarget; + buildConfigurationList = B1DD35B3198A6FAA00EF7043 /* Build configuration list for PBXNativeTarget "pfc-Mac" */; + buildPhases = ( + B1DD35AB198A6FAA00EF7043 /* Sources */, + B1DD35AC198A6FAA00EF7043 /* Frameworks */, + B1DD35AD198A6FAA00EF7043 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "pfc-Mac"; + productName = pfc; + productReference = B1DD35AF198A6FAA00EF7043 /* libpfc-Mac.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + B1DD35A7198A6FAA00EF7043 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1320; + ORGANIZATIONNAME = "___FULLUSERNAME___"; + }; + buildConfigurationList = B1DD35AA198A6FAA00EF7043 /* Build configuration list for PBXProject "pfc" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = B1DD35A6198A6FAA00EF7043; + productRefGroup = B1DD35B0198A6FAA00EF7043 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + B1DD35AE198A6FAA00EF7043 /* pfc-Mac */, + B16695F319ACC12A0001728F /* pfc-iOS */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + B16695F019ACC12A0001728F /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B10D405C19ADFADB004D2596 /* audio_sample.cpp in Sources */, + B10D406A19ADFADB004D2596 /* string_base.cpp in Sources */, + 0F643513253A250600D6335A /* string-conv-lite.cpp in Sources */, + B10D405B19ADFADB004D2596 /* audio_math.cpp in Sources */, + B10D406E19ADFADB004D2596 /* threads.cpp in Sources */, + B10D406619ADFADB004D2596 /* printf.cpp in Sources */, + 0F54079726C2964500A118C8 /* splitString2.cpp in Sources */, + 0FFFAEAF23C9DB640023328B /* crashWithMessage.cpp in Sources */, + 0F65005A25122FD5001B03BA /* string-lite.cpp in Sources */, + B10D406419ADFADB004D2596 /* other.cpp in Sources */, + B10D406519ADFADB004D2596 /* pathUtils.cpp in Sources */, + B10D406319ADFADB004D2596 /* nix-objects.cpp in Sources */, + B10D406219ADFADB004D2596 /* guid.cpp in Sources */, + B10D405F19ADFADB004D2596 /* bsearch.cpp in Sources */, + B10D406719ADFADB004D2596 /* selftest.cpp in Sources */, + 0F7A1B6B2A692C88004F89FB /* filetimetools.cpp in Sources */, + B10D406919ADFADB004D2596 /* stdafx.cpp in Sources */, + B10D406819ADFADB004D2596 /* sort.cpp in Sources */, + 0F65005625122FD5001B03BA /* string-compare.cpp in Sources */, + B12CBBC91BD4D96A00952805 /* bigmem.cpp in Sources */, + B10D406D19ADFADB004D2596 /* synchro_nix.cpp in Sources */, + B10D406019ADFADB004D2596 /* cpuid.cpp in Sources */, + 0F7EDDAB27FAFDA5000996AA /* unicode-normalize.cpp in Sources */, + B10D405D19ADFADB004D2596 /* base64.cpp in Sources */, + B10D406B19ADFADB004D2596 /* string_conv.cpp in Sources */, + 0F0794D927C90AA8006BAD7F /* charDownConvert.cpp in Sources */, + B10D407019ADFADB004D2596 /* utf8.cpp in Sources */, + B10D407319ADFE52004D2596 /* obj-c.mm in Sources */, + 0FAC031927C8EC6A00BA9E97 /* SmartStrStr.cpp in Sources */, + B10D407119ADFADB004D2596 /* wildcard.cpp in Sources */, + 0F2F4BFA250BFF660014812D /* pfc-fb2k-hooks.cpp in Sources */, + B10D405E19ADFADB004D2596 /* bit_array.cpp in Sources */, + B10D407219ADFADB004D2596 /* win-objects.cpp in Sources */, + B10D406119ADFADB004D2596 /* filehandle.cpp in Sources */, + B10D406F19ADFADB004D2596 /* timers.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B1DD35AB198A6FAA00EF7043 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B1DD3647198A702E00EF7043 /* win-objects.cpp in Sources */, + B1DD3611198A702E00EF7043 /* bsearch.cpp in Sources */, + 0F643512253A250600D6335A /* string-conv-lite.cpp in Sources */, + B1DD3609198A702E00EF7043 /* base64.cpp in Sources */, + B1DD363A198A702E00EF7043 /* string_base.cpp in Sources */, + B1DD362D198A702E00EF7043 /* printf.cpp in Sources */, + 0FB717E326C295370040D7FE /* splitString2.cpp in Sources */, + 0FFFAEAE23C9C9580023328B /* crashWithMessage.cpp in Sources */, + 0F65005925122FD5001B03BA /* string-lite.cpp in Sources */, + B1D8A0D1198FB83D00A23435 /* audio_sample.cpp in Sources */, + B1DD3637198A702E00EF7043 /* string_conv.cpp in Sources */, + B1C37D7F19922EF500EE6ABC /* filehandle.cpp in Sources */, + B1DD3643198A702E00EF7043 /* threads.cpp in Sources */, + B1DD3624198A702E00EF7043 /* obj-c.mm in Sources */, + B1D8A0D0198FB83D00A23435 /* audio_math.cpp in Sources */, + 0F7A1B6A2A692C88004F89FB /* filetimetools.cpp in Sources */, + B1DD3628198A702E00EF7043 /* pathUtils.cpp in Sources */, + B1DD3646198A702E00EF7043 /* utf8.cpp in Sources */, + 0F65005525122FD5001B03BA /* string-compare.cpp in Sources */, + B1DD3636198A702E00EF7043 /* stdafx.cpp in Sources */, + B12CBBC81BD4D96A00952805 /* bigmem.cpp in Sources */, + B1DD362E198A702E00EF7043 /* timers.cpp in Sources */, + 0F7EDDAA27FAFDA5000996AA /* unicode-normalize.cpp in Sources */, + B1DD3622198A702E00EF7043 /* nix-objects.cpp in Sources */, + B1DD3640198A702E00EF7043 /* synchro_nix.cpp in Sources */, + 0F0794D727C90AA4006BAD7F /* charDownConvert.cpp in Sources */, + B1DD3633198A702E00EF7043 /* selftest.cpp in Sources */, + B1DD3626198A702E00EF7043 /* other.cpp in Sources */, + 0FAC031727C8EC6500BA9E97 /* SmartStrStr.cpp in Sources */, + B1DD360E198A702E00EF7043 /* bit_array.cpp in Sources */, + B1DD3619198A702E00EF7043 /* guid.cpp in Sources */, + 0F2F4BF9250BFF660014812D /* pfc-fb2k-hooks.cpp in Sources */, + B1DD3634198A702E00EF7043 /* sort.cpp in Sources */, + B1DD3616198A702E00EF7043 /* cpuid.cpp in Sources */, + B1B502D5198FF75000525EAF /* wildcard.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + B166961419ACC12A0001728F /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + DSTROOT = /tmp/pfc_iOS.dst; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + }; + name = Debug; + }; + B166961519ACC12A0001728F /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + DSTROOT = /tmp/pfc_iOS.dst; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + B1DD35B1198A6FAA00EF7043 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "pfc-lite.h"; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.1; + MACOSX_DEPLOYMENT_TARGET = 10.13; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + B1DD35B2198A6FAA00EF7043 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "pfc-lite.h"; + GCC_PREPROCESSOR_DEFINITIONS = "NDEBUG=1"; + GCC_SYMBOLS_PRIVATE_EXTERN = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.1; + MACOSX_DEPLOYMENT_TARGET = 10.13; + SDKROOT = macosx; + SKIP_INSTALL = YES; + }; + name = Release; + }; + B1DD35B4198A6FAA00EF7043 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + EXECUTABLE_PREFIX = lib; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + B1DD35B5198A6FAA00EF7043 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + EXECUTABLE_PREFIX = lib; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + B166961819ACC12A0001728F /* Build configuration list for PBXNativeTarget "pfc-iOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B166961419ACC12A0001728F /* Debug */, + B166961519ACC12A0001728F /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B1DD35AA198A6FAA00EF7043 /* Build configuration list for PBXProject "pfc" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B1DD35B1198A6FAA00EF7043 /* Debug */, + B1DD35B2198A6FAA00EF7043 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B1DD35B3198A6FAA00EF7043 /* Build configuration list for PBXNativeTarget "pfc-Mac" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B1DD35B4198A6FAA00EF7043 /* Debug */, + B1DD35B5198A6FAA00EF7043 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = B1DD35A7198A6FAA00EF7043 /* Project object */; +} diff --git a/sdk/pfc/sort.cpp b/sdk/pfc/sort.cpp index 53299e6..56da0bd 100644 --- a/sdk/pfc/sort.cpp +++ b/sdk/pfc/sort.cpp @@ -1,5 +1,6 @@ #include "pfc-lite.h" #include "sort.h" +#include "sort2.h" #include "bit_array_impl.h" #include "ref_counter.h" @@ -267,5 +268,15 @@ void sort_stable(sort_callback & p_callback,t_size p_count) sort(cb,p_count); } + + +permutation_t make_identitiy(size_t count) { + permutation_t ret; ret.set_size_discard(count); + for (size_t walk = 0; walk < count; ++walk) { + ret[walk] = walk; + } + return ret; +} + } diff --git a/sdk/pfc/sort2.h b/sdk/pfc/sort2.h new file mode 100644 index 0000000..0ad1eb9 --- /dev/null +++ b/sdk/pfc/sort2.h @@ -0,0 +1,34 @@ +#pragma once + +#include "sort.h" + +// 2023 additions + + +namespace pfc { + + typedef array_t permutation_t; + + permutation_t make_identitiy(size_t); + + template + permutation_t sort_get_permutation(container_t const& data, compare_t compare) { + const size_t count = std::size(data); + auto ret = make_identitiy( count ); + if ( count > 0 ) sort_get_permutation_t(data, compare, count, ret.get_ptr() ); + return ret; + } + template + permutation_t sort_stable_get_permutation(container_t const& data, compare_t compare) { + const size_t count = std::size(data); + auto ret = make_identitiy( count ); + if ( count > 0 ) sort_stable_get_permutation_t(data, compare, count, ret.get_ptr() ); + return ret; + } + + template + void reorder(container_t& data, permutation_t const& order) { + PFC_ASSERT( std::size(data) == std::size(order) ); + reorder_t( data, order.get_ptr(), order.get_size() ); + } +} \ No newline at end of file diff --git a/sdk/pfc/string-compare.cpp b/sdk/pfc/string-compare.cpp index 0b3c0e5..246e856 100644 --- a/sdk/pfc/string-compare.cpp +++ b/sdk/pfc/string-compare.cpp @@ -134,7 +134,32 @@ namespace pfc { int naturalSortCompareI(const char* s1, const char* s2) throw() { return naturalSortCompareInternal(s1, s2, true); } - +#ifdef _WIN32 + int winNaturalSortCompare(const char* s1, const char* s2); + int winNaturalSortCompareI(const char* s1, const char* s2); +#endif +#ifdef __APPLE__ + int appleNaturalSortCompare(const char* s1, const char* s2); + int appleNaturalSortCompareI(const char* s1, const char* s2); +#endif + int sysNaturalSortCompare(const char* s1, const char* s2) { +#ifdef _WIN32 + return winNaturalSortCompare(s1, s2); +#elif defined(__APPLE__) + return appleNaturalSortCompare(s1, s2); +#else + return naturalSortCompare(s1, s2); +#endif + } + int sysNaturalSortCompareI(const char* s1, const char* s2) { +#ifdef _WIN32 + return winNaturalSortCompareI(s1, s2); +#elif defined(__APPLE__) + return appleNaturalSortCompareI(s1, s2); +#else + return naturalSortCompareI(s1, s2); +#endif + } const char* _stringComparatorCommon::myStringToPtr(string_part_ref) { pfc::crash(); return nullptr; } diff --git a/sdk/pfc/string-compare.h b/sdk/pfc/string-compare.h index 551a108..230d7d4 100644 --- a/sdk/pfc/string-compare.h +++ b/sdk/pfc/string-compare.h @@ -6,9 +6,16 @@ namespace pfc { int wstricmp_ascii(const wchar_t* s1, const wchar_t* s2) throw(); int stricmp_ascii(const char* s1, const char* s2) throw(); int stricmp_ascii_ex(const char* s1, t_size len1, const char* s2, t_size len2) throw(); + + // Platform-independant lowlevel natural sort implementation int naturalSortCompare(const char* s1, const char* s2) throw(); int naturalSortCompareI(const char* s1, const char* s2) throw(); + // System-specialized natural sort compare, better ordering of Unicode text, specialized for Apple and MS platforms + // Falls back to naturalSortCompare/naturalSortCompareI where not available + int sysNaturalSortCompare(const char* s1, const char* s2); + int sysNaturalSortCompareI(const char* s1, const char* s2); + int strcmp_ex(const char* p1, t_size n1, const char* p2, t_size n2) throw(); int strcmp_nc(const char* p1, size_t n1, const char* p2, size_t n2) throw(); diff --git a/sdk/pfc/string-lite.h b/sdk/pfc/string-lite.h index 5f698e0..9d3fb71 100644 --- a/sdk/pfc/string-lite.h +++ b/sdk/pfc/string-lite.h @@ -124,7 +124,8 @@ namespace pfc { char firstChar() const; char lastChar() const; - bool isEmpty() const { return length() == 0; } + bool isEmpty() const { return empty(); } + bool empty() const { return length() == 0;} stringLite replace(stringp strOld, stringp strNew) const; stringLite trim(char c) const; diff --git a/sdk/pfc/string_conv.h b/sdk/pfc/string_conv.h index a45e7e1..e3f12e3 100644 --- a/sdk/pfc/string_conv.h +++ b/sdk/pfc/string_conv.h @@ -72,14 +72,14 @@ namespace pfc { template<> inline const char * null_string_t() {return "";} template<> inline const wchar_t * null_string_t() {return L"";} - template t_size strlen_t(const t_char * p_string,t_size p_string_size = ~0) { + template t_size strlen_t(const t_char * p_string,t_size p_string_size = SIZE_MAX) { for(t_size n=0;n bool string_is_empty_t(const t_char * p_string,t_size p_string_size = ~0) { + template bool string_is_empty_t(const t_char * p_string,t_size p_string_size = SIZE_MAX) { if (p_string_size == 0) return true; return p_string[0] == 0; } @@ -101,9 +101,9 @@ namespace pfc { class string_utf8_from_wide_t { public: string_utf8_from_wide_t() {} - string_utf8_from_wide_t(const wchar_t * p_source,t_size p_source_size = ~0) {convert(p_source,p_source_size);} + string_utf8_from_wide_t(const wchar_t * p_source,t_size p_source_size = SIZE_MAX) {convert(p_source,p_source_size);} - void convert(const wchar_t * p_source,t_size p_source_size = ~0) { + void convert(const wchar_t * p_source,t_size p_source_size = SIZE_MAX) { t_size size = estimate_wide_to_utf8(p_source,p_source_size); m_buffer.set_size(size); convert_wide_to_utf8( m_buffer.get_ptr_var(),size,p_source,p_source_size); @@ -173,9 +173,9 @@ namespace pfc { class string_wide_from_win1252_t { public: string_wide_from_win1252_t() {} - string_wide_from_win1252_t(const char * p_source,t_size p_source_size = ~0) {convert(p_source,p_source_size);} + string_wide_from_win1252_t(const char * p_source,t_size p_source_size = SIZE_MAX) {convert(p_source,p_source_size);} - void convert(const char * p_source,t_size p_source_size = ~0) { + void convert(const char * p_source,t_size p_source_size = SIZE_MAX) { t_size size = estimate_win1252_to_wide(p_source,p_source_size); m_buffer.set_size(size); convert_win1252_to_wide(m_buffer.get_ptr_var(),size,p_source,p_source_size); @@ -196,9 +196,9 @@ namespace pfc { class string_win1252_from_wide_t { public: string_win1252_from_wide_t() {} - string_win1252_from_wide_t(const wchar_t * p_source,t_size p_source_size = ~0) {convert(p_source,p_source_size);} + string_win1252_from_wide_t(const wchar_t * p_source,t_size p_source_size = SIZE_MAX) {convert(p_source,p_source_size);} - void convert(const wchar_t * p_source,t_size p_source_size = ~0) { + void convert(const wchar_t * p_source,t_size p_source_size = SIZE_MAX) { t_size size = estimate_wide_to_win1252(p_source,p_source_size); m_buffer.set_size(size); convert_wide_to_win1252(m_buffer.get_ptr_var(),size,p_source,p_source_size); @@ -219,9 +219,9 @@ namespace pfc { class string_utf8_from_win1252_t { public: string_utf8_from_win1252_t() {} - string_utf8_from_win1252_t(const char * p_source,t_size p_source_size = ~0) {convert(p_source,p_source_size);} + string_utf8_from_win1252_t(const char * p_source,t_size p_source_size = SIZE_MAX) {convert(p_source,p_source_size);} - void convert(const char * p_source,t_size p_source_size = ~0) { + void convert(const char * p_source,t_size p_source_size = SIZE_MAX) { t_size size = estimate_win1252_to_utf8(p_source,p_source_size); m_buffer.set_size(size); convert_win1252_to_utf8(m_buffer.get_ptr_var(),size,p_source,p_source_size); @@ -242,9 +242,9 @@ namespace pfc { class string_win1252_from_utf8_t { public: string_win1252_from_utf8_t() {} - string_win1252_from_utf8_t(const char * p_source,t_size p_source_size = ~0) {convert(p_source,p_source_size);} + string_win1252_from_utf8_t(const char * p_source,t_size p_source_size = SIZE_MAX) {convert(p_source,p_source_size);} - void convert(const char * p_source,t_size p_source_size = ~0) { + void convert(const char * p_source,t_size p_source_size = SIZE_MAX) { t_size size = estimate_utf8_to_win1252(p_source,p_source_size); m_buffer.set_size(size); convert_utf8_to_win1252(m_buffer.get_ptr_var(),size,p_source,p_source_size); @@ -263,9 +263,9 @@ namespace pfc { class string_ascii_from_utf8 { public: string_ascii_from_utf8() {} - string_ascii_from_utf8( const char * p_source, t_size p_source_size = ~0) { convert(p_source, p_source_size); } + string_ascii_from_utf8( const char * p_source, t_size p_source_size = SIZE_MAX) { convert(p_source, p_source_size); } - void convert( const char * p_source, t_size p_source_size = ~0) { + void convert( const char * p_source, t_size p_source_size = SIZE_MAX) { t_size size = estimate_utf8_to_ascii(p_source, p_source_size); m_buffer.set_size(size); convert_utf8_to_ascii(m_buffer.get_ptr_var(), size, p_source, p_source_size); @@ -283,9 +283,9 @@ namespace pfc { class string_utf8_from_utf16 { public: string_utf8_from_utf16() {} - string_utf8_from_utf16( const char16_t * p_source, size_t p_source_size = ~0) {convert(p_source, p_source_size);} + string_utf8_from_utf16( const char16_t * p_source, size_t p_source_size = SIZE_MAX) {convert(p_source, p_source_size);} - void convert( const char16_t * p_source, size_t p_source_size = ~0) { + void convert( const char16_t * p_source, size_t p_source_size = SIZE_MAX) { size_t size = estimate_utf16_to_utf8(p_source, p_source_size); m_buffer.set_size(size); convert_utf16_to_utf8(m_buffer.get_ptr_var(), size, p_source, p_source_size ); @@ -387,9 +387,9 @@ namespace pfc { public: string_wide_from_codepage_t() {} string_wide_from_codepage_t(const string_wide_from_codepage_t & p_source) : m_buffer(p_source.m_buffer) {} - string_wide_from_codepage_t(unsigned p_codepage,const char * p_source,t_size p_source_size = ~0) {convert(p_codepage,p_source,p_source_size);} + string_wide_from_codepage_t(unsigned p_codepage,const char * p_source,t_size p_source_size = SIZE_MAX) {convert(p_codepage,p_source,p_source_size);} - void convert(unsigned p_codepage,const char * p_source,t_size p_source_size = ~0) { + void convert(unsigned p_codepage,const char * p_source,t_size p_source_size = SIZE_MAX) { t_size size = estimate_codepage_to_wide(p_codepage,p_source,p_source_size); m_buffer.set_size(size); convert_codepage_to_wide(p_codepage, m_buffer.get_ptr_var(),size,p_source,p_source_size); @@ -411,9 +411,9 @@ namespace pfc { public: string_codepage_from_wide_t() {} string_codepage_from_wide_t(const string_codepage_from_wide_t & p_source) : m_buffer(p_source.m_buffer) {} - string_codepage_from_wide_t(unsigned p_codepage,const wchar_t * p_source,t_size p_source_size = ~0) {convert(p_codepage,p_source,p_source_size);} + string_codepage_from_wide_t(unsigned p_codepage,const wchar_t * p_source,t_size p_source_size = SIZE_MAX) {convert(p_codepage,p_source,p_source_size);} - void convert(unsigned p_codepage,const wchar_t * p_source,t_size p_source_size = ~0) { + void convert(unsigned p_codepage,const wchar_t * p_source,t_size p_source_size = SIZE_MAX) { t_size size = estimate_wide_to_codepage(p_codepage,p_source,p_source_size); m_buffer.set_size(size); convert_wide_to_codepage(p_codepage, m_buffer.get_ptr_var(),size,p_source,p_source_size); @@ -433,7 +433,7 @@ namespace pfc { public: string_codepage_from_utf8() {} string_codepage_from_utf8(const string_codepage_from_utf8 & p_source) : m_buffer(p_source.m_buffer) {} - string_codepage_from_utf8(unsigned p_codepage,const char * p_source,t_size p_source_size = ~0) {convert(p_codepage,p_source,p_source_size);} + string_codepage_from_utf8(unsigned p_codepage,const char * p_source,t_size p_source_size = SIZE_MAX) {convert(p_codepage,p_source,p_source_size);} void convert(unsigned p_codepage,const char * p_source,t_size p_source_size = SIZE_MAX) { string_wide_from_utf8 temp; @@ -456,9 +456,9 @@ namespace pfc { public: string_utf8_from_codepage() {} string_utf8_from_codepage(const string_utf8_from_codepage & p_source) : m_buffer(p_source.m_buffer) {} - string_utf8_from_codepage(unsigned p_codepage,const char * p_source,t_size p_source_size = ~0) {convert(p_codepage,p_source,p_source_size);} + string_utf8_from_codepage(unsigned p_codepage,const char * p_source,t_size p_source_size = SIZE_MAX) {convert(p_codepage,p_source,p_source_size);} - void convert(unsigned p_codepage,const char * p_source,t_size p_source_size = ~0) { + void convert(unsigned p_codepage,const char * p_source,t_size p_source_size = SIZE_MAX) { string_wide_from_codepage temp; temp.convert(p_codepage,p_source,p_source_size); t_size size = estimate_wide_to_utf8(temp,SIZE_MAX); @@ -480,13 +480,13 @@ namespace pfc { public: string_utf8_from_ansi() {} string_utf8_from_ansi(const string_utf8_from_ansi & p_source) : m_buffer(p_source.m_buffer) {} - string_utf8_from_ansi(const char * p_source,t_size p_source_size = ~0) : m_buffer(codepage_system,p_source,p_source_size) {} + string_utf8_from_ansi(const char * p_source,t_size p_source_size = SIZE_MAX) : m_buffer(codepage_system,p_source,p_source_size) {} operator const char * () const {return get_ptr();} const char * get_ptr() const {return m_buffer.get_ptr();} const char * toString() const {return get_ptr();} bool is_empty() const {return string_is_empty_t(get_ptr());} t_size length() const {return strlen_t(get_ptr());} - void convert(const char * p_source,t_size p_source_size = ~0) {m_buffer.convert(codepage_system,p_source,p_source_size);} + void convert(const char * p_source,t_size p_source_size = SIZE_MAX) {m_buffer.convert(codepage_system,p_source,p_source_size);} private: string_utf8_from_codepage m_buffer; @@ -496,13 +496,13 @@ namespace pfc { public: string_ansi_from_utf8() {} string_ansi_from_utf8(const string_ansi_from_utf8 & p_source) : m_buffer(p_source.m_buffer) {} - string_ansi_from_utf8(const char * p_source,t_size p_source_size = ~0) : m_buffer(codepage_system,p_source,p_source_size) {} + string_ansi_from_utf8(const char * p_source,t_size p_source_size = SIZE_MAX) : m_buffer(codepage_system,p_source,p_source_size) {} operator const char * () const {return get_ptr();} const char * get_ptr() const {return m_buffer.get_ptr();} bool is_empty() const {return string_is_empty_t(get_ptr());} t_size length() const {return strlen_t(get_ptr());} - void convert(const char * p_source,t_size p_source_size = ~0) {m_buffer.convert(codepage_system,p_source,p_source_size);} + void convert(const char * p_source,t_size p_source_size = SIZE_MAX) {m_buffer.convert(codepage_system,p_source,p_source_size);} private: string_codepage_from_utf8 m_buffer; @@ -512,13 +512,13 @@ namespace pfc { public: string_wide_from_ansi() {} string_wide_from_ansi(const string_wide_from_ansi & p_source) : m_buffer(p_source.m_buffer) {} - string_wide_from_ansi(const char * p_source,t_size p_source_size = ~0) : m_buffer(codepage_system,p_source,p_source_size) {} + string_wide_from_ansi(const char * p_source,t_size p_source_size = SIZE_MAX) : m_buffer(codepage_system,p_source,p_source_size) {} operator const wchar_t * () const {return get_ptr();} const wchar_t * get_ptr() const {return m_buffer.get_ptr();} bool is_empty() const {return string_is_empty_t(get_ptr());} t_size length() const {return strlen_t(get_ptr());} - void convert(const char * p_source,t_size p_source_size = ~0) {m_buffer.convert(codepage_system,p_source,p_source_size);} + void convert(const char * p_source,t_size p_source_size = SIZE_MAX) {m_buffer.convert(codepage_system,p_source,p_source_size);} private: string_wide_from_codepage m_buffer; @@ -528,13 +528,13 @@ namespace pfc { public: string_ansi_from_wide() {} string_ansi_from_wide(const string_ansi_from_wide & p_source) : m_buffer(p_source.m_buffer) {} - string_ansi_from_wide(const wchar_t * p_source,t_size p_source_size = ~0) : m_buffer(codepage_system,p_source,p_source_size) {} + string_ansi_from_wide(const wchar_t * p_source,t_size p_source_size = SIZE_MAX) : m_buffer(codepage_system,p_source,p_source_size) {} operator const char * () const {return get_ptr();} const char * get_ptr() const {return m_buffer.get_ptr();} bool is_empty() const {return string_is_empty_t(get_ptr());} t_size length() const {return strlen_t(get_ptr());} - void convert(const wchar_t * p_source,t_size p_source_size = ~0) {m_buffer.convert(codepage_system,p_source,p_source_size);} + void convert(const wchar_t * p_source,t_size p_source_size = SIZE_MAX) {m_buffer.convert(codepage_system,p_source,p_source_size);} private: string_codepage_from_wide m_buffer; @@ -552,14 +552,14 @@ namespace pfc { class string_utf8_from_os_ex { public: - template string_utf8_from_os_ex(const t_source * source, t_size sourceLen = ~0) { + template string_utf8_from_os_ex(const t_source * source, t_size sourceLen = SIZE_MAX) { convert(source,sourceLen); } - void convert(const char * source, t_size sourceLen = ~0) { + void convert(const char * source, t_size sourceLen = SIZE_MAX) { m_buffer = string_utf8_from_ansi(source,sourceLen); } - void convert(const wchar_t * source, t_size sourceLen = ~0) { + void convert(const wchar_t * source, t_size sourceLen = SIZE_MAX) { m_buffer = string_utf8_from_wide(source,sourceLen); } diff --git a/sdk/pfc/threads.h b/sdk/pfc/threads.h index dd3ecce..1338e34 100644 --- a/sdk/pfc/threads.h +++ b/sdk/pfc/threads.h @@ -59,7 +59,10 @@ namespace pfc { thread(); ~thread() {PFC_ASSERT(!isActive()); waitTillDone();} void start( arg_t const & arg = argCurrentThread() ); + //! Valid thread object (created and not joined)? bool isActive() const; + //! Joins the thread: blocks until complete, releases resources. \n + //! After waitTillDone() returns, isActive() becomes false. void waitTillDone() {close();} #ifdef _WIN32 void winStart(int priority, DWORD * outThreadID); diff --git a/sdk/pfc/win-objects.cpp b/sdk/pfc/win-objects.cpp index 0bacb83..0ed07bb 100644 --- a/sdk/pfc/win-objects.cpp +++ b/sdk/pfc/win-objects.cpp @@ -515,6 +515,19 @@ namespace pfc { pfc::string8 unicodeNormalizeC(const char* str) { return winUnicodeNormalize(str, NormalizationC); } + + int winNaturalSortCompare(const char* s1, const char* s2) { + return winNaturalSortCompare(wideFromUTF8(s1), wideFromUTF8(s2)); + } + int winNaturalSortCompare(const wchar_t* s1, const wchar_t* s2) { + return lstrcmp(s1, s2); + } + int winNaturalSortCompareI(const char* s1, const char* s2) { + return winNaturalSortCompareI(wideFromUTF8(s1), wideFromUTF8(s2)); + } + int winNaturalSortCompareI(const wchar_t* s1, const wchar_t* s2) { + return lstrcmpi(s1, s2); + } } #endif // _WIN32 diff --git a/sdk/pfc/win-objects.h b/sdk/pfc/win-objects.h index 29eb282..c7a78e9 100644 --- a/sdk/pfc/win-objects.h +++ b/sdk/pfc/win-objects.h @@ -337,4 +337,10 @@ namespace pfc { pfc::string8 format_window(HWND wnd); pfc::string8 format_windowStyle(DWORD); #endif // PFC_WINDOWS_DESKTOP_APP + + int winNaturalSortCompare(const char* s1, const char* s2); + int winNaturalSortCompare(const wchar_t* s1, const wchar_t* s2); + int winNaturalSortCompareI(const char* s1, const char* s2); + int winNaturalSortCompareI(const wchar_t* s1, const wchar_t* s2); + } diff --git a/sdk/sdk-readme.html b/sdk/sdk-readme.html index 4201831..7335454 100644 --- a/sdk/sdk-readme.html +++ b/sdk/sdk-readme.html @@ -8,7 +8,7 @@

-foobar2000 SDK, version 2023-05-10 +foobar2000 SDK, version 2023-09-09

Documentation:
From 276049bfbaf64f89ba19e9503d673c5c197164f4 Mon Sep 17 00:00:00 2001 From: Hyperblast Date: Wed, 12 Feb 2025 08:45:19 +0500 Subject: [PATCH 08/12] update to SDK-2023-09-13 --- sdk/foobar2000/SDK/audio_chunk.cpp | 16 +++++- sdk/foobar2000/SDK/audio_chunk.h | 2 +- sdk/foobar2000/SDK/contextmenu.h | 2 +- sdk/foobar2000/SDK/core_api.h | 3 +- sdk/foobar2000/SDK/foobar2000-versions.h | 17 ++++-- sdk/foobar2000/SDK/guids.cpp | 2 +- sdk/foobar2000/SDK/ui.cpp | 2 +- sdk/foobar2000/SDK/ui.h | 20 ++++--- sdk/foobar2000/shared/shared-Win32.lib | Bin 38796 -> 38796 bytes sdk/foobar2000/shared/shared-x64.lib | Bin 36632 -> 36632 bytes sdk/pfc/audio_sample.cpp | 65 +++++++++++++++++++++++ sdk/pfc/audio_sample.h | 6 +++ sdk/pfc/string_base.cpp | 6 ++- sdk/pfc/string_base.h | 3 +- sdk/sdk-readme.html | 2 +- 15 files changed, 127 insertions(+), 19 deletions(-) diff --git a/sdk/foobar2000/SDK/audio_chunk.cpp b/sdk/foobar2000/SDK/audio_chunk.cpp index fe48839..8210b7e 100644 --- a/sdk/foobar2000/SDK/audio_chunk.cpp +++ b/sdk/foobar2000/SDK/audio_chunk.cpp @@ -308,7 +308,7 @@ void audio_chunk::set_data_32(const float* src, size_t samples, unsigned nch, un void audio_chunk::set_data_floatingpoint_ex(const void * ptr,t_size size,unsigned srate,unsigned nch,unsigned bps,unsigned flags,unsigned p_channel_config) { - PFC_ASSERT(bps==32 || bps==64); + PFC_ASSERT(is_supported_floatingpoint(bps)); PFC_ASSERT( check_exclusive(flags,FLAG_LITTLE_ENDIAN|FLAG_BIG_ENDIAN) ); PFC_ASSERT( ! (flags & (FLAG_SIGNED|FLAG_UNSIGNED) ) ); @@ -331,6 +331,20 @@ void audio_chunk::set_data_floatingpoint_ex(const void * ptr,t_size size,unsigne process_float_multi_swap(out,reinterpret_cast(ptr),count); else process_float_multi(out,reinterpret_cast(ptr),count); + } else if (bps == 16) { + const uint16_t * in = reinterpret_cast(ptr); + if (use_swap) { + for(size_t walk = 0; walk < count; ++walk) out[walk] = audio_math::decodeFloat16(pfc::byteswap_t(in[walk])); + } else { + for(size_t walk = 0; walk < count; ++walk) out[walk] = audio_math::decodeFloat16(in[walk]); + } + } else if (bps == 24) { + const uint8_t * in = reinterpret_cast(ptr); + if (use_swap) { + for(size_t walk = 0; walk < count; ++walk) out[walk] = audio_math::decodeFloat24ptrbs(&in[walk*3]); + } else { + for(size_t walk = 0; walk < count; ++walk) out[walk] = audio_math::decodeFloat24ptr(&in[walk*3]); + } } else pfc::throw_exception_with_message< exception_io_data >("invalid bit depth"); set_sample_count(count/nch); diff --git a/sdk/foobar2000/SDK/audio_chunk.h b/sdk/foobar2000/SDK/audio_chunk.h index eda0889..073e632 100644 --- a/sdk/foobar2000/SDK/audio_chunk.h +++ b/sdk/foobar2000/SDK/audio_chunk.h @@ -206,7 +206,7 @@ class NOVTABLE audio_chunk { void set_data_fixedpoint_ms(const void * ptr, size_t bytes, unsigned sampleRate, unsigned channels, unsigned bps, unsigned channelConfig); void set_data_floatingpoint_ex(const void * ptr,t_size bytes,unsigned p_sample_rate,unsigned p_channels,unsigned p_bits_per_sample,unsigned p_flags,unsigned p_channel_config);//signed/unsigned flags dont apply - static bool is_supported_floatingpoint(unsigned bps) { return bps == 32 || bps == 64; } + static bool is_supported_floatingpoint(unsigned bps) { return bps == 32 || bps == 64 || bps == 16 || bps == 24; } void set_data_32(const float* src, t_size samples, unsigned nch, unsigned srate); void set_data_32(const float* src, t_size samples, spec_t const & spec ); diff --git a/sdk/foobar2000/SDK/contextmenu.h b/sdk/foobar2000/SDK/contextmenu.h index fef570c..d7da1b0 100644 --- a/sdk/foobar2000/SDK/contextmenu.h +++ b/sdk/foobar2000/SDK/contextmenu.h @@ -358,7 +358,7 @@ class contextmenu_item_lambda : public contextmenu_item_simple { p_out = m_desc; return true; } - double get_sort_priority() override { return 0; } + double get_sort_priority() override { return m_sortPriority; } GUID get_parent() override { return m_parentGuid; } private: const std::function m_func; diff --git a/sdk/foobar2000/SDK/core_api.h b/sdk/foobar2000/SDK/core_api.h index 071bd8f..df75f88 100644 --- a/sdk/foobar2000/SDK/core_api.h +++ b/sdk/foobar2000/SDK/core_api.h @@ -10,7 +10,8 @@ namespace core_api { const char * get_my_file_name(); //! Retrieves full path of calling dll, e.g. c:\blah\foobar2000\foo_asdf.dll . No file:// prefix, this path can interop with win32 API calls. const char * get_my_full_path(); - //! Retrieves main app window. WARNING: this is provided for parent of dialog windows and such only; using it for anything else (such as hooking windowproc to alter app behaviors) is absolutely illegal. + //! Retrieves main app window. WARNING: this is provided for parent of dialog windows and such only; using it for anything else (such as hooking windowproc to alter app behaviors) is absolutely illegal. \n + //! Becomes valid when main window has been fully initialized. Returns NULL during creation of main window's embedded elements. fb2k::hwnd_t get_main_window(); //! Tests whether services are available at this time. They are not available only during DLL startup or shutdown (e.g. inside static object constructors or destructors). bool are_services_available(); diff --git a/sdk/foobar2000/SDK/foobar2000-versions.h b/sdk/foobar2000/SDK/foobar2000-versions.h index 8b780ed..31879d0 100644 --- a/sdk/foobar2000/SDK/foobar2000-versions.h +++ b/sdk/foobar2000/SDK/foobar2000-versions.h @@ -2,9 +2,13 @@ // foobar2000-versions.h // foobar2000 SDK version and target API levels are declared in this header +#ifdef _WIN32 +// Windows + // This SDK does NOT SUPPORT targets older than API 80 / foobar2000 v1.5 -// #define FOOBAR2000_TARGET_VERSION 80 // 1.5, 1.6 -#define FOOBAR2000_TARGET_VERSION 81 // 2.0 +#define FOOBAR2000_TARGET_VERSION 80 // 1.5, 1.6 +// #define FOOBAR2000_TARGET_VERSION 81 // 2.0 + #ifdef _M_IX86 #define FOOBAR2000_TARGET_VERSION_COMPATIBLE 72 @@ -14,12 +18,19 @@ #define FOOBAR2000_TARGET_VERSION_COMPATIBLE 80 #endif + +#else // _WIN32 +// Not Windows +#define FOOBAR2000_TARGET_VERSION 81 +#define FOOBAR2000_TARGET_VERSION_COMPATIBLE 81 +#endif // _WIN32 + // Can safely use foobar2000 v2.0 features? #define FOOBAR2020 (FOOBAR2000_TARGET_VERSION>=81) // Use this to determine what foobar2000 SDK version is in use, undefined for releases older than 2018 -#define FOOBAR2000_SDK_VERSION 20230510 +#define FOOBAR2000_SDK_VERSION 20230913 // cfg_var downgrade support, experimental, intended for specific components only. // Allows new style configStore data to be imported back to old foobar2000 friendly cfg_vars. diff --git a/sdk/foobar2000/SDK/guids.cpp b/sdk/foobar2000/SDK/guids.cpp index 35b5961..26de10f 100644 --- a/sdk/foobar2000/SDK/guids.cpp +++ b/sdk/foobar2000/SDK/guids.cpp @@ -238,10 +238,10 @@ FOOGUIDDECL const GUID titleformat_compiler::class_guid = FOOGUIDDECL const GUID titleformat_compiler_v2::class_guid = { 0xa81de54, 0x8131, 0x4c43, { 0x92, 0xef, 0x15, 0xc5, 0x8b, 0xd4, 0x72, 0x7a } }; -#ifdef _WIN32 FOOGUIDDECL const GUID user_interface::class_guid = { 0x1add4dc4, 0xb278, 0x4a0c, { 0xa1, 0x5, 0x26, 0x29, 0xf4, 0xb3, 0x12, 0xf4 } }; FOOGUIDDECL const GUID user_interface_v2::class_guid = { 0x5f5ac82b, 0x44a7, 0x4872,{ 0xb7, 0x86, 0x1c, 0x1f, 0xc6, 0x56, 0x6b, 0x60 } }; +#ifdef _WIN32 FOOGUIDDECL const GUID user_interface_v2::cap_suppress_core_shellhook = { 0xe5950632, 0x750d, 0x4265,{ 0x8c, 0xea, 0x6c, 0xf2, 0x77, 0x91, 0x44, 0x40 } }; FOOGUIDDECL const GUID user_interface_v2::cap_suppress_core_uvc = { 0xe35156b2, 0xfbac, 0x450d,{ 0xa3, 0xf7, 0xf1, 0xda, 0x46, 0xb6, 0xdf, 0x8d } }; diff --git a/sdk/foobar2000/SDK/ui.cpp b/sdk/foobar2000/SDK/ui.cpp index 6532287..cbca598 100644 --- a/sdk/foobar2000/SDK/ui.cpp +++ b/sdk/foobar2000/SDK/ui.cpp @@ -19,6 +19,7 @@ bool ui_drop_item_callback::g_is_accepted_type(interface IDataObject * pDataObje } return false; } +#endif // _WIN32 bool user_interface::g_find(service_ptr_t & p_out,const GUID & p_guid) { @@ -30,7 +31,6 @@ bool user_interface::g_find(service_ptr_t & p_out,const GUID & p } return false; } -#endif // _WIN32 // ui_edit_context.h code diff --git a/sdk/foobar2000/SDK/ui.h b/sdk/foobar2000/SDK/ui.h index acc2c64..9454f45 100644 --- a/sdk/foobar2000/SDK/ui.h +++ b/sdk/foobar2000/SDK/ui.h @@ -1,20 +1,25 @@ #pragma once -#ifdef _WIN32 //! Entrypoint service for user interface modules. Implement when registering an UI module. Do not call existing implementations; only core enumerates / dispatches calls. To control UI behaviors from other components, use ui_control API. \n //! Use user_interface_factory_t<> to register, e.g static user_interface_factory_t g_myclass_factory; class NOVTABLE user_interface : public service_base { FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(user_interface); public: +#ifdef _WIN32 //!HookProc usage: \n //! in your windowproc, call HookProc first, and if it returns true, return LRESULT value it passed to you typedef BOOL (WINAPI * HookProc_t)(HWND wnd,UINT msg,WPARAM wp,LPARAM lp,LRESULT * ret); - +#endif //! Retrieves name (UTF-8 null-terminated string) of the UI module. virtual const char * get_name()=0; - //! Initializes the UI module - creates the main app window, etc. Failure should be signaled by appropriate exception (std::exception or a derivative). - virtual HWND init(HookProc_t hook)=0; + //! Initializes the UI module - creates the main app window, etc. Failure should be signaled by appropriate exception (std::exception or a derivative). \n + //! Mac OS: return NSWindow cast to hwnd_t +#ifdef _WIN32 + virtual HWND init(HookProc_t hook)=0; +#else + virtual fb2k::hwnd_t init() = 0; +#endif //! Deinitializes the UI module - destroys the main app window, etc. virtual void shutdown()=0; //! Activates main app window. @@ -31,7 +36,7 @@ class NOVTABLE user_interface : public service_base { //! Disables statusbar text override. virtual void revert_statusbar_text() = 0; - //! Shows now-playing item somehow (e.g. system notification area popup). + //! Shows now-playing item somehow (e.g. system notification area popup). virtual void show_now_playing() = 0; static bool g_find(service_ptr_t & p_out,const GUID & p_guid); @@ -48,6 +53,7 @@ class NOVTABLE user_interface_v2 : public user_interface { //! Allows the core to ask the UI module about a specific feature. virtual bool query_capability( const GUID & cap ) = 0; +#ifdef _WIN32 //! Suppress core's shellhook window for intercepting systemwide WM_APPCOMMAND? \n //! Recommended: false - return true only if your UI does this on its own. static const GUID cap_suppress_core_shellhook; @@ -56,8 +62,10 @@ class NOVTABLE user_interface_v2 : public user_interface { //! Note that cap_suppress_core_shellhook is queried first, as core can't use UVC if this UI does global WM_APPCOMMAND handling on its own. \n //! Returning true from cap_suppress_core_shellhook implies the same from cap_suppress_core_uvc. static const GUID cap_suppress_core_uvc; +#endif }; +#ifdef _WIN32 class ui_config_manager; //! \since 2.0 class NOVTABLE user_interface_v3 : public user_interface_v2 { @@ -65,7 +73,7 @@ class NOVTABLE user_interface_v3 : public user_interface_v2 { public: virtual service_ptr_t< ui_config_manager > get_config_manager() = 0; }; -#endif // _WIN32 +#endif //! Interface class allowing you to override UI statusbar text. There may be multiple callers trying to override statusbar text; backend decides which one succeeds so you will not always get what you want. Statusbar text override is automatically cancelled when the object is released.\n //! Use ui_control::override_status_text_create() to instantiate. diff --git a/sdk/foobar2000/shared/shared-Win32.lib b/sdk/foobar2000/shared/shared-Win32.lib index a9f0dd0c055d341c3d7682b42437b50c13b57fcb..da0ccb0a90350e2a2c71db58b40028f1dffb3f31 100644 GIT binary patch delta 111 zcmeBK&(yP?X~QWWmN~u!&nBPqS<9lzV9_wS-ZzrTqG3{?)Z{O|e^|q|UB0(tvUY&{ rWD);Vm;!Y!hvfX+0=>)>h{6;8aV#69`>#&c3V<6TjihE%V2>LB$iFJ$ delta 111 zcmeBK&(yP?X~QWW7KaPP$0nciS<9l#aIBGb&Du$UQj@><{$c%Dz4qXa$=U(( slSTYfVG7i_9Fp^M3-mHmAPP_T$FUq)`Sj;xtpKWo+5i9m diff --git a/sdk/foobar2000/shared/shared-x64.lib b/sdk/foobar2000/shared/shared-x64.lib index 285e090b4f72f4f64b84f7ee35a3a576a62a6e0f..ce643a80efff8c999dbf64ec3d49f95d8ae873f6 100644 GIT binary patch delta 105 zcmbO+k7>p{rVU(fEXDVF?@#7)Tg#%#V9_vnzgr{|kb37KHQB`d53AM``*S-cXM4&| l4)I8ZsZgJ6=fwe0Rl)pHcFW{U&vh_4WrUp6<|MCeE&y6AC*%MC delta 105 zcmbO+k7>p{rVU(fEYtFvUry$8Tg#%%aI<#uez!;_Aob2eYO;y@A69(sourcePtr); + u.bytes[0] = 0; + u.bytes[1] = s[0]; + u.bytes[2] = s[1]; + u.bytes[3] = s[2]; + return u.v; + } + float audio_math::decodeFloat24ptrbs(const void* sourcePtr) { + PFC_STATIC_ASSERT(pfc::byte_order_is_little_endian); + union { + uint8_t bytes[4]; + float v; + } u; + const uint8_t* s = reinterpret_cast(sourcePtr); + u.bytes[0] = 0; + u.bytes[1] = s[2]; + u.bytes[2] = s[1]; + u.bytes[3] = s[0]; + return u.v; + } + + float audio_math::decodeFloat16(uint16_t source) { + const unsigned fractionBits = 10; + const unsigned widthBits = 16; + typedef uint16_t source_t; + + /* typedef uint64_t out_t; typedef double retval_t; + enum { + outExponent = 11, + outFraction = 52, + outExponentShift = (1 << (outExponent-1))-1 + };*/ + + typedef uint32_t out_t; typedef float retval_t; + enum { + outExponent = 8, + outFraction = 23, + outExponentShift = (1 << (outExponent - 1)) - 1 + }; + + const unsigned exponentBits = widthBits - fractionBits - 1; + // 1 bit sign | exponent | fraction + source_t fraction = source & (((source_t)1 << fractionBits) - 1); + source >>= fractionBits; + int exponent = (int)(source & (((source_t)1 << exponentBits) - 1)) - (int)((1 << (exponentBits - 1)) - 1); + source >>= exponentBits; + + if (outExponent + outExponentShift <= 0) return 0; + + out_t output = (out_t)(source & 1); + output <<= outExponent; + output |= (unsigned)(exponent + outExponentShift) & ((1 << outExponent) - 1); + output <<= outFraction; + int shift = (int)outFraction - (int)fractionBits; + if (shift < 0) output |= (out_t)(fraction >> -shift); + else output |= (out_t)(fraction << shift); + return *(retval_t*)&output / pfc::audio_math::float16scale; + } + unsigned audio_math::bitrate_kbps(uint64_t fileSize, double duration) { if (fileSize > 0 && duration > 0) return (unsigned)floor((double)fileSize * 8 / (duration * 1000) + 0.5); return 0; diff --git a/sdk/pfc/audio_sample.h b/sdk/pfc/audio_sample.h index 3014b16..bfcaf5c 100644 --- a/sdk/pfc/audio_sample.h +++ b/sdk/pfc/audio_sample.h @@ -62,6 +62,12 @@ namespace pfc { static inline double scale_to_gain(double scale) { return 20.0*log10(scale); } static unsigned bitrate_kbps( uint64_t fileSize, double duration ); + + static constexpr float float16scale = 65536.f; + + static float decodeFloat24ptr(const void* sourcePtr); + static float decodeFloat24ptrbs(const void* sourcePtr); + static float decodeFloat16(uint16_t source); }; // class audio_math } // namespace pfc diff --git a/sdk/pfc/string_base.cpp b/sdk/pfc/string_base.cpp index d920bce..2c82abf 100644 --- a/sdk/pfc/string_base.cpp +++ b/sdk/pfc/string_base.cpp @@ -337,9 +337,11 @@ static double pfc_string_to_float_internal(const char * src) noexcept return (double) val * exp_int(10, div); } +double string_to_float(const char * src) noexcept { + return pfc_string_to_float_internal(src); +} double string_to_float(const char * src,t_size max) noexcept { - //old function wants an oldstyle nullterminated string, and i don't currently care enough to rewrite it as it works appropriately otherwise - char blargh[128]; + char blargh[128]; if (max > 127) max = 127; t_size walk; for(walk = 0; walk < max && src[walk]; walk++) blargh[walk] = src[walk]; diff --git a/sdk/pfc/string_base.h b/sdk/pfc/string_base.h index 56dfbed..c68793c 100644 --- a/sdk/pfc/string_base.h +++ b/sdk/pfc/string_base.h @@ -222,7 +222,8 @@ namespace pfc { string8 string_directory(const char * p_path); void float_to_string(char * out,t_size out_max,double val,unsigned precision,bool force_sign = false);//doesnt add E+X etc, has internal range limits, useful for storing float numbers as strings without having to bother with international coma/dot settings BS - double string_to_float(const char * src,t_size len = SIZE_MAX) noexcept; + double string_to_float(const char * src,t_size len) noexcept; + double string_to_float(const char * src) noexcept; string8 format_float(double p_val,unsigned p_width = 0,unsigned p_prec = 7); diff --git a/sdk/sdk-readme.html b/sdk/sdk-readme.html index 7335454..3f7a7a5 100644 --- a/sdk/sdk-readme.html +++ b/sdk/sdk-readme.html @@ -8,7 +8,7 @@

-foobar2000 SDK, version 2023-09-09 +foobar2000 SDK, version 2023-09-13

Documentation:
From 23a471a3bac3be81250842ad6ef0073a7668265f Mon Sep 17 00:00:00 2001 From: Hyperblast Date: Wed, 12 Feb 2025 08:56:18 +0500 Subject: [PATCH 09/12] update to SDK-2023-09-23 --- sdk/foobar2000/SDK/file_info.h | 4 ++ sdk/foobar2000/SDK/filesystem.cpp | 27 ++++++-- sdk/foobar2000/SDK/filesystem.h | 1 + sdk/foobar2000/SDK/foobar2000-versions.h | 2 +- .../foobar2000_SDK.xcodeproj/project.pbxproj | 4 +- sdk/foobar2000/SDK/replaygain_info.cpp | 25 +++++--- .../foo_sample/Mac/fooSampleDSPView.xib | 2 +- .../foo_sample.xcodeproj/project.pbxproj | 2 + .../foo_sample/foobar2000-mac-class-suffix.h | 1 + .../helpers-mac/fooDecibelFormatter.h | 4 ++ sdk/foobar2000/helpers-mac/fooGenericDialog.h | 5 -- .../helpers-mac/fooGenericDialog.mm | 31 --------- .../helpers-mac/fooGenericDialog.xib | 60 ------------------ sdk/foobar2000/helpers-mac/fooTimeFormatter.h | 5 +- .../helpers-mac/fooWindowWithCancel.h | 5 +- .../helpers-mac/foobar2000-mac-helpers.h | 16 +++++ .../project.pbxproj | 4 +- sdk/foobar2000/helpers/meta_table_builder.h | 10 ++- sdk/foobar2000/shared/shared-ARM64.lib | Bin 36632 -> 36632 bytes sdk/foobar2000/shared/shared-ARM64EC.lib | Bin 40388 -> 40388 bytes sdk/foobar2000/shared/shared-nix.cpp | 17 +++++ sdk/foobar2000/shared/shared-nix.h | 3 + .../shared/shared.xcodeproj/project.pbxproj | 4 +- sdk/pfc/order_helper.h | 2 + sdk/pfc/other.cpp | 12 +++- sdk/pfc/pfc.xcodeproj/project.pbxproj | 4 +- sdk/pfc/string-compare.cpp | 14 +++- sdk/pfc/string-compare.h | 1 + sdk/pfc/string-lite.h | 4 +- sdk/sdk-readme.html | 2 +- 30 files changed, 137 insertions(+), 134 deletions(-) create mode 100644 sdk/foobar2000/foo_sample/foobar2000-mac-class-suffix.h delete mode 100644 sdk/foobar2000/helpers-mac/fooGenericDialog.h delete mode 100644 sdk/foobar2000/helpers-mac/fooGenericDialog.mm delete mode 100644 sdk/foobar2000/helpers-mac/fooGenericDialog.xib create mode 100644 sdk/foobar2000/helpers-mac/foobar2000-mac-helpers.h diff --git a/sdk/foobar2000/SDK/file_info.h b/sdk/foobar2000/SDK/file_info.h index c4530cc..d09f22d 100644 --- a/sdk/foobar2000/SDK/file_info.h +++ b/sdk/foobar2000/SDK/file_info.h @@ -23,6 +23,10 @@ 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);} + + typedef std::function for_each_t; + void for_each(for_each_t) const; + 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); diff --git a/sdk/foobar2000/SDK/filesystem.cpp b/sdk/foobar2000/SDK/filesystem.cpp index baa2679..d2f3721 100644 --- a/sdk/foobar2000/SDK/filesystem.cpp +++ b/sdk/foobar2000/SDK/filesystem.cpp @@ -84,7 +84,7 @@ void file::g_transfer_object(stream_reader * p_src,stream_writer * p_dst,t_files void filesystem::g_get_canonical_path(const char * path,pfc::string_base & out) { - TRACK_CALL_TEXT("filesystem::g_get_canonical_path"); + // TRACK_CALL_TEXT("filesystem::g_get_canonical_path"); for (auto ptr : enumerate()) { if (ptr->get_canonical_path(path, out)) return; } @@ -92,9 +92,28 @@ void filesystem::g_get_canonical_path(const char * path,pfc::string_base & out) out = path; } +void filesystem::g_get_display_path(const char* path, pfc::string_base& out, filesystem::ptr& reuseMe) { + + if (reuseMe.is_valid() && reuseMe->is_our_path(path)) { + if (!reuseMe->get_display_path(path, out)) { + // should not get here + out = path; + } + } else { + if (!g_get_interface(reuseMe, path)) { + out = path; + return; + } + if (!reuseMe->get_display_path(path, out)) { + // should not get here + out = path; + } + } +} + void filesystem::g_get_display_path(const char * path,pfc::string_base & out) { - TRACK_CALL_TEXT("filesystem::g_get_display_path"); + // TRACK_CALL_TEXT("filesystem::g_get_display_path"); service_ptr_t ptr; if (!g_get_interface(ptr,path)) { @@ -155,7 +174,7 @@ bool filesystem::g_get_interface(service_ptr_t & p_out,const char * for (auto ptr : enumerate()) { if (ptr->is_our_path(path)) { - p_out = ptr; + p_out = std::move(ptr); return true; } } @@ -1437,7 +1456,7 @@ bool foobar2000_io::testIfHasProtocol( const char * input ) { bool foobar2000_io::matchProtocol(const char * fullString, const char * protocolName) { const t_size len = strlen(protocolName); - if (pfc::stricmp_ascii_ex(fullString, len, protocolName, len) != 0) return false; + if (!pfc::stringEqualsI_ascii_ex(fullString, len, protocolName, len)) return false; return fullString[len] == ':' && fullString[len+1] == '/' && fullString[len+2] == '/'; } void foobar2000_io::substituteProtocol(pfc::string_base & out, const char * fullString, const char * protocolName) { diff --git a/sdk/foobar2000/SDK/filesystem.h b/sdk/foobar2000/SDK/filesystem.h index 74c5508..3e0c809 100644 --- a/sdk/foobar2000/SDK/filesystem.h +++ b/sdk/foobar2000/SDK/filesystem.h @@ -89,6 +89,7 @@ namespace foobar2000_io static void g_get_canonical_path(const char * path,pfc::string_base & out); static void g_get_display_path(const char * path,pfc::string_base & out); + static void g_get_display_path(const char* path, pfc::string_base& out, filesystem::ptr & reuseMe); //! Retrieves a shortened display name for this file. By default this is implemented by returning filename.ext portion of the path. static bool g_get_display_name_short( const char * path, pfc::string_base & out ); //! Extracts the native filesystem path, sets out to the input path if native path cannot be extracted so the output is always set. diff --git a/sdk/foobar2000/SDK/foobar2000-versions.h b/sdk/foobar2000/SDK/foobar2000-versions.h index 31879d0..5f7c3c2 100644 --- a/sdk/foobar2000/SDK/foobar2000-versions.h +++ b/sdk/foobar2000/SDK/foobar2000-versions.h @@ -30,7 +30,7 @@ // Use this to determine what foobar2000 SDK version is in use, undefined for releases older than 2018 -#define FOOBAR2000_SDK_VERSION 20230913 +#define FOOBAR2000_SDK_VERSION 20230923 // cfg_var downgrade support, experimental, intended for specific components only. // Allows new style configStore data to be imported back to old foobar2000 friendly cfg_vars. diff --git a/sdk/foobar2000/SDK/foobar2000_SDK.xcodeproj/project.pbxproj b/sdk/foobar2000/SDK/foobar2000_SDK.xcodeproj/project.pbxproj index 5745ae3..63965b5 100644 --- a/sdk/foobar2000/SDK/foobar2000_SDK.xcodeproj/project.pbxproj +++ b/sdk/foobar2000/SDK/foobar2000_SDK.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -857,7 +857,7 @@ ORGANIZATIONNAME = "___FULLUSERNAME___"; }; buildConfigurationList = B1DD3652198A721800EF7043 /* Build configuration list for PBXProject "foobar2000_SDK" */; - compatibilityVersion = "Xcode 3.2"; + compatibilityVersion = "Xcode 12.0"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( diff --git a/sdk/foobar2000/SDK/replaygain_info.cpp b/sdk/foobar2000/SDK/replaygain_info.cpp index 0d2f62c..98c9e71 100644 --- a/sdk/foobar2000/SDK/replaygain_info.cpp +++ b/sdk/foobar2000/SDK/replaygain_info.cpp @@ -62,32 +62,32 @@ void replaygain_info::reset() bool replaygain_info::g_is_meta_replaygain(const char * p_name,t_size p_name_len) { return - stricmp_utf8_ex(p_name,p_name_len,meta_album_gain,~0) == 0 || - stricmp_utf8_ex(p_name,p_name_len,meta_album_peak,~0) == 0 || - stricmp_utf8_ex(p_name,p_name_len,meta_track_gain,~0) == 0 || - stricmp_utf8_ex(p_name,p_name_len,meta_track_peak,~0) == 0; + stricmp_utf8_ex(p_name,p_name_len,meta_album_gain,SIZE_MAX) == 0 || + stricmp_utf8_ex(p_name,p_name_len,meta_album_peak,SIZE_MAX) == 0 || + stricmp_utf8_ex(p_name,p_name_len,meta_track_gain,SIZE_MAX) == 0 || + stricmp_utf8_ex(p_name,p_name_len,meta_track_peak,SIZE_MAX) == 0; } bool replaygain_info::set_from_meta_ex(const char * p_name,t_size p_name_len,const char * p_value,t_size p_value_len) { RG_FPU(); - if (stricmp_utf8_ex(p_name,p_name_len,meta_album_gain,~0) == 0) + if (stricmp_utf8_ex(p_name,p_name_len,meta_album_gain,SIZE_MAX) == 0) { m_album_gain = (float)pfc::string_to_float(p_value,p_value_len); return true; } - else if (stricmp_utf8_ex(p_name,p_name_len,meta_album_peak,~0) == 0) + else if (stricmp_utf8_ex(p_name,p_name_len,meta_album_peak,SIZE_MAX) == 0) { m_album_peak = (float)pfc::string_to_float(p_value,p_value_len); if (m_album_peak < 0) m_album_peak = 0; return true; } - else if (stricmp_utf8_ex(p_name,p_name_len,meta_track_gain,~0) == 0) + else if (stricmp_utf8_ex(p_name,p_name_len,meta_track_gain,SIZE_MAX) == 0) { m_track_gain = (float)pfc::string_to_float(p_value,p_value_len); return true; } - else if (stricmp_utf8_ex(p_name,p_name_len,meta_track_peak,~0) == 0) + else if (stricmp_utf8_ex(p_name,p_name_len,meta_track_peak,SIZE_MAX) == 0) { m_track_peak = (float)pfc::string_to_float(p_value,p_value_len); if (m_track_peak < 0) m_track_peak = 0; @@ -161,3 +161,12 @@ replaygain_info replaygain_info::g_merge(replaygain_info r1,replaygain_info r2) if (!ret.is_track_peak_present()) ret.m_track_peak = r2.m_track_peak; return ret; } + + +void replaygain_info::for_each(for_each_t f) const { + t_text_buffer buffer; + if (format_track_gain(buffer)) f(meta_track_gain, buffer); + if (format_track_peak(buffer)) f(meta_track_peak, buffer); + if (format_album_gain(buffer)) f(meta_album_gain, buffer); + if (format_album_peak(buffer)) f(meta_album_peak, buffer); +} \ No newline at end of file diff --git a/sdk/foobar2000/foo_sample/Mac/fooSampleDSPView.xib b/sdk/foobar2000/foo_sample/Mac/fooSampleDSPView.xib index 799f6e3..2e44f4c 100644 --- a/sdk/foobar2000/foo_sample/Mac/fooSampleDSPView.xib +++ b/sdk/foobar2000/foo_sample/Mac/fooSampleDSPView.xib @@ -34,7 +34,7 @@ - + diff --git a/sdk/foobar2000/foo_sample/foo_sample.xcodeproj/project.pbxproj b/sdk/foobar2000/foo_sample/foo_sample.xcodeproj/project.pbxproj index c52e3f3..6079040 100644 --- a/sdk/foobar2000/foo_sample/foo_sample.xcodeproj/project.pbxproj +++ b/sdk/foobar2000/foo_sample/foo_sample.xcodeproj/project.pbxproj @@ -49,6 +49,7 @@ 0F6244072AA1E4F4004FEC96 /* preferences.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = preferences.cpp; sourceTree = ""; }; 0F6D10EF2AA3C35C00774EED /* fooDecibelFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = fooDecibelFormatter.m; sourceTree = ""; }; 0F6D10F02AA3C35C00774EED /* fooDecibelFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fooDecibelFormatter.h; sourceTree = ""; }; + 0F7F817F2AB87BA70051262F /* foobar2000-mac-class-suffix.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "foobar2000-mac-class-suffix.h"; sourceTree = ""; }; 0FBE14402AA1E85F00B1F71E /* NSView+embed.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSView+embed.h"; sourceTree = ""; }; 0FBE14452AA1E85F00B1F71E /* NSView+embed.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSView+embed.m"; sourceTree = ""; }; 0FBE14522AA1E8C800B1F71E /* fooSampleMacPreferences.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = fooSampleMacPreferences.h; sourceTree = ""; }; @@ -91,6 +92,7 @@ 0F1FDDA42AA0AD9B00DE8967 = { isa = PBXGroup; children = ( + 0F7F817F2AB87BA70051262F /* foobar2000-mac-class-suffix.h */, 0FBE146B2AA1FF1500B1F71E /* ui_and_threads.cpp */, 0FBE14592AA1F74200B1F71E /* contextmenu.cpp */, 0FBE145B2AA1F74200B1F71E /* decode.cpp */, diff --git a/sdk/foobar2000/foo_sample/foobar2000-mac-class-suffix.h b/sdk/foobar2000/foo_sample/foobar2000-mac-class-suffix.h new file mode 100644 index 0000000..11fef1c --- /dev/null +++ b/sdk/foobar2000/foo_sample/foobar2000-mac-class-suffix.h @@ -0,0 +1 @@ +#define FOOBAR2000_MAC_CLASS_SUFFIX _foo_sample diff --git a/sdk/foobar2000/helpers-mac/fooDecibelFormatter.h b/sdk/foobar2000/helpers-mac/fooDecibelFormatter.h index f428dbb..9c079d9 100644 --- a/sdk/foobar2000/helpers-mac/fooDecibelFormatter.h +++ b/sdk/foobar2000/helpers-mac/fooDecibelFormatter.h @@ -1,5 +1,9 @@ #import +#import "foobar2000-mac-helpers.h" + +#define fooDecibelFormatter FB2K_OBJC_CLASS(fooDecibelFormatter) + @interface fooDecibelFormatter : NSFormatter @property (nonatomic) NSNumber * minValue; diff --git a/sdk/foobar2000/helpers-mac/fooGenericDialog.h b/sdk/foobar2000/helpers-mac/fooGenericDialog.h deleted file mode 100644 index babba46..0000000 --- a/sdk/foobar2000/helpers-mac/fooGenericDialog.h +++ /dev/null @@ -1,5 +0,0 @@ -#import - -@interface fooGenericDialog : NSWindowController -@property (nonatomic) NSViewController * theContent; -@end diff --git a/sdk/foobar2000/helpers-mac/fooGenericDialog.mm b/sdk/foobar2000/helpers-mac/fooGenericDialog.mm deleted file mode 100644 index 20fd2da..0000000 --- a/sdk/foobar2000/helpers-mac/fooGenericDialog.mm +++ /dev/null @@ -1,31 +0,0 @@ -#import "fooGenericDialog.h" - -@interface fooGenericDialog () - -@end - -@implementation fooGenericDialog { - __weak IBOutlet NSStackView *m_stack; -} - -- (instancetype)init { - return [self initWithWindowNibName:@"fooGenericDialog"]; -} -- (void)windowDidLoad { - [super windowDidLoad]; - - [m_stack setViews: @[_theContent.view] inGravity:NSStackViewGravityCenter]; -} -- (IBAction)onDone:(id)sender { - [self.window makeFirstResponder: self.window]; - [self endDialog: NSModalResponseOK]; -} -- (void)cancelOperation:(id)sender { - [self endDialog: NSModalResponseCancel]; -} - -- (void) endDialog: (NSModalResponse) response { - [self.window.sheetParent endSheet: self.window returnCode: response]; -} - -@end diff --git a/sdk/foobar2000/helpers-mac/fooGenericDialog.xib b/sdk/foobar2000/helpers-mac/fooGenericDialog.xib deleted file mode 100644 index 2daeb26..0000000 --- a/sdk/foobar2000/helpers-mac/fooGenericDialog.xib +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/sdk/foobar2000/helpers-mac/fooTimeFormatter.h b/sdk/foobar2000/helpers-mac/fooTimeFormatter.h index 2306605..db449c4 100644 --- a/sdk/foobar2000/helpers-mac/fooTimeFormatter.h +++ b/sdk/foobar2000/helpers-mac/fooTimeFormatter.h @@ -6,11 +6,10 @@ // #import +#import "foobar2000-mac-helpers.h" -NS_ASSUME_NONNULL_BEGIN +#define fooTimeFormatter FB2K_OBJC_CLASS(fooTimeFormatter) @interface fooTimeFormatter : NSFormatter @property (nonatomic) NSNumber * digits; @end - -NS_ASSUME_NONNULL_END diff --git a/sdk/foobar2000/helpers-mac/fooWindowWithCancel.h b/sdk/foobar2000/helpers-mac/fooWindowWithCancel.h index 50de04d..9d41a9d 100644 --- a/sdk/foobar2000/helpers-mac/fooWindowWithCancel.h +++ b/sdk/foobar2000/helpers-mac/fooWindowWithCancel.h @@ -1,9 +1,8 @@ #import +#import "foobar2000-mac-helpers.h" -NS_ASSUME_NONNULL_BEGIN +#define fooWindowWithCancel FB2K_OBJC_CLASS(fooWindowWithCancel) @interface fooWindowWithCancel : NSWindow @end - -NS_ASSUME_NONNULL_END diff --git a/sdk/foobar2000/helpers-mac/foobar2000-mac-helpers.h b/sdk/foobar2000/helpers-mac/foobar2000-mac-helpers.h new file mode 100644 index 0000000..5c65212 --- /dev/null +++ b/sdk/foobar2000/helpers-mac/foobar2000-mac-helpers.h @@ -0,0 +1,16 @@ +#pragma once + +// Mitigation for Objective-C class name clashes +// Your component must have its own foobar2000-mac-class-suffix.h, with a single line: +// #define FOOBAR2000_MAC_CLASS_SUFFIX _foo_mycomponentname +// This suffixes all common class names with _foo_mycomponentname preventing clashes + +#include "foobar2000-mac-class-suffix.h" + +#ifndef FOOBAR2000_MAC_CLASS_SUFFIX +#error PLEASE DECLARE FOOBAR2000_MAC_CLASS_SUFFIX PROPERLY +#endif + +#define FB2K_OBJC_CLASS(X) _FB2K_OBJC_CONCAT(X, FOOBAR2000_MAC_CLASS_SUFFIX) +#define _FB2K_OBJC_CONCAT(a, b) _FB2K_OBJC_CONCAT_INNER(a, b) +#define _FB2K_OBJC_CONCAT_INNER(a, b) a ## b diff --git a/sdk/foobar2000/helpers/foobar2000_SDK_helpers.xcodeproj/project.pbxproj b/sdk/foobar2000/helpers/foobar2000_SDK_helpers.xcodeproj/project.pbxproj index 51bf036..6fd2dc0 100644 --- a/sdk/foobar2000/helpers/foobar2000_SDK_helpers.xcodeproj/project.pbxproj +++ b/sdk/foobar2000/helpers/foobar2000_SDK_helpers.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -594,7 +594,7 @@ ORGANIZATIONNAME = "___FULLUSERNAME___"; }; buildConfigurationList = B12D1DAC1991061A0087CEF3 /* Build configuration list for PBXProject "foobar2000_SDK_helpers" */; - compatibilityVersion = "Xcode 3.2"; + compatibilityVersion = "Xcode 12.0"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( diff --git a/sdk/foobar2000/helpers/meta_table_builder.h b/sdk/foobar2000/helpers/meta_table_builder.h index 459883a..396643b 100644 --- a/sdk/foobar2000/helpers/meta_table_builder.h +++ b/sdk/foobar2000/helpers/meta_table_builder.h @@ -105,12 +105,10 @@ class meta_table_builder { from_info_overwrite(p_info); from_RG_overwrite(p_info.get_replaygain()); } - void from_RG_overwrite(replaygain_info info) { - replaygain_info::t_text_buffer buffer; - if (info.format_album_gain(buffer)) set("replaygain_album_gain", buffer); - if (info.format_track_gain(buffer)) set("replaygain_track_gain", buffer); - if (info.format_album_peak(buffer)) set("replaygain_album_peak", buffer); - if (info.format_track_peak(buffer)) set("replaygain_track_peak", buffer); + void from_RG_overwrite(replaygain_info const & info) { + info.for_each([&](const char* key, const char* value) { + set(key, value); + }); } void from_info_overwrite(const file_info & p_info) { for(t_size metawalk = 0, metacount = p_info.meta_get_count(); metawalk < metacount; ++metawalk ) { diff --git a/sdk/foobar2000/shared/shared-ARM64.lib b/sdk/foobar2000/shared/shared-ARM64.lib index 25737391234bb74c95c987cf0546fca6ceec6a7f..8780666614a364cb143278eaddcd080065fb0ad0 100644 GIT binary patch delta 105 zcmbO+k7>p{rVU(fEQ%9?PE6)=Tg#%#V9_vnzgr{|kb37KHQB`d59?3)_=`IxXM4&| l4)I8ZsZgJ6=fwe0Rl)2T^?P!r=Q^02GD1#jbCTCK7XTfCCsP0b delta 105 zcmbO+k7>p{rVU(fEK=fWPbc%atz}VWxLG@Szgr{|kb37KHQB`d59_j;`44wY&i0g_ l9O97*Q=vZD&Wi)0s)D(A_O;2Gp6g(8$_P2B%}HL{Tma0ID^dUe diff --git a/sdk/foobar2000/shared/shared-ARM64EC.lib b/sdk/foobar2000/shared/shared-ARM64EC.lib index 77fe8eafc6e2905d4e80e09d3df76b0f1b533067..ea9bbe91d4aa504b44601a2df9ce7fde6e92a2b9 100644 GIT binary patch delta 139 zcmX@Io9W1IrVVlKoH6E0e{wN0FmO!n^^~4`&r5ppT=yatRR)WO$%0<$ldU|Am@FDL z=Xr=Rvi^v9@?pp1{a*5uS9qqvl;{JcC+B%cO^)%3W3fr7crkgO*IJmQGM7Vger|zY cW(ri%Ht#1~vKr4G=rAxaurY03;-e4<0GyOCxBvhE delta 139 zcmX@Io9W1IrVVlKoI0hiFLE(5FmO!n^^~4`&r5ppT=yatWrmxzlLfuhCtG}^K%RI cGE<<6ws}9{y5PomOoxGiVJY+GB|Zv)0Cj*gyZ`_I diff --git a/sdk/foobar2000/shared/shared-nix.cpp b/sdk/foobar2000/shared/shared-nix.cpp index e13f114..de8d1c3 100644 --- a/sdk/foobar2000/shared/shared-nix.cpp +++ b/sdk/foobar2000/shared/shared-nix.cpp @@ -1,6 +1,7 @@ #include "shared.h" #include #include +#include // foobar2000 SDK project method... bah namespace foobar2000_io { @@ -193,3 +194,19 @@ void fb2k::crashWithMessage [[noreturn]] ( const char * msg_ ) { // there used to be code throwing Objective-C exceptions, but those were of no use, pfc::crashWithMessageOnStack(msg_); } + +bool uSetCurrentDirectory(const char * path) { + return chdir(path) == 0; +} +bool uGetCurrentDirectory(pfc::string_base & out) { + pfc::array_t work; + work.resize( PATH_MAX ); + for(;;) { + errno = 0; + if ( getcwd(work.get_ptr(), work.size()) != nullptr ) { + out = work.get_ptr(); return true; + } + if ( errno != ENAMETOOLONG ) return false; + work.resize( work.size() * 2 ); + } +} diff --git a/sdk/foobar2000/shared/shared-nix.h b/sdk/foobar2000/shared/shared-nix.h index a6a80ad..3596c41 100644 --- a/sdk/foobar2000/shared/shared-nix.h +++ b/sdk/foobar2000/shared/shared-nix.h @@ -23,3 +23,6 @@ bool uGetTempPath(pfc::string_base & out); bool uGetTempFileName(const char * path_name,const char * prefix,unsigned unique,pfc::string_base & out); pfc::string8 uGetTempFileName(); + +bool uSetCurrentDirectory(const char * path); +bool uGetCurrentDirectory(pfc::string_base & out); diff --git a/sdk/foobar2000/shared/shared.xcodeproj/project.pbxproj b/sdk/foobar2000/shared/shared.xcodeproj/project.pbxproj index 3eb996b..8b47996 100644 --- a/sdk/foobar2000/shared/shared.xcodeproj/project.pbxproj +++ b/sdk/foobar2000/shared/shared.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 50; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -142,7 +142,7 @@ }; }; buildConfigurationList = 0F75F3742A6B1A3900A45078 /* Build configuration list for PBXProject "shared" */; - compatibilityVersion = "Xcode 9.3"; + compatibilityVersion = "Xcode 12.0"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( diff --git a/sdk/pfc/order_helper.h b/sdk/pfc/order_helper.h index 373c686..93aae8f 100644 --- a/sdk/pfc/order_helper.h +++ b/sdk/pfc/order_helper.h @@ -14,6 +14,8 @@ namespace pfc { void create_move_item_permutation( size_t * p_output, size_t p_count, size_t from, size_t to ); bool create_drop_permutation(size_t * out, size_t itemCount, pfc::bit_array const & maskSelected, size_t insertMark ); + + bool is_identity(size_t const* order, size_t count); } class order_helper diff --git a/sdk/pfc/other.cpp b/sdk/pfc/other.cpp index aa6fec3..618c8c9 100644 --- a/sdk/pfc/other.cpp +++ b/sdk/pfc/other.cpp @@ -152,6 +152,12 @@ namespace pfc { return false; } + bool is_identity(size_t const* order, size_t count) { + for (size_t walk = 0; walk < count; ++walk) { + if (order[walk] != walk) return false; + } + return true; + } } void order_helper::g_swap(t_size * data,t_size ptr1,t_size ptr2) @@ -252,7 +258,11 @@ void pfc::myassert_win32(const wchar_t * _Message, const wchar_t *_File, unsigne void pfc::myassert(const char * _Message, const char *_File, unsigned _Line) { PFC_DEBUGLOG << "Assert failure: \"" << _Message << "\" in: " << _File << " line " << _Line; - crash(); +#ifdef _WIN32 + __debugbreak(); +#else + raise(SIGTRAP); +#endif } #endif diff --git a/sdk/pfc/pfc.xcodeproj/project.pbxproj b/sdk/pfc/pfc.xcodeproj/project.pbxproj index 04e2313..14c6c2a 100644 --- a/sdk/pfc/pfc.xcodeproj/project.pbxproj +++ b/sdk/pfc/pfc.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -591,7 +591,7 @@ ORGANIZATIONNAME = "___FULLUSERNAME___"; }; buildConfigurationList = B1DD35AA198A6FAA00EF7043 /* Build configuration list for PBXProject "pfc" */; - compatibilityVersion = "Xcode 3.2"; + compatibilityVersion = "Xcode 12.0"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( diff --git a/sdk/pfc/string-compare.cpp b/sdk/pfc/string-compare.cpp index 246e856..cd598dd 100644 --- a/sdk/pfc/string-compare.cpp +++ b/sdk/pfc/string-compare.cpp @@ -19,6 +19,19 @@ namespace pfc { } } + bool stringEqualsI_ascii_ex(const char* s1, size_t len1, const char* s2, size_t len2) throw() { + t_size walk1 = 0, walk2 = 0; + for (;;) { + char c1 = (walk1 < len1) ? s1[walk1] : 0; + char c2 = (walk2 < len2) ? s2[walk2] : 0; + c1 = ascii_tolower(c1); c2 = ascii_tolower(c2); + if (c1 != c2) return false; + if (c1 == 0) return true; + walk1++; + walk2++; + } + } + int stricmp_ascii_ex(const char* const s1, t_size const len1, const char* const s2, t_size const len2) throw() { t_size walk1 = 0, walk2 = 0; for (;;) { @@ -31,7 +44,6 @@ namespace pfc { walk1++; walk2++; } - } int wstricmp_ascii(const wchar_t* s1, const wchar_t* s2) throw() { diff --git a/sdk/pfc/string-compare.h b/sdk/pfc/string-compare.h index 230d7d4..53f5e26 100644 --- a/sdk/pfc/string-compare.h +++ b/sdk/pfc/string-compare.h @@ -21,6 +21,7 @@ namespace pfc { bool stringEqualsI_utf8(const char* p1, const char* p2) throw(); bool stringEqualsI_ascii(const char* p1, const char* p2) throw(); + bool stringEqualsI_ascii_ex(const char* p1, size_t l1, const char* p2, size_t l2) throw(); int stringCompareCaseInsensitive(const char* s1, const char* s2); int stringCompareCaseInsensitiveEx(string_part_ref s1, string_part_ref s2); diff --git a/sdk/pfc/string-lite.h b/sdk/pfc/string-lite.h index 9d3fb71..974afb9 100644 --- a/sdk/pfc/string-lite.h +++ b/sdk/pfc/string-lite.h @@ -11,8 +11,10 @@ namespace pfc { class stringLite : public string_base { public: - class tagNoShrink {}; + struct tagNoShrink {}; + struct tagPrealloc { size_t amount; }; stringLite(tagNoShrink) { this->setNoShrink(); } + stringLite(tagPrealloc const& tag) { this->prealloc(tag.amount); } stringLite() {} stringLite( const stringLite & other ) { copy(other); } stringLite( stringLite && other ) noexcept { move(other); } diff --git a/sdk/sdk-readme.html b/sdk/sdk-readme.html index 3f7a7a5..820aa52 100644 --- a/sdk/sdk-readme.html +++ b/sdk/sdk-readme.html @@ -8,7 +8,7 @@

-foobar2000 SDK, version 2023-09-13 +foobar2000 SDK, version 2023-09-23

Documentation:
From 3aed9b46d17afc4abf13cc28f7413b3ff5ee04e2 Mon Sep 17 00:00:00 2001 From: Hyperblast Date: Wed, 12 Feb 2025 09:10:26 +0500 Subject: [PATCH 10/12] update to SDK-2024-08-07 --- cmake/FileLists.cmake | 5 +- sdk/foobar2000/SDK/abort_callback.cpp | 9 + sdk/foobar2000/SDK/abort_callback.h | 14 +- sdk/foobar2000/SDK/advconfig.h | 12 +- sdk/foobar2000/SDK/advconfig_impl.h | 8 +- sdk/foobar2000/SDK/album_art.cpp | 17 +- sdk/foobar2000/SDK/album_art.h | 2 + sdk/foobar2000/SDK/app_close_blocker.cpp | 4 + sdk/foobar2000/SDK/app_close_blocker.h | 5 +- sdk/foobar2000/SDK/archive.h | 2 + sdk/foobar2000/SDK/audio_chunk.cpp | 14 +- sdk/foobar2000/SDK/audio_chunk.h | 12 +- .../SDK/audio_chunk_channel_config.cpp | 5 +- sdk/foobar2000/SDK/cfg_var.cpp | 4 + sdk/foobar2000/SDK/cfg_var_legacy.cpp | 2 +- sdk/foobar2000/SDK/cfg_var_legacy.h | 1 + sdk/foobar2000/SDK/chapterizer.h | 10 +- sdk/foobar2000/SDK/componentversion.cpp | 7 +- sdk/foobar2000/SDK/configStore.h | 76 ++++-- sdk/foobar2000/SDK/dsp.cpp | 165 +++++++++---- sdk/foobar2000/SDK/dsp.h | 169 ++++++++----- sdk/foobar2000/SDK/dsp_manager.cpp | 4 +- sdk/foobar2000/SDK/dsp_manager.h | 4 +- sdk/foobar2000/SDK/file.h | 2 + sdk/foobar2000/SDK/file_cached_impl.cpp | 1 + sdk/foobar2000/SDK/file_info.cpp | 36 +++ sdk/foobar2000/SDK/file_info.h | 10 + sdk/foobar2000/SDK/filesystem.cpp | 155 +++++++++--- sdk/foobar2000/SDK/filesystem.h | 9 +- sdk/foobar2000/SDK/filesystem_helper.cpp | 18 ++ sdk/foobar2000/SDK/filesystem_helper.h | 21 +- sdk/foobar2000/SDK/foobar2000-versions.h | 2 +- sdk/foobar2000/SDK/foobar2000-winver.h | 1 + sdk/foobar2000/SDK/foobar2000_SDK.vcxproj | 11 +- .../SDK/foobar2000_SDK.vcxproj.filters | 6 +- .../foobar2000_SDK.xcodeproj/project.pbxproj | 8 +- sdk/foobar2000/SDK/foosort.cpp | 2 +- sdk/foobar2000/SDK/foosortstring.cpp | 24 -- sdk/foobar2000/SDK/foosortstring.h | 16 +- sdk/foobar2000/SDK/fsItem.cpp | 23 +- sdk/foobar2000/SDK/guids.cpp | 18 +- sdk/foobar2000/SDK/info_lookup_handler.h | 14 +- sdk/foobar2000/SDK/input.cpp | 12 +- sdk/foobar2000/SDK/input.h | 11 + sdk/foobar2000/SDK/input_file_type.cpp | 20 ++ sdk/foobar2000/SDK/input_file_type.h | 3 + sdk/foobar2000/SDK/main_thread_callback.cpp | 7 + sdk/foobar2000/SDK/mainmenu.cpp | 10 +- sdk/foobar2000/SDK/output.cpp | 104 +++++--- sdk/foobar2000/SDK/output.h | 54 ++++- sdk/foobar2000/SDK/packet_decoder.cpp | 2 +- sdk/foobar2000/SDK/packet_decoder.h | 2 +- sdk/foobar2000/SDK/play_callback.h | 4 +- sdk/foobar2000/SDK/playback_stream_capture.h | 4 +- sdk/foobar2000/SDK/playlistColumnProvider.h | 8 +- sdk/foobar2000/SDK/playlist_loader.cpp | 44 ++-- sdk/foobar2000/SDK/preferences_page.cpp | 8 +- sdk/foobar2000/SDK/tag_processor.cpp | 43 +++- sdk/foobar2000/SDK/tag_processor.h | 35 ++- sdk/foobar2000/SDK/tag_processor_id3v2.cpp | 16 +- sdk/foobar2000/SDK/threaded_process.cpp | 6 +- sdk/foobar2000/SDK/threadsLite.h | 3 + sdk/foobar2000/SDK/timer.h | 2 + sdk/foobar2000/SDK/titleformat.h | 18 +- sdk/foobar2000/SDK/titleformat_object.h | 20 ++ sdk/foobar2000/SDK/ui.h | 25 +- sdk/foobar2000/SDK/ui_element.h | 2 +- sdk/foobar2000/SDK/utility.cpp | 6 +- sdk/foobar2000/foo_sample/dsp_sample.cpp | 4 +- sdk/foobar2000/foo_sample/dsp_sample.h | 1 + sdk/foobar2000/foo_sample/foo_sample.vcxproj | 9 +- .../foo_sample.xcodeproj/project.pbxproj | 5 +- sdk/foobar2000/foo_sample/rating.cpp | 2 +- sdk/foobar2000/foo_sample/ui_and_threads.cpp | 2 +- .../foobar2000_component_client.vcxproj | 9 +- .../project.pbxproj | 4 +- sdk/foobar2000/helpers-mac/CFObject.h | 57 +---- .../helpers-mac/NSAttributedString+ppaddons.h | 1 + .../helpers-mac/NSAttributedString+ppaddons.m | 4 +- .../helpers/CModelessDialogMessages.h | 17 ++ sdk/foobar2000/helpers/ProfileCache.h | 4 +- sdk/foobar2000/helpers/ThreadUtils.cpp | 7 +- .../helpers/WindowPositionUtils.cpp | 13 +- sdk/foobar2000/helpers/WindowPositionUtils.h | 4 +- sdk/foobar2000/helpers/atl-misc.h | 2 +- sdk/foobar2000/helpers/cfg_obj.h | 4 +- .../helpers/create_directory_helper.cpp | 12 +- sdk/foobar2000/helpers/cue_creator.cpp | 39 ++- sdk/foobar2000/helpers/cue_parser.cpp | 27 +-- .../helpers/cuesheet_index_list.cpp | 4 - sdk/foobar2000/helpers/fb2kWorkerTool.h | 2 +- sdk/foobar2000/helpers/file_list_helper.h | 8 +- .../project.pbxproj | 4 +- .../helpers/foobar2000_sdk_helpers.vcxproj | 10 +- .../foobar2000_sdk_helpers.vcxproj.filters | 3 + sdk/foobar2000/helpers/input_helpers.cpp | 129 +++++++--- sdk/foobar2000/helpers/input_helpers.h | 26 +- sdk/foobar2000/helpers/readers.cpp | 37 ++- sdk/foobar2000/helpers/readers.h | 4 +- sdk/foobar2000/helpers/rethrow.h | 8 +- .../helpers/tag_write_callback_impl.h | 4 +- sdk/foobar2000/helpers/ui_element_helpers.cpp | 8 +- sdk/foobar2000/helpers/writer_wav.cpp | 105 ++++---- sdk/foobar2000/helpers/writer_wav.h | 7 +- sdk/foobar2000/shared/Utility.cpp | 11 +- sdk/foobar2000/shared/crash_info.cpp | 1 + sdk/foobar2000/shared/fb2kdebug.h | 11 +- sdk/foobar2000/shared/filedialogs.cpp | 8 +- sdk/foobar2000/shared/filedialogs_vista.cpp | 12 +- sdk/foobar2000/shared/shared-apple.mm | 29 +++ sdk/foobar2000/shared/shared-nix.cpp | 2 +- sdk/foobar2000/shared/shared.h | 2 +- sdk/foobar2000/shared/shared.vcxproj | 28 +-- .../shared/shared.xcodeproj/project.pbxproj | 4 +- sdk/libPPUI/CEditWithButtons.h | 24 +- sdk/libPPUI/CListAccessible.cpp | 4 +- sdk/libPPUI/CListControl-Subst.cpp | 11 +- sdk/libPPUI/CListControlWithSelection.cpp | 10 +- sdk/libPPUI/CListControlWithSelection.h | 1 + sdk/libPPUI/DarkMode.cpp | 14 +- sdk/libPPUI/DarkMode.h | 1 + sdk/libPPUI/IDataObjectUtils.cpp | 4 +- sdk/libPPUI/ImageEncoder.cpp | 6 +- sdk/libPPUI/PaintUtils.cpp | 23 +- sdk/libPPUI/TreeMultiSel.h | 51 +++- sdk/libPPUI/gdiplus_helpers.cpp | 54 ++--- sdk/libPPUI/libPPUI-license.txt | 2 +- sdk/libPPUI/libPPUI.vcxproj | 20 +- sdk/libPPUI/stdafx.h | 5 + sdk/libPPUI/win32_utility.cpp | 42 +++- sdk/libPPUI/win32_utility.h | 6 + sdk/libPPUI/wtl-pp.h | 3 + sdk/pfc/CFObject.h | 59 +++++ sdk/pfc/SmartStrStr-table.h | 1 + sdk/pfc/SmartStrStr.cpp | 225 ++++++++---------- sdk/pfc/SmartStrStr.h | 18 +- sdk/pfc/alloc.h | 2 +- sdk/pfc/array.h | 2 +- sdk/pfc/avltree.h | 14 +- sdk/pfc/bsearch_inline.h | 4 +- sdk/pfc/charDownConvert.h | 2 +- sdk/pfc/debug.h | 9 +- sdk/pfc/event_std.h | 49 ++++ sdk/pfc/filehandle.cpp | 4 +- sdk/pfc/filehandle.h | 20 +- sdk/pfc/filetimetools.cpp | 9 +- sdk/pfc/iterators.h | 6 + sdk/pfc/list.h | 4 +- sdk/pfc/map.h | 5 + sdk/pfc/nix-objects.cpp | 50 +++- sdk/pfc/nix-objects.h | 4 +- sdk/pfc/obj-c.mm | 19 ++ sdk/pfc/other.cpp | 16 +- sdk/pfc/pathUtils.cpp | 11 +- sdk/pfc/pfc-license.txt | 2 +- sdk/pfc/pfc.vcxproj | 19 +- sdk/pfc/pfc.vcxproj.filters | 6 + sdk/pfc/pfc.xcodeproj/project.pbxproj | 22 +- sdk/pfc/pocket_char_ops.h | 5 + sdk/pfc/primitives.h | 12 +- sdk/pfc/sortstring.h | 30 +++ sdk/pfc/string-compare.cpp | 71 ++++-- sdk/pfc/string_base.cpp | 46 ++++ sdk/pfc/string_base.h | 26 +- sdk/pfc/string_list.h | 2 + sdk/pfc/syncd_storage.h | 27 ++- sdk/pfc/threadSafeObj.h | 39 +++ sdk/pfc/threads.cpp | 10 +- sdk/pfc/threads.h | 3 +- sdk/pfc/timers.h | 36 ++- sdk/pfc/utf8.cpp | 56 ++++- sdk/pfc/wait_queue.h | 40 +++- sdk/pfc/win-objects.cpp | 38 ++- sdk/pfc/win-objects.h | 4 +- sdk/sdk-license.txt | 4 +- sdk/sdk-readme.html | 6 +- 176 files changed, 2388 insertions(+), 1021 deletions(-) delete mode 100644 sdk/foobar2000/SDK/foosortstring.cpp create mode 100644 sdk/foobar2000/SDK/titleformat_object.h create mode 100644 sdk/foobar2000/helpers/CModelessDialogMessages.h create mode 100644 sdk/pfc/CFObject.h create mode 100644 sdk/pfc/event_std.h create mode 100644 sdk/pfc/sortstring.h create mode 100644 sdk/pfc/threadSafeObj.h diff --git a/cmake/FileLists.cmake b/cmake/FileLists.cmake index e880204..53d6981 100644 --- a/cmake/FileLists.cmake +++ b/cmake/FileLists.cmake @@ -92,6 +92,7 @@ set( sdk/pfc/cpuid.h sdk/pfc/debug.h sdk/pfc/event.h + sdk/pfc/event_std.h sdk/pfc/filehandle.h sdk/pfc/filetimetools.h sdk/pfc/fixed_map.h @@ -129,6 +130,7 @@ set( sdk/pfc/SmartStrStr.h sdk/pfc/sort.h sdk/pfc/sort2.h + sdk/pfc/sortstring.h sdk/pfc/splitString.h sdk/pfc/splitString2.h sdk/pfc/stdsort.h @@ -187,7 +189,6 @@ set( sdk/foobar2000/SDK/filesystem.cpp sdk/foobar2000/SDK/filesystem_helper.cpp sdk/foobar2000/SDK/foosort.cpp - sdk/foobar2000/SDK/foosortstring.cpp sdk/foobar2000/SDK/fsItem.cpp sdk/foobar2000/SDK/guids.cpp sdk/foobar2000/SDK/hasher_md5.cpp @@ -358,6 +359,7 @@ set( sdk/foobar2000/SDK/threadsLite.h sdk/foobar2000/SDK/timer.h sdk/foobar2000/SDK/titleformat.h + sdk/foobar2000/SDK/titleformat_object.h sdk/foobar2000/SDK/toolbarDropDown.h sdk/foobar2000/SDK/track_property.h sdk/foobar2000/SDK/tracks.h @@ -432,6 +434,7 @@ set( sdk/foobar2000/helpers/cfg_var_import.h sdk/foobar2000/helpers/CListControlFb2kColors.h sdk/foobar2000/helpers/CmdThread.h + sdk/foobar2000/helpers/CModelessDialogMessages.h sdk/foobar2000/helpers/CPropVariant.h sdk/foobar2000/helpers/CSingleThreadWrapper.h sdk/foobar2000/helpers/CTableEditHelper-Legacy.h diff --git a/sdk/foobar2000/SDK/abort_callback.cpp b/sdk/foobar2000/SDK/abort_callback.cpp index 67f62cf..c59413b 100644 --- a/sdk/foobar2000/SDK/abort_callback.cpp +++ b/sdk/foobar2000/SDK/abort_callback.cpp @@ -50,3 +50,12 @@ void abort_callback::waitForEvent(pfc::event& evt) { namespace fb2k { abort_callback_dummy noAbort; } + +abort_callback_event abort_callback_clone::clone(abort_callback_event arg) { + return pfc::fileHandleDup(arg); +} + +void abort_callback_clone::close(abort_callback_event arg) { + return pfc::fileHandleClose(arg); +} + diff --git a/sdk/foobar2000/SDK/abort_callback.h b/sdk/foobar2000/SDK/abort_callback.h index cfc772d..c4497f1 100644 --- a/sdk/foobar2000/SDK/abort_callback.h +++ b/sdk/foobar2000/SDK/abort_callback.h @@ -90,10 +90,20 @@ class abort_callback_usehandle : public abort_callback { bool is_aborting() const override; abort_callback_event get_abort_event() const override { return m_handle; } -private: +protected: const abort_callback_event m_handle; }; - + +class abort_callback_clone : public abort_callback_usehandle { +public: + abort_callback_clone(abort_callback_event handle) : abort_callback_usehandle(clone(handle)) {} + abort_callback_clone(abort_callback & arg) : abort_callback_usehandle(clone(arg.get_handle())) {} + ~abort_callback_clone() { close(m_handle); } + + static abort_callback_event clone(abort_callback_event); + static void close(abort_callback_event); +}; + //! Dummy abort_callback that never gets aborted. \n //! Note that there's no need to create instances of it, use shared fb2k::noAbort object instead. class abort_callback_dummy : public abort_callback { diff --git a/sdk/foobar2000/SDK/advconfig.h b/sdk/foobar2000/SDK/advconfig.h index 616db76..0ba8a96 100644 --- a/sdk/foobar2000/SDK/advconfig.h +++ b/sdk/foobar2000/SDK/advconfig.h @@ -71,10 +71,14 @@ class NOVTABLE advconfig_entry_string : public advconfig_entry { void get_default_state_(pfc::string_base & out); - enum { - flag_is_integer = 1 << 0, - flag_is_signed = 1 << 1, - }; + static constexpr uint32_t + flag_is_integer = 1 << 0, + flag_is_signed = 1 << 1, + // Since 2.2: hint to treat these fields as file/folder paths, providing hints if suitable + flag_is_file_path = 1 << 2, + flag_is_folder_path = 1 << 3, + // Since 2.2: multiple values, semicolon delimited + flag_semicolon_delimited = 1 << 4; FB2K_MAKE_SERVICE_INTERFACE(advconfig_entry_string,advconfig_entry); }; diff --git a/sdk/foobar2000/SDK/advconfig_impl.h b/sdk/foobar2000/SDK/advconfig_impl.h index fa456a4..6e8065e 100644 --- a/sdk/foobar2000/SDK/advconfig_impl.h +++ b/sdk/foobar2000/SDK/advconfig_impl.h @@ -31,6 +31,7 @@ class advconfig_branch_impl : public advconfig_branch { namespace fb2k { pfc::string8 advconfig_autoName(const GUID& id); + pfc::string8 advconfig_autoName(const GUID& id, const char * specified); } @@ -104,9 +105,12 @@ class advconfig_checkbox_factory_t : public advconfig_checkbox_factory_(p_name, varName, p_guid, p_parent, p_priority, p_initialstate, p_prefFlags) {} advconfig_string_factory(const char* p_name, const GUID& p_guid, const GUID& p_parent, double p_priority, const char* p_initialstate, t_uint32 p_prefFlags = 0) : service_factory_single_t(p_name, fb2k::advconfig_autoName(p_guid), p_guid, p_parent, p_priority, p_initialstate, p_prefFlags) {} + advconfig_string_factory(advconfig_entry_string_desc const& arg) : service_factory_single_t(arg) {} void get(pfc::string_base& out) { get_static_instance().get_state(out); } pfc::string8 get() { pfc::string8 temp; get(temp); return temp; } diff --git a/sdk/foobar2000/SDK/album_art.cpp b/sdk/foobar2000/SDK/album_art.cpp index 1d315d0..056e2a6 100644 --- a/sdk/foobar2000/SDK/album_art.cpp +++ b/sdk/foobar2000/SDK/album_art.cpp @@ -17,7 +17,7 @@ GUID album_art_editor::get_guid() { } 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; } + try { out = query(what, abort); return true; } catch (exception_album_art_not_found const &) { return false; } } service_ptr_t album_art_extractor_instance::query_image_(const GUID & what, abort_callback& a) { @@ -26,7 +26,7 @@ service_ptr_t album_art_extractor_instance::query_image_(const GUID } bool album_art_extractor_instance::have_entry(const GUID & what, abort_callback & abort) { - try { query(what, abort); return true; } catch(exception_album_art_not_found) { return false; } + try { query(what, abort); return true; } catch(exception_album_art_not_found const &) { return false; } } void album_art_editor_instance::remove_all_() { @@ -37,8 +37,8 @@ void album_art_editor_instance::remove_all_() { 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) {} + } catch(exception_io_data const &) {} + catch(exception_album_art_not_found const &) {} } } } @@ -107,7 +107,7 @@ album_art_extractor_instance_ptr album_art_extractor::g_open(file_ptr p_filehint album_art_extractor_instance_ptr album_art_extractor::g_open_allowempty(file_ptr p_filehint,const char * p_path,abort_callback & p_abort) { try { return g_open(p_filehint, p_path, p_abort); - } catch(exception_album_art_not_found) { + } catch(exception_album_art_not_found const &) { return new service_impl_t(); } } @@ -198,6 +198,13 @@ const char * album_art_ids::capitalized_name_of( const GUID & id) { return nullptr; } +GUID album_art_ids::by_name(const char* arg) { + for (size_t w = 0; w < num_types(); ++w) { + if (pfc::stringEqualsI_ascii(query_name(w), arg)) return query_type(w); + } + return pfc::guid_null; +} + bool album_art_path_list::equals(album_art_path_list const& v1, album_art_path_list const& v2) { const size_t n = v1.get_count(); if (n != v2.get_count()) return false; diff --git a/sdk/foobar2000/SDK/album_art.h b/sdk/foobar2000/SDK/album_art.h index ce95988..7e4e229 100644 --- a/sdk/foobar2000/SDK/album_art.h +++ b/sdk/foobar2000/SDK/album_art.h @@ -31,6 +31,8 @@ namespace album_art_ids { // returns Capitalized name const char * query_capitalized_name( size_t ); const char * capitalized_name_of( const GUID & ); + + GUID by_name(const char*); }; PFC_DECLARE_EXCEPTION(exception_album_art_not_found,exception_io_not_found,"Attached picture not found"); diff --git a/sdk/foobar2000/SDK/app_close_blocker.cpp b/sdk/foobar2000/SDK/app_close_blocker.cpp index 3c10c40..58d35e2 100644 --- a/sdk/foobar2000/SDK/app_close_blocker.cpp +++ b/sdk/foobar2000/SDK/app_close_blocker.cpp @@ -43,6 +43,10 @@ app_close_blocking_task_impl::app_close_blocking_task_impl(const char * name) : PFC_ASSERT( core_api::is_main_thread() ); app_close_blocking_task_manager::get()->register_task(this); } +app_close_blocking_task_impl::app_close_blocking_task_impl(pfc::string8&& name) : m_name(std::move(name)) { + PFC_ASSERT(core_api::is_main_thread()); + app_close_blocking_task_manager::get()->register_task(this); +} app_close_blocking_task_impl::~app_close_blocking_task_impl() { PFC_ASSERT( core_api::is_main_thread() ); diff --git a/sdk/foobar2000/SDK/app_close_blocker.h b/sdk/foobar2000/SDK/app_close_blocker.h index aed5bfd..2137c78 100644 --- a/sdk/foobar2000/SDK/app_close_blocker.h +++ b/sdk/foobar2000/SDK/app_close_blocker.h @@ -48,6 +48,7 @@ class NOVTABLE app_close_blocking_task_manager : public service_base { class app_close_blocking_task_impl : public app_close_blocking_task { public: app_close_blocking_task_impl(const char * name = ""); + app_close_blocking_task_impl(pfc::string8&& name); ~app_close_blocking_task_impl(); //! Override me, or provide name to constructor @@ -56,7 +57,7 @@ class app_close_blocking_task_impl : public app_close_blocking_task { app_close_blocking_task_impl( const app_close_blocking_task_impl & ) = delete; void operator=(const app_close_blocking_task_impl & ) = delete; private: - const char * const m_name; + const pfc::string8 m_name; }; class app_close_blocking_task_impl_dynamic : public app_close_blocking_task { @@ -70,7 +71,7 @@ class app_close_blocking_task_impl_dynamic : public app_close_blocking_task { void toggle_blocking(bool state); private: bool m_taskActive = false; - const char * const m_name; + const pfc::string8 m_name; }; diff --git a/sdk/foobar2000/SDK/archive.h b/sdk/foobar2000/SDK/archive.h index d2ad63e..3c1af67 100644 --- a/sdk/foobar2000/SDK/archive.h +++ b/sdk/foobar2000/SDK/archive.h @@ -23,6 +23,8 @@ namespace foobar2000_io { //! Lists archive contents. \n //! May be called with any path, not only path accepted by is_our_archive. \n //! It is strongly recommended to use the lambda_based archive_list() helper instead of calling this directly. + //! @param p_reader Optional reader to use, if the caller already has one. Implementation will open the file if no reader is supplied. + //! @param p_want_readers Flag to tell if the callback wants a reader object for each file in the archive, or just wants to list contents. virtual void archive_list(const char * p_path,const service_ptr_t & p_reader,archive_callback & p_callback,bool p_want_readers) = 0; //! Helper implemented on top of the other archive_list, uses lambda instead of callback, avoids having to implement archive_callback. diff --git a/sdk/foobar2000/SDK/audio_chunk.cpp b/sdk/foobar2000/SDK/audio_chunk.cpp index 8210b7e..dc45e44 100644 --- a/sdk/foobar2000/SDK/audio_chunk.cpp +++ b/sdk/foobar2000/SDK/audio_chunk.cpp @@ -2,9 +2,19 @@ #include "mem_block_container.h" #include "audio_chunk.h" -void audio_chunk::set_data(const audio_sample* src, size_t samples, spec_t const & spec) { +void audio_chunk::allocate(size_t size, bool bQuicker) { + if (bQuicker) { + const size_t before = this->get_data_size(); + const size_t allow_waste = pfc::max_t(size, 4096); + const size_t upper = (size + allow_waste > size) ? size + allow_waste : SIZE_MAX; + if (before >= size && before <= upper) return; + } + this->set_data_size(size); +} + +void audio_chunk::set_data(const audio_sample* src, size_t samples, spec_t const & spec, bool bQuicker) { t_size size = samples * spec.chanCount; - set_data_size(size); + allocate(size, bQuicker); if (src) pfc::memcpy_t(get_data(), src, size); else diff --git a/sdk/foobar2000/SDK/audio_chunk.h b/sdk/foobar2000/SDK/audio_chunk.h index 073e632..2d705ac 100644 --- a/sdk/foobar2000/SDK/audio_chunk.h +++ b/sdk/foobar2000/SDK/audio_chunk.h @@ -99,7 +99,8 @@ class NOVTABLE audio_chunk { //! Resizes audio data buffer to specified size. Throws std::bad_alloc on failure. virtual void set_data_size(t_size p_new_size) = 0; //! Sanity helper, same as set_data_size. - void allocate(size_t size) { set_data_size( size ); } + //! @param bQuicker Avoid memory allocation, permit up to 2x memory used + void allocate(size_t size, bool bQuicker = false); //! Retrieves sample rate of contained audio data. virtual unsigned get_srate() const = 0; @@ -177,7 +178,7 @@ class NOVTABLE audio_chunk { //! Helper, sets chunk data to contents of specified buffer, with specified number of channels / sample rate / channel map. void set_data(const audio_sample * src,size_t samples,unsigned nch,unsigned srate,unsigned channel_config); - void set_data(const audio_sample* src, size_t samples, spec_t const& spec); + void set_data(const audio_sample* src, size_t samples, spec_t const& spec, bool bQucker = false); void set_data(const audio_sample* src, t_size samples, unsigned nch, unsigned srate); void set_data_int16(const int16_t * src,t_size samples,unsigned nch,unsigned srate,unsigned channel_config); @@ -221,7 +222,7 @@ class NOVTABLE audio_chunk { void pad_with_silence_ex(t_size samples,unsigned hint_nch,unsigned hint_srate); //! Appends silent samples at the end of the chunk. \n //! The chunk must have valid sample rate & channel count prior to this call. - //! @param samples Number of silent samples to append.s + //! @param samples Number of silent samples to append. void pad_with_silence(t_size samples); //! Inserts silence at the beginning of the audio chunk. //! @param samples Number of silent samples to insert. @@ -269,8 +270,9 @@ class NOVTABLE audio_chunk { void scale(audio_sample p_value); //! Helper; copies content of another audio chunk to this chunk. - void copy(const audio_chunk & p_source) { - set_data(p_source.get_data(),p_source.get_sample_count(),p_source.get_channels(),p_source.get_srate(),p_source.get_channel_config()); + //! @param bQuicker Avoid memory allocation, permit up to 2x memory used + void copy(const audio_chunk & p_source, bool bQuicker = false) { + set_data(p_source.get_data(),p_source.get_sample_count(),p_source.get_spec(), bQuicker); } const audio_chunk & operator=(const audio_chunk & p_source) { diff --git a/sdk/foobar2000/SDK/audio_chunk_channel_config.cpp b/sdk/foobar2000/SDK/audio_chunk_channel_config.cpp index 85a92cd..1751b3a 100644 --- a/sdk/foobar2000/SDK/audio_chunk_channel_config.cpp +++ b/sdk/foobar2000/SDK/audio_chunk_channel_config.cpp @@ -74,7 +74,8 @@ unsigned audio_chunk::g_guess_channel_config(unsigned count) 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; + // Warning: 1u<<32u behaves stupidly + ret = (unsigned)( (1ull << count) - 1 ); } PFC_ASSERT(g_count_channels(ret) == count); return ret; @@ -86,6 +87,8 @@ unsigned audio_chunk::g_guess_channel_config_xiph(unsigned count) { return audio_chunk::channel_front_left | audio_chunk::channel_front_center | audio_chunk::channel_front_right; case 5: return audio_chunk::channel_front_left | audio_chunk::channel_front_center | audio_chunk::channel_front_right | audio_chunk::channel_back_left | audio_chunk::channel_back_right; + case 7: + return audio_chunk::channel_config_5point1 | audio_chunk::channel_back_center; default: return g_guess_channel_config(count); } diff --git a/sdk/foobar2000/SDK/cfg_var.cpp b/sdk/foobar2000/SDK/cfg_var.cpp index 8b0dd2c..bc51083 100644 --- a/sdk/foobar2000/SDK/cfg_var.cpp +++ b/sdk/foobar2000/SDK/cfg_var.cpp @@ -9,6 +9,10 @@ namespace fb2k { pfc::string8 advconfig_autoName(const GUID& id) { return pfc::format("advconfig.unnamed.", pfc::print_guid(id)); } + pfc::string8 advconfig_autoName(const GUID& id, const char* specified) { + if (specified) return specified; + return advconfig_autoName(id); + } } namespace cfg_var_modern { diff --git a/sdk/foobar2000/SDK/cfg_var_legacy.cpp b/sdk/foobar2000/SDK/cfg_var_legacy.cpp index c96f167..670c248 100644 --- a/sdk/foobar2000/SDK/cfg_var_legacy.cpp +++ b/sdk/foobar2000/SDK/cfg_var_legacy.cpp @@ -36,7 +36,7 @@ namespace cfg_var_legacy { stream_reader_limited_ref wrapper(p_stream, size); try { iter->m_value->set_data_raw(&wrapper, size, p_abort); - } catch (exception_io_data) {} + } catch (exception_io_data const&) {} wrapper.flush_remaining(p_abort); } else { p_stream->skip_object(size, p_abort); diff --git a/sdk/foobar2000/SDK/cfg_var_legacy.h b/sdk/foobar2000/SDK/cfg_var_legacy.h index 943c86e..02b044d 100644 --- a/sdk/foobar2000/SDK/cfg_var_legacy.h +++ b/sdk/foobar2000/SDK/cfg_var_legacy.h @@ -122,6 +122,7 @@ namespace cfg_var_legacy { inline operator t_inttype() const { return m_val; } inline t_inttype get_value() const { return m_val; } + inline t_inttype get() const { return m_val; } }; typedef cfg_int_t cfg_int; diff --git a/sdk/foobar2000/SDK/chapterizer.h b/sdk/foobar2000/SDK/chapterizer.h index adc897a..14d3e6d 100644 --- a/sdk/foobar2000/SDK/chapterizer.h +++ b/sdk/foobar2000/SDK/chapterizer.h @@ -21,7 +21,11 @@ class NOVTABLE chapter_list { //! @param p_info New chapter description. Note that length part of file_info is used to calculate chapter marks. virtual void set_info(t_size p_chapter,const file_info & p_info) = 0; + //! Gets first track pregap - offset into audio at which first track begins. + //! Not every chapterizer supports this, see chapterizer::supports_pregaps() virtual double get_pregap() const = 0; + //! Sets first track pregap - offset into audio at which first track begins. + //! Not every chapterizer supports this, see chapterizer::supports_pregaps() virtual void set_pregap(double val) = 0; //! Copies contents of specified chapter_list object to this object. @@ -38,10 +42,9 @@ class NOVTABLE chapter_list { template class chapter_list_impl_t : public chapter_list { public: - chapter_list_impl_t() : m_pregap() {} + chapter_list_impl_t() {} typedef chapter_list_impl_t t_self; chapter_list_impl_t(const chapter_list & p_source) : m_pregap() {copy(p_source);} - const t_self & operator=(const chapter_list & p_source) {copy(p_source); return *this;} t_size get_chapter_count() const {return m_infos.get_size();} @@ -55,7 +58,7 @@ class chapter_list_impl_t : public chapter_list { void set_pregap(double val) {PFC_ASSERT(val >= 0); m_pregap = val;} private: pfc::array_t m_infos; - double m_pregap; + double m_pregap = 0; }; typedef chapter_list_impl_t<> chapter_list_impl; @@ -80,6 +83,7 @@ class NOVTABLE chapterizer : public service_base { //! @param p_abort abort_callback object signaling user aborting the operation. virtual void get_chapters(const char * p_path,chapter_list & p_list,abort_callback & p_abort) = 0; + //! @returns Whether this chapterizer supports altering pregap before first track, see chapter_list::get_pregap() & set_pregap() virtual bool supports_pregaps() = 0; //! Static helper, tries to find chapterizer interface that supports specified file. diff --git a/sdk/foobar2000/SDK/componentversion.cpp b/sdk/foobar2000/SDK/componentversion.cpp index f6055e2..1651a0f 100644 --- a/sdk/foobar2000/SDK/componentversion.cpp +++ b/sdk/foobar2000/SDK/componentversion.cpp @@ -10,6 +10,7 @@ bool component_installation_validator::test_my_name(const char * fn) { path += pfc::scan_filename(path); bool retVal = ( strcmp(path, fn) == 0 ); PFC_ASSERT( retVal ); + if (!retVal) uAddDebugEvent(pfc::format("Component rename detected: ", fn, " >> ", path)); return retVal; } bool component_installation_validator::have_other_file(const char * fn) { @@ -26,11 +27,11 @@ bool component_installation_validator::have_other_file(const char * fn) { FB2K_console_formatter() << "Component integrity check error: " << e << " (on: " << fn << ")"; throw; } - } catch(exception_io_denied) { + } catch(exception_io_denied const &) { - } catch(exception_io_sharing_violation) { + } catch(exception_io_sharing_violation const &) { - } catch(exception_io_file_corrupted) { // happens + } catch(exception_io_file_corrupted const &) { // happens return false; } catch(...) { uBugCheck(); diff --git a/sdk/foobar2000/SDK/configStore.h b/sdk/foobar2000/SDK/configStore.h index 6782938..db912ee 100644 --- a/sdk/foobar2000/SDK/configStore.h +++ b/sdk/foobar2000/SDK/configStore.h @@ -35,22 +35,6 @@ class configStore : public service_base { virtual void setConfigInt( const char * name, int64_t val ) = 0; virtual void deleteConfigInt(const char * name) = 0; - //! Helper around getConfigInt. - bool getConfigBool( const char * name, bool defVal = false ); - //! Helper around setConfigInt. - void setConfigBool( const char * name, bool val ); - //! Helper around setConfigInt. - bool toggleConfigBool (const char * name, bool defVal = false ); - //! Helper around deleteConfigInt. - void deleteConfigBool( const char * name ); - - //! Helper around getConfigString. - GUID getConfigGUID(const char* name, const GUID& defVal = pfc::guid_null); - //! Helper around setConfigString. - void setConfigGUID(const char* name, const GUID& val); - //! Helper around deleteConfigString. - void deleteConfigGUID(const char* name); - virtual fb2k::stringRef getConfigString( const char * name, fb2k::stringRef defaVal = fb2k::string::stringWithString("")) = 0; virtual void setConfigString( const char * name, const char * value ) = 0; virtual void deleteConfigString(const char * name) = 0; @@ -74,6 +58,22 @@ class configStore : public service_base { objRef addNotify( const char * name, std::function f ); void addPermanentNotify( const char * name, std::function f ); + //! Helper around getConfigInt. + bool getConfigBool( const char * name, bool defVal = false ); + //! Helper around setConfigInt. + void setConfigBool( const char * name, bool val ); + //! Helper around setConfigInt. + bool toggleConfigBool (const char * name, bool defVal = false ); + //! Helper around deleteConfigInt. + void deleteConfigBool( const char * name ); + + //! Helper around getConfigString. + GUID getConfigGUID(const char* name, const GUID& defVal = pfc::guid_null); + //! Helper around setConfigString. + void setConfigGUID(const char* name, const GUID& val); + //! Helper around deleteConfigString. + void deleteConfigGUID(const char* name); + //! For internal core use, notifies everyone interested about off-process change to configuration data. virtual void callNotify(const char * name) = 0; @@ -129,4 +129,48 @@ stringRef val = api->getConfigString( "myComponent.foo", "defaultVal" ); // use api->commitBlocking() } */ + + +//! \since 2.2 +class configStore2 : public configStore { + FB2K_MAKE_SERVICE_COREAPI_EXTENSION(configStore2, configStore); +public: + // Use flagSuppressCache to prevent value from being cached. Prevents memory usage creep if querying lots of uniquely named variables. + static constexpr uint32_t flagSuppressCache = 1; + + virtual int64_t getConfigInt2( const char * name, int64_t defVal = 0, uint32_t flags = 0 ) = 0; + virtual void setConfigInt2( const char * name, int64_t val, uint32_t flags = 0 ) = 0; + virtual void deleteConfigInt2(const char * name, uint32_t flags = 0) = 0; + + virtual fb2k::stringRef getConfigString2( const char * name, fb2k::stringRef defaVal = fb2k::string::stringWithString(""), uint32_t flags = 0) = 0; + virtual void setConfigString2( const char * name, const char * value, uint32_t flags = 0 ) = 0; + virtual void deleteConfigString2(const char * name, uint32_t flags = 0) = 0; + + virtual fb2k::memBlockRef getConfigBlob2( const char * name, fb2k::memBlockRef defVal = fb2k::memBlock::empty(), uint32_t flags = 0) = 0; + virtual void setConfigBlob2(const char* name, const void* ptr, size_t bytes, uint32_t flags = 0) = 0; + virtual void setConfigBlob2(const char* name, fb2k::memBlockRef val, uint32_t flags = 0) = 0; + virtual void deleteConfigBlob2(const char * name, uint32_t flags = 0) = 0; + + virtual double getConfigFloat2( const char * name, double defVal = 0, uint32_t flags = 0) = 0; + virtual void setConfigFloat2( const char * name, double val, uint32_t flags = 0) = 0; + virtual void deleteConfigFloat2( const char * name, uint32_t flags = 0) = 0; + + + int64_t getConfigInt( const char * name, int64_t defVal ) override final { return getConfigInt2(name, defVal); } + void setConfigInt( const char * name, int64_t val ) override final { setConfigInt2(name, val); } + void deleteConfigInt(const char * name) override final { deleteConfigInt2(name); } + + fb2k::stringRef getConfigString( const char * name, fb2k::stringRef defaVal) override final { return getConfigString2(name, defaVal); } + void setConfigString( const char * name, const char * value ) override final { setConfigString2(name, value); } + void deleteConfigString(const char * name) override final { deleteConfigString2(name); } + + fb2k::memBlockRef getConfigBlob( const char * name, fb2k::memBlockRef defVal ) override final { return getConfigBlob2(name, defVal); } + void setConfigBlob(const char* name, const void* ptr, size_t bytes) override final { setConfigBlob2(name, ptr, bytes); } + void setConfigBlob(const char* name, fb2k::memBlockRef val) override final { setConfigBlob2(name, val); } + void deleteConfigBlob(const char * name) override final { deleteConfigBlob2(name); } + + double getConfigFloat( const char * name, double defVal ) override final { return getConfigFloat2(name, defVal); } + void setConfigFloat( const char * name, double val ) override final { setConfigFloat2(name, val); } + void deleteConfigFloat( const char * name ) override final { deleteConfigFloat2(name); } +}; } // namespace fb2k diff --git a/sdk/foobar2000/SDK/dsp.cpp b/sdk/foobar2000/SDK/dsp.cpp index 1d23b94..6bb8fb3 100644 --- a/sdk/foobar2000/SDK/dsp.cpp +++ b/sdk/foobar2000/SDK/dsp.cpp @@ -22,40 +22,41 @@ void dsp_chunk_list::add_chunk(const audio_chunk * chunk) { if (dst) dst->copy(*chunk); } -t_size dsp_chunk_list_impl::get_count() const {return m_data.get_count();} +t_size dsp_chunk_list_impl::get_count() const {return m_data.size();} -audio_chunk * dsp_chunk_list_impl::get_item(t_size n) const {return nmax) idx = max; - pfc::rcptr_t ret; - if (m_recycled.get_count()>0) + chunk_ptr_t ret; + if (!m_recycled.empty()) { t_size best; - if (hint_size>0) + if (hint_size > 0) { best = 0; - t_size best_found = m_recycled[0]->get_data_size(), n, total = m_recycled.get_count(); - for(n=1;nget_data_size(), n, total = m_recycled.size(); + for (n = 1; n < total; n++) { - if (best_found==hint_size) break; + if (best_found == hint_size) break; t_size size = m_recycled[n]->get_data_size(); int delta_old = abs((int)best_found - (int)hint_size), delta_new = abs((int)size - (int)hint_size); if (delta_new < delta_old) @@ -64,18 +65,18 @@ audio_chunk * dsp_chunk_list_impl::insert_item(t_size idx,t_size hint_size) best = n; } } - } - else best = m_recycled.get_count()-1; + } else best = m_recycled.size() - 1; - ret = m_recycled.remove_by_idx(best); + ret = std::move(m_recycled[best]); + m_recycled.erase(m_recycled.begin() + best); ret->set_sample_count(0); ret->set_channels(0); ret->set_srate(0); - } - else ret = pfc::rcnew_t(); - if (idx==max) m_data.add_item(ret); - else m_data.insert_item(ret,idx); - return &*ret; + } else ret = std::make_unique(); + auto pRet = &*ret; + if (idx == max) m_data.push_back(std::move(ret)); + else m_data.insert(m_data.begin() + idx, std::move(ret)); + return pRet; } void dsp_chunk_list::remove_bad_chunks() @@ -223,17 +224,59 @@ void dsp_chain_config::remove_all() remove_mask(pfc::bit_array_true()); } -void dsp_chain_config::instantiate(service_list_t & p_out) -{ - p_out.remove_all(); - t_size n, m = get_count(); - for(n=0;n temp; - auto const & preset = this->get_item(n); - if (dsp_entry::g_instantiate(temp,preset) || dsp_entry_hidden::g_instantiate(temp, preset)) - p_out.add_item(temp); - } +size_t dsp_chain_config::find_first_of_type( const GUID & dspID ) const { + const size_t count = this->get_count(); + for(size_t w = 0; w < count; ++w) { + if (this->get_item(w).get_owner() == dspID) return w; + } + return pfc_infinite; +} + +bool dsp_chain_config::contains_dsp( const GUID & dspID ) const { + return find_first_of_type( dspID ) != pfc_infinite; +} + +bool dsp_chain_config::enable_dsp( const GUID & dspID ) { + if (this->contains_dsp( dspID )) return false; + dsp_preset_impl preset; + dsp_entry::g_get_default_preset( preset, dspID ); + insert_item( preset, 0 ); + return true; +} + +bool dsp_chain_config::disable_dsp( const GUID & dspID ) { + const size_t count = this->get_count(); + if (count == 0) return false; + bool rv = false; + pfc::bit_array_bittable mask( count ); + for(size_t w = 0; w < count; ++ w) { + if (this->get_item(w).get_owner() == dspID ) { + rv = true; + mask.set(w, true); + } + } + if (rv) this->remove_mask( mask ); + return rv; +} + +bool dsp_chain_config::enable_dsp( const dsp_preset & preset ) { + dsp_chain_config & cfg = *this; + bool found = false; + bool changed = false; + t_size n,m = cfg.get_count(); + for(n=0;nshow_config_popup_v3(parent, callback); - } catch (pfc::exception_not_implemented) { + } catch (pfc::exception_not_implemented const &) { } } @@ -464,12 +507,6 @@ void dsp_entry::g_show_config_popup_v2(const dsp_preset & p_preset,fb2k::hwnd_t } #endif -#ifndef _WIN32 -service_ptr dsp_entry::show_config_popup( fb2k::hwnd_t, dsp_preset_edit_callback_v2::ptr ) { - throw pfc::exception_not_implemented(); -} -#endif - service_ptr_t dsp_entry::g_get_interface(const GUID& guid) { for (auto ptr : enumerate()) { if (ptr->get_guid() == guid) return ptr; @@ -490,12 +527,14 @@ bool dsp_entry::g_get_interface(service_ptr_t & p_out,const GUID & p_ bool resampler_entry::g_get_interface(service_ptr_t & p_out,unsigned p_srate_from,unsigned p_srate_to) { -#if FOOBAR2000_TARGET_VERSION >= 79 +#if defined(FOOBAR2000_DESKTOP) && FOOBAR2000_TARGET_VERSION >= 79 auto r = resampler_manager::get()->get_resampler( p_srate_from, p_srate_to ); bool v = r.is_valid(); if ( v ) p_out = std::move(r); return v; #else + +#ifdef FOOBAR2000_DESKTOP { resampler_manager::ptr api; if ( resampler_manager::tryGet(api) ) { @@ -505,6 +544,7 @@ bool resampler_entry::g_get_interface(service_ptr_t & p_out,uns return v; } } +#endif resampler_entry::ptr ptr_resampler; service_enum_t e; @@ -597,7 +637,7 @@ pfc::string8 dsp_chain_config::get_name_list() const { return output; } -void dsp::run_abortable(dsp_chunk_list * p_chunk_list,const metadb_handle_ptr & p_cur_file,int p_flags,abort_callback & p_abort) { +void dsp::run_abortable(dsp_chunk_list * p_chunk_list,const dsp_track_t & p_cur_file,int p_flags,abort_callback & p_abort) { service_ptr_t this_v2; if (this->service_query_t(this_v2)) this_v2->run_v2(p_chunk_list,p_cur_file,p_flags,p_abort); else run(p_chunk_list,p_cur_file,p_flags); @@ -635,6 +675,23 @@ bool dsp_entry_v2::show_config_popup(dsp_preset & p_data,fb2k::hwnd_t p_parent) } #endif +#ifdef FOOBAR2000_MOBILE +void dsp_entry::g_show_config_popup( menu_context_ptr ctx, dsp_preset_edit_callback_v2::ptr callback) { + GUID dspID; + { + dsp_preset_impl temp; + callback->get_preset( temp ); + dspID = temp.get_owner(); + } + + dsp_entry::ptr entry; + if (!g_get_interface( entry, dspID)) return; + if (!entry->have_config_popup()) return; + entry->show_config_popup( ctx, callback ); +} +#endif // FOOBAR2000_MOBILE + +#ifdef FOOBAR2000_DESKTOP void resampler_manager::make_chain_(dsp_chain_config& outChain, unsigned rateFrom, unsigned rateTo, float qualityScale) { resampler_manager_v2::ptr v2; if (v2 &= this) { @@ -650,6 +707,7 @@ void resampler_manager::make_chain_(dsp_chain_config& outChain, unsigned rateFro } } } +#endif void dsp_preset_edit_callback_v2::reset() { dsp_preset_impl temp; get_preset( temp ); @@ -675,4 +733,25 @@ void dsp_entry::get_display_name_(const dsp_preset& arg, pfc::string_base& out) get_name(out); } +bool dsp_entry::enumerate_default_presets_(dsp_chain_config& ret) { + ret.remove_all(); + dsp_entry_v5::ptr v5; + if (v5 &= this) { + bool rv = v5->enumerate_default_presets(ret); +#if PFC_DEBUG + for (size_t walk = 0; walk < ret.get_count(); ++walk) { + PFC_ASSERT(ret.get_item(walk).get_owner() == get_guid()); + } +#endif + return rv; + } + return false; +} + +bool dsp_entry::match_preset_subclass_(dsp_preset const& x, dsp_preset const& y) { + dsp_entry_v5::ptr v5; + if (v5 &= this) return v5->match_preset_subclass(x, y); + return true; +} + #endif // FOOBAR2000_HAVE_DSP diff --git a/sdk/foobar2000/SDK/dsp.h b/sdk/foobar2000/SDK/dsp.h index caf941f..4e882e9 100644 --- a/sdk/foobar2000/SDK/dsp.h +++ b/sdk/foobar2000/SDK/dsp.h @@ -4,7 +4,20 @@ #ifdef FOOBAR2000_HAVE_DSP -class dsp_preset; // forward declaration +#ifdef FOOBAR2000_MOBILE +#include "dsp-context.h" +#endif + +#include +#include + +class dsp_preset; class dsp_chain_config; // forward declaration + +#ifdef FOOBAR2000_HAVE_METADB +typedef metadb_handle_ptr dsp_track_t; +#else +typedef trackRef dsp_track_t; +#endif //! Interface to a DSP chunk list. A DSP chunk list object is passed to the DSP chain each time, since DSPs are allowed to remove processed chunks or insert new ones. class NOVTABLE dsp_chunk_list { @@ -31,13 +44,19 @@ class NOVTABLE dsp_chunk_list { class dsp_chunk_list_impl : public dsp_chunk_list//implementation { - pfc::list_t > m_data, m_recycled; + typedef std::unique_ptr chunk_ptr_t; + std::vector m_data, m_recycled; public: + dsp_chunk_list_impl() {} + dsp_chunk_list_impl(const dsp_chunk_list_impl&) = delete; + void operator=(const dsp_chunk_list_impl&) = delete; t_size get_count() const; audio_chunk * get_item(t_size n) const; void remove_by_idx(t_size idx); void remove_mask(const bit_array & mask); audio_chunk * insert_item(t_size idx,t_size hint_size=0); + + audio_chunk_impl* get_item_(size_t n) const { return m_data[n].get(); } }; //! Instance of a DSP.\n @@ -55,7 +74,7 @@ class NOVTABLE dsp : public service_base { //! @param p_chunk_list List of chunks to process. The implementation may alter the list in any way, inserting chunks of different sample rate / channel configuration etc. //! @param p_cur_file Optional, location of currently decoded file. May be null. //! @param p_flags Flags. Can be null, or a combination of END_OF_TRACK and FLUSH constants. - virtual void run(dsp_chunk_list * p_chunk_list,const metadb_handle_ptr & p_cur_file,int p_flags)=0; + virtual void run(dsp_chunk_list * p_chunk_list,const dsp_track_t & p_cur_file,int p_flags)=0; //! Flushes the DSP (reinitializes / drops any buffered data). Called after seeking, etc. virtual void flush() = 0; @@ -68,7 +87,7 @@ class NOVTABLE dsp : public service_base { //! Signaling this will often break regular gapless playback so don't use it unless you have reasons to. virtual bool need_track_change_mark() = 0; - void run_abortable(dsp_chunk_list * p_chunk_list,const metadb_handle_ptr & p_cur_file,int p_flags,abort_callback & p_abort); + void run_abortable(dsp_chunk_list * p_chunk_list,const dsp_track_t & p_cur_file,int p_flags,abort_callback & p_abort); //! Attempts to apply preset without recreating the DSP, if supported. //! @returns True on success, false if not supported (DSP needs re-creating). @@ -81,9 +100,9 @@ class NOVTABLE dsp : public service_base { class NOVTABLE dsp_v2 : public dsp { public: //! Abortable version of dsp::run(). See dsp::run() for descriptions of parameters. - 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; + virtual void run_v2(dsp_chunk_list * p_chunk_list,const dsp_track_t & 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) { + void run(dsp_chunk_list * p_chunk_list,const dsp_track_t & p_cur_file,int p_flags) { run_v2(p_chunk_list,p_cur_file,p_flags,fb2k::noAbort); } @@ -114,19 +133,19 @@ class dsp_impl_base_t : public t_baseclass { typedef dsp_impl_base_t t_self; dsp_chunk_list * m_list = nullptr; t_size m_chunk_ptr = 0; - metadb_handle* m_cur_file = nullptr; - void run_v2(dsp_chunk_list * p_list,const metadb_handle_ptr & p_cur_file,int p_flags,abort_callback & p_abort) override; + dsp_track_t m_cur_file = nullptr; + void run_v2(dsp_chunk_list * p_list,const dsp_track_t & p_cur_file,int p_flags,abort_callback & p_abort) override; protected: //! Call only from on_chunk / on_endoftrack (on_endoftrack will give info on track being finished).\n //! May return false when there's no known track and the metadb_handle ptr will be empty/null. - bool get_cur_file(metadb_handle_ptr & p_out) const {p_out = m_cur_file; return p_out.is_valid();} - metadb_handle_ptr get_cur_file() const { return m_cur_file; } + bool get_cur_file(dsp_track_t & p_out) const {p_out = m_cur_file; return p_out.is_valid();} + dsp_track_t get_cur_file() const { return m_cur_file; } dsp_impl_base_t() {} //! Inserts a new chunk of audio data. \n //! You can call this only from on_chunk(), on_endofplayback() and on_endoftrack(). You're NOT allowed to call this from flush() which should just drop any queued data. - //! @param hint_size Optional, amount of buffer space that you require (in audio_samples). This is just a hint for memory allocation logic and will not cause the framework to allocate the chunk for you. + //! @param p_hint_size Optional, amount of buffer space that you require (in audio_samples). This is just a hint for memory allocation logic and will not cause the framework to allocate the chunk for you. //! @returns A pointer to the newly allocated chunk. Pass the audio data you want to insert to this chunk object. The chunk is owned by the framework, you can't delete it etc. audio_chunk * insert_chunk(t_size p_hint_size = 0) { PFC_ASSERT(m_list != NULL); @@ -176,9 +195,9 @@ class dsp_impl_base_t : public t_baseclass { }; template -void dsp_impl_base_t::run_v2(dsp_chunk_list * p_list,const metadb_handle_ptr & p_cur_file,int p_flags,abort_callback & p_abort) { +void dsp_impl_base_t::run_v2(dsp_chunk_list * p_list,const dsp_track_t & p_cur_file,int p_flags,abort_callback & p_abort) { pfc::vartoggle_t l_list_toggle(m_list,p_list); - pfc::vartoggle_t l_cur_file_toggle(m_cur_file,p_cur_file.get_ptr()); + auto track_toggle = pfc::autoToggle(m_cur_file, p_cur_file); for(m_chunk_ptr = 0;m_chunk_ptrget_count();m_chunk_ptr++) { audio_chunk * c = m_list->get_item(m_chunk_ptr); @@ -326,15 +345,23 @@ class NOVTABLE dsp_entry : public service_base { virtual bool instantiate(service_ptr_t & p_out,const dsp_preset & p_preset) = 0; virtual GUID get_guid() = 0; virtual bool have_config_popup() = 0; + +#ifdef FOOBAR2000_MOBILE + virtual void show_config_popup( fb2k::dspConfigContext_t parent, dsp_preset_edit_callback_v2::ptr callback ) {} +#endif + +#ifdef FOOBAR2000_DESKTOP #ifdef _WIN32 //! Shows configuration popup. Call from main thread only! \n //! Blocks until done. Returns true if preset has been altered, false otherwise. - virtual bool show_config_popup(dsp_preset & p_data,fb2k::hwnd_t p_parent) = 0; -#else + //! Legacy method, replaced in dsp_entry_v2 and newer. + virtual bool show_config_popup(dsp_preset & p_data,fb2k::hwnd_t p_parent) { return false; } +#else // non-Windows desktop //! Shows configuration popup. Main thread only! \n //! Mac: returns NSObjectWrapper holding NSViewController - virtual service_ptr show_config_popup( fb2k::hwnd_t parent, dsp_preset_edit_callback_v2::ptr callback ); + virtual service_ptr show_config_popup( fb2k::hwnd_t parent, dsp_preset_edit_callback_v2::ptr callback ) { throw pfc::exception_not_implemented(); } #endif +#endif // FOOBAR2000_DESKTOP //! Obsolete method, hidden DSPs now use a different entry class. bool is_user_accessible() { return true; } @@ -371,8 +398,14 @@ class NOVTABLE dsp_entry : public service_base { service_ptr show_config_popup_v3_(fb2k::hwnd_t parent, dsp_preset_edit_callback_v2::ptr callback); #endif +#ifdef FOOBAR2000_MOBILE + static void g_show_config_popup( fb2k::dspConfigContext_t parent, dsp_preset_edit_callback_v2::ptr callback); +#endif + bool get_display_name_supported(); void get_display_name_(const dsp_preset& arg, pfc::string_base& out); + bool enumerate_default_presets_(dsp_chain_config& ret); + bool match_preset_subclass_(dsp_preset const& x, dsp_preset const& y); FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(dsp_entry); }; @@ -382,9 +415,6 @@ class NOVTABLE dsp_entry_v2 : public dsp_entry { #ifdef _WIN32 //! Shows configuration popup. Main thread only! virtual void show_config_popup_v2(const dsp_preset & p_data,fb2k::hwnd_t p_parent,dsp_preset_edit_callback & p_callback) = 0; -#endif - -#ifdef _WIN32 // Obsolete method, redirected to show_config_popup_v2() by default, no need to implement. bool show_config_popup(dsp_preset& p_data, fb2k::hwnd_t p_parent) override; #endif @@ -417,6 +447,19 @@ class NOVTABLE dsp_entry_v4 : public dsp_entry_v3 { virtual dsp::ptr instantiate_v4( const dsp_preset & arg, unsigned flags ) = 0; }; +//! \since 2.2 +class NOVTABLE dsp_entry_v5 : public dsp_entry_v4 { + FB2K_MAKE_SERVICE_INTERFACE(dsp_entry_v5, dsp_entry_v4); +public: + //! If your DSP implementation is meant to preset as multiple item in available DSP list, implement this method. \n + //! @returns True if preset list has been returned (your DSP will be hidden if blank), false if your DSP is meant to be shown as just one item. + virtual bool enumerate_default_presets(dsp_chain_config& ret) { return false; } + //! Can possibly reach state Y by editing state X, and vice versa? \n + //! If this DSP has no configuration UI, this should just test if the presets are identical. + //! Frontend will use this to pin running presets to one of available DSP list items. + virtual bool match_preset_subclass(dsp_preset const& x, dsp_preset const& y) { return true; } +}; + class NOVTABLE dsp_entry_hidden : public service_base { FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(dsp_entry_hidden); public: @@ -434,14 +477,14 @@ class NOVTABLE dsp_entry_hidden : public service_base { template class dsp_entry_impl_nopreset_t : public t_entry { public: - void get_name(pfc::string_base & p_out) {T::g_get_name(p_out);} - bool get_default_preset(dsp_preset & p_out) + void get_name(pfc::string_base & p_out) override {T::g_get_name(p_out);} + bool get_default_preset(dsp_preset & p_out) override { p_out.set_owner(T::g_get_guid()); p_out.set_data(0,0); return true; } - bool instantiate(service_ptr_t & p_out,const dsp_preset & p_preset) + bool instantiate(service_ptr_t & p_out,const dsp_preset & p_preset) override { if (p_preset.get_owner() == T::g_get_guid() && p_preset.get_data_size() == 0) { @@ -450,10 +493,9 @@ class dsp_entry_impl_nopreset_t : public t_entry { } else return false; } - GUID get_guid() {return T::g_get_guid();} + GUID get_guid() override {return T::g_get_guid();} - bool have_config_popup() {return false;} - bool show_config_popup(dsp_preset & p_data,fb2k::hwnd_t p_parent) {return false;} + bool have_config_popup() override {return false;} }; template @@ -470,18 +512,21 @@ class dsp_entry_common_t : public interface_t { GUID get_guid() override { return T::g_get_guid(); } bool have_config_popup() override { return T::g_have_config_popup(); } +#ifdef FOOBAR2000_MOBILE + void show_config_popup( fb2k::dspConfigContext_t parent, dsp_preset_edit_callback_v2::ptr callback ) override { T::g_show_config_popup(parent, callback); } +#endif +#if defined(FOOBAR2000_DESKTOP) && !defined(_WIN32) + service_ptr show_config_popup( fb2k::hwnd_t parent, dsp_preset_edit_callback_v2::ptr callback ) override { + return T::g_show_config_popup(parent, callback); + } +#endif }; template class dsp_entry_impl_t : public dsp_entry_common_t { public: - #ifdef _WIN32 - bool show_config_popup(dsp_preset & p_data,fb2k::hwnd_t p_parent) override {return T::g_show_config_popup(p_data,p_parent);} -#else - service_ptr show_config_popup( fb2k::hwnd_t parent, dsp_preset_edit_callback_v2::ptr callback ) override { - return T::g_show_config_popup(parent, callback); - } + bool show_config_popup(dsp_preset & p_data,fb2k::hwnd_t p_parent) override {return T::g_show_config_popup(p_data,p_parent);} #endif }; @@ -490,10 +535,6 @@ class dsp_entry_v2_impl_t : public dsp_entry_common_t { public: #ifdef _WIN32 void show_config_popup_v2(const dsp_preset & p_data,fb2k::hwnd_t p_parent,dsp_preset_edit_callback & p_callback) override {T::g_show_config_popup(p_data,p_parent,p_callback);} -#else - service_ptr show_config_popup( fb2k::hwnd_t parent, dsp_preset_edit_callback_v2::ptr callback ) override { - return T::g_show_config_popup(parent, callback); - } #endif }; @@ -520,32 +561,44 @@ class dsp_entry_v4_impl_t : public dsp_entry_v3_impl_t< dsp_t, entry_t > { } }; -template +template +class dsp_entry_v5_impl_t : public dsp_entry_v4_impl_t< dsp_t, entry_t > { +public: + bool enumerate_default_presets(dsp_chain_config& ret) { + return dsp_t::g_enumerate_default_presets(ret); + } + bool match_preset_subclass(dsp_preset const& x, dsp_preset const& y) { + return dsp_t::g_match_preset_subclass(x, y); + } +}; + +template class dsp_entry_hidden_t : public dsp_entry_hidden { public: - bool instantiate(service_ptr_t & p_out,const dsp_preset & p_preset) { - if (p_preset.get_owner() == T::g_get_guid()) { - p_out = new service_impl_t(p_preset); + bool instantiate(service_ptr_t & p_out,const dsp_preset & p_preset) override { + if (p_preset.get_owner() == dsp_t::g_get_guid()) { + p_out = new service_impl_t(p_preset); return true; } else return false; } - GUID get_guid() {return T::g_get_guid();} -#if 0 - void get_name( pfc::string_base& out ) {out = ""; } - bool get_default_preset(dsp_preset & p_out) { return false; } - bool have_config_popup() { return false; } - bool show_config_popup(dsp_preset & p_data,HWND p_parent) { uBugCheck(); } - void show_config_popup_v2(const dsp_preset & p_data,HWND p_parent,dsp_preset_edit_callback & p_callback) { uBugCheck(); } - - bool is_user_accessible() { return false; } -#endif + GUID get_guid() override {return dsp_t::g_get_guid();} }; +template +class implement_dsp_entry; + +template class implement_dsp_entry : public dsp_entry_impl_t {}; +template class implement_dsp_entry : public dsp_entry_v2_impl_t {}; +template class implement_dsp_entry : public dsp_entry_v3_impl_t {}; +template class implement_dsp_entry : public dsp_entry_v4_impl_t {}; +template class implement_dsp_entry : public dsp_entry_v5_impl_t {}; +template class implement_dsp_entry : public dsp_entry_hidden_t {}; + template class dsp_factory_nopreset_t : public service_factory_single_t > {}; -template -class dsp_factory_t : public service_factory_single_t > {}; +template +class dsp_factory_t : public service_factory_single_t > {}; template class dsp_factory_hidden_t : public service_factory_single_t< dsp_entry_hidden_t > {}; @@ -571,15 +624,23 @@ class NOVTABLE dsp_chain_config fb2k::memBlock::ptr to_blob() const; void from_blob(const void* p, size_t size); void from_blob(fb2k::memBlock::ptr); - - void instantiate(service_list_t & p_out); - + pfc::string8 get_name_list() const; 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); + //! Helpers to enable/disable specific DSP in this chain. Return true if the chain has been altered, false otherwise. + bool enable_dsp( const GUID & dspID ); + //! Helpers to enable/disable specific DSP in this chain. Return true if the chain has been altered, false otherwise. + bool disable_dsp( const GUID & dspID ); + //! Helpers to enable/disable specific DSP in this chain. Return true if the chain has been altered, false otherwise. + bool enable_dsp( const dsp_preset & preset ); + + size_t find_first_of_type( const GUID & dspID ) const; + bool contains_dsp( const GUID & dspID ) const; + pfc::string8 debug() const; bool operator==(const dsp_chain_config & other) const {return equals(*this, other);} diff --git a/sdk/foobar2000/SDK/dsp_manager.cpp b/sdk/foobar2000/SDK/dsp_manager.cpp index 3567bcc..f4a8687 100644 --- a/sdk/foobar2000/SDK/dsp_manager.cpp +++ b/sdk/foobar2000/SDK/dsp_manager.cpp @@ -22,7 +22,7 @@ bool dsp_manager::need_track_change_mark() const { return false; } -void dsp_manager::dsp_run(t_dsp_chain::const_iterator p_iter,dsp_chunk_list * p_list,const metadb_handle_ptr & cur_file,unsigned flags,double & latency,abort_callback & p_abort) +void dsp_manager::dsp_run(t_dsp_chain::const_iterator p_iter,dsp_chunk_list * p_list,const dsp_track_t & cur_file,unsigned flags,double & latency,abort_callback & p_abort) { p_list->remove_bad_chunks(); @@ -30,7 +30,7 @@ void dsp_manager::dsp_run(t_dsp_chain::const_iterator p_iter,dsp_chunk_list * p_ TRACK_CODE("dsp::get_latency",latency += p_iter->m_dsp->get_latency()); } -double dsp_manager::run(dsp_chunk_list * p_list,const metadb_handle_ptr & p_cur_file,unsigned p_flags,abort_callback & p_abort) { +double dsp_manager::run(dsp_chunk_list * p_list,const dsp_track_t & p_cur_file,unsigned p_flags,abort_callback & p_abort) { TRACK_CALL_TEXT("dsp_manager::run"); try { diff --git a/sdk/foobar2000/SDK/dsp_manager.h b/sdk/foobar2000/SDK/dsp_manager.h index e1976d6..80cacb6 100644 --- a/sdk/foobar2000/SDK/dsp_manager.h +++ b/sdk/foobar2000/SDK/dsp_manager.h @@ -13,7 +13,7 @@ class dsp_manager { void set_config( const dsp_chain_config & p_data ); //! Runs DSP on the specified chunk list. //! @returns Current DSP latency in seconds. - double run(dsp_chunk_list * p_list,const metadb_handle_ptr & p_cur_file,unsigned p_flags,abort_callback & p_abort); + double run(dsp_chunk_list * p_list,dsp_track_t const & p_cur_file,unsigned p_flags,abort_callback & p_abort); //! Flushes the DSP (e.g. when seeking). void flush(); @@ -37,7 +37,7 @@ class dsp_manager { dsp_chain_config_impl m_config; bool m_config_changed = false; - 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&); + void dsp_run(t_dsp_chain::const_iterator p_iter,dsp_chunk_list * list,const dsp_track_t & cur_file,unsigned flags,double & latency,abort_callback&); dsp_manager(const dsp_manager &) = delete; const dsp_manager & operator=(const dsp_manager&) = delete; diff --git a/sdk/foobar2000/SDK/file.h b/sdk/foobar2000/SDK/file.h index f889b73..e99ff80 100644 --- a/sdk/foobar2000/SDK/file.h +++ b/sdk/foobar2000/SDK/file.h @@ -505,5 +505,7 @@ namespace foobar2000_io //! Alternate version of read() intended for network resources.\n //! Returns as soon as any data is available (usually less than requested), or EOF has been reached (0 returned). virtual size_t receive(void*, size_t, abort_callback&) = 0; + + size_t read_using_receive(void*, size_t, abort_callback&); }; } diff --git a/sdk/foobar2000/SDK/file_cached_impl.cpp b/sdk/foobar2000/SDK/file_cached_impl.cpp index 276df20..0ef0107 100644 --- a/sdk/foobar2000/SDK/file_cached_impl.cpp +++ b/sdk/foobar2000/SDK/file_cached_impl.cpp @@ -143,6 +143,7 @@ class file_cached_impl_v2 : public service_multi_inherit< file_v2, service_multi } t_filesize get_position(abort_callback & p_abort) override { p_abort.check(); + PFC_ASSERT( m_position <= m_size ); return m_position; } void set_eof(abort_callback & p_abort) { diff --git a/sdk/foobar2000/SDK/file_info.cpp b/sdk/foobar2000/SDK/file_info.cpp index d5c721d..d190e53 100644 --- a/sdk/foobar2000/SDK/file_info.cpp +++ b/sdk/foobar2000/SDK/file_info.cpp @@ -412,6 +412,14 @@ bool replaygain_info::g_equal(const replaygain_info & item1,const replaygain_inf item1.m_track_peak == item2.m_track_peak; } +void replaygain_info::adjust(double deltaDB) { + if (this->is_album_gain_present()) this->m_album_gain -= (float)deltaDB; + if (this->is_track_gain_present()) this->m_track_gain -= (float)deltaDB; + const auto scale = audio_math::gain_to_scale(deltaDB); + if (this->is_album_peak_present()) this->m_album_peak *= (float)scale; + if (this->is_track_peak_present()) this->m_track_peak *= (float)scale; +} + bool file_info::are_meta_fields_identical(t_size p_index1,t_size p_index2) const { const t_size count = meta_enum_value_count(p_index1); @@ -499,6 +507,11 @@ bool file_info::is_encoding_lossy() const { return false; } +bool file_info::is_encoding_lossless() const { + const char* encoding = info_get("encoding"); + return encoding != nullptr && pfc::stringEqualsI_ascii(encoding, "lossless"); +} + bool file_info::g_is_meta_equal(const file_info & p_item1,const file_info & p_item2) { const t_size count = p_item1.meta_get_count(); if (count != p_item2.meta_get_count()) { @@ -932,6 +945,22 @@ void file_info::meta_enumerate(meta_enumerate_t cb) const { } } +bool file_info::meta_value_exists( const char * name, const char * findValue, bool insensitive ) const { + const auto idx = this->meta_find(name); + if ( idx != SIZE_MAX ) { + const auto count = this->meta_enum_value_count(idx); + for( size_t walk = 0; walk < count; ++ walk) { + auto value = this->meta_enum_value(idx, walk); + if ( insensitive ) { + if (pfc::stringEqualsI_utf8(value, findValue)) return true; + } else { + if ( strcmp(value, findValue) == 0 ) return true; + } + } + } + return false; +} + #ifdef FOOBAR2000_MOBILE #include "album_art.h" #include "hasher_md5.h" @@ -944,6 +973,13 @@ pfc::array_t file_info::info_get_pictures( ) const { return album_art_ids::string_to_ids( this->info_get( "pictures" ) ); } +bool file_info::info_have_picture( const GUID & arg ) const { + for( auto & walk : info_get_pictures() ) { + if ( walk == arg ) return true; + } + return false; +} + uint64_t file_info::makeMetaHash() const { pfc::string_formatter temp; diff --git a/sdk/foobar2000/SDK/file_info.h b/sdk/foobar2000/SDK/file_info.h index d09f22d..78ac1ba 100644 --- a/sdk/foobar2000/SDK/file_info.h +++ b/sdk/foobar2000/SDK/file_info.h @@ -57,6 +57,12 @@ struct replaygain_info static bool g_equal(const replaygain_info & item1,const replaygain_info & item2); void reset(); + void clear() { reset(); } + void clear_gain() { m_album_gain = m_track_gain = gain_invalid; } + void clear_peak() { m_album_peak = m_track_peak = peak_invalid; } + + // Alter gain/peak info, if available, by dB - after file gain has been altered by other means + void adjust(double deltaDB); }; class format_rg_gain { @@ -173,6 +179,7 @@ class NOVTABLE file_info { inline t_size meta_find(const char* p_name) const { PFC_ASSERT(p_name != nullptr); return meta_find_ex(p_name, SIZE_MAX); } inline bool meta_exists(const char* p_name) const { PFC_ASSERT(p_name != nullptr); return meta_exists_ex(p_name, SIZE_MAX); } + bool meta_value_exists( const char * name, const char * value, bool insensitive = false ) const; inline void meta_remove_field(const char* p_name) { PFC_ASSERT(p_name != nullptr); meta_remove_field_ex(p_name, SIZE_MAX); } inline t_size meta_set(const char* p_name, const char* p_value) { PFC_ASSERT(p_name != nullptr && p_value != nullptr); 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);} @@ -242,6 +249,8 @@ class NOVTABLE file_info { //! Is a lossy codec? bool is_encoding_lossy() const; + //! Is explicitly reported as lossless codec? + bool is_encoding_lossless() const; //! Is lossless/PCM that can't be sanely represented in this fb2k build due to audio_sample limitations? \n //! Always returns false in 64-bit fb2k. bool is_encoding_overkill() const; @@ -319,6 +328,7 @@ class NOVTABLE file_info { #ifdef FOOBAR2000_MOBILE void info_set_pictures( const GUID * guids, size_t size ); pfc::array_t info_get_pictures( ) const; + bool info_have_picture(const GUID&) const; uint64_t makeMetaHash() const; #endif protected: diff --git a/sdk/foobar2000/SDK/filesystem.cpp b/sdk/foobar2000/SDK/filesystem.cpp index d2f3721..a73f540 100644 --- a/sdk/foobar2000/SDK/filesystem.cpp +++ b/sdk/foobar2000/SDK/filesystem.cpp @@ -29,7 +29,7 @@ void unpacker::g_open(service_ptr_t & p_out,const service_ptr_t & p, } void file::seek_probe(t_filesize p_position, abort_callback & p_abort) { - try { seek(p_position, p_abort); } catch(exception_io_seek_out_of_range) {throw exception_io_data();} + try { seek(p_position, p_abort); } catch(exception_io_seek_out_of_range const &) {throw exception_io_data();} } void file::seek_ex(t_sfilesize p_position, file::t_seek_mode p_mode, abort_callback &p_abort) { @@ -53,7 +53,7 @@ static void makeBuffer(pfc::array_t & buffer, size_t size) { try { buffer.set_size_discard( size ); return; - } catch(std::bad_alloc) { + } catch(std::bad_alloc const &) { if (size < 256) throw; size >>= 1; } @@ -127,9 +127,9 @@ void filesystem::g_get_display_path(const char * path,pfc::string_base & out) } } -pfc::string8 filesystem::g_get_native_path( const char * path ) { +pfc::string8 filesystem::g_get_native_path( const char * path, abort_callback & a ) { pfc::string8 ret; - g_get_native_path( path, ret ); + g_get_native_path( path, ret, a); return ret; } @@ -155,6 +155,10 @@ bool filesystem::g_get_native_path( const char * path, pfc::string_base & out, a return strstr( path, "://" ) == NULL; } +filesystem::ptr filesystem::getLocalFS() { + return get("file://dummy"); +} + filesystem::ptr filesystem::tryGet(const char* path) { filesystem::ptr rv; g_get_interface(rv, path); @@ -167,11 +171,81 @@ filesystem::ptr filesystem::g_get_interface(const char * path) { return rv; } + +#define USE_FSCACHE 1 +#if USE_FSCACHE +#include + +static pfc::readWriteLock fsCacheGuard; + +typedef size_t protoHash_t; +static protoHash_t protoHash(const char * URL) { + const char* delim = strstr(URL, "://"); + if (delim == nullptr) return 0; + + union { + protoHash_t hash; + char chars[sizeof(protoHash_t)]; + } u; + u.hash = 0; + unsigned i = 0; + for (const char* walk = URL; walk != delim; ++walk) { + u.chars[i] ^= pfc::ascii_tolower_lookup(*walk); + i = (i + 1) % std::size(u.chars); + } + return u.hash; +} + +// Do not use service_ptr in static objects, do not try to release them in static object destructor +static std::unordered_multimap< protoHash_t, filesystem* > fsCache; + +static bool read_fs_cache(protoHash_t key, const char * path, filesystem::ptr& ret) { + auto range = fsCache.equal_range(key); + for (auto walk = range.first; walk != range.second; ++walk) { + if (walk->second->is_our_path(path)) { + ret = walk->second; + return true; + } + } + return false; +} + bool filesystem::g_get_interface(service_ptr_t & p_out,const char * path) { PFC_ASSERT( path != nullptr ); PFC_ASSERT( path[0] != 0 ); + const auto key = protoHash(path); + + { + PFC_INSYNC_READ(fsCacheGuard); + if (read_fs_cache(key, path, p_out)) return true; + } + + for (auto ptr : enumerate()) { + if (ptr->is_our_path(path)) { + { + PFC_INSYNC_WRITE(fsCacheGuard); + filesystem::ptr dummy; // make sure it didn't just get added + if (!read_fs_cache(key, path, dummy)) { + auto addref = ptr; + fsCache.insert({ key, addref.detach()}); + } + } + p_out = std::move(ptr); + return true; + } + } + return false; +} + + +#else +bool filesystem::g_get_interface(service_ptr_t& p_out, const char* path) +{ + PFC_ASSERT(path != nullptr); + PFC_ASSERT(path[0] != 0); + for (auto ptr : enumerate()) { if (ptr->is_our_path(path)) { p_out = std::move(ptr); @@ -181,6 +255,7 @@ bool filesystem::g_get_interface(service_ptr_t & p_out,const char * return false; } +#endif void filesystem::g_open(service_ptr_t & p_out,const char * path,t_open_mode mode,abort_callback & p_abort) { @@ -199,7 +274,7 @@ bool filesystem::g_exists(const char * p_path,abort_callback & p_abort) bool dummy; try { g_get_stats(p_path,stats,dummy,p_abort); - } catch(exception_io_not_found) {return false;} + } catch(exception_io_not_found const &) {return false;} return true; } @@ -209,7 +284,7 @@ bool filesystem::g_exists_writeable(const char * p_path,abort_callback & p_abort bool writeable; try { g_get_stats(p_path,stats,writeable,p_abort); - } catch(exception_io_not_found) {return false;} + } catch(exception_io_not_found const &) {return false;} return writeable; } @@ -439,15 +514,15 @@ void archive_impl::open(service_ptr_t & p_out,const char * path,t_open_mod void archive_impl::remove(const char * path,abort_callback & p_abort) { - throw exception_io_denied(); + pfc::throw_exception_with_message< exception_io_denied> ("Cannot delete files within archives"); } void archive_impl::move(const char * src,const char * dst,abort_callback & p_abort) { - throw exception_io_denied(); + pfc::throw_exception_with_message< exception_io_denied> ("Cannot move files within archives"); } void archive_impl::move_overwrite(const char* src, const char* dst, abort_callback& abort) { - throw exception_io_denied(); + pfc::throw_exception_with_message< exception_io_denied> ("Cannot move files within archives"); } bool archive_impl::is_remote(const char * src) { @@ -543,7 +618,7 @@ fb2k::arrayRef archive_impl::archive_list_v4( fsItemFilePtr item, file::ptr read archive * blah = this; // multi inheritance fix, more than one path to filesystem which has makeItemFileStd() ret->add(blah->makeItemFileStd(URL, stats2)); }, false, a); - } catch( exception_io_data ) { + } catch( exception_io_data const & ) { if ( ret->count() == 0 ) throw; } return ret->makeConst(); @@ -619,7 +694,7 @@ namespace { if (is_subdirectory) { try { m_fs->create_directory(m_target,p_abort); - } catch(exception_io_already_exists) {} + } catch(exception_io_already_exists const &) {} m_target.end_with_slash(); owner->list_directory(url,*this,p_abort); } else { @@ -687,7 +762,7 @@ void filesystem::copy_directory_contents(const char* p_src, const char* p_dst, a void filesystem::copy_directory(const char * src, const char * dst, abort_callback & p_abort) { try { this->create_directory( dst, p_abort ); - } catch(exception_io_already_exists) {} + } catch(exception_io_already_exists const &) {} this->copy_directory_contents(src, dst, p_abort); } @@ -695,7 +770,7 @@ void filesystem::g_copy_directory(const char * src,const char * dst,abort_callba filesystem::ptr dstFS = filesystem::g_get_interface(dst); try { dstFS->create_directory( dst, p_abort ); - } catch(exception_io_already_exists) {} + } catch(exception_io_already_exists const &) {} directory_callback_impl_copy cb(dst, dstFS); g_list_directory(src,cb,p_abort); } @@ -720,7 +795,7 @@ void filesystem::g_copy(const char * src,const char * dst,abort_callback & p_abo try { file::g_copy_timestamps(r_src, r_dst, p_abort); - } catch (exception_io) {} + } catch (exception_io const &) {} } void stream_reader::read_object(void * p_buffer,t_size p_bytes,abort_callback & p_abort) { @@ -1058,7 +1133,8 @@ PFC_NORETURN void foobar2000_io::exception_io_from_nix(int code) { throw exception_io_object_not_seekable(); case ENOTDIR: throw exception_io_not_directory(); - + case ENAMETOOLONG: + pfc::throw_exception_with_message("Name too long"); default: pfc::throw_exception_with_message< exception_io>( PFC_string_formatter() << "Unknown I/O error (#" << code << ")"); } @@ -1267,7 +1343,7 @@ void filesystem::remove_directory_content(const char * path, abort_callback & ab if (p_is_subdirectory) p_owner->list_directory(p_url, *this, p_abort); try { p_owner->remove(p_url, p_abort); - } catch(exception_io_not_found) {} + } catch(exception_io_not_found const &) {} return true; } }; @@ -1289,7 +1365,7 @@ void filesystem::remove_object_recur(const char * path, abort_callback & abort) // the classic way try { remove_directory_content(path, abort); - } catch(exception_io_not_found) {} + } catch(exception_io_not_found const &) {} remove(path, abort); } @@ -1311,7 +1387,7 @@ void foobar2000_io::purgeOldFiles(const char * directory, t_filetimestamp period if (!p_is_subdirectory && p_stats.m_timestamp < m_base) { try { filesystem::g_remove_timeout(p_url, 1, p_abort); - } catch(exception_io_not_found) {} + } catch(exception_io_not_found const &) {} } return true; } @@ -1478,7 +1554,7 @@ void filesystem::move_overwrite(const char * src, const char * dst, abort_callba } try { this->remove(dst, abort); - } catch (exception_io_not_found) {} + } catch (exception_io_not_found const &) {} this->move(src, dst, abort); } @@ -1500,7 +1576,7 @@ void filesystem::make_directory(const char * path, abort_callback & abort, bool try { create_directory( path, abort ); rv = true; - } catch(exception_io_already_exists) { + } catch(exception_io_already_exists const &) { } if (didCreate != nullptr) * didCreate = rv; } @@ -1520,7 +1596,7 @@ bool filesystem::directory_exists(const char * path, abort_callback & abort) { directory_callback_dummy cb; list_directory(path, cb, abort); return true; - } catch (exception_io) { return false; } + } catch (exception_io const &) { return false; } } bool filesystem::exists(const char* path, abort_callback& a) { @@ -1530,7 +1606,7 @@ bool filesystem::exists(const char* path, abort_callback& a) { try { v3->get_stats2(path, stats2_fileOrFolder, a); return true; - } catch (exception_io_not_found) { return false; } + } catch (exception_io_not_found const &) { return false; } } filesystem_v2::ptr v2; if (v2 &= this) { @@ -1541,12 +1617,12 @@ bool filesystem::exists(const char* path, abort_callback& a) { t_filestats stats; bool writable; get_stats(path, stats, writable, a); return true; - } catch (exception_io) { } + } catch (exception_io const &) { } try { directory_callback_dummy cb; list_directory(path, cb, a); return true; - } catch (exception_io) { } + } catch (exception_io const &) { } return false; } @@ -1559,7 +1635,7 @@ bool filesystem::file_exists(const char * path, abort_callback & abort) { t_filestats stats; bool writable; get_stats(path, stats, writable, abort ); return true; - } catch(exception_io) { return false; } + } catch(exception_io const &) { return false; } } char filesystem::pathSeparator() { @@ -1720,7 +1796,7 @@ void filesystem::rewrite_directory(const char * path, abort_callback & abort, do // folder.new folder already existed? clear contents try { retryFileDelete(opTimeout, abort, [&] { this->remove_directory_content(fnNew, abort); }); - } catch(exception_io_not_found) {} + } catch(exception_io_not_found const &) {} } // write to folder.new @@ -1732,12 +1808,12 @@ void filesystem::rewrite_directory(const char * path, abort_callback & abort, do if (this->directory_exists(fnOld, abort)) { try { retryFileDelete(opTimeout, abort, [&] { this->remove_object_recur(fnOld, abort); }); - } catch (exception_io_not_found) {} + } catch(exception_io_not_found const &) {} } try { retryFileMove(opTimeout, abort, [&] { this->move( path, fnOld, abort ); } ) ; haveOld = true; - } catch(exception_io_not_found) {} + } catch(exception_io_not_found const &) {} } // move folder.new to folder @@ -1749,7 +1825,7 @@ void filesystem::rewrite_directory(const char * path, abort_callback & abort, do // delete folder.old if we made one try { retryFileDelete( opTimeout, abort, [&] { this->remove_object_recur( fnOld, abort); } ); - } catch (exception_io_not_found) {} + } catch (exception_io_not_found const &) {} } } } @@ -2037,13 +2113,13 @@ void filesystem_v3::list_directory_ex(const char* p_path, directory_callback& p_ bool filesystem_v3::directory_exists(const char* path, abort_callback& abort) { try { return get_stats2(path, stats2_fileOrFolder, abort).is_folder(); - } catch (exception_io_not_found) { return false; } + } catch (exception_io_not_found const &) { return false; } } bool filesystem_v3::file_exists(const char* path, abort_callback& abort) { try { return get_stats2(path, stats2_fileOrFolder, abort).is_file(); - } catch (exception_io_not_found) { return false; } + } catch (exception_io_not_found const &) { return false; } } @@ -2208,9 +2284,9 @@ static void readStatsMultiStd(fb2k::arrayRef items, uint32_t s2flags, t_filestat try { fsItemPtr f; f ^= items->itemAt(w); out = f->getStats2(s2flags, abort); - } catch (exception_aborted) { + } catch (exception_aborted const &) { throw; - } catch (exception_io) { + } catch (exception_io const &) { out = filestats2_invalid; } } @@ -2420,3 +2496,16 @@ drivespace_t filesystem::getDriveSpace_(const char* pathAt, abort_callback& abor if (v3 &= this) return v3->getDriveSpace(pathAt, abort); throw pfc::exception_not_implemented(); } + +size_t stream_receive::read_using_receive(void* ptr_, size_t bytes, abort_callback& a) { + size_t walk = 0; + auto ptr = reinterpret_cast(ptr_); + while(walk < bytes) { + size_t want = bytes-walk; + size_t delta = this->receive(ptr+walk, want, a); + PFC_ASSERT( delta <= want ); + if ( delta == 0 ) break; + walk += delta; + } + return walk; +} \ No newline at end of file diff --git a/sdk/foobar2000/SDK/filesystem.h b/sdk/foobar2000/SDK/filesystem.h index 3e0c809..7a94fa0 100644 --- a/sdk/foobar2000/SDK/filesystem.h +++ b/sdk/foobar2000/SDK/filesystem.h @@ -95,12 +95,13 @@ namespace foobar2000_io //! Extracts the native filesystem path, sets out to the input path if native path cannot be extracted so the output is always set. //! @returns True if native path was extracted successfully, false otherwise (but output is set anyway). static bool g_get_native_path( const char * path, pfc::string_base & out, abort_callback & a = fb2k::noAbort); - static pfc::string8 g_get_native_path( const char * path ); + static pfc::string8 g_get_native_path( const char * path, abort_callback & a = fb2k::noAbort ); static bool g_get_interface(service_ptr_t & p_out,const char * path);//path is AFTER get_canonical_path static filesystem::ptr g_get_interface(const char * path);// throws exception_io_no_handler_for_path on failure - static filesystem::ptr get( const char * path ) { return g_get_interface(path); } // shortened - static filesystem::ptr tryGet(const char* path); + static filesystem::ptr get( const char * path ) { return g_get_interface(path); } // shortened; never returns null, throws on failure + static filesystem::ptr getLocalFS(); // returns local filesystem object + static filesystem::ptr tryGet(const char* path); // returns null if not found instead of throwing static bool g_is_remote(const char * p_path);//path is AFTER get_canonical_path static bool g_is_recognized_and_remote(const char * p_path);//path is AFTER get_canonical_path static bool g_is_remote_safe(const char * p_path) {return g_is_recognized_and_remote(p_path);} @@ -404,7 +405,7 @@ namespace foobar2000_io directory_callback_retrieveListRecur(t_list & p_list) : m_list(p_list) {} bool on_entry(filesystem * owner,abort_callback & p_abort,const char * path, bool isSubdir, const t_filestats&) { if (isSubdir) { - try { owner->list_directory(path,*this,p_abort); } catch(exception_io) {} + try { owner->list_directory(path,*this,p_abort); } catch(exception_io const &) {} } else { m_list.add_item(path); } diff --git a/sdk/foobar2000/SDK/filesystem_helper.cpp b/sdk/foobar2000/SDK/filesystem_helper.cpp index 2011574..7ae5b0f 100644 --- a/sdk/foobar2000/SDK/filesystem_helper.cpp +++ b/sdk/foobar2000/SDK/filesystem_helper.cpp @@ -278,3 +278,21 @@ pfc::string8 file_path_display(const char* src) { filesystem::g_get_display_path(src, ret); return ret; } + +pfc::string8 fb2k::filename_ext( const char * path, filesystem::ptr & fs) { + if ( fs.is_empty() || ! fs->is_our_path( path ) ) { + fs = filesystem::tryGet( path ); + } + if ( fs.is_valid() ) return fs->extract_filename_ext( path ); + // UGLY FALLBACK + return pfc::string_filename_ext( path ); + +} +pfc::string8 fb2k::filename_ext( const char * path ) { + filesystem::ptr no_reuse; + return filename_ext( path, no_reuse ); +} + +pfc::string8 fb2k::filename( const char * path ) { + return pfc::remove_ext_v2( filename_ext( path ) ); +} diff --git a/sdk/foobar2000/SDK/filesystem_helper.h b/sdk/foobar2000/SDK/filesystem_helper.h index 79ff32a..ab308ee 100644 --- a/sdk/foobar2000/SDK/filesystem_helper.h +++ b/sdk/foobar2000/SDK/filesystem_helper.h @@ -43,6 +43,15 @@ namespace foobar2000_io { pfc::string8 file_path_canonical(const char* src); pfc::string8 file_path_display(const char* src); +namespace fb2k { + //! Sane replacement for pfc::string_filename_ext(), which isn't safe to use in cross-platform code. + //! @returns Filename with extension extracted from path. + pfc::string8 filename_ext( const char * path ); + pfc::string8 filename_ext( const char * path, filesystem::ptr & fs_reuse); + //! Sane replacement for pfc::string_filename(), which isn't safe to use in cross-platform code + //! @returns Filename without extension extracted from path. + pfc::string8 filename( const char * path ); +} class stream_reader_memblock_ref : public stream_reader { @@ -549,7 +558,7 @@ template class _stream_writer_formatter_translator { pfc::lores_timer timer; timer.start(); \ for(;;) { \ try { {OP;} break; } \ - catch(EXCEPTION) { if (timer.query() > TIMEOUT) throw;} \ + catch(const EXCEPTION &) { if (timer.query() > TIMEOUT) throw;} \ ABORT.sleep(0.05); \ } \ } @@ -559,8 +568,8 @@ template class _stream_writer_formatter_translator { pfc::lores_timer timer; timer.start(); \ for(;;) { \ try { {OP;} break; } \ - catch(EXCEPTION1) { if (timer.query() > TIMEOUT) throw;} \ - catch(EXCEPTION2) { if (timer.query() > TIMEOUT) throw;} \ + catch(const EXCEPTION1 &) { if (timer.query() > TIMEOUT) throw;} \ + catch(const EXCEPTION2 &) { if (timer.query() > TIMEOUT) throw;} \ ABORT.sleep(0.05); \ } \ } @@ -570,9 +579,9 @@ template class _stream_writer_formatter_translator { pfc::lores_timer timer; timer.start(); \ for(;;) { \ try { {OP;} break; } \ - catch(EXCEPTION1) { if (timer.query() > TIMEOUT) throw;} \ - catch(EXCEPTION2) { if (timer.query() > TIMEOUT) throw;} \ - catch(EXCEPTION3) { if (timer.query() > TIMEOUT) throw;} \ + catch(const EXCEPTION1 &) { if (timer.query() > TIMEOUT) throw;} \ + catch(const EXCEPTION2 &) { if (timer.query() > TIMEOUT) throw;} \ + catch(const EXCEPTION3 &) { if (timer.query() > TIMEOUT) throw;} \ ABORT.sleep(0.05); \ } \ } diff --git a/sdk/foobar2000/SDK/foobar2000-versions.h b/sdk/foobar2000/SDK/foobar2000-versions.h index 5f7c3c2..6353053 100644 --- a/sdk/foobar2000/SDK/foobar2000-versions.h +++ b/sdk/foobar2000/SDK/foobar2000-versions.h @@ -30,7 +30,7 @@ // Use this to determine what foobar2000 SDK version is in use, undefined for releases older than 2018 -#define FOOBAR2000_SDK_VERSION 20230923 +#define FOOBAR2000_SDK_VERSION 20240807 // cfg_var downgrade support, experimental, intended for specific components only. // Allows new style configStore data to be imported back to old foobar2000 friendly cfg_vars. diff --git a/sdk/foobar2000/SDK/foobar2000-winver.h b/sdk/foobar2000/SDK/foobar2000-winver.h index 7aab1d8..9376f22 100644 --- a/sdk/foobar2000/SDK/foobar2000-winver.h +++ b/sdk/foobar2000/SDK/foobar2000-winver.h @@ -23,6 +23,7 @@ #ifdef __APPLE__ #define FOOBAR2000_SUPPORT_DLLS 1 +#define FOOBAR2000_MAC #endif #ifndef FOOBAR2000_SUPPORT_DLLS diff --git a/sdk/foobar2000/SDK/foobar2000_SDK.vcxproj b/sdk/foobar2000/SDK/foobar2000_SDK.vcxproj index fa8b8dc..56b3983 100644 --- a/sdk/foobar2000/SDK/foobar2000_SDK.vcxproj +++ b/sdk/foobar2000/SDK/foobar2000_SDK.vcxproj @@ -37,6 +37,7 @@ {E8091321-D79D-4575-86EF-064EA1A4A20D} foobar2000_SDK + 10.0 @@ -44,14 +45,14 @@ false Unicode true - v143 + v142 StaticLibrary false Unicode true - v143 + v142 StaticLibrary @@ -71,13 +72,13 @@ StaticLibrary false Unicode - v143 + v142 StaticLibrary false Unicode - v143 + v142 StaticLibrary @@ -466,6 +467,7 @@ + @@ -514,7 +516,6 @@ - diff --git a/sdk/foobar2000/SDK/foobar2000_SDK.vcxproj.filters b/sdk/foobar2000/SDK/foobar2000_SDK.vcxproj.filters index aa813f5..5d72358 100644 --- a/sdk/foobar2000/SDK/foobar2000_SDK.vcxproj.filters +++ b/sdk/foobar2000/SDK/foobar2000_SDK.vcxproj.filters @@ -407,6 +407,9 @@ Header Files + + Header Files + @@ -595,9 +598,6 @@ Source Files - - Source Files - Source Files diff --git a/sdk/foobar2000/SDK/foobar2000_SDK.xcodeproj/project.pbxproj b/sdk/foobar2000/SDK/foobar2000_SDK.xcodeproj/project.pbxproj index 63965b5..837e644 100644 --- a/sdk/foobar2000/SDK/foobar2000_SDK.xcodeproj/project.pbxproj +++ b/sdk/foobar2000/SDK/foobar2000_SDK.xcodeproj/project.pbxproj @@ -89,7 +89,6 @@ 0F75F4E32A6B1CA800A45078 /* track_property.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4172A6B1CA200A45078 /* track_property.h */; }; 0F75F4E42A6B1CA800A45078 /* cfg_var.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F4182A6B1CA200A45078 /* cfg_var.cpp */; }; 0F75F4E52A6B1CA800A45078 /* shortcut_actions.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F4192A6B1CA200A45078 /* shortcut_actions.h */; }; - 0F75F4E62A6B1CA800A45078 /* foosortstring.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F41A2A6B1CA200A45078 /* foosortstring.cpp */; }; 0F75F4E72A6B1CA800A45078 /* exceptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F41B2A6B1CA200A45078 /* exceptions.h */; }; 0F75F4E82A6B1CA800A45078 /* component_client.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F75F41C2A6B1CA200A45078 /* component_client.h */; }; 0F75F4E92A6B1CA800A45078 /* playable_location.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F75F41D2A6B1CA200A45078 /* playable_location.cpp */; }; @@ -297,7 +296,6 @@ 0F75F4172A6B1CA200A45078 /* track_property.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = track_property.h; sourceTree = ""; }; 0F75F4182A6B1CA200A45078 /* cfg_var.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cfg_var.cpp; sourceTree = ""; }; 0F75F4192A6B1CA200A45078 /* shortcut_actions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = shortcut_actions.h; sourceTree = ""; }; - 0F75F41A2A6B1CA200A45078 /* foosortstring.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = foosortstring.cpp; sourceTree = ""; }; 0F75F41B2A6B1CA200A45078 /* exceptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = exceptions.h; sourceTree = ""; }; 0F75F41C2A6B1CA200A45078 /* component_client.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = component_client.h; sourceTree = ""; }; 0F75F41D2A6B1CA200A45078 /* playable_location.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = playable_location.cpp; sourceTree = ""; }; @@ -560,7 +558,6 @@ 0F75F48E2A6B1CA700A45078 /* foobar2000.h */, 0F75F3C82A6B1CA000A45078 /* foosort.cpp */, 0F75F40B2A6B1CA200A45078 /* foosort.h */, - 0F75F41A2A6B1CA200A45078 /* foosortstring.cpp */, 0F75F4502A6B1CA400A45078 /* foosortstring.h */, 0F75F3EB2A6B1CA100A45078 /* forward_types.h */, 0F75F4532A6B1CA400A45078 /* fsItem.cpp */, @@ -941,7 +938,6 @@ 0F75F5502A6B1CA800A45078 /* hasher_md5.cpp in Sources */, 0F75F55C2A6B1CA800A45078 /* metadb_handle.cpp in Sources */, 0F75F5582A6B1CA800A45078 /* dsp_manager.cpp in Sources */, - 0F75F4E62A6B1CA800A45078 /* foosortstring.cpp in Sources */, 0F75F4C42A6B1CA800A45078 /* filesystem_helper.cpp in Sources */, 0F75F4F92A6B1CA800A45078 /* commandline.cpp in Sources */, 0F75F4972A6B1CA800A45078 /* titleformat.cpp in Sources */, @@ -1006,7 +1002,7 @@ ../.., ); IPHONEOS_DEPLOYMENT_TARGET = 12.1; - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 11.0; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; SKIP_INSTALL = YES; @@ -1064,7 +1060,7 @@ ../.., ); IPHONEOS_DEPLOYMENT_TARGET = 12.1; - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 11.0; SDKROOT = macosx; SKIP_INSTALL = YES; }; diff --git a/sdk/foobar2000/SDK/foosort.cpp b/sdk/foobar2000/SDK/foosort.cpp index 5436e5f..aa81f1b 100644 --- a/sdk/foobar2000/SDK/foosort.cpp +++ b/sdk/foobar2000/SDK/foosort.cpp @@ -128,7 +128,7 @@ namespace { newsort(base2, count2, con2); break; } - } catch (exception_aborted) {} + } catch (exception_aborted const &) {} }, 2); m_abort.check(); } else { diff --git a/sdk/foobar2000/SDK/foosortstring.cpp b/sdk/foobar2000/SDK/foosortstring.cpp deleted file mode 100644 index 50cdb22..0000000 --- a/sdk/foobar2000/SDK/foosortstring.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "foobar2000-sdk-pch.h" -#include "foosortstring.h" - -#ifdef _WIN32 -#include -#endif - -namespace fb2k { -#ifdef _WIN32 - sortString_t makeSortString(const char* in) { - wchar_t* out = new wchar_t[pfc::stringcvt::estimate_utf8_to_wide(in) + 1]; - out[0] = ' ';//StrCmpLogicalW bug workaround. - pfc::stringcvt::convert_utf8_to_wide_unchecked(out + 1, in); - return sortString_t(out); - } - int sortStringCompare(sortString_t const& s1, sortString_t const& s2) { - return StrCmpLogicalW(s1.get(), s2.get()); - } -#else - int sortStringCompare(const char* str1, const char* str2) { - return pfc::naturalSortCompare(str1, str2); - } -#endif -} \ No newline at end of file diff --git a/sdk/foobar2000/SDK/foosortstring.h b/sdk/foobar2000/SDK/foosortstring.h index 62da612..1216982 100644 --- a/sdk/foobar2000/SDK/foosortstring.h +++ b/sdk/foobar2000/SDK/foosortstring.h @@ -1,18 +1,12 @@ #pragma once +#include #ifdef _WIN32 #include // std::unique_ptr<> #endif namespace fb2k { -#ifdef _WIN32 - typedef std::unique_ptr sortString_t; - sortString_t makeSortString(const char* str); - int sortStringCompare(sortString_t const & s1, sortString_t const & s2); -#else - typedef pfc::string8 sortString_t; - inline sortString_t makeSortString(const char* str) { return str; } - inline sortString_t makeSortString(pfc::string8 && str) { return std::move(str); } - int sortStringCompare(const char* str1, const char* str2); -#endif -} \ No newline at end of file + using pfc::sortString_t; + using pfc::sortStringCompare; + using pfc::makeSortString; +} diff --git a/sdk/foobar2000/SDK/fsItem.cpp b/sdk/foobar2000/SDK/fsItem.cpp index 2161848..a644bef 100644 --- a/sdk/foobar2000/SDK/fsItem.cpp +++ b/sdk/foobar2000/SDK/fsItem.cpp @@ -72,9 +72,8 @@ fsItemPtr fsItemBase::copyTo(fsItemFolderPtr folder, const char* desiredName, un } fsItemPtr fsItemBase::copyTo(fsItemFolderPtr folder, unsigned createMode, abort_callback& aborter) { - auto temp = pfc::string_filename_ext(this->canonicalPath()->c_str()); - if (temp.length() == 0) throw pfc::exception_invalid_params(); - return this->copyTo(folder, temp.c_str(), createMode, aborter); + auto temp = this->nameWithExt(); + return this->copyTo(folder, temp->c_str(), createMode, aborter); } fsItemPtr fsItemBase::moveTo(fsItemFolderPtr folder, const char* desiredName, unsigned createMode, abort_callback& aborter) { @@ -106,11 +105,11 @@ fb2k::memBlockRef fsItemFile::readWhole(size_t sizeSanity, abort_callback& abort namespace { static void uniqueFn(pfc::string8& fn, unsigned add) { if (add > 0) { - auto fnOnly = pfc::string_filename(fn); - auto ext = pfc::string_extension(fn); - fn.reset(); - fn << fnOnly << " (" << add << ")"; - if (ext.length() > 0) fn << "." << ext.get_ptr(); + pfc::string8 fnOnly = pfc::remove_ext_v2(fn); + pfc::string8 ext = pfc::extract_ext_v2(fn); + fn = std::move(fnOnly); + fn << " (" << add << ")"; + if (ext.length() > 0) fn << "." << ext; } } @@ -166,7 +165,7 @@ namespace { try { if (createMode == createMode::allowExisting) m_fs->move_overwrite(m_path->c_str(), dst, aborter); else m_fs->move(m_path->c_str(), dst, aborter); - } catch (exception_io_already_exists) { + } catch (exception_io_already_exists const &) { bDidExist = true; } @@ -277,7 +276,7 @@ namespace { try { stats = m_fs->get_stats2_( sub->c_str(), stats2_all, aborter ); bDidExist = stats.is_file(); - } catch(exception_io_not_found) {} + } catch(exception_io_not_found const &) {} switch (createMode) { case createMode::allowExisting: break; // OK @@ -310,7 +309,7 @@ namespace { bool bDidExist = false; try { m_fs->create_directory(sub->c_str(), aborter); - } catch (exception_io_already_exists) { + } catch (exception_io_already_exists const &) { bDidExist = true; } switch (createMode) { @@ -342,7 +341,7 @@ namespace { try { if (createMode == createMode::allowExisting) m_fs->move_overwrite(m_path->c_str(), dst, aborter); else m_fs->move(m_path->c_str(), dst, aborter); - } catch (exception_io_already_exists) { + } catch (exception_io_already_exists const &) { bDidExist = true; } diff --git a/sdk/foobar2000/SDK/guids.cpp b/sdk/foobar2000/SDK/guids.cpp index 26de10f..15e499d 100644 --- a/sdk/foobar2000/SDK/guids.cpp +++ b/sdk/foobar2000/SDK/guids.cpp @@ -51,6 +51,7 @@ FOOGUIDDECL const GUID dsp_entry_v2::class_guid = { 0x9ec5d45e, 0x10f5, 0x46a7, FOOGUIDDECL const GUID dsp_entry_hidden::class_guid = { 0xe3f0c95f, 0x7a0b, 0x48bc, { 0x96, 0x58, 0x71, 0xa4, 0x69, 0x68, 0x88, 0x76 } }; FOOGUIDDECL const GUID dsp_entry_v3::class_guid = { 0xb4d5a127, 0x5e59, 0x466d, { 0x93, 0x6b, 0x39, 0x5e, 0xdf, 0xb9, 0x37, 0xa4 } }; FOOGUIDDECL const GUID dsp_entry_v4::class_guid = { 0xf13a5ce9, 0xd6e8, 0x4ad8, { 0x9e, 0xba, 0x9d, 0x6a, 0x34, 0x84, 0x29, 0x61 } }; +FOOGUIDDECL const GUID dsp_entry_v5::class_guid = { 0x7325e6ce, 0x945b, 0x4f58, { 0xa7, 0x62, 0xfc, 0xa1, 0x38, 0x4c, 0xe5, 0xeb } }; FOOGUIDDECL const GUID dsp_preset_edit_callback_v2::class_guid = { 0x904173f6, 0x345e, 0x47d0, { 0x88, 0x60, 0x63, 0xa2, 0xc9, 0xd0, 0x9, 0x52 } }; @@ -244,9 +245,10 @@ FOOGUIDDECL const GUID user_interface_v2::class_guid = { 0x5f5ac82b, 0x44a7, 0x4 #ifdef _WIN32 FOOGUIDDECL const GUID user_interface_v2::cap_suppress_core_shellhook = { 0xe5950632, 0x750d, 0x4265,{ 0x8c, 0xea, 0x6c, 0xf2, 0x77, 0x91, 0x44, 0x40 } }; FOOGUIDDECL const GUID user_interface_v2::cap_suppress_core_uvc = { 0xe35156b2, 0xfbac, 0x450d,{ 0xa3, 0xf7, 0xf1, 0xda, 0x46, 0xb6, 0xdf, 0x8d } }; +#endif FOOGUIDDECL const GUID user_interface_v3::class_guid = { 0x4fa87b73, 0x7e4, 0x4814, { 0x8f, 0x70, 0x66, 0x28, 0x7a, 0x18, 0x8b, 0xaa } }; -#endif +FOOGUIDDECL const GUID user_interface_v4::class_guid = { 0xd9069882, 0x51ed, 0x4f05, { 0x82, 0x46, 0x9b, 0x50, 0x82, 0xe0, 0x25, 0x26 } }; // {994C0D0E-319E-45f3-92FC-518616E73ADC} FOOGUIDDECL const GUID contextmenu_item::caller_now_playing = @@ -322,6 +324,10 @@ FOOGUIDDECL const GUID packet_decoder::owner_MP4_FLAC = FOOGUIDDECL const GUID packet_decoder::owner_MP4_Opus = { 0x595ff6b0, 0xf860, 0x43cf, { 0xa5, 0x4c, 0x6d, 0x8d, 0x29, 0xe1, 0x2f, 0x62 } }; +// {E10C6D93-3271-4AAA-B0E6-231AB14BEFFA} +FOOGUIDDECL const GUID packet_decoder::owner_MP4_MPEGH = +{ 0xe10c6d93, 0x3271, 0x4aaa, { 0xb0, 0xe6, 0x23, 0x1a, 0xb1, 0x4b, 0xef, 0xfa } }; + // {AF5B7CB0-A08E-404a-A3C0-5C5EA1A8A05C} FOOGUIDDECL const GUID packet_decoder::owner_ADTS = { 0xaf5b7cb0, 0xa08e, 0x404a, { 0xa3, 0xc0, 0x5c, 0x5e, 0xa1, 0xa8, 0xa0, 0x5c } }; @@ -1134,6 +1140,8 @@ FOOGUIDDECL const GUID playback_control_v2::class_guid = { 0x1eb67bda, 0x1345, 0 FOOGUIDDECL const GUID info_lookup_handler::class_guid = { 0x4fcfdab7, 0x55b5, 0x47d6, { 0xb1, 0x9d, 0xa4, 0xdc, 0x9f, 0xd7, 0x69, 0x4c } }; FOOGUIDDECL const GUID info_lookup_handler_v2::class_guid = { 0x3c9728a5, 0x89e5, 0x4560, { 0xb6, 0x8b, 0x9b, 0x9b, 0x90, 0x1f, 0x0, 0x7b } }; +FOOGUIDDECL const GUID info_lookup_handler_v3::class_guid = { 0x7d337e3c, 0x5f83, 0x4dee, { 0x9f, 0x39, 0xe4, 0x3b, 0xc1, 0x51, 0xe4, 0xa1 } }; + FOOGUIDDECL const GUID completion_notify::class_guid = { 0xdf26d586, 0xf7ec, 0x40c3, { 0x9f, 0xe8, 0x2e, 0xa0, 0x72, 0x5d, 0x76, 0xc0 } }; @@ -1373,6 +1381,7 @@ FOOGUIDDECL const GUID output_v2::class_guid = { 0x4f679e4b, 0x79e0, 0x4fc9, { 0 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_v6::class_guid = { 0xcf632053, 0xd612, 0x4c33, { 0xa6, 0x90, 0xfe, 0x68, 0x64, 0x5b, 0x3b, 0xc9 } }; @@ -1444,8 +1453,11 @@ FOOGUIDDECL const GUID file_lowLevelIO::guid_setFileTimes = { 0x46501e0d, 0x644d FOOGUIDDECL const GUID async_task_manager::class_guid = { 0xea055f49, 0x7c6d, 0x4695, { 0x8c, 0xf, 0xeb, 0xbd, 0x92, 0xdb, 0xa7, 0xa7 } }; FOOGUIDDECL const GUID fb2k::configStore::class_guid = { 0x97aad7fd, 0xb216, 0x4286, { 0x9e, 0xb3, 0x18, 0x8d, 0x35, 0xee, 0x84, 0x1c } }; +FOOGUIDDECL const GUID fb2k::configStore2::class_guid = { 0xd0c958db, 0x59c0, 0x4c5e, { 0x8c, 0xf2, 0xd, 0xb5, 0xd7, 0x9e, 0x9a, 0x1e } }; +#if FOOBAR2020 FOOGUIDDECL const GUID fb2k::timerManager::class_guid = { 0xa93c35e3, 0x3a61, 0x40b2, { 0xa5, 0x29, 0x26, 0x49, 0xd9, 0xab, 0x7d, 0x6 } }; +#endif // FOOBAR2020 FOOGUIDDECL const GUID read_ahead_tools::class_guid = { 0x709671bf, 0x449a, 0x4dc8, { 0x9f, 0xcf, 0x84, 0xb3, 0xbc, 0xec, 0x98, 0x4d } }; @@ -1518,3 +1530,7 @@ FOOGUIDDECL const GUID stream_receive::class_guid = { 0x1d36b5af, 0xaa6b, 0x450d #ifdef __APPLE__ FOOGUIDDECL const GUID fb2k::NSObjectWrapper::class_guid = { 0x6ec55805, 0x96f7, 0x4a8f, { 0x92, 0xb3, 0xbd, 0x33, 0xee, 0x10, 0x53, 0x17 } }; #endif + +FOOGUIDDECL const GUID tag_processor_trailing_v2::class_guid = { 0x62b128c6, 0xc179, 0x4585, { 0x95, 0xfc, 0x30, 0x1, 0x95, 0xee, 0x99, 0x7a } }; +FOOGUIDDECL const GUID tag_processor_id3v2_v2::class_guid = { 0x9b7b982f, 0xbaf0, 0x4225, { 0xa5, 0x60, 0xa7, 0xac, 0x51, 0xd0, 0xce, 0xed } }; + diff --git a/sdk/foobar2000/SDK/info_lookup_handler.h b/sdk/foobar2000/SDK/info_lookup_handler.h index fdf194a..300e66f 100644 --- a/sdk/foobar2000/SDK/info_lookup_handler.h +++ b/sdk/foobar2000/SDK/info_lookup_handler.h @@ -5,12 +5,14 @@ class NOVTABLE info_lookup_handler : public service_base { enum { flag_album_lookup = 1 << 0, flag_track_lookup = 1 << 1, + //! \since 2.2: supports lookup_noninteractive() call; before 2.2, lookup_noninteractive was assumed supported if info_lookup_handler_v2 was implemented. + flag_noninteractive = 1 << 2, }; //! Retrieves human-readable name of the lookup handler to display in user interface. virtual void get_name(pfc::string_base & p_out) = 0; - //! Returns one or more of flag_track_lookup, and flag_album_lookup. + //! Returns one or more of flag_track_lookup, flag_album_lookup, flag_noninteractive. virtual t_uint32 get_flags() = 0; virtual fb2k::hicon_t get_icon(int p_width, int p_height) = 0; @@ -31,3 +33,13 @@ class NOVTABLE info_lookup_handler_v2 : public info_lookup_handler { virtual double merit() {return 0;} virtual void lookup_noninteractive(metadb_handle_list_cref items, completion_notify::ptr notify, fb2k::hwnd_t parent) = 0; }; + +//! Since 2.2 +class NOVTABLE info_lookup_handler_v3 : public info_lookup_handler_v2 { + FB2K_MAKE_SERVICE_INTERFACE(info_lookup_handler_v3, info_lookup_handler_v2); +public: + //! Some handlers depend on user settings to access multiple actual online services. \n + //! Use this method to retrieve individual handlers for specific services, with proper name, icon, etc. + //! @returns Array of info_lookup_handler objects, null if there are no subhandlers and this object should be used. + virtual fb2k::arrayRef subhandlers() { return nullptr; } +}; \ No newline at end of file diff --git a/sdk/foobar2000/SDK/input.cpp b/sdk/foobar2000/SDK/input.cpp index 1452a6d..e01eae2 100644 --- a/sdk/foobar2000/SDK/input.cpp +++ b/sdk/foobar2000/SDK/input.cpp @@ -199,11 +199,11 @@ service_ptr input_entry::g_open_from_list(input_entry_list_t const & p_list, con auto ret = p_list[n]->open(whatFor, p_filehint, p_path, logger, p_abort); if (outGUID != nullptr) * outGUID = input_get_guid(p_list[n]); return ret; - } catch (exception_io_no_handler_for_path) { + } catch (exception_io_no_handler_for_path const &) { //do nothing, skip over - } catch(exception_io_unsupported_format) { + } catch(exception_io_unsupported_format const &) { if (!errUnsupported) errUnsupported = std::current_exception(); - } catch (exception_io_data) { + } catch (exception_io_data const &) { if (!errData) errData = std::current_exception(); } } @@ -267,7 +267,7 @@ service_ptr input_entry::g_open(const GUID & whatFor, file::ptr p_filehint, cons if (g_find_inputs_by_content_type(list, content_type, p_from_redirect)) { try { return g_open_from_list(list, whatFor, l_file, p_path, logger, p_abort); - } catch (exception_io_unsupported_format) { + } catch (exception_io_unsupported_format const &) { #if PFC_DEBUG FB2K_DebugLog() << "Failed to open by content type, using fallback"; #endif @@ -312,7 +312,7 @@ void input_entry::g_open_for_info_write_timeout(service_ptr_t try { g_open_for_info_write(p_instance,p_filehint,p_path,p_abort,p_from_redirect); break; - } catch(exception_io_sharing_violation) { + } catch(exception_io_sharing_violation const &) { if (timer.query() > p_timeout) throw; p_abort.sleep(0.01); } @@ -429,7 +429,7 @@ t_filestats2 input_info_reader::get_stats2_(const char* fallbackPath, uint32_t f try { auto fs = filesystem::tryGet(fallbackPath); if (fs.is_valid()) ret = fs->get_stats2_(fallbackPath, f, a); - } catch (exception_io) {} + } catch (exception_io const &) {} } return ret; } diff --git a/sdk/foobar2000/SDK/input.h b/sdk/foobar2000/SDK/input.h index f49dc15..7873700 100644 --- a/sdk/foobar2000/SDK/input.h +++ b/sdk/foobar2000/SDK/input.h @@ -7,12 +7,23 @@ PFC_DECLARE_EXCEPTION(exception_tagging_unsupported, exception_io_data, "Tagging of this file format is not supported") enum { + // Seek commands won't be issued, can skip initializing seektables etc that sequential decode doesn't need. input_flag_no_seeking = 1 << 0, + // Do not loop, also ignore user looping settings. input_flag_no_looping = 1 << 1, + // Opening for actual playback, not for conversion/scan/test. input_flag_playback = 1 << 2, + // Testing integrity, perform additional checks and report errors. Not mutually exlusive with input_flag_playback! input_flag_testing_integrity = 1 << 3, + // OK to perform cheap but inaccurate seeking. + // Note that seeking should be ALWAYS sample accurate. This setting is a hint for decoding formats that are expensive to seek properly, indicating that no obvious harm will come from taking shortcuts. input_flag_allow_inaccurate_seeking = 1 << 4, + // Suppress decode_postprocessor use. Handled by decode_postprocessor framework. input_flag_no_postproc = 1 << 5, + // DSD decoders only: Send DSD as DoP. If not set, DSD should be decimated to PCM. + input_flag_dop = 1 << 6, + // Auotmated test suite running, disregard user options if possible + input_flag_canonical_decode = 1 << 7, input_flag_simpledecode = input_flag_no_seeking|input_flag_no_looping, }; diff --git a/sdk/foobar2000/SDK/input_file_type.cpp b/sdk/foobar2000/SDK/input_file_type.cpp index ef072fc..116cb02 100644 --- a/sdk/foobar2000/SDK/input_file_type.cpp +++ b/sdk/foobar2000/SDK/input_file_type.cpp @@ -25,6 +25,26 @@ static void formatMaskList(pfc::string_base & out, t_fnList const & in, const ch } } +void input_file_type::for_each_media_ext( std::function fn, bool bDotExt) { + for( auto p : input_file_type::enumerate()) { + const unsigned cnt = p->get_count(); + for (unsigned w = 0; w < cnt; ++w) { + pfc::string8 maskCombined; + p->get_mask(w, maskCombined); + + pfc::chain_list_v2_t masks; + pfc::splitStringByChar(masks, maskCombined, ';'); + for( auto i : masks ) { + const char * m = i.get_ptr(); + if (pfc::strcmp_partial(m, "*.") == 0) { + const char * ext = m + 1; // .ext + if (!bDotExt) ++ext; + fn(ext); + } + } + } + } +} void input_file_type::make_filetype_support_fingerprint(pfc::string_base & str) { pfc::string_formatter out; pfc::avltree_t names; diff --git a/sdk/foobar2000/SDK/input_file_type.h b/sdk/foobar2000/SDK/input_file_type.h index 4a09af2..686da57 100644 --- a/sdk/foobar2000/SDK/input_file_type.h +++ b/sdk/foobar2000/SDK/input_file_type.h @@ -1,4 +1,5 @@ #pragma once +#include //! Entrypoint interface for registering media file types that can be opened through "open file" dialogs or associated with foobar2000 application in Windows shell. \n //! Instead of implementing this directly, use DECLARE_FILE_TYPE() / DECLARE_FILE_TYPE_EX() macros. @@ -8,6 +9,8 @@ class input_file_type : public service_base { virtual bool get_name(unsigned idx,pfc::string_base & out)=0;//eg. "MPEG files" virtual bool get_mask(unsigned idx,pfc::string_base & out)=0;//eg. "*.MP3;*.MP2"; separate with semicolons virtual bool is_associatable(unsigned idx) = 0; + + static void for_each_media_ext( std::function, bool bDotExt = false); #if FOOBAR2000_TARGET_VERSION >= 76 static void build_openfile_mask(pfc::string_base & out,bool b_include_playlists=true, bool b_include_archives = false); diff --git a/sdk/foobar2000/SDK/main_thread_callback.cpp b/sdk/foobar2000/SDK/main_thread_callback.cpp index 500ccb6..65931ba 100644 --- a/sdk/foobar2000/SDK/main_thread_callback.cpp +++ b/sdk/foobar2000/SDK/main_thread_callback.cpp @@ -32,6 +32,13 @@ void fb2k::inMainThread( std::function f ) { main_thread_callback_add( new service_impl_t(f)); } +void fb2k::inMainThread(std::function f, abort_callback& a) { + auto abort = std::make_shared< abort_callback_clone >(a); + inMainThread([f, abort] { + if (!abort->is_set()) f(); + }); +} + void fb2k::inMainThread2( std::function f ) { if ( core_api::is_main_thread() ) { f(); diff --git a/sdk/foobar2000/SDK/mainmenu.cpp b/sdk/foobar2000/SDK/mainmenu.cpp index 372ae0b..6647c06 100644 --- a/sdk/foobar2000/SDK/mainmenu.cpp +++ b/sdk/foobar2000/SDK/mainmenu.cpp @@ -7,12 +7,18 @@ bool mainmenu_commands::g_execute_dynamic(const GUID & p_guid, const GUID & p_su mainmenu_commands_v2::ptr v2; if (!ptr->service_query_t(v2)) return false; if (!v2->is_command_dynamic(index)) return false; - return v2->dynamic_execute(index, p_subGuid, p_callback); + bool rv = false; + fb2k::crashOnException([&] { + rv = v2->dynamic_execute(index, p_subGuid, p_callback);; + }, "mainmenu_commands::dynamic_execute"); + return rv; } bool mainmenu_commands::g_execute(const GUID & p_guid,service_ptr_t p_callback) { mainmenu_commands::ptr ptr; t_uint32 index; if (!menu_item_resolver::g_resolve_main_command(p_guid, ptr, index)) return false; - ptr->execute(index, p_callback); + fb2k::crashOnException( [&] { + ptr->execute(index, p_callback); + }, "mainmenu_commands::execute"); return true; } diff --git a/sdk/foobar2000/SDK/output.cpp b/sdk/foobar2000/SDK/output.cpp index b78e7e0..eb6d231 100644 --- a/sdk/foobar2000/SDK/output.cpp +++ b/sdk/foobar2000/SDK/output.cpp @@ -69,6 +69,13 @@ pfc::eventHandle_t output::get_trigger_event_() { return pfc::eventInvalid; } +size_t output::process_samples_v2_(const audio_chunk& c) { + output_v6::ptr v6; + if (v6 &= this) return v6->process_samples_v2(c); + this->process_samples(c); + return c.get_sample_count(); +} + void output_impl::on_flush_internal() { m_eos = false; m_sent_force_play = false; m_incoming_ptr = 0; @@ -89,33 +96,49 @@ void output_impl::update(bool & p_ready) { p_ready = update_v2() > 0; } size_t output_impl::update_v2() { + + // Clear preemptively + m_can_write = 0; + on_update(); - if (m_incoming_spec != m_active_spec && m_incoming_ptr < m_incoming.get_size()) { + + // No data yet, nothing to do, want data, can't signal how much because we don't know the format + if (!m_incoming_spec.is_valid()) return SIZE_MAX; + + // First chunk in or format change + if (m_incoming_spec != m_active_spec) { if (get_latency_samples() == 0) { + // Ready for new format m_sent_force_play = false; open(m_incoming_spec); m_active_spec = m_incoming_spec; } else { + // Previous format still playing, accept no more data this->send_force_play(); + return 0; } } - 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.chanCount; - t_size delta = pfc::min_t(m_incoming.get_size() - m_incoming_ptr,cw); + + // opened for m_incoming_spec stream + + // Store & update m_can_write on our end + // We don't know what can_write_samples() actually does, could be expensive, avoid calling it repeatedly + m_can_write = this->can_write_samples(); + + if (m_incoming_ptr < m_incoming.get_size()) { + t_size delta = pfc::min_t(m_incoming.get_size() - m_incoming_ptr, m_can_write * m_incoming_spec.chanCount); if (delta > 0) { PFC_ASSERT(!m_sent_force_play); - write(audio_chunk_temp_impl(m_incoming.get_ptr()+m_incoming_ptr,delta / m_incoming_spec.chanCount,m_incoming_spec.sampleRate,m_incoming_spec.chanCount,m_incoming_spec.chanMask)); + write(audio_chunk_temp_impl(m_incoming.get_ptr() + m_incoming_ptr, delta / m_incoming_spec.chanCount, m_incoming_spec.sampleRate, m_incoming_spec.chanCount, m_incoming_spec.chanMask)); m_incoming_ptr += delta; - if ( m_eos && this->queue_empty() ) { + if (m_eos && this->queue_empty()) { this->send_force_play(); } } - retCanWriteSamples = (cw - delta) / m_incoming_spec.chanCount; - } else if ( m_incoming_ptr == m_incoming.get_size() ) { - retCanWriteSamples = SIZE_MAX; - } - return retCanWriteSamples; + + m_can_write -= delta / m_incoming_spec.chanCount; + } + return m_can_write; } double output_impl::get_latency() { @@ -140,35 +163,50 @@ void output_impl::send_force_play() { this->on_force_play(); } +static void spec_sanity(audio_chunk::spec_t const& spec) { + if (!spec.is_valid()) pfc::throw_exception_with_message< exception_io_data >("Invalid audio stream specifications"); +} + +size_t output_impl::process_samples_v2(const audio_chunk& p_chunk) { + PFC_ASSERT(queue_empty()); + PFC_ASSERT(!m_eos); + const auto spec = p_chunk.get_spec(); + if (m_incoming_spec != spec) { + spec_sanity(spec); + m_incoming_spec = spec; + return 0; + } + + auto in = p_chunk.get_sample_count(); + if (in > m_can_write) in = m_can_write; + if (in > 0) { + write(audio_chunk_partial_ref(p_chunk, 0, in)); + m_can_write -= in; + } + return in; +} + void output_impl::process_samples(const audio_chunk & p_chunk) { PFC_ASSERT(queue_empty()); PFC_ASSERT( !m_eos ); - auto spec = p_chunk.get_spec(); - if (!spec.is_valid()) pfc::throw_exception_with_message< exception_io_data >("Invalid audio stream specifications"); - m_incoming_spec = spec; - t_size length = p_chunk.get_used_size(); - m_incoming.set_data_fromptr(p_chunk.get_data(),length); + const auto spec = p_chunk.get_spec(); + size_t taken = 0; + if (m_incoming_spec == spec) { + // Try bypassing intermediate buffer + taken = this->process_samples_v2(p_chunk); + if (taken == p_chunk.get_sample_count()) return; // all written, success + taken *= spec.chanCount; + } else { + spec_sanity(spec); + m_incoming_spec = spec; + } + // Queue what's left for update() to eat later + m_incoming.set_data_fromptr(p_chunk.get_data() + taken, p_chunk.get_used_size() - taken); m_incoming_ptr = 0; } void output_v3::get_injected_dsps( dsp_chain_config & dsps ) { 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 } size_t output_v4::update_v2() { diff --git a/sdk/foobar2000/SDK/output.h b/sdk/foobar2000/SDK/output.h index 459edbd..3cafb58 100644 --- a/sdk/foobar2000/SDK/output.h +++ b/sdk/foobar2000/SDK/output.h @@ -58,10 +58,12 @@ class NOVTABLE output : public service_base { public: //! Retrieves amount of audio data queued for playback, in seconds. virtual double get_latency() = 0; - //! Sends new samples to the device. Allowed to be called only when update() indicates that the device is ready. - //! update() should be called AGAIN after each process_samples() to know if the device is ready for more. + //! Sends new samples to the device. Allowed to be called only when update() indicates that the device is ready. \n + //! update() should be called AGAIN after each process_samples() to know if the device is ready for more. \n + //! This method SHOULD NOT block, only copy passed chunk and return immediately. virtual void process_samples(const audio_chunk & p_chunk) = 0; - //! Updates playback; queries whether the device is ready to receive new data. + //! Updates playback; queries whether the device is ready to receive new data. \n + //! This method SHOULD NOT block, only update internal state and return immediately. //! @param p_ready On success, receives value indicating whether the device is ready for next process_samples() call. virtual void update(bool & p_ready) = 0; //! Pauses/unpauses playback. @@ -81,6 +83,8 @@ class NOVTABLE output : public service_base { size_t update_v2_(); //! Helper, see output_v4::get_trigger_event() pfc::eventHandle_t get_trigger_event_(); + //! Helper, see output_v6::process_samples_v2() + size_t process_samples_v2_(const audio_chunk&); //! Helper for output_entry implementation. static uint32_t g_extra_flags() { return 0; } @@ -125,11 +129,12 @@ class NOVTABLE output_v4 : public output_v3 { //! Returns whether the audio stream is currently being played or not. \n //! Typically, for a short period of time, initially sent 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;} + virtual bool is_progressing() = 0; //! 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. + //! The output may return SIZE_MAX to indicate that it can take data but does not currently have any hints to tell how much. \n + //! This method SHOULD NOT block, only update output state and return immediately. virtual size_t update_v2(); }; @@ -140,6 +145,15 @@ class output_v5 : public output_v4 { virtual unsigned get_forced_channel_mask() { return 0; } }; +//! \since 2.2 +class output_v6 : public output_v5 { + FB2K_MAKE_SERVICE_INTERFACE(output_v6, output_v5); +public: + //! Extended process_samples(), allowed to read only part of the chunk if out of buffer space to take whole. + //! @returns Number of samples actually taken. + virtual size_t process_samples_v2(const audio_chunk&) = 0; +}; + class NOVTABLE output_entry : public service_base { FB2K_MAKE_SERVICE_INTERFACE_ENTRYPOINT(output_entry); public: @@ -220,25 +234,42 @@ class output_entry_impl_t : public E template class output_factory_t : public service_factory_single_t > {}; -class output_impl : public output_v5 { +//! Helper base class for output implementations. \n +//! This is the preferred way of implementing output. \n +//! This is NOT a public interface and its layout changes between foobar2000 SDK versions, do not assume other outputs to implement it. +class output_impl : public output_v6 { protected: output_impl() {} + + //! Called periodically. You can update your state in this method. Can do nothing if not needed. virtual void on_update() = 0; - //! Will never get more input than as returned by can_write_samples(). + //! Writes an audio chunk to your output. \n + //! Will never get more than last can_write_samples() asked for. \n + //! Format being send will match last open(). virtual void write(const audio_chunk & p_data) = 0; + //! @returns How many samples write() can take at this moment. \n + //! It's called immediately after on_update() and can reuse value calculated in last on_update(). virtual t_size can_write_samples() = 0; + //! @returns Current latency, delay between last written sample and currently heard audio. virtual t_size get_latency_samples() = 0; + //! Flush output, after seek etc. virtual void on_flush() = 0; + //! Flush output due to manual track change in progress. \n + //! Same as on_flush() by default. virtual void on_flush_changing_track() {on_flush();} + //! Called before first chunk and on stream format change. \n + //! Following write() calls will deliver chunks in the same format as specified here. virtual void open(audio_chunk::spec_t const & p_spec) = 0; - // base class virtual methods - // virtual void pause(bool p_state) = 0; - // virtual void volume_set(double p_val) = 0; //! Override this, not force_play(). \n //! output_impl will defer call to on_force_play() until out of data in its buffer. virtual void on_force_play() = 0; + + // base class virtual methods which derived class must also implement + // virtual void pause(bool p_state) = 0; + // virtual void volume_set(double p_val) = 0; + // virtual bool is_progressing() = 0; protected: void on_need_reopen() {m_active_spec.clear(); } private: @@ -248,6 +279,7 @@ class output_impl : public output_v5 { size_t update_v2() override final; double get_latency() override final; void process_samples(const audio_chunk & p_chunk) override final; + size_t process_samples_v2(const audio_chunk&) override final; void force_play() override final; void on_flush_internal(); void send_force_play(); @@ -255,7 +287,7 @@ class output_impl : public output_v5 { bool queue_empty() const { return m_incoming_ptr == m_incoming.get_size(); } pfc::array_t m_incoming; - t_size m_incoming_ptr = 0; + size_t m_incoming_ptr = 0, m_can_write = 0; audio_chunk::spec_t m_incoming_spec,m_active_spec; bool m_eos = false; // EOS issued by caller / no more data expected until a flush bool m_sent_force_play = false; // set if sent on_force_play() diff --git a/sdk/foobar2000/SDK/packet_decoder.cpp b/sdk/foobar2000/SDK/packet_decoder.cpp index 07e9edc..0fbd813 100644 --- a/sdk/foobar2000/SDK/packet_decoder.cpp +++ b/sdk/foobar2000/SDK/packet_decoder.cpp @@ -16,7 +16,7 @@ void packet_decoder::g_open(service_ptr_t & p_out,bool p_decode, try { ptr->open(p_out, p_decode, p_owner, p_param1, p_param2, p_param2size, p_abort); return; - } catch (exception_io_data) { + } catch (exception_io_data const &) { rethrow = std::current_exception(); } } diff --git a/sdk/foobar2000/SDK/packet_decoder.h b/sdk/foobar2000/SDK/packet_decoder.h index 06cf8e1..45c945a 100644 --- a/sdk/foobar2000/SDK/packet_decoder.h +++ b/sdk/foobar2000/SDK/packet_decoder.h @@ -51,7 +51,7 @@ class NOVTABLE packet_decoder : public service_base { //! Static helper, creates a packet_decoder instance and initializes it with specific decoder setup data. static void g_open(service_ptr_t & 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, owner_MP4_FLAC, owner_MP4_Opus; + 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, owner_MP4_FLAC, owner_MP4_Opus, owner_MP4_MPEGH; struct matroska_setup { diff --git a/sdk/foobar2000/SDK/play_callback.h b/sdk/foobar2000/SDK/play_callback.h index 8f60bbf..62e7006 100644 --- a/sdk/foobar2000/SDK/play_callback.h +++ b/sdk/foobar2000/SDK/play_callback.h @@ -78,7 +78,7 @@ class NOVTABLE play_callback_manager_v2 : public play_callback_manager { class play_callback_impl_base : public play_callback { public: play_callback_impl_base(unsigned p_flags = 0xFFFFFFFF) { - play_callback_manager::get()->register_callback(this,p_flags,false); + if (p_flags != 0) play_callback_manager::get()->register_callback(this,p_flags,false); } ~play_callback_impl_base() { play_callback_manager::get()->unregister_callback(this); @@ -86,7 +86,7 @@ class play_callback_impl_base : public play_callback { void play_callback_reregister(unsigned flags, bool refresh = false) { auto api = play_callback_manager::get(); api->unregister_callback(this); - api->register_callback(this,flags,refresh); + if (flags != 0) api->register_callback(this,flags,refresh); } void on_playback_starting(play_control::t_track_command p_command,bool p_paused) {} void on_playback_new_track(metadb_handle_ptr p_track) {} diff --git a/sdk/foobar2000/SDK/playback_stream_capture.h b/sdk/foobar2000/SDK/playback_stream_capture.h index bb147e4..c3c7d12 100644 --- a/sdk/foobar2000/SDK/playback_stream_capture.h +++ b/sdk/foobar2000/SDK/playback_stream_capture.h @@ -34,7 +34,8 @@ class NOVTABLE playback_stream_capture_v2 : public playback_stream_capture { public: //! @param requestInterval Interval, in seconds, in which the callback expects to be called. \n //! Set to -1 to use defaults. \n - //! Note that if many callbacks are registered, they all get called at once; one callback requesting lower interval lowers the interval for all. + //! Note that if many callbacks are registered, they all get called at once; one callback requesting lower interval lowers the interval for all. \n + //! Non negative values are clamped to allowed range, that is, request of zero results in lowest possible update interval. virtual void add_callback_v2(playback_stream_capture_callback* cb, double requestInterval = -1) = 0; }; @@ -42,6 +43,7 @@ class playback_stream_capture_callback_impl : public playback_stream_capture_cal public: void on_chunk(const audio_chunk&) override {} + //! @param interval requested update interval, see playback_stream_capture_v2::add_callback_v2() playback_stream_capture_callback_impl(double interval = -1) { PFC_ASSERT(core_api::is_main_thread()); #if FOOBAR2020 diff --git a/sdk/foobar2000/SDK/playlistColumnProvider.h b/sdk/foobar2000/SDK/playlistColumnProvider.h index 234c30e..45aea1a 100644 --- a/sdk/foobar2000/SDK/playlistColumnProvider.h +++ b/sdk/foobar2000/SDK/playlistColumnProvider.h @@ -20,9 +20,11 @@ namespace fb2k { //! See flag_* constants. virtual unsigned columnFlags(size_t col) = 0; - static constexpr unsigned flag_alignLeft = 0; - static constexpr unsigned flag_alignRight = 1 << 0; - static constexpr unsigned flag_alignCenter = 1 << 1; + static constexpr unsigned + flag_alignLeft = 0, flag_alignRight = 1 << 0, flag_alignCenter = 1 << 1, // alignment + flag_numeric = 1 << 2, // prefer fixed width font, not all renderers support this + flag_positionDependant = 1 << 3, // value changes with position in playlist, mainly used by list index etc + flag_glyphs = 1 << 4; // internal/reserved static constexpr unsigned flag_alignMask = (flag_alignLeft|flag_alignRight|flag_alignCenter); }; } diff --git a/sdk/foobar2000/SDK/playlist_loader.cpp b/sdk/foobar2000/SDK/playlist_loader.cpp index ab14942..b06afbe 100644 --- a/sdk/foobar2000/SDK/playlist_loader.cpp +++ b/sdk/foobar2000/SDK/playlist_loader.cpp @@ -9,7 +9,8 @@ #include #include -static void process_path_internal(const char * p_path,const service_ptr_t & p_reader,playlist_loader_callback::ptr callback, abort_callback & abort,playlist_loader_callback::t_entry_type type,const t_filestats & p_stats); +constexpr unsigned allowRecurseBase = 2; // max. 2 archive levels - mitigate droste.zip stack overflow +static void process_path_internal(const char * p_path,const service_ptr_t & p_reader,playlist_loader_callback::ptr callback, abort_callback & abort,playlist_loader_callback::t_entry_type type,const t_filestats & p_stats, unsigned allowRecurse ); bool playlist_loader::g_try_load_playlist(file::ptr fileHint,const char * p_path,playlist_loader_callback::ptr p_callback, abort_callback & p_abort) { // Determine if this file is a playlist or not (which usually means that it's a media file) @@ -27,7 +28,7 @@ bool playlist_loader::g_try_load_playlist(file::ptr fileHint,const char * p_path if (fs->supports_content_types()) { try { fs->open(l_file,filepath,filesystem::open_mode_read,p_abort); - } catch(exception_io) { return false; } // fall thru + } catch(exception_io const &) { return false; } // fall thru } } } @@ -54,7 +55,7 @@ bool playlist_loader::g_try_load_playlist(file::ptr fileHint,const char * p_path try { TRACK_CODE("playlist_loader::open",l->open(filepath,l_file,p_callback, p_abort)); return true; - } catch(exception_io_unsupported_format) { + } catch(exception_io_unsupported_format const &) { l_file->reopen(p_abort); } } @@ -69,7 +70,7 @@ bool playlist_loader::g_try_load_playlist(file::ptr fileHint,const char * p_path try { TRACK_CODE("playlist_loader::open",l->open(filepath,l_file,p_callback,p_abort)); return true; - } catch(exception_io_unsupported_format) { + } catch(exception_io_unsupported_format const &) { l_file->reopen(p_abort); } } @@ -113,10 +114,10 @@ static void index_tracks_helper(const char * p_path,const service_ptr_t & service_ptr_t instance; try { input_entry::g_open_for_info_read(instance,p_reader,p_path,p_abort); - } catch(exception_io_unsupported_format) { + } catch(exception_io_unsupported_format const &) { // specifically bail throw; - } catch(exception_io) { + } catch(exception_io const &) { // broken file or some other error, open() failed - show it anyway metadb_handle_ptr handle; p_callback->handle_create(handle, make_playable_location(p_path, 0)); @@ -169,9 +170,9 @@ static void track_indexer__g_get_tracks_wrap(const char * p_path,const service_p bool fail = false; try { index_tracks_helper(p_path,p_reader,p_stats,p_type,p_callback,p_abort, got_input); - } catch(exception_aborted) { + } catch(exception_aborted const &) { throw; - } catch(exception_io_unsupported_format) { + } catch(exception_io_unsupported_format const &) { fail = true; } catch(std::exception const & e) { fail = true; @@ -272,8 +273,9 @@ namespace { } -static void process_path_internal(const char * p_path,const service_ptr_t & p_reader,playlist_loader_callback::ptr callback, abort_callback & abort,playlist_loader_callback::t_entry_type type,const t_filestats & p_stats) +static void process_path_internal(const char * p_path,const service_ptr_t & p_reader,playlist_loader_callback::ptr callback, abort_callback & abort,playlist_loader_callback::t_entry_type type,const t_filestats & p_stats, unsigned allowRecurse) { + if (allowRecurse == 0) return; //p_path must be canonical abort.check(); @@ -288,8 +290,8 @@ static void process_path_internal(const char * p_path,const service_ptr_t results.main( p_path, abort ); for( auto & i : results.m_entries ) { try { - process_path_internal(i.m_path.c_str(), 0, callback, abort, playlist_loader_callback::entry_directory_enumerated, i.m_stats); - } catch (exception_aborted) { + process_path_internal(i.m_path.c_str(), 0, callback, abort, playlist_loader_callback::entry_directory_enumerated, i.m_stats, allowRecurse); + } catch (exception_aborted const &) { throw; } catch (std::exception const& e) { FB2K_console_formatter() << "Error walking path (" << e << "): " << file_path_display(i.m_path.c_str()); @@ -298,11 +300,11 @@ static void process_path_internal(const char * p_path,const service_ptr_t } } return; // successfully enumerated directory - go no further - } catch(exception_aborted) { + } catch(exception_aborted const &) { throw; - } catch (exception_io_not_directory) { + } catch (exception_io_not_directory const &) { // disregard - } catch(exception_io_not_found) { + } catch(exception_io_not_found const &) { // disregard } catch (std::exception const& e) { FB2K_console_formatter() << "Error walking directory (" << e << "): " << p_path; @@ -311,7 +313,7 @@ static void process_path_internal(const char * p_path,const service_ptr_t } } - { + if (allowRecurse > 1) { for (auto f : filesystem::enumerate()) { abort.check(); service_ptr_t arch; @@ -319,12 +321,12 @@ static void process_path_internal(const char * p_path,const service_ptr_t if (p_reader.is_valid()) p_reader->reopen(abort); try { - archive::list_func_t archive_results = [callback, &abort](const char* p_path, const t_filestats& p_stats, file::ptr p_reader) { - process_path_internal(p_path,p_reader,callback,abort,playlist_loader_callback::entry_directory_enumerated,p_stats); + archive::list_func_t archive_results = [callback, &abort, allowRecurse](const char* p_path, const t_filestats& p_stats, file::ptr p_reader) { + process_path_internal(p_path,p_reader,callback,abort,playlist_loader_callback::entry_directory_enumerated,p_stats,allowRecurse - 1); }; TRACK_CODE("archive::archive_list",arch->archive_list(p_path,p_reader,archive_results,/*want readers*/true, abort)); return; - } catch(exception_aborted) {throw;} + } catch(exception_aborted const &) {throw;} catch(...) { // Something failed hard // Is is_our_archive() meaningful? @@ -354,7 +356,7 @@ static void process_path_internal(const char * p_path,const service_ptr_t track_indexer__g_get_tracks_wrap(temp,0,filestats_invalid,playlist_loader_callback::entry_from_playlist,callback, abort); return;//success - } catch(exception_aborted) {throw;} + } catch(exception_aborted const &) {throw;} catch(...) {} } } @@ -415,7 +417,7 @@ void playlist_loader::g_process_path(const char * p_filename,playlist_loader_cal auto filename = file_path_canonical(p_filename); - process_path_internal(filename,0,callback,abort, type,filestats_invalid); + process_path_internal(filename,0,callback,abort, type,filestats_invalid, allowRecurseBase); } void playlist_loader::g_save_playlist(const char * p_filename,const pfc::list_base_const_t & data,abort_callback & p_abort) @@ -436,7 +438,7 @@ void playlist_loader::g_save_playlist(const char * p_filename,const pfc::list_ba try { TRACK_CODE("playlist_loader::write",l->write(filename,r,data,p_abort)); return; - } catch(exception_io_data) {} + } catch(exception_io_data const &) {} } } while(e.next(l)); throw exception_io_data(); diff --git a/sdk/foobar2000/SDK/preferences_page.cpp b/sdk/foobar2000/SDK/preferences_page.cpp index 85bb535..7103502 100644 --- a/sdk/foobar2000/SDK/preferences_page.cpp +++ b/sdk/foobar2000/SDK/preferences_page.cpp @@ -3,8 +3,12 @@ #include "coreversion.h" void preferences_page::get_help_url_helper(pfc::string_base & out, const char * category, const GUID & id, const char * name) { - out.reset(); - out << "http://help.foobar2000.org/" << core_version_info::g_get_version_string() << "/" << category << "/" << pfc::print_guid(id) << "/" << name; + out = "https://help.foobar2000.org/"; + pfc::urlEncodeAppend(out, core_version_info::g_get_version_string()); + out << "/"; + pfc::urlEncodeAppend(out, category); + out << "/" << pfc::print_guid(id) << "/"; + pfc::urlEncodeAppend(out, name); } bool preferences_page::get_help_url(pfc::string_base & p_out) { get_help_url_helper(p_out,"preferences",get_guid(), get_name()); diff --git a/sdk/foobar2000/SDK/tag_processor.cpp b/sdk/foobar2000/SDK/tag_processor.cpp index 04b5884..22bd73a 100644 --- a/sdk/foobar2000/SDK/tag_processor.cpp +++ b/sdk/foobar2000/SDK/tag_processor.cpp @@ -18,6 +18,21 @@ void tag_processor_trailing::write_apev2_id3v1(const service_ptr_t & p_fil } +t_filesize tag_processor_trailing::read_v2_(const file::ptr & file, file_info& outInfo, abort_callback& abort) { + { + tag_processor_trailing_v2::ptr v2; + if (v2 &= this) return v2->read_v2(file, outInfo, abort); + } + // no new API, emulate with old + try { + t_filesize ret = filesize_invalid; + this->read_ex(file, outInfo, ret, abort); + PFC_ASSERT(ret != filesize_invalid); + return ret; + } catch (exception_io_data const&) { + return filesize_invalid; + } +} enum { @@ -125,29 +140,31 @@ void tag_processor::read_trailing_ex(const service_ptr_t & p_file,file_inf tag_processor_trailing::get()->read_ex(p_file,p_info,p_tagoffset,p_abort); } +t_filesize tag_processor::read_trailing_nothrow(const service_ptr_t& p_file, file_info& p_info, abort_callback& p_abort) { + return tag_processor_trailing::get()->read_v2_(p_file, p_info, p_abort); +} + void tag_processor::read_id3v2(const service_ptr_t & p_file,file_info & p_info,abort_callback & p_abort) { tag_processor_id3v2::get()->read(p_file,p_info,p_abort); } -void tag_processor::read_id3v2_trailing(const service_ptr_t & p_file,file_info & p_info,abort_callback & p_abort) +void tag_processor::read_id3v2_trailing(const service_ptr_t& p_file, file_info& p_info, abort_callback& p_abort) { + if (!read_id3v2_trailing_nothrow(p_file, p_info, p_abort)) throw exception_tag_not_found(); +} + +bool tag_processor::read_id3v2_trailing_nothrow(const service_ptr_t & p_file,file_info & p_info,abort_callback & p_abort) { file_info_impl id3v2, trailing; - bool have_id3v2 = true, have_trailing = true; - try { - read_id3v2(p_file,id3v2,p_abort); - } catch(exception_io_data const &) { - have_id3v2 = false; - } + const bool have_id3v2 = tag_processor_id3v2::get()->read_v2_(p_file, id3v2, p_abort); const bool have_id3v2_text = have_id3v2 && id3v2.meta_get_count() > 0; - if (!have_id3v2_text || !p_file->is_remote()) try { - read_trailing(p_file,trailing,p_abort); - } catch(exception_io_data const &) { - have_trailing = false; + bool have_trailing = false; + if (!have_id3v2_text || !p_file->is_remote()) { + have_trailing = tag_processor_trailing::get()->read_v2_(p_file, trailing, p_abort) != filesize_invalid; } - if (!have_id3v2 && !have_trailing) throw exception_tag_not_found(); + if (!have_id3v2 && !have_trailing) return false; if (have_id3v2) { p_info._set_tag(id3v2); @@ -156,6 +173,8 @@ void tag_processor::read_id3v2_trailing(const service_ptr_t & p_file,file_ } else { p_info._set_tag(trailing); } + + return true; } void tag_processor::skip_id3v2(const service_ptr_t & p_file,t_filesize & p_size_skipped,abort_callback & p_abort) { diff --git a/sdk/foobar2000/SDK/tag_processor.h b/sdk/foobar2000/SDK/tag_processor.h index 58b0409..2b7d981 100644 --- a/sdk/foobar2000/SDK/tag_processor.h +++ b/sdk/foobar2000/SDK/tag_processor.h @@ -39,9 +39,19 @@ class NOVTABLE tag_processor_id3v2 : public service_base static void g_remove_ex(tag_write_callback & p_callback,const service_ptr_t & p_file,t_filesize & p_size_removed,abort_callback & p_abort); static uint32_t g_tagsize(const void* pHeader10bytes); + bool read_v2_(file::ptr const& file, file_info& outInfo, abort_callback& abort); + FB2K_MAKE_SERVICE_COREAPI(tag_processor_id3v2); }; +//! \since 2.2 +class NOVTABLE tag_processor_id3v2_v2 : public tag_processor_id3v2 { + FB2K_MAKE_SERVICE_COREAPI_EXTENSION(tag_processor_id3v2_v2, tag_processor_id3v2); +public: + //! Returns bool (valid tag found or not) instead of throwing exception_tag_not_found. + virtual bool read_v2(file::ptr const& file, file_info& outInfo, abort_callback& abort) = 0; +}; + //! For internal use - call tag_processor namespace methods instead. class NOVTABLE tag_processor_trailing : public service_base { @@ -62,10 +72,19 @@ class NOVTABLE tag_processor_trailing : public service_base void write_apev2(const service_ptr_t & p_file,const file_info & p_info,abort_callback & p_abort); void write_apev2_id3v1(const service_ptr_t & p_file,const file_info & p_info,abort_callback & p_abort); + t_filesize read_v2_(const file::ptr & file, file_info& outInfo, abort_callback& abort); FB2K_MAKE_SERVICE_COREAPI(tag_processor_trailing); }; +//! \since 2.2 +class NOVTABLE tag_processor_trailing_v2 : public tag_processor_trailing { + FB2K_MAKE_SERVICE_COREAPI_EXTENSION(tag_processor_trailing_v2, tag_processor_trailing); +public: + //! Returns tag offset, filesize_invalid if not found - does not throw exception_tag_not_found. + virtual t_filesize read_v2(const file::ptr & file, file_info& outInfo, abort_callback& abort) = 0; +}; + namespace tag_processor { //! Strips all recognized tags from the file and writes an ID3v1 tag with specified info. void write_id3v1(const service_ptr_t & p_file,const file_info & p_info,abort_callback & p_abort); @@ -85,17 +104,21 @@ namespace tag_processor { void remove_trailing(const service_ptr_t & p_file,abort_callback & p_abort); //! Removes ID3v2 tags from the file. Returns true when a tag was removed, false when the file was not altered. bool remove_id3v2(const service_ptr_t & p_file,abort_callback & p_abort); - //! Removes ID3v2 and trailing tags from specified file (not to be confused with trailing ID3v2 which are not yet supported). + //! Removes ID3v2 and trailing tags from specified file (not to be confused with trailing ID3v2 which are not supported). void remove_id3v2_trailing(const service_ptr_t & p_file,abort_callback & p_abort); - //! Reads trailing tags from the file. + //! Reads trailing tags from the file. Throws exception_tag_not_found if no tag was found. void read_trailing(const service_ptr_t & p_file,file_info & p_info,abort_callback & p_abort); - //! Reads trailing tags from the file. Extended version, returns offset at which parsed tags start. \n - //! p_tagoffset set to offset of found tags, to EOF if no tags were found. + //! Reads trailing tags from the file. Extended version, returns offset at which parsed tags start. Throws exception_tag_not_found if no tag was found. + //! p_tagoffset set to offset of found tags on success. void read_trailing_ex(const service_ptr_t & p_file,file_info & p_info,t_filesize & p_tagoffset,abort_callback & p_abort); - //! Reads ID3v2 tags from specified file. + //! Non-throwing version of read_trailing, returns offset at which tags begin, filesize_invalid if no tags found instead of throwing exception_tag_not_found. + t_filesize read_trailing_nothrow(const service_ptr_t& p_file, file_info& p_info, abort_callback& p_abort); + //! Reads ID3v2 tags from specified file. Throws exception_tag_not_found if no tag was found. void read_id3v2(const service_ptr_t & p_file,file_info & p_info,abort_callback & p_abort); - //! Reads ID3v2 and trailing tags from specified file (not to be confused with trailing ID3v2 which are not yet supported). + //! Reads ID3v2 and trailing tags from specified file (not to be confused with trailing ID3v2 which are not supported). Throws exception_tag_not_found if neither tag type was found. void read_id3v2_trailing(const service_ptr_t & p_file,file_info & p_info,abort_callback & p_abort); + //! Non-throwing version of read_id3v2_trailing, returns bool indicating whether any tag was read instead of throwing exception_tag_not_found. + bool read_id3v2_trailing_nothrow(const service_ptr_t& p_file, file_info& p_info, abort_callback& p_abort); void skip_id3v2(const service_ptr_t & p_file,t_filesize & p_size_skipped,abort_callback & p_abort); t_filesize skip_id3v2(file::ptr const & f, abort_callback & a); diff --git a/sdk/foobar2000/SDK/tag_processor_id3v2.cpp b/sdk/foobar2000/SDK/tag_processor_id3v2.cpp index 71ea6b7..6472436 100644 --- a/sdk/foobar2000/SDK/tag_processor_id3v2.cpp +++ b/sdk/foobar2000/SDK/tag_processor_id3v2.cpp @@ -103,7 +103,7 @@ void tag_processor_id3v2::g_skip_at(const service_ptr_t & p_file,t_filesiz try { p_file->seek ( p_base + ret, p_abort ); - } catch(exception_io_seek_out_of_range) { + } catch(exception_io_seek_out_of_range const &) { p_file->seek( p_base, p_abort ); p_size_skipped = 0; return; @@ -111,3 +111,17 @@ void tag_processor_id3v2::g_skip_at(const service_ptr_t & p_file,t_filesiz p_size_skipped = ret; } + +bool tag_processor_id3v2::read_v2_(file::ptr const& file, file_info& outInfo, abort_callback& abort) { + { + tag_processor_id3v2_v2::ptr v2; + if (v2 &= this) return v2->read_v2(file, outInfo, abort); + } + // emulate new behavior with old API + try { + this->read(file, outInfo, abort); + return true; + } catch (exception_io_data const&) { + return false; + } +} \ No newline at end of file diff --git a/sdk/foobar2000/SDK/threaded_process.cpp b/sdk/foobar2000/SDK/threaded_process.cpp index b8fc8ef..f86a108 100644 --- a/sdk/foobar2000/SDK/threaded_process.cpp +++ b/sdk/foobar2000/SDK/threaded_process.cpp @@ -59,8 +59,9 @@ void threaded_process_status::set_items(pfc::list_base_const_t cons if (count == 1) { set_item_path(items[0]); } pfc::string8 acc; + filesystem::ptr fs; for (size_t w = 0; w < count; ++w) { - pfc::string8 name = pfc::string_filename_ext(items[w]); + pfc::string8 name = fb2k::filename_ext(items[w], fs); if (w > 0 && acc.length() + name.length() > set_items_max_characters) { acc << " and " << (count - w) << " more"; break; @@ -78,8 +79,9 @@ void threaded_process_status::set_items(metadb_handle_list_cref items) { if ( count == 1 ) { set_item_path(items[0]->get_path()); } pfc::string8 acc; + filesystem::ptr fs; for( size_t w = 0; w < count; ++w ) { - pfc::string8 name = pfc::string_filename_ext(items[w]->get_path()); + pfc::string8 name = fb2k::filename_ext(items[w]->get_path(), fs); if ( w > 0 && acc.length() + name.length() > set_items_max_characters) { acc << " and " << (count-w) << " more"; break; diff --git a/sdk/foobar2000/SDK/threadsLite.h b/sdk/foobar2000/SDK/threadsLite.h index ca5ab18..1a25565 100644 --- a/sdk/foobar2000/SDK/threadsLite.h +++ b/sdk/foobar2000/SDK/threadsLite.h @@ -22,6 +22,9 @@ namespace fb2k { //! Call f synchronously if called from main thread, queue call if called from another. void inMainThread2(std::function f); + //! Clone abort_callback, suppress call if original abort_callback becomes set prior to reaching main thread. + void inMainThread(std::function f, abort_callback&); + //! Synchronous / abortable version. May exit *before* f() finishes, if abort becomes set. void inMainThreadSynchronous(std::function f, abort_callback& abort); diff --git a/sdk/foobar2000/SDK/timer.h b/sdk/foobar2000/SDK/timer.h index edab718..08a3f9f 100644 --- a/sdk/foobar2000/SDK/timer.h +++ b/sdk/foobar2000/SDK/timer.h @@ -2,6 +2,7 @@ #include #include "completion_notify.h" +#if FOOBAR2020 namespace fb2k { //! \since 2.0 class NOVTABLE timerManager : public service_base { @@ -13,3 +14,4 @@ namespace fb2k { objRef registerTimer( double interval, std::function func ); void callLater( double timeAfter, std::function< void () > func ); } +#endif // FOOBAR2020 \ No newline at end of file diff --git a/sdk/foobar2000/SDK/titleformat.h b/sdk/foobar2000/SDK/titleformat.h index 2a70fd5..12fdd95 100644 --- a/sdk/foobar2000/SDK/titleformat.h +++ b/sdk/foobar2000/SDK/titleformat.h @@ -1,12 +1,14 @@ #pragma once +#include "titleformat_object.h" + namespace titleformat_inputtypes { extern const GUID meta, unknown; }; class NOVTABLE titleformat_text_out { public: - virtual void write(const GUID & p_inputtype,const char * p_data,t_size p_data_length = ~0) = 0; + virtual void write(const GUID & p_inputtype,const char * p_data,t_size p_data_length = SIZE_MAX) = 0; void write_int(const GUID & p_inputtype,t_int64 val); void write_int_padded(const GUID & p_inputtype,t_int64 val,t_int64 maxval); protected: @@ -39,20 +41,6 @@ class NOVTABLE titleformat_hook virtual bool process_field(titleformat_text_out * p_out,const char * p_name,t_size p_name_length,bool & p_found_flag) = 0; virtual bool process_function(titleformat_text_out * p_out,const char * p_name,t_size p_name_length,titleformat_hook_function_params * p_params,bool & p_found_flag) = 0; }; -//! Represents precompiled executable title-formatting script. Use titleformat_compiler to instantiate; do not reimplement. -class NOVTABLE titleformat_object : public service_base -{ -public: - virtual void run(titleformat_hook * p_source,pfc::string_base & p_out,titleformat_text_filter * p_filter)=0; - - void run_hook(const playable_location & p_location,const file_info * p_source,titleformat_hook * p_hook,pfc::string_base & p_out,titleformat_text_filter * p_filter); - void run_simple(const playable_location & p_location,const file_info * p_source,pfc::string_base & p_out); - - //! Helper, see titleformat_object_v2::requires_metadb_info() - bool requires_metadb_info_(); - - FB2K_MAKE_SERVICE_INTERFACE(titleformat_object,service_base); -}; //! \since 2.0 class NOVTABLE titleformat_object_v2 : public titleformat_object { diff --git a/sdk/foobar2000/SDK/titleformat_object.h b/sdk/foobar2000/SDK/titleformat_object.h new file mode 100644 index 0000000..e3d7498 --- /dev/null +++ b/sdk/foobar2000/SDK/titleformat_object.h @@ -0,0 +1,20 @@ +#pragma once + +// titleformat_object extracted from titleformat.h as it's more commonly used than other titleformat.h stuff + +class file_info; class titleformat_hook; class titleformat_text_filter; + +//! Represents precompiled executable title-formatting script. Use titleformat_compiler to instantiate; do not reimplement. +class NOVTABLE titleformat_object : public service_base +{ +public: + virtual void run(titleformat_hook * p_source,pfc::string_base & p_out,titleformat_text_filter * p_filter)=0; + + void run_hook(const playable_location & p_location,const file_info * p_source,titleformat_hook * p_hook,pfc::string_base & p_out,titleformat_text_filter * p_filter); + void run_simple(const playable_location & p_location,const file_info * p_source,pfc::string_base & p_out); + + //! Helper, see titleformat_object_v2::requires_metadb_info() + bool requires_metadb_info_(); + + FB2K_MAKE_SERVICE_INTERFACE(titleformat_object,service_base); +}; diff --git a/sdk/foobar2000/SDK/ui.h b/sdk/foobar2000/SDK/ui.h index 9454f45..5795d5e 100644 --- a/sdk/foobar2000/SDK/ui.h +++ b/sdk/foobar2000/SDK/ui.h @@ -10,16 +10,14 @@ class NOVTABLE user_interface : public service_base { //!HookProc usage: \n //! in your windowproc, call HookProc first, and if it returns true, return LRESULT value it passed to you typedef BOOL (WINAPI * HookProc_t)(HWND wnd,UINT msg,WPARAM wp,LPARAM lp,LRESULT * ret); +#else + typedef void* HookProc_t; // RESERVED #endif //! Retrieves name (UTF-8 null-terminated string) of the UI module. virtual const char * get_name()=0; //! Initializes the UI module - creates the main app window, etc. Failure should be signaled by appropriate exception (std::exception or a derivative). \n //! Mac OS: return NSWindow cast to hwnd_t -#ifdef _WIN32 - virtual HWND init(HookProc_t hook)=0; -#else - virtual fb2k::hwnd_t init() = 0; -#endif + virtual fb2k::hwnd_t init(HookProc_t hook) = 0; //! Deinitializes the UI module - destroys the main app window, etc. virtual void shutdown()=0; //! Activates main app window. @@ -36,7 +34,7 @@ class NOVTABLE user_interface : public service_base { //! Disables statusbar text override. virtual void revert_statusbar_text() = 0; - //! Shows now-playing item somehow (e.g. system notification area popup). + //! Shows now-playing item somehow (e.g. system tray popup). virtual void show_now_playing() = 0; static bool g_find(service_ptr_t & p_out,const GUID & p_guid); @@ -65,15 +63,22 @@ class NOVTABLE user_interface_v2 : public user_interface { #endif }; -#ifdef _WIN32 class ui_config_manager; + //! \since 2.0 class NOVTABLE user_interface_v3 : public user_interface_v2 { FB2K_MAKE_SERVICE_INTERFACE(user_interface_v3, user_interface_v2); public: virtual service_ptr_t< ui_config_manager > get_config_manager() = 0; }; -#endif + +//! \since 2.1 +class NOVTABLE user_interface_v4 : public user_interface_v3 { + FB2K_MAKE_SERVICE_INTERFACE(user_interface_v4, user_interface_v3); +public: + static constexpr uint32_t flagHide = 1; + virtual fb2k::hwnd_t init_v4(HookProc_t hook, uint32_t flags) = 0; +}; //! Interface class allowing you to override UI statusbar text. There may be multiple callers trying to override statusbar text; backend decides which one succeeds so you will not always get what you want. Statusbar text override is automatically cancelled when the object is released.\n //! Use ui_control::override_status_text_create() to instantiate. @@ -246,7 +251,7 @@ class ui_selection_callback_impl_base : public ui_selection_callback { } //avoid pure virtual function calls in rare cases - provide a dummy implementation - void on_selection_changed(metadb_handle_list_cref p_selection) {} + void on_selection_changed(metadb_handle_list_cref p_selection) override {} PFC_CLASS_NOT_COPYABLE_EX(ui_selection_callback_impl_base); private: @@ -274,7 +279,7 @@ class ui_selection_callback_impl_base_ex : public ui_selection_callback { } //avoid pure virtual function calls in rare cases - provide a dummy implementation - void on_selection_changed(metadb_handle_list_cref p_selection) {} + void on_selection_changed(metadb_handle_list_cref p_selection) override {} PFC_CLASS_NOT_COPYABLE(ui_selection_callback_impl_base_ex, ui_selection_callback_impl_base_ex); private: diff --git a/sdk/foobar2000/SDK/ui_element.h b/sdk/foobar2000/SDK/ui_element.h index 49432d3..d3001ec 100644 --- a/sdk/foobar2000/SDK/ui_element.h +++ b/sdk/foobar2000/SDK/ui_element.h @@ -529,7 +529,7 @@ class NOVTABLE ui_element_common_methods_v3 : public ui_element_common_methods_v FB2K_MAKE_SERVICE_COREAPI_EXTENSION(ui_element_common_methods_v3, ui_element_common_methods_v2); public: //! Creates a "Replace UI Element" or "Add New UI Element" dialog. - //! @param parent Parent *element* window handle, the dialog will be a child of its parent popup window but centered on top of the specified window. + //! @param wndElem Parent *element* window handle, the dialog will be a child of its parent popup window but centered on top of the specified window. //! @param elemReplacing GUID of element being replaced; specify null to show "Add UI Element" dialog. //! @param notify Callback object receiving OK/Cancel notifications. //! @returns Handle to the newly created dialog. You can just destroy this window if you need to abort the dialog programatically. diff --git a/sdk/foobar2000/SDK/utility.cpp b/sdk/foobar2000/SDK/utility.cpp index 8218b87..9e1d92e 100644 --- a/sdk/foobar2000/SDK/utility.cpp +++ b/sdk/foobar2000/SDK/utility.cpp @@ -126,6 +126,7 @@ namespace fb2k { } +#if FOOBAR2020 // timer.h functionality #include "timer.h" #include @@ -135,9 +136,9 @@ namespace fb2k { PFC_ASSERT( core_api::is_main_thread() ); auto releaseMe = std::make_shared(); *releaseMe = registerTimer(timeAfter, [=] { - if (releaseMe->is_valid()) { - releaseMe->release(); + if (releaseMe->is_valid()) { // ensure we get here once func(); + releaseMe->release(); // warning: this should destroy objects that called us, hence func() call must go first } }); } @@ -146,6 +147,7 @@ namespace fb2k { return static_api_ptr_t()->addTimer(interval, makeCompletionNotify([func](unsigned) { func(); })); } } +#endif // FOOBAR2020 // autoplaylist.h functionality #include "autoplaylist.h" diff --git a/sdk/foobar2000/foo_sample/dsp_sample.cpp b/sdk/foobar2000/foo_sample/dsp_sample.cpp index 9514ef5..0818773 100644 --- a/sdk/foobar2000/foo_sample/dsp_sample.cpp +++ b/sdk/foobar2000/foo_sample/dsp_sample.cpp @@ -20,9 +20,7 @@ class dsp_sample : public dsp_impl_base } static GUID g_get_guid() { - //This is our GUID. Generate your own one when reusing this code. - static const GUID guid = { 0x890827b, 0x67df, 0x4c27, { 0xba, 0x1a, 0x4f, 0x95, 0x8d, 0xf, 0xb5, 0xd0 } }; - return guid; + return dsp_sample_common::guid; } static void g_get_name(pfc::string_base & p_out) { p_out = "Sample DSP";} diff --git a/sdk/foobar2000/foo_sample/dsp_sample.h b/sdk/foobar2000/foo_sample/dsp_sample.h index b0d6a2f..1e81044 100644 --- a/sdk/foobar2000/foo_sample/dsp_sample.h +++ b/sdk/foobar2000/foo_sample/dsp_sample.h @@ -1,6 +1,7 @@ #pragma once namespace dsp_sample_common { + //This is our GUID. Generate your own one when reusing this code. static constexpr GUID guid = { 0x890827b, 0x67df, 0x4c27, { 0xba, 0x1a, 0x4f, 0x95, 0x8d, 0xf, 0xb5, 0xd0 } }; static void make_preset(float gain, dsp_preset & out) { diff --git a/sdk/foobar2000/foo_sample/foo_sample.vcxproj b/sdk/foobar2000/foo_sample/foo_sample.vcxproj index dc4de5c..1ebf459 100644 --- a/sdk/foobar2000/foo_sample/foo_sample.vcxproj +++ b/sdk/foobar2000/foo_sample/foo_sample.vcxproj @@ -38,19 +38,20 @@ {85FBFD09-0099-4FE9-9DB6-78DB6F60F817} foo_input_raw Win32Proj + 10.0 DynamicLibrary Unicode true - v143 + v142 DynamicLibrary Unicode true - v143 + v142 DynamicLibrary @@ -67,12 +68,12 @@ DynamicLibrary Unicode - v143 + v142 DynamicLibrary Unicode - v143 + v142 DynamicLibrary diff --git a/sdk/foobar2000/foo_sample/foo_sample.xcodeproj/project.pbxproj b/sdk/foobar2000/foo_sample/foo_sample.xcodeproj/project.pbxproj index 6079040..9e757a8 100644 --- a/sdk/foobar2000/foo_sample/foo_sample.xcodeproj/project.pbxproj +++ b/sdk/foobar2000/foo_sample/foo_sample.xcodeproj/project.pbxproj @@ -313,7 +313,7 @@ .., ../.., ); - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -363,6 +363,7 @@ GCC_NO_COMMON_BLOCKS = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = stdafx.h; + GCC_PREPROCESSOR_DEFINITIONS = "NDEBUG=1"; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; @@ -373,7 +374,7 @@ .., ../.., ); - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = macosx; diff --git a/sdk/foobar2000/foo_sample/rating.cpp b/sdk/foobar2000/foo_sample/rating.cpp index 37b6912..861f03b 100644 --- a/sdk/foobar2000/foo_sample/rating.cpp +++ b/sdk/foobar2000/foo_sample/rating.cpp @@ -139,7 +139,7 @@ namespace { return ret; - } catch (exception_io_data) { + } catch (exception_io_data const &) { // we get here as a result of stream formatter data error // fall thru to return a blank record } diff --git a/sdk/foobar2000/foo_sample/ui_and_threads.cpp b/sdk/foobar2000/foo_sample/ui_and_threads.cpp index dcbf7bb..b143a26 100644 --- a/sdk/foobar2000/foo_sample/ui_and_threads.cpp +++ b/sdk/foobar2000/foo_sample/ui_and_threads.cpp @@ -124,7 +124,7 @@ namespace { // anon namespace local classes for good measure // In worker thread! try { work( shared, aborter ); - } catch(exception_aborted) { + } catch(exception_aborted const &) { return; // user abort? } catch(std::exception const & e) { // should not really get here diff --git a/sdk/foobar2000/foobar2000_component_client/foobar2000_component_client.vcxproj b/sdk/foobar2000/foobar2000_component_client/foobar2000_component_client.vcxproj index 51a2fdb..339e7ff 100644 --- a/sdk/foobar2000/foobar2000_component_client/foobar2000_component_client.vcxproj +++ b/sdk/foobar2000/foobar2000_component_client/foobar2000_component_client.vcxproj @@ -37,6 +37,7 @@ {71AD2674-065B-48F5-B8B0-E1F9D3892081} foobar2000_component_client + 10.0 @@ -44,14 +45,14 @@ false Unicode true - v143 + v142 StaticLibrary false Unicode true - v143 + v142 StaticLibrary @@ -71,13 +72,13 @@ StaticLibrary false Unicode - v143 + v142 StaticLibrary false Unicode - v143 + v142 StaticLibrary diff --git a/sdk/foobar2000/foobar2000_component_client/foobar2000_component_client.xcodeproj/project.pbxproj b/sdk/foobar2000/foobar2000_component_client/foobar2000_component_client.xcodeproj/project.pbxproj index 14f285e..7029197 100644 --- a/sdk/foobar2000/foobar2000_component_client/foobar2000_component_client.xcodeproj/project.pbxproj +++ b/sdk/foobar2000/foobar2000_component_client/foobar2000_component_client.xcodeproj/project.pbxproj @@ -170,7 +170,7 @@ .., ../.., ); - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -226,7 +226,7 @@ .., ../.., ); - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = macosx; diff --git a/sdk/foobar2000/helpers-mac/CFObject.h b/sdk/foobar2000/helpers-mac/CFObject.h index 0cc29b3..314af3d 100644 --- a/sdk/foobar2000/helpers-mac/CFObject.h +++ b/sdk/foobar2000/helpers-mac/CFObject.h @@ -1,57 +1,4 @@ #pragma once +#include +using pfc::CFObject; -#include - -template -class CFObject { -public: - typedef CFObject self_t; - type_t p = NULL; - - ~CFObject() { - if ( p ) CFRelease(p); - } - - void Retain(type_t * arg) { - if ( p ) CFRelease(p); - p = arg; - if ( p ) CFRetain(p); - } - - void Attach(type_t * arg) { - if ( p ) CFRelease(p); - p = arg; - } - - void operator=( self_t const & arg ) { - if ( p ) CFRelease(p); - p = arg.p; - if ( p ) CFRetain(p); - } - CFObject() {} - CFObject( self_t const & arg ) { - p = arg.p; - if ( p ) CFRetain(p); - } - - CFObject(self_t && arg ) { - p = arg.p; arg.p = NULL; - } - void operator=(self_t && arg) { - if ( p ) CFRelease(p); - p = arg.p; arg.p = NULL; - } - - operator bool() const { return p != NULL; } - operator type_t() const { return p;} - - - void reset() { - if ( p ) CFRelease(p); - p = NULL; - } - - void operator=(nullptr_t) { - reset(); - } -}; diff --git a/sdk/foobar2000/helpers-mac/NSAttributedString+ppaddons.h b/sdk/foobar2000/helpers-mac/NSAttributedString+ppaddons.h index 3a0170c..0fe24b3 100644 --- a/sdk/foobar2000/helpers-mac/NSAttributedString+ppaddons.h +++ b/sdk/foobar2000/helpers-mac/NSAttributedString+ppaddons.h @@ -6,4 +6,5 @@ + (NSAttributedString*) attributedStringWithImageNamed:(NSString *)name size: (NSSize) size; + (NSAttributedString*) attributedStringWithImageNamed:(NSString *)name squareSize: (CGFloat) size; + (NSAttributedString*) hyperlinkFromString:(NSString*)inString withURL:(NSURL*)aURL; ++ (NSAttributedString*) string: (NSString*) text withFont: (NSFont*) font; @end diff --git a/sdk/foobar2000/helpers-mac/NSAttributedString+ppaddons.m b/sdk/foobar2000/helpers-mac/NSAttributedString+ppaddons.m index a01aaf2..68bd2fa 100644 --- a/sdk/foobar2000/helpers-mac/NSAttributedString+ppaddons.m +++ b/sdk/foobar2000/helpers-mac/NSAttributedString+ppaddons.m @@ -45,5 +45,7 @@ +(NSAttributedString*)hyperlinkFromString:(NSString*)inString withURL:(NSURL*)aU return attrString; } - ++ (NSAttributedString*) string: (NSString*) text withFont: (NSFont*) font { + return [[self alloc] initWithString: text attributes:@{NSFontAttributeName: font}]; +} @end diff --git a/sdk/foobar2000/helpers/CModelessDialogMessages.h b/sdk/foobar2000/helpers/CModelessDialogMessages.h new file mode 100644 index 0000000..1eb7a5a --- /dev/null +++ b/sdk/foobar2000/helpers/CModelessDialogMessages.h @@ -0,0 +1,17 @@ +#pragma once +#include + +class CModelessDialogMessages { +public: + static BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult) { + switch (uMsg) { + case WM_INITDIALOG: + modeless_dialog_manager::g_add(hWnd); break; + case WM_DESTROY: + modeless_dialog_manager::g_remove(hWnd); break; + } + return FALSE; + } +}; + +#define FB2K_MODELESS_DIALOG_MESSAGES() CHAIN_MSG_MAP(CModelessDialogMessages) diff --git a/sdk/foobar2000/helpers/ProfileCache.h b/sdk/foobar2000/helpers/ProfileCache.h index e13f2e5..041cd97 100644 --- a/sdk/foobar2000/helpers/ProfileCache.h +++ b/sdk/foobar2000/helpers/ProfileCache.h @@ -15,7 +15,7 @@ namespace ProfileCache { try { fLocal = fsLocal->openWriteExisting(path, abort, timeoutVal ); fetch = fLocal->get_timestamp(abort) < filetimestamp_from_system_timer() - acceptableAge; - } catch(exception_io_not_found) { + } catch(exception_io_not_found const &) { fLocal = fsLocal->openWriteNew(path, abort, timeoutVal); fetch = true; } @@ -25,7 +25,7 @@ namespace ProfileCache { file::ptr fRemote; filesystem::g_open(fRemote, webURL, filesystem::open_mode_read, abort); file::g_transfer_file(fRemote, fLocal, abort ); - } catch(exception_io) { + } catch(exception_io const &) { fLocal.release(); try { retryOnSharingViolation(timeoutVal, abort, [&] {fsLocal->remove(path, abort);} ); diff --git a/sdk/foobar2000/helpers/ThreadUtils.cpp b/sdk/foobar2000/helpers/ThreadUtils.cpp index 5d806c6..e9604b1 100644 --- a/sdk/foobar2000/helpers/ThreadUtils.cpp +++ b/sdk/foobar2000/helpers/ThreadUtils.cpp @@ -7,21 +7,20 @@ namespace ThreadUtils { bool CRethrow::exec( std::function f ) throw() { - m_rethrow = nullptr; + m_exception = nullptr; bool rv = false; try { f(); rv = true; } catch( ... ) { - auto e = std::current_exception(); - m_rethrow = [e] { std::rethrow_exception(e); }; + m_exception = std::current_exception(); } return rv; } void CRethrow::rethrow() const { - if ( m_rethrow ) m_rethrow(); + if (m_exception) std::rethrow_exception(m_exception); } } #ifdef _WIN32 diff --git a/sdk/foobar2000/helpers/WindowPositionUtils.cpp b/sdk/foobar2000/helpers/WindowPositionUtils.cpp index c04171e..86fdae5 100644 --- a/sdk/foobar2000/helpers/WindowPositionUtils.cpp +++ b/sdk/foobar2000/helpers/WindowPositionUtils.cpp @@ -214,8 +214,15 @@ bool cfgWindowPosition::apply_to_window(HWND wnd, bool allowHidden) { return data.applyTo( wnd, allowHidden ); } -void cfgWindowPosition::windowCreated(HWND wnd, bool allowHidden) { - if (!apply_to_window(wnd, allowHidden)) { - ::ShowWindow( wnd, SW_SHOWDEFAULT ); +void cfgWindowPosition::windowCreated(HWND wnd, bool allowHidden, DWORD showHow) { + auto data = get(); + switch (showHow) { + case SW_HIDE: + case SW_MINIMIZE: + data.m_wp.showCmd = showHow; + break; + } + if (!data.applyTo(wnd, allowHidden)) { + ::ShowWindow( wnd, showHow); } } \ No newline at end of file diff --git a/sdk/foobar2000/helpers/WindowPositionUtils.h b/sdk/foobar2000/helpers/WindowPositionUtils.h index 78b0b10..a4d6566 100644 --- a/sdk/foobar2000/helpers/WindowPositionUtils.h +++ b/sdk/foobar2000/helpers/WindowPositionUtils.h @@ -133,7 +133,7 @@ FB2K_STREAM_READER_OVERLOAD(cfgDialogPositionData) { stream >> value.m_width >> value.m_height; try { stream >> value.m_posX >> value.m_posY >> value.m_dpiX >> value.m_dpiY; - } catch (exception_io_data) { + } catch (exception_io_data const &) { value.m_posX = value.m_posY = cfgDialogPositionData::posInvalid; value.m_dpiX = value.m_dpiY = cfgDialogPositionData::dpiInvalid; } @@ -165,7 +165,7 @@ class cfgWindowPosition : public cfg_struct_t { //! Apply saved size data to HWND. bool apply_to_window(HWND, bool allowHidden = false); //! New window created, show it with saved metrics. - void windowCreated(HWND, bool allowHidden = false); + void windowCreated(HWND, bool allowHidden = false, DWORD showHow = SW_SHOW); }; class cfgDialogPositionTracker { diff --git a/sdk/foobar2000/helpers/atl-misc.h b/sdk/foobar2000/helpers/atl-misc.h index 01be5fa..f7e6b73 100644 --- a/sdk/foobar2000/helpers/atl-misc.h +++ b/sdk/foobar2000/helpers/atl-misc.h @@ -249,7 +249,7 @@ namespace fb2k { static void AppendMenuPopup(HMENU menu, UINT flags, CMenu & popup, const TCHAR * label) { PFC_ASSERT( flags & MF_POPUP ); - WIN32_OP( CMenuHandle(menu).AppendMenu(flags, popup, label) ); + WIN32_OP_D( CMenuHandle(menu).AppendMenu(flags, popup, label) ); popup.Detach(); } diff --git a/sdk/foobar2000/helpers/cfg_obj.h b/sdk/foobar2000/helpers/cfg_obj.h index db37004..c22c50a 100644 --- a/sdk/foobar2000/helpers/cfg_obj.h +++ b/sdk/foobar2000/helpers/cfg_obj.h @@ -36,7 +36,7 @@ namespace cfg_var_modern { try { stream_reader_formatter<> fmt(*p_stream, p_abort); fmt >> o; - } catch (exception_io_data) { return; } + } catch (exception_io_data const &) { return; } set(std::move(o)); } #endif @@ -54,7 +54,7 @@ namespace cfg_var_modern { try { stream_reader_formatter_simple<> source(blob->data(), blob->size()); source >> v; - } catch (exception_io_data) { + } catch (exception_io_data const &) { v = m_initVal; // revert } } diff --git a/sdk/foobar2000/helpers/create_directory_helper.cpp b/sdk/foobar2000/helpers/create_directory_helper.cpp index ef9e50b..1a7f88c 100644 --- a/sdk/foobar2000/helpers/create_directory_helper.cpp +++ b/sdk/foobar2000/helpers/create_directory_helper.cpp @@ -1,15 +1,23 @@ #include "StdAfx.h" #include "create_directory_helper.h" #include +#include namespace create_directory_helper { static void create_path_internal(const char * p_path,t_size p_base,abort_callback & p_abort) { pfc::string8_fastalloc temp; + auto fs = filesystem::get(p_path); + auto api_lock = file_lock_manager::get(); for(t_size walk = p_base; p_path[walk]; walk++) { if (p_path[walk] == '\\') { temp.set_string(p_path,walk); - try {filesystem::g_create_directory(temp.get_ptr(),p_abort);} catch(exception_io_already_exists) {} + // 2024-03 Google Drive bug: + // Creating the same folder concurrently from multiple threads causes erratic behavior + // Thread that got here first behaves OK, others get "already exists" and return, but creating files in the folder fail with "path not found" + // Block other threads trying to do the same until we've finished + const auto lock = api_lock->acquire_write(temp, p_abort); + fs->make_directory(temp, p_abort); } } } @@ -90,7 +98,7 @@ namespace create_directory_helper { if (!last_char_is_dir_sep) { - if (really_create_dirs) try{filesystem::g_create_directory(out,p_abort);}catch(exception_io_already_exists){} + if (really_create_dirs) try{filesystem::g_create_directory(out,p_abort);}catch(exception_io_already_exists const &){} out.add_char('\\'); last_char_is_dir_sep = true; } diff --git a/sdk/foobar2000/helpers/cue_creator.cpp b/sdk/foobar2000/helpers/cue_creator.cpp index 6ca36e6..36502d3 100644 --- a/sdk/foobar2000/helpers/cue_creator.cpp +++ b/sdk/foobar2000/helpers/cue_creator.cpp @@ -2,23 +2,14 @@ #include "cue_creator.h" #include "../SDK/chapterizer.h" -namespace { - - class format_meta - { - public: - format_meta(const file_info & p_source,const char * p_name,bool p_allow_space = true) - { - p_source.meta_format(p_name,m_buffer); - m_buffer.replace_byte('\"','\''); - uReplaceString(m_buffer,pfc::string8(m_buffer),pfc_infinite,"\x0d\x0a",2,"\\",1,false); - if (!p_allow_space) m_buffer.replace_byte(' ','_'); - m_buffer.replace_nontext_chars(); - } - inline operator const char*() const {return m_buffer;} - private: - pfc::string8_fastalloc m_buffer; - }; +static pfc::string8 format_meta(const file_info& p_source, const char* p_name, bool p_allow_space = true) { + pfc::string8 temp, ret; + p_source.meta_format(p_name, temp); + temp.replace_byte('\"', '\''); + uReplaceString(ret, temp, pfc_infinite, "\x0d\x0a", 2, "\\", 1, false); + if (!p_allow_space) ret.replace_byte(' ', '_'); + ret.replace_nontext_chars(); + return ret; } static bool is_meta_same_everywhere(const cue_creator::t_entry_list & p_list,const char * p_meta) @@ -26,14 +17,14 @@ static bool is_meta_same_everywhere(const cue_creator::t_entry_list & p_list,con pfc::string8_fastalloc reference,temp; bool first = true; - for(auto iter = p_list.first(); iter.is_valid(); ++ iter ) { - if ( ! iter->isTrackAudio() ) continue; + for(auto & iter : p_list) { + if ( ! iter.isTrackAudio() ) continue; if ( first ) { first = false; - if (!iter->m_infos.meta_format(p_meta,reference)) return false; + if (!iter.m_infos.meta_format(p_meta,reference)) return false; } else { - if (!iter->m_infos.meta_format(p_meta,temp)) return false; + if (!iter.m_infos.meta_format(p_meta,temp)) return false; if (strcmp(temp,reference)!=0) return false; } } @@ -77,6 +68,12 @@ namespace cue_creator if (comment_global) { p_out << "REM COMMENT " << format_meta(firstTrack->m_infos,"comment") << g_eol; } + if (is_meta_same_everywhere(p_data, "discnumber")) { + p_out << "REM DISCNUMBER " << format_meta(firstTrack->m_infos, "discnumber") << g_eol; + } + if (is_meta_same_everywhere(p_data, "totaldiscs")) { + p_out << "REM TOTALDISCS " << format_meta(firstTrack->m_infos, "totaldiscs") << g_eol; + } if (catalog_global) { p_out << "CATALOG " << format_meta(firstTrack->m_infos,"catalog") << g_eol; } diff --git a/sdk/foobar2000/helpers/cue_parser.cpp b/sdk/foobar2000/helpers/cue_parser.cpp index d4ed561..7eec463 100644 --- a/sdk/foobar2000/helpers/cue_parser.cpp +++ b/sdk/foobar2000/helpers/cue_parser.cpp @@ -27,20 +27,15 @@ static bool is_linebreak(char c) } static void validate_file_type(const char * p_type,t_size p_type_length) { - if ( - //standard types - stricmp_utf8_ex(p_type,p_type_length,"WAVE",pfc_infinite) != 0 && - stricmp_utf8_ex(p_type,p_type_length,"MP3",pfc_infinite) != 0 && - stricmp_utf8_ex(p_type,p_type_length,"AIFF",pfc_infinite) != 0 && - //common user-entered types - stricmp_utf8_ex(p_type,p_type_length,"APE",pfc_infinite) != 0 && - stricmp_utf8_ex(p_type,p_type_length,"FLAC",pfc_infinite) != 0 && - stricmp_utf8_ex(p_type,p_type_length,"WV",pfc_infinite) != 0 && - stricmp_utf8_ex(p_type,p_type_length,"WAVPACK",pfc_infinite) != 0 && - // BINARY - stricmp_utf8_ex(p_type,p_type_length,"BINARY",pfc_infinite) != 0 - ) - pfc::throw_exception_with_message< exception_cue >(PFC_string_formatter() << "expected WAVE, MP3 or AIFF, got : \"" << pfc::string_part(p_type,p_type_length) << "\""); + const char* const allowedTypes[] = { + "WAVE", "MP3", "AIFF", // standard typers + "APE", "FLAC", "WV", "WAVPACK", "MP4", // common user-entered types + "BINARY" // BINARY + }; + for (auto walk : allowedTypes) { + if (pfc::stringEqualsI_ascii_ex(p_type, p_type_length, walk, SIZE_MAX)) return; + } + pfc::throw_exception_with_message< exception_cue >(PFC_string_formatter() << "expected WAVE, MP3 or AIFF, got : \"" << pfc::string_part(p_type,p_type_length) << "\""); } namespace { @@ -72,9 +67,9 @@ namespace { protected: static bool is_known_meta(const char * p_name,t_size p_length) { - static const char * metas[] = {"genre","date","discid","comment","replaygain_track_gain","replaygain_track_peak","replaygain_album_gain","replaygain_album_peak"}; + static const char * metas[] = {"genre","date","discid","comment","replaygain_track_gain","replaygain_track_peak","replaygain_album_gain","replaygain_album_peak", "discnumber", "totaldiscs"}; for (const char* m : metas) { - if (!stricmp_utf8_ex(p_name, p_length, m, pfc_infinite)) return true; + if (!stricmp_utf8_ex(p_name, p_length, m, SIZE_MAX)) return true; } return false; } diff --git a/sdk/foobar2000/helpers/cuesheet_index_list.cpp b/sdk/foobar2000/helpers/cuesheet_index_list.cpp index a851a51..d323134 100644 --- a/sdk/foobar2000/helpers/cuesheet_index_list.cpp +++ b/sdk/foobar2000/helpers/cuesheet_index_list.cpp @@ -3,10 +3,6 @@ #include "cue_parser.h" // exception_bad_cuesheet -#ifndef _MSC_VER -#define sprintf_s sprintf -#endif - bool t_cuesheet_index_list::is_valid() const { if (m_positions[1] < m_positions[0]) return false; for(t_size n = 2; n < count && m_positions[n] > 0; n++) { diff --git a/sdk/foobar2000/helpers/fb2kWorkerTool.h b/sdk/foobar2000/helpers/fb2kWorkerTool.h index 486b669..e5c5657 100644 --- a/sdk/foobar2000/helpers/fb2kWorkerTool.h +++ b/sdk/foobar2000/helpers/fb2kWorkerTool.h @@ -48,7 +48,7 @@ namespace fb2k { pThis->workDone(); } }); - } catch(exception_aborted) {} + } catch(exception_aborted const &) {} } ); } } diff --git a/sdk/foobar2000/helpers/file_list_helper.h b/sdk/foobar2000/helpers/file_list_helper.h index af721da..fcf33dc 100644 --- a/sdk/foobar2000/helpers/file_list_helper.h +++ b/sdk/foobar2000/helpers/file_list_helper.h @@ -2,13 +2,15 @@ namespace file_list_helper { + typedef pfc::list_base_const_t base_t; + //list guaranteed to be sorted by metadb::path_compare - class file_list_from_metadb_handle_list : public pfc::list_base_const_t { + class file_list_from_metadb_handle_list : public base_t { public: file_list_from_metadb_handle_list() {} file_list_from_metadb_handle_list( metadb_handle_list_cref lst, bool bDisplayPaths = false ); - static t_size g_get_count(const list_base_const_t & p_list, t_size max = ~0); + static t_size g_get_count(const list_base_const_t & p_list, t_size max = SIZE_MAX); void init_from_list(const list_base_const_t & p_list); void init_from_list_display(const list_base_const_t & p_list); @@ -22,7 +24,5 @@ namespace file_list_helper void _add(const char * p_what); pfc::ptr_list_t m_data; }; - - }; diff --git a/sdk/foobar2000/helpers/foobar2000_SDK_helpers.xcodeproj/project.pbxproj b/sdk/foobar2000/helpers/foobar2000_SDK_helpers.xcodeproj/project.pbxproj index 6fd2dc0..56f136b 100644 --- a/sdk/foobar2000/helpers/foobar2000_SDK_helpers.xcodeproj/project.pbxproj +++ b/sdk/foobar2000/helpers/foobar2000_SDK_helpers.xcodeproj/project.pbxproj @@ -710,7 +710,7 @@ .., ); IPHONEOS_DEPLOYMENT_TARGET = 12.1; - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 11.0; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; SKIP_INSTALL = YES; @@ -768,7 +768,7 @@ .., ); IPHONEOS_DEPLOYMENT_TARGET = 12.1; - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 11.0; SDKROOT = macosx; SKIP_INSTALL = YES; }; diff --git a/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj b/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj index 2e38ddd..26a97da 100644 --- a/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj +++ b/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj @@ -37,19 +37,20 @@ {EE47764E-A202-4F85-A767-ABDAB4AFF35F} foobar2000_sdk_helpers + 10.0 StaticLibrary false Unicode - v143 + v142 StaticLibrary false Unicode - v143 + v142 StaticLibrary @@ -68,14 +69,14 @@ false Unicode true - v143 + v142 StaticLibrary false Unicode true - v143 + v142 StaticLibrary @@ -515,6 +516,7 @@ + diff --git a/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj.filters b/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj.filters index 5e32b96..eaed348 100644 --- a/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj.filters +++ b/sdk/foobar2000/helpers/foobar2000_sdk_helpers.vcxproj.filters @@ -418,5 +418,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/sdk/foobar2000/helpers/input_helpers.cpp b/sdk/foobar2000/helpers/input_helpers.cpp index 62d237b..9265d48 100644 --- a/sdk/foobar2000/helpers/input_helpers.cpp +++ b/sdk/foobar2000/helpers/input_helpers.cpp @@ -7,6 +7,10 @@ #include #include "readers_lite.h" +#define LOCAL_DEBUG_PRINT(...) // PFC_DEBUG_PRINT(__VA_ARGS__) + +#define FILE_DECODEDAUDIO_PRINT(...) LOCAL_DEBUG_PRINT("file_decodeaudio(", pfc::format_ptr(this), "): ", __VA_ARGS__) + input_helper::ioFilter_t input_helper::ioFilter_full_buffer(t_filesize val) { if (val == 0) return nullptr; return [val] ( file_ptr & f, const char * path, abort_callback & aborter) { @@ -16,7 +20,7 @@ input_helper::ioFilter_t input_helper::ioFilter_full_buffer(t_filesize val) { try { f = createFileMemMirrorAsync(f, nullptr, aborter); return true; - } catch (std::bad_alloc) {} // keep orig file object + } catch (std::bad_alloc const &) {} // keep orig file object } } return false; @@ -38,6 +42,15 @@ input_helper::ioFilter_t input_helper::ioFilter_block_buffer(size_t arg) { }; } +static bool looksLikePlaylist(filesystem::ptr const& fs, const char* path) { + auto ext = fs->get_extension(path); + // match against common internet playlist extensions + // yes, this could query fb2k services instead, but uses a fixed list by design + for (auto walk : { "m3u", "pls", "m3u8", "asx" }) { + if (pfc::stringEqualsI_ascii(walk, ext)) return true; + } + return false; +} static input_helper::ioFilter_t makeReadAhead(size_t arg, bool bRemote) { if (arg == 0) return nullptr; @@ -46,6 +59,7 @@ static input_helper::ioFilter_t makeReadAhead(size_t arg, bool bRemote) { filesystem::ptr fs; if (!filesystem::g_get_interface(fs, p_path)) return false; if (bRemote != fs->is_remote(p_path)) return false; + if (looksLikePlaylist(fs, p_path)) return false; fs->open(p_file, p_path, filesystem::open_mode_read, p_abort); } else if (bRemote != p_file->is_remote()) return false; if (p_file->is_in_memory()) return false; @@ -62,9 +76,13 @@ input_helper::ioFilter_t input_helper::ioFilter_local_read_ahead(size_t arg) { return makeReadAhead(arg, false); } -void input_helper::open(service_ptr_t p_filehint,metadb_handle_ptr p_location,unsigned p_flags,abort_callback & p_abort,bool p_from_redirect,bool p_skip_hints) +void input_helper::open(trackRef location, abort_callback & abort, decodeOpen_t const & other) { + this->open( trackGetLocation(location), abort, other); +} + +void input_helper::open(service_ptr_t p_filehint,trackRef p_location,unsigned p_flags,abort_callback & p_abort,bool p_from_redirect,bool p_skip_hints) { - open(p_filehint,p_location->get_location(),p_flags,p_abort,p_from_redirect,p_skip_hints); + open(p_filehint,trackGetLocation( p_location ),p_flags,p_abort,p_from_redirect,p_skip_hints); } bool input_helper::test_if_lockless(abort_callback& a) { @@ -78,7 +96,7 @@ bool input_helper::test_if_lockless(abort_callback& a) { try { fileOpenWriteExisting(m_path, a); return true; - } catch (exception_io) {} + } catch (exception_io const &) {} } } #endif @@ -119,12 +137,16 @@ bool input_helper::open_path(const char * path, abort_callback & abort, decodeOp m_input ^= input_entry::g_open(input_decoder::class_guid, l_file, path, m_logger, abort, other.m_from_redirect ); ); -#ifdef FOOBAR2000_HAVE_METADB if (!other.m_skip_hints) { try { + if ( other.m_infoHook ) { + other.m_infoHook( m_input, path, abort ); + } +#ifdef FOOBAR2000_HAVE_METADB metadb_io::get()->hint_reader(m_input.get_ptr(), path, abort); +#endif } - catch (exception_io_data) { + catch (exception_io_data const &) { //Don't fail to decode when this barfs, might be barfing when reading info from another subsong than the one we're trying to decode etc. m_input.release(); if (l_file.is_valid()) l_file->reopen(abort); @@ -133,7 +155,6 @@ bool input_helper::open_path(const char * path, abort_callback & abort, decodeOp ); } } -#endif if (other.m_shim) m_input = other.m_shim(m_input, path, abort); @@ -202,7 +223,7 @@ bool input_helper::run_raw_v2(audio_chunk& p_chunk, mem_block_container& p_raw, try { return v2->run_raw(p_chunk, p_raw, p_abort); // UGLY: it may STILL FAIL with exception_not_implemented due to some underlying code not being able to handle the request!! - } catch (pfc::exception_not_implemented) {} + } catch (pfc::exception_not_implemented const &) {} } if (!m_input->run(p_chunk, p_abort)) return false; @@ -293,7 +314,7 @@ void input_helper::g_set_info(const playable_location & p_location,file_info & p instance->commit(p_abort); } - +#ifdef FOOBAR2000_HAVE_METADB bool dead_item_filter::run(const pfc::list_base_const_t & p_list,bit_array_var & p_mask) { file_list_helper::file_list_from_metadb_handle_list path_list; path_list.init_from_list(p_list); @@ -358,6 +379,8 @@ bool input_helper::g_mark_dead(const pfc::list_base_const_t & return filter.run(p_list,p_mask); } +#endif // #ifdef FOOBAR2000_HAVE_METADB + void input_info_read_helper::open(const char * p_path,abort_callback & p_abort) { if (m_input.is_empty() || playable_location::path_compare(m_path,p_path) != 0) { @@ -375,6 +398,7 @@ void input_info_read_helper::get_info(const playable_location & p_location,file_ TRACK_CODE("input_info_reader::get_info",m_input->get_info(p_location.get_subsong_index(),p_info,p_abort)); } +#ifdef FOOBAR2000_HAVE_METADB void input_info_read_helper::get_info_check(const playable_location & p_location,file_info & p_info,t_filestats & p_stats,bool & p_reloaded,abort_callback & p_abort) { open(p_location.get_path(),p_abort); t_filestats newstats; @@ -387,18 +411,20 @@ void input_info_read_helper::get_info_check(const playable_location & p_location p_reloaded = false; } } - - - +#endif // #ifdef FOOBAR2000_HAVE_METADB // openAudioData code +static constexpr openAudioDataFormat formatNative = (sizeof(audio_sample) == sizeof(double)) ? openAudioDataFormat::float64 : openAudioDataFormat::float32; + namespace { class file_decodedaudio : public file_readonly { public: - void init(const playable_location & loc, input_helper::decodeOpen_t const & arg, abort_callback & aborter) { + void init(const playable_location & loc, input_helper::decodeOpen_t const & arg, openAudioDataFormat format, abort_callback & aborter) { + FILE_DECODEDAUDIO_PRINT("opening: ", loc ); m_length = -1; m_lengthKnown = false; + m_format = format; m_subsong = loc.get_subsong(); m_decoder ^= input_entry::g_open( input_decoder::class_guid, arg.m_hint, loc.get_path(), arg.m_logger, aborter, arg.m_from_redirect); m_seekable = ( arg.m_flags & input_flag_no_seeking ) == 0 && m_decoder->can_seek(); @@ -407,6 +433,7 @@ namespace { readChunk(aborter, true); } void init(const playable_location & loc, bool bSeekable, file::ptr fileHint, abort_callback & aborter) { + FILE_DECODEDAUDIO_PRINT("opening: ", loc); m_length = -1; m_lengthKnown = false; m_subsong = loc.get_subsong(); input_entry::g_open_for_decoding(m_decoder, fileHint, loc.get_path(), aborter); @@ -415,7 +442,7 @@ namespace { readChunk(aborter, true); } - void reopen(abort_callback & aborter) { + void reopen(abort_callback & aborter) override { // Have valid chunk and it is the first chunk in the stream? Reset read pointers and bail, no need to reopen if (m_chunk.get_sample_count() > 0 && m_chunkBytesPtr == m_currentPosition) { @@ -429,22 +456,22 @@ namespace { readChunk(aborter); } - bool is_remote() { + bool is_remote() override { return false; } - t_filetimestamp get_timestamp(abort_callback & p_abort) { + t_filetimestamp get_timestamp(abort_callback & p_abort) override { return m_decoder->get_file_stats(p_abort).m_timestamp; } - void on_idle(abort_callback & p_abort) { + void on_idle(abort_callback & p_abort) override { m_decoder->on_idle(p_abort); } - bool get_content_type(pfc::string_base & p_out) { + bool get_content_type(pfc::string_base & p_out) override { return false; } - bool can_seek() { + bool can_seek() override { return m_seekable; } - void seek(t_filesize p_position, abort_callback & p_abort) { + void seek(t_filesize p_position, abort_callback & p_abort) override { if (!m_seekable) throw exception_io_object_not_seekable(); @@ -464,8 +491,7 @@ namespace { if (s != filesize_invalid) { if (p_position > s) throw exception_io_seek_out_of_range(); if (p_position == s) { - m_chunk.reset(); - m_chunkBytesPtr = 0; + m_chunk.reset(); m_curChunkBytes = 0; m_chunkBytesPtr = 0; m_currentPosition = p_position; m_eof = true; return; @@ -475,7 +501,7 @@ namespace { - const size_t row = m_spec.chanCount * sizeof(audio_sample); + const auto row = m_spec.chanCount * sampleBytes(); t_filesize samples = p_position / row; const double seekTime = audio_math::samples_to_time(samples, m_spec.sampleRate); m_decoder->seek(seekTime, p_abort); @@ -494,15 +520,16 @@ namespace { m_eof = false; } - t_filesize get_size(abort_callback & aborter) { + t_filesize get_size(abort_callback & aborter) override { const double l = length(aborter); if (l <= 0) return filesize_invalid; - return audio_math::time_to_samples(l, m_spec.sampleRate) * m_spec.chanCount * sizeof(audio_sample); + return audio_math::time_to_samples(l, m_spec.sampleRate) * m_spec.chanCount * sampleBytes(); } - t_filesize get_position(abort_callback & p_abort) { + t_filesize get_position(abort_callback & p_abort) override { return m_currentPosition; } - t_size read(void * p_buffer, t_size p_bytes, abort_callback & p_abort) { + t_size read(void * p_buffer, t_size p_bytes, abort_callback & p_abort) override { + FILE_DECODEDAUDIO_PRINT("read(", p_bytes, ")"); size_t done = 0; for (;;) { p_abort.check(); @@ -510,7 +537,7 @@ namespace { const size_t inChunk = curChunkBytes(); const size_t inChunkRemaining = inChunk - m_chunkBytesPtr; const size_t delta = pfc::min_t(inChunkRemaining, (p_bytes - done)); - memcpy((uint8_t*)p_buffer + done, (const uint8_t*)m_chunk.get_data() + m_chunkBytesPtr, delta); + memcpy((uint8_t*)p_buffer + done, (const uint8_t*)m_curChunkPtr + m_chunkBytesPtr, delta); m_chunkBytesPtr += delta; done += delta; m_currentPosition += delta; @@ -519,6 +546,7 @@ namespace { } if (!readChunk(p_abort)) break; } + FILE_DECODEDAUDIO_PRINT("read(", p_bytes, ") returning ", done); return done; } audio_chunk::spec_t const & get_spec() const { return m_spec; } @@ -532,22 +560,47 @@ namespace { m_currentPosition = 0; } size_t curChunkBytes() const { - return m_chunk.get_used_size() * sizeof(audio_sample); + return m_curChunkBytes; } bool readChunk(abort_callback & aborter, bool initial = false) { m_chunkBytesPtr = 0; + FILE_DECODEDAUDIO_PRINT("readChunk()"); for (;;) { if (m_eof || !m_decoder->run(m_chunk, aborter)) { if (initial) throw std::runtime_error("Decoder produced no data"); m_eof = true; - m_chunk.reset(); + m_chunk.reset(); m_curChunkBytes = 0; + FILE_DECODEDAUDIO_PRINT("readChunk() EOF"); return false; } if (m_chunk.is_valid()) break; } + PFC_ASSERT(m_chunk.get_peak() < 100); audio_chunk::spec_t spec = m_chunk.get_spec(); if (initial) m_spec = spec; else if (m_spec != spec) throw std::runtime_error("Sample format change in mid stream"); + + auto inPtr = m_chunk.get_data(); + const size_t inCount = m_chunk.get_used_size(); + m_curChunkBytes = inCount * sampleBytes(); + FILE_DECODEDAUDIO_PRINT("readChunk(): ", m_chunk.get_sample_count(), " samples, ", m_curChunkBytes, " bytes"); + if ( m_format == formatNative ) { + m_curChunkPtr = inPtr; + } else { + m_altFormatBuffer.grow_size(m_curChunkBytes); + m_curChunkPtr = m_altFormatBuffer.get_ptr(); + switch (m_format) { + case openAudioDataFormat::float32: + { auto out = reinterpret_cast(m_curChunkPtr); for (size_t walk = 0; walk < inCount; ++walk) out[walk] = (float)inPtr[walk]; } + break; + case openAudioDataFormat::float64: + { auto out = reinterpret_cast(m_curChunkPtr); for (size_t walk = 0; walk < inCount; ++walk) out[walk] = (double)inPtr[walk]; } + break; + default: + PFC_ASSERT(!"???"); + } + } + return true; } double length(abort_callback & aborter) { @@ -559,6 +612,9 @@ namespace { } return m_length; } + unsigned sampleBytes() const { + return m_format == openAudioDataFormat::float32 ? 4 : 8; + } audio_chunk_fast_impl m_chunk; size_t m_chunkBytesPtr; audio_chunk::spec_t m_spec; @@ -570,13 +626,18 @@ namespace { bool m_eof; t_filesize m_currentPosition; unsigned m_flags = 0; + openAudioDataFormat m_format = formatNative; + + pfc::array_t m_altFormatBuffer; + void* m_curChunkPtr = nullptr; + size_t m_curChunkBytes = 0; }; } -openAudioData_t openAudioData2(playable_location const & loc, input_helper::decodeOpen_t const & openArg, abort_callback & aborter) { +openAudioData_t openAudioData3(playable_location const& loc, input_helper::decodeOpen_t const& openArg, openAudioDataFormat format, abort_callback& aborter) { service_ptr_t f; f = new service_impl_t < file_decodedaudio >; - f->init(loc, openArg, aborter); + f->init(loc, openArg, format, aborter); openAudioData_t oad = {}; oad.audioData = f; @@ -584,6 +645,10 @@ openAudioData_t openAudioData2(playable_location const & loc, input_helper::deco return oad; } +openAudioData_t openAudioData2(playable_location const & loc, input_helper::decodeOpen_t const & openArg, abort_callback & aborter) { + return openAudioData3(loc, openArg, formatNative, aborter); +} + openAudioData_t openAudioData(playable_location const & loc, bool bSeekable, file::ptr fileHint, abort_callback & aborter) { service_ptr_t f; f = new service_impl_t < file_decodedaudio > ; f->init(loc, bSeekable, fileHint, aborter); diff --git a/sdk/foobar2000/helpers/input_helpers.h b/sdk/foobar2000/helpers/input_helpers.h index d16b636..d35c263 100644 --- a/sdk/foobar2000/helpers/input_helpers.h +++ b/sdk/foobar2000/helpers/input_helpers.h @@ -3,12 +3,14 @@ #include #include #include +#include class input_helper { public: input_helper(); typedef std::function shim_t; + typedef std::function infoHook_t; typedef std::function< bool ( file::ptr &, const char *, abort_callback & ) > ioFilter_t; typedef std::list ioFilters_t; @@ -28,15 +30,17 @@ class input_helper { ioFilters_t m_ioFilters; event_logger::ptr m_logger; + infoHook_t m_infoHook; shim_t m_shim; }; - void open(service_ptr_t p_filehint,metadb_handle_ptr p_location,unsigned p_flags,abort_callback & p_abort,bool p_from_redirect = false,bool p_skip_hints = false); void open(service_ptr_t p_filehint,const playable_location & p_location,unsigned p_flags,abort_callback & p_abort,bool p_from_redirect = false,bool p_skip_hints = false); void attach(input_decoder::ptr dec, const char * path); void open(const playable_location & location, abort_callback & abort, decodeOpen_t const & other); - void open(metadb_handle_ptr location, abort_callback & abort, decodeOpen_t const & other) {this->open(location->get_location(), abort, other);} + + void open(service_ptr_t p_filehint,trackRef p_location,unsigned p_flags,abort_callback & p_abort,bool p_from_redirect = false,bool p_skip_hints = false); + void open(trackRef location, abort_callback & abort, decodeOpen_t const & other); //! Multilevel open helpers. @@ -92,8 +96,10 @@ class input_helper { static void g_set_info(const playable_location & p_location,file_info & p_info,abort_callback & p_abort,bool p_from_redirect = false); +#ifdef FOOBAR2000_HAVE_METADB static bool g_mark_dead(const pfc::list_base_const_t & p_list,bit_array_var & p_mask,abort_callback & p_abort); - +#endif + static void fileOpenTools(service_ptr_t& p_file, const char* p_path, ioFilters_t const& filters, abort_callback& p_abort); bool test_if_lockless(abort_callback&); @@ -107,18 +113,22 @@ class input_helper { event_logger::ptr m_logger; }; +#ifdef FOOBAR2000_HAVE_METADB class NOVTABLE dead_item_filter : public abort_callback { public: virtual void on_progress(t_size p_position,t_size p_total) = 0; bool run(const pfc::list_base_const_t & p_list,bit_array_var & p_mask); }; +#endif class input_info_read_helper { public: input_info_read_helper() {} void get_info(const playable_location & p_location,file_info & p_info,t_filestats & p_stats,abort_callback & p_abort); +#ifdef FOOBAR2000_HAVE_METADB void get_info_check(const playable_location & p_location,file_info & p_info,t_filestats & p_stats,bool & p_reloaded,abort_callback & p_abort); +#endif private: void open(const char * p_path,abort_callback & p_abort); @@ -127,8 +137,6 @@ class input_info_read_helper { }; - - //! openAudioData return value, see openAudioData() struct openAudioData_t { file::ptr audioData; // audio data stream @@ -144,3 +152,11 @@ struct openAudioData_t { //! However, if you want 100% functionality regardless of file format being worked with, mirror the content to a temp file and let go of the file object returned by openAudioData(). openAudioData_t openAudioData(playable_location const & loc, bool bSeekable, file::ptr fileHint, abort_callback & aborter); openAudioData_t openAudioData2(playable_location const & loc, input_helper::decodeOpen_t const & openArg, abort_callback & aborter); + + +//! openAudioData3 allows explicit format: float32 or float64, for use cases that need such. +enum class openAudioDataFormat { + float32, + float64 +}; +openAudioData_t openAudioData3(playable_location const& loc, input_helper::decodeOpen_t const& openArg, openAudioDataFormat format, abort_callback& aborter); diff --git a/sdk/foobar2000/helpers/readers.cpp b/sdk/foobar2000/helpers/readers.cpp index dc54aad..543d28b 100644 --- a/sdk/foobar2000/helpers/readers.cpp +++ b/sdk/foobar2000/helpers/readers.cpp @@ -6,6 +6,7 @@ #include #include #include +#include t_size reader_membuffer_base::read(void * p_buffer, t_size p_bytes, abort_callback & p_abort) { p_abort.check_e(); @@ -45,7 +46,7 @@ file::ptr fullFileBuffer::open(const char * path, abort_callback & abort, file:: r->init(f, abort); f = r; } - catch (std::bad_alloc) {} + catch (std::bad_alloc const &) {} return f; } @@ -59,7 +60,7 @@ file::ptr fullFileBuffer::open(const char * path, abort_callback & abort, file:: #include -#include "rethrow.h" +#include #include #include @@ -74,9 +75,10 @@ namespace { pfc::array_t m_buffer; size_t m_bufferBegin, m_bufferEnd; - pfc::event m_canRead, m_canWrite; + pfc::event m_canRead; + pfc::event_std m_canWrite; pfc::mutex m_guard; - ThreadUtils::CRethrow m_error; + std::exception_ptr m_error; t_filesize m_seekto; abort_callback_impl m_abort; bool m_remote; @@ -86,7 +88,7 @@ namespace { std::list m_dynamicInfo; }; typedef std::shared_ptr readAheadInstanceRef; - static const t_filesize seek_reopen = (filesize_invalid-1); + static constexpr t_filesize seek_reopen = (filesize_invalid-1); class fileReadAhead : public file_readonly_t< service_multi_inherit< service_multi_inherit, stream_receive > > { service_ptr m_metadata; public: @@ -153,7 +155,7 @@ namespace { pfc::mutexScope guard ( i.m_guard ); size_t got = i.m_bufferEnd - i.m_bufferBegin; if (got == 0) { - i.m_error.rethrow(); + if (i.m_error) std::rethrow_exception(i.m_error); if ( initial && ! i.m_atEOF ) { initial = false; continue; // proceed to wait for more data } @@ -171,7 +173,7 @@ namespace { got -= delta; m_position += delta; - if (!i.m_error.didFail() && !i.m_atEOF) { + if (!i.m_error && !i.m_atEOF) { if ( got == 0 ) i.m_canRead.set_state( false ); const bool wakeUpNow = got < i.m_wakeUpThreschold; // Only set the event when *crossing* the boundary @@ -269,7 +271,7 @@ namespace { void seekInternal( t_filesize p_position ) { auto & i = * m_instance; insync( i.m_guard ); - i.m_error.rethrow(); + if (i.m_error) std::rethrow_exception(i.m_error); i.m_bufferBegin = i.m_bufferEnd = 0; i.m_canWrite.set_state(true); i.m_seekto = p_position; @@ -279,11 +281,10 @@ namespace { m_position = ( p_position == seek_reopen ) ? 0 : p_position; } static void worker( readAheadInstance_t & i ) { - ThreadUtils::CRethrow err; - err.exec( [&i] { + try { bool atEOF = false; uint8_t* bufptr = i.m_buffer.get_ptr(); - const size_t readAtOnceLimit = i.m_remote ? 256 : 4*1024; + const size_t readAtOnceLimit = i.m_remote ? 64*1024 : 256 * 1024; for ( ;; ) { i.m_canWrite.wait_for(-1); size_t readHowMuch = 0, readOffset = 0; @@ -361,11 +362,9 @@ namespace { } } - } ); - - if ( err.didFail( ) ) { - pfc::mutexScope guard( i.m_guard ); - i.m_error = err; + } catch (...) { + pfc::mutexScope guard(i.m_guard); + i.m_error = std::current_exception(); i.m_canRead.set_state(true); } } @@ -490,7 +489,7 @@ namespace { bool m_is_remote = false; pfc::string8 m_contentType; service_ptr m_metadata; - t_filesize m_position = 0; + size_t m_position = 0; fb2k::thread m_thread; public: ~file_memMirrorAsync() { @@ -535,7 +534,7 @@ namespace { void seek(t_filesize p_position, abort_callback& p_abort) override { if (p_position > get_size(p_abort)) throw exception_io_seek_out_of_range(); - m_position = p_position; + m_position = (size_t)p_position; } bool can_seek() override { return true; } @@ -582,7 +581,7 @@ namespace { PFC_ASSERT(total >= m_position ); auto left = total - m_position; if (p_bytes > left) p_bytes = left; - m_position += p_bytes; + m_position += (size_t)p_bytes; return p_bytes; } }; diff --git a/sdk/foobar2000/helpers/readers.h b/sdk/foobar2000/helpers/readers.h index 246d00f..61f0ea0 100644 --- a/sdk/foobar2000/helpers/readers.h +++ b/sdk/foobar2000/helpers/readers.h @@ -161,12 +161,12 @@ class reader_limited : public file_readonly_t { if (positionWas == filesize_invalid || positionWas > position) { r->reopen(abort); try { r->skip_object(position, abort); } - catch (exception_io_data) { throw exception_io_seek_out_of_range(); } + catch (exception_io_data const &) { throw exception_io_seek_out_of_range(); } } else { t_filesize skipMe = position - positionWas; if (skipMe > 0) { try { r->skip_object(skipMe, abort); } - catch (exception_io_data) { throw exception_io_seek_out_of_range(); } + catch (exception_io_data const &) { throw exception_io_seek_out_of_range(); } } } } diff --git a/sdk/foobar2000/helpers/rethrow.h b/sdk/foobar2000/helpers/rethrow.h index 81a09bb..dde4124 100644 --- a/sdk/foobar2000/helpers/rethrow.h +++ b/sdk/foobar2000/helpers/rethrow.h @@ -2,14 +2,16 @@ #include +#include + namespace ThreadUtils { class CRethrow { private: - std::function m_rethrow; + std::exception_ptr m_exception; public: bool exec( std::function f ) throw(); void rethrow() const; - bool didFail() const { return !! m_rethrow; } - void clear() { m_rethrow = nullptr; } + bool didFail() const { return !!m_exception; } + void clear() { m_exception = nullptr; } }; } diff --git a/sdk/foobar2000/helpers/tag_write_callback_impl.h b/sdk/foobar2000/helpers/tag_write_callback_impl.h index b0723ea..58d143f 100644 --- a/sdk/foobar2000/helpers/tag_write_callback_impl.h +++ b/sdk/foobar2000/helpers/tag_write_callback_impl.h @@ -23,7 +23,7 @@ class tag_write_callback_impl : public tag_write_callback { service_ptr_t l_tempfile; try { openTempFile(l_tempfile, p_abort); - } catch(exception_io) {return false;} + } catch(exception_io const &) {return false;} p_out = m_tempfile = l_tempfile; return true; } @@ -38,7 +38,7 @@ class tag_write_callback_impl : public tag_write_callback { if (p_owner.is_valid()) { try { file::g_copy_creation_time(p_owner, m_tempfile, p_abort); - } catch (exception_io) {} + } catch (exception_io const &) {} } m_tempfile.release(); diff --git a/sdk/foobar2000/helpers/ui_element_helpers.cpp b/sdk/foobar2000/helpers/ui_element_helpers.cpp index 895e7f7..934e2a4 100644 --- a/sdk/foobar2000/helpers/ui_element_helpers.cpp +++ b/sdk/foobar2000/helpers/ui_element_helpers.cpp @@ -44,7 +44,7 @@ namespace ui_element_helpers { if (!find(ptr,cfg->get_guid())) return NULL; try { return ptr->enumerate_children(cfg); - } catch(exception_io_data) { + } catch(exception_io_data const &) { return NULL; } } @@ -120,7 +120,7 @@ void ui_element_helpers::ui_element_edit_tools::standard_edit_context_menu(LPARA } CMenu menu; - WIN32_OP( menu.CreatePopupMenu() ); + WIN32_OP_D( menu.CreatePopupMenu() ); const GUID sourceItemGuid = p_item->get_guid(); const bool sourceItemEmpty = !!(sourceItemGuid == pfc::guid_null); @@ -304,7 +304,7 @@ bool ui_element_helpers::recurse_for_elem_config(ui_element_config::ptr root, ui ui_element_children_enumerator::ptr children; try { children = elem->enumerate_children(root); - } catch(exception_io_data) {return false;} + } catch(exception_io_data const &) {return false;} if (children.is_empty()) return false; const t_size childrenTotal = children->get_count(); for(t_size walk = 0; walk < childrenTotal; ++walk) { @@ -367,7 +367,7 @@ void ui_element_instance_standard_context_menu(service_ptr_tedit_mode_context_menu_test(pt, fromKeyboard)) { const unsigned idBase = 1; CMenu menu; - WIN32_OP(menu.CreatePopupMenu()); + WIN32_OP_D(menu.CreatePopupMenu()); p_elem->edit_mode_context_menu_build(pt, fromKeyboard, menu, idBase); int cmd; diff --git a/sdk/foobar2000/helpers/writer_wav.cpp b/sdk/foobar2000/helpers/writer_wav.cpp index c1ee01f..766c0db 100644 --- a/sdk/foobar2000/helpers/writer_wav.cpp +++ b/sdk/foobar2000/helpers/writer_wav.cpp @@ -14,6 +14,7 @@ static const GUID guid_RIFF = pfc::GUID_from_text("66666972-912E-11CF-A5D6-28DB0 static const GUID guid_WAVE = pfc::GUID_from_text("65766177-ACF3-11D3-8CD1-00C04F8EDB8A"); static const GUID guid_FMT = pfc::GUID_from_text("20746D66-ACF3-11D3-8CD1-00C04F8EDB8A"); static const GUID guid_DATA = pfc::GUID_from_text("61746164-ACF3-11D3-8CD1-00C04F8EDB8A"); +static const GUID guid_JUNK = pfc::GUID_from_text("6b6E756A-ACF3-11D3-8CD1-00C04f8EDB8A"); struct RIFF_chunk_desc { GUID m_guid; @@ -25,6 +26,7 @@ static const RIFF_chunk_desc RIFF_chunks[] = { {guid_WAVE, "WAVE"}, {guid_FMT , "fmt "}, {guid_DATA, "data"}, + {guid_JUNK, "JUNK"}, }; bool wavWriterSetup_t::needWFXE() const { @@ -56,17 +58,13 @@ void wavWriterSetup_t::initialize3(const audio_chunk::spec_t & spec, unsigned bp m_float = bFloat; m_dither = bDither; m_wave64 = bWave64; + + m_rf64_explicit = false; + m_rf64_implicit = false; } void wavWriterSetup_t::initialize2(const audio_chunk & p_chunk, unsigned p_bps, unsigned p_bpsValid, bool p_float, bool p_dither, bool p_wave64) { - m_bps = p_bps; - m_bpsValid = p_bpsValid; - m_samplerate = p_chunk.get_srate(); - m_channels = p_chunk.get_channels(); - m_channel_mask = p_chunk.get_channel_config(); - m_float = p_float; - m_dither = p_dither; - m_wave64 = p_wave64; + initialize3(p_chunk.get_spec(), p_bps, p_bpsValid, p_float, p_dither, p_wave64); } void wavWriterSetup_t::initialize(const audio_chunk & p_chunk, unsigned p_bps, bool p_float, bool p_dither, bool p_wave64) @@ -102,9 +100,9 @@ void CWavWriter::writeID(const GUID & id, abort_callback & abort) { if (is64()) { m_file->write_object_t(id, abort); } else { - for(t_size walk = 0; walk < PFC_TABSIZE(RIFF_chunks); ++walk) { - if (id == RIFF_chunks[walk].m_guid) { - m_file->write(RIFF_chunks[walk].m_name, 4, abort); return; + for( auto & walk : RIFF_chunks) { + if (id == walk.m_guid) { + m_file->write(walk.m_name, 4, abort); return; } } uBugCheck(); @@ -113,11 +111,11 @@ void CWavWriter::writeID(const GUID & id, abort_callback & abort) { void CWavWriter::writeSize(t_uint64 size, abort_callback & abort) { if (is64()) { - if (size != ~0) size += 24; + if (size != UINT64_MAX) size += 24; m_file->write_lendian_t(size, abort); } else { t_uint32 clipped; - if (size > 0xFFFFFFFF) clipped = 0xFFFFFFFF; + if (size > UINT32_MAX) clipped = UINT32_MAX; else clipped = (t_uint32) size; m_file->write_lendian_t(clipped, abort); } @@ -166,23 +164,40 @@ void CWavWriter::open(service_ptr_t p_file, const wavWriterSetup_t & p_set m_wfxe = m_setup.needWFXE(); - writeID(guid_RIFF, p_abort); + if (m_setup.m_wave64) { + m_file->write_object_t(guid_RIFF, p_abort); + } else if (m_setup.m_rf64_explicit) { + m_file->write("RF64", 4, p_abort); + } else { + m_file->write("RIFF", 4, p_abort); + } + m_offset_fix1 = m_file->get_position(p_abort); - writeSize(~0, p_abort); + writeSize(UINT64_MAX, p_abort); writeID(guid_WAVE, p_abort); - + + if (!is64() && m_file->can_seek() && (m_setup.m_rf64_explicit || m_setup.m_rf64_implicit)) { + // write JUNK placeholder for DS64 + m_ds64_at = m_file->get_position(p_abort); + static const uint8_t dummy[28] = {}; // riffsize64, datasize64, samplecount64, tablecount32 + writeID(guid_JUNK, p_abort); + writeSize(sizeof(dummy), p_abort); + m_file->write_object(dummy, sizeof(dummy), p_abort); + } + + writeID(guid_FMT, p_abort); if (m_wfxe) { writeSize(sizeof(WAVEFORMATEXTENSIBLE),p_abort); - WAVEFORMATEXTENSIBLE wfxe; + WAVEFORMATEXTENSIBLE wfxe = {}; m_setup.setup_wfxe(wfxe); m_file->write_object(&wfxe,sizeof(wfxe),p_abort); } else { writeSize(sizeof(PCMWAVEFORMAT),p_abort); - WAVEFORMATEX wfx; + WAVEFORMATEX wfx = {}; m_setup.setup_wfx(wfx); m_file->write_object(&wfx,/* blah */ sizeof(PCMWAVEFORMAT),p_abort); } @@ -193,7 +208,6 @@ void CWavWriter::open(service_ptr_t p_file, const wavWriterSetup_t & p_set writeSize(UINT64_MAX, p_abort); m_offset_fix1_delta = m_file->get_position(p_abort) - chunkOverhead(); - m_bytes_written = 0; if (!m_setup.m_float) @@ -236,9 +250,30 @@ void CWavWriter::finalize(abort_callback & p_abort) if (m_file->can_seek()) { m_file->seek(m_offset_fix1,p_abort); - writeSize(m_bytes_written + alignG + m_offset_fix1_delta, p_abort); + const uint64_t riffSize = m_bytes_written + alignG + m_offset_fix1_delta; + writeSize(riffSize, p_abort); m_file->seek(m_offset_fix2,p_abort); writeSize(m_bytes_written, p_abort); + + if (!is64() && (m_setup.m_rf64_explicit || (m_setup.m_rf64_implicit && m_bytes_written > UINT32_MAX))) { + if (!m_setup.m_rf64_explicit) { // turn RIFF into RF64? + m_file->seek(0, p_abort); + m_file->write("RF64", 4, p_abort); + } + m_file->seek(m_ds64_at, p_abort); + m_file->write("ds64", 4, p_abort); + writeSize(28, p_abort); + + // RIFF size, data size, sample count + m_file->write_lendian_t(riffSize, p_abort); + m_file->write_lendian_t(m_bytes_written, p_abort); + + unsigned sampleBytes = (m_setup.m_bps + 7) / 8 * m_setup.m_channels; + uint64_t samples = m_bytes_written / sampleBytes; + m_file->write_lendian_t(samples, p_abort); + uint32_t tableCount = 0; + m_file->write_lendian_t(tableCount, p_abort); + } } m_file.release(); } @@ -262,7 +297,7 @@ audio_chunk::spec_t CWavWriter::get_spec() const { namespace { class fileWav : public foobar2000_io::file { public: - size_t read( void * buffer, size_t bytes, abort_callback & aborter ) { + size_t read( void * buffer, size_t bytes, abort_callback & aborter ) override { aborter.check(); uint8_t * out = (uint8_t*) buffer; size_t ret = 0; @@ -281,10 +316,9 @@ class fileWav : public foobar2000_io::file { } return ret; } - void write( const void * buffer, size_t bytes, abort_callback & aborter ) { + void write( const void * buffer, size_t bytes, abort_callback & aborter ) override { throw exception_io_denied(); } - // old fb2k SDK workaround fileWav( std::vector const & header, file::ptr data) { m_data = data; m_position = 0; @@ -295,34 +329,25 @@ class fileWav : public foobar2000_io::file { m_position = 0; m_header = std::move(header); } - t_filesize get_size(abort_callback & p_abort) { + t_filesize get_size(abort_callback & p_abort) override { t_filesize s = m_data->get_size( p_abort ); if (s != filesize_invalid) s += m_header.size(); return s; } - t_filesize get_position(abort_callback & p_abort) { + t_filesize get_position(abort_callback & p_abort) override { return m_position; } - void resize(t_filesize p_size,abort_callback & p_abort) { + void resize(t_filesize p_size,abort_callback & p_abort) override { throw exception_io_denied(); } - void seek(t_filesize p_position,abort_callback & p_abort) { + void seek(t_filesize p_position,abort_callback & p_abort) override { if (p_position > get_size(p_abort)) throw exception_io_seek_out_of_range(); m_position = p_position; } - bool can_seek() { - return true; - } - bool get_content_type(pfc::string_base & p_out) { return false; } - void reopen(abort_callback & p_abort) { seek(0, p_abort); } - bool is_remote() { - return m_data->is_remote(); - } - t_filestats get_stats(abort_callback & p_abort) { - t_filestats s = m_data->get_stats( p_abort ); - if (s.m_size != filesize_invalid) s.m_size += m_header.size(); - return s; - } + bool can_seek() override {return true; } + bool get_content_type(pfc::string_base & p_out) override { return false; } + void reopen(abort_callback & p_abort) override { seek(0, p_abort); } + bool is_remote() override { return m_data->is_remote(); } private: std::vector m_header; t_filesize m_position; diff --git a/sdk/foobar2000/helpers/writer_wav.h b/sdk/foobar2000/helpers/writer_wav.h index 6907dc8..bc42aa3 100644 --- a/sdk/foobar2000/helpers/writer_wav.h +++ b/sdk/foobar2000/helpers/writer_wav.h @@ -10,6 +10,7 @@ struct wavWriterSetup_t { unsigned m_bps,m_bpsValid,m_samplerate,m_channels,m_channel_mask; bool m_float,m_dither, m_wave64; + bool m_rf64_implicit, m_rf64_explicit; void initialize(const audio_chunk & p_chunk,unsigned p_bps,bool p_float,bool p_dither, bool p_wave64 = false); @@ -41,13 +42,13 @@ class CWavWriter void writeSize(t_uint64 size, abort_callback & abort); bool is64() const {return m_setup.m_wave64;} t_uint32 chunkOverhead() const {return is64() ? 24 : 8;} - t_uint32 idOverhead() const {return is64() ? 16 : 4;} void writeID(const GUID & id, abort_callback & abort); service_ptr_t m_file; service_ptr_t m_postprocessor; wavWriterSetup_t m_setup; - bool m_wfxe; - t_uint64 m_offset_fix1,m_offset_fix2,m_offset_fix1_delta,m_bytes_written; + bool m_wfxe = false; + t_uint64 m_offset_fix1 = 0,m_offset_fix2 = 0,m_offset_fix1_delta = 0,m_bytes_written = 0; + uint64_t m_ds64_at = 0; mem_block_container_aligned_incremental_impl<16> m_postprocessor_output; }; diff --git a/sdk/foobar2000/shared/Utility.cpp b/sdk/foobar2000/shared/Utility.cpp index 842bc2d..14999f8 100644 --- a/sdk/foobar2000/shared/Utility.cpp +++ b/sdk/foobar2000/shared/Utility.cpp @@ -51,13 +51,6 @@ static unsigned CALLBACK createFileThread(void* p) { } -typedef BOOL (WINAPI * pCancelSynchronousIo_t)(HANDLE hThread); -static BOOL myCancelSynchronousIo(HANDLE hThread) { - pCancelSynchronousIo_t pCancelSynchronousIo = (pCancelSynchronousIo_t) GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "CancelSynchronousIo"); - if (pCancelSynchronousIo == NULL) {SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE;} - return pCancelSynchronousIo(hThread); -} - HANDLE SHARED_EXPORT CreateFileAbortable( __in LPCWSTR lpFileName, __in DWORD dwDesiredAccess, __in DWORD dwShareMode, @@ -113,11 +106,11 @@ HANDLE SHARED_EXPORT CreateFileAbortable( __in LPCWSTR lpFileName, break; case WAIT_OBJECT_0 + 1: // aborted dwErrorCode = ERROR_OPERATION_ABORTED; - myCancelSynchronousIo(hThread); + CancelSynchronousIo(hThread); break; default: // unexpected, use last-error code from WFMO dwErrorCode = GetLastError(); - myCancelSynchronousIo(hThread); + CancelSynchronousIo(hThread); break; } req->Release(); diff --git a/sdk/foobar2000/shared/crash_info.cpp b/sdk/foobar2000/shared/crash_info.cpp index e01f3ab..70b1ae9 100644 --- a/sdk/foobar2000/shared/crash_info.cpp +++ b/sdk/foobar2000/shared/crash_info.cpp @@ -585,6 +585,7 @@ void SHARED_EXPORT uPrintCrashInfo_OnEvent(const char * message, t_size length) pfc::string8 msg = pfc::format("[", queryDebugTimer(), "ms] "); msg.add_string( message, length ); + uOutputDebugString(msg + "\n"); insync(g_lastEventsSync); logEvent(msg); diff --git a/sdk/foobar2000/shared/fb2kdebug.h b/sdk/foobar2000/shared/fb2kdebug.h index e4f5d26..5382638 100644 --- a/sdk/foobar2000/shared/fb2kdebug.h +++ b/sdk/foobar2000/shared/fb2kdebug.h @@ -1,5 +1,7 @@ #pragma once +#include + class uDebugLog_ : public pfc::string_formatter { public: ~uDebugLog_() {*this << "\n"; uOutputDebugString(get_ptr());} @@ -77,8 +79,8 @@ inline int uExceptFilterProc_inline(LPEXCEPTION_POINTERS param) { #define FB2K_DYNAMIC_ASSERT( X ) { if (!(X)) uBugCheck(); } -#define __except_instacrash __except(uExceptFilterProc(GetExceptionInformation())) #if FB2K_SUPPORT_CRASH_LOGS +#define __except_instacrash __except(uExceptFilterProc(GetExceptionInformation())) #define fb2k_instacrash_scope(X) __try { X; } __except_instacrash {} #else #define fb2k_instacrash_scope(X) {X;} @@ -160,11 +162,18 @@ namespace fb2k { uAddDebugEvent(msg); uBugCheck(); } + inline void crashOnException(std::function const & f, const char* context = nullptr) { + fb2k_instacrash_scope(f()); + } #else void crashWithMessage [[noreturn]] (const char*); + void crashOnException(std::function, const char* context = nullptr); #endif + } +#define FB2K_CrashOnException( ... ) ::fb2k::crashWithMessage(__VA_ARGS__) + // implement me #define FB2K_TRACE_ENABLED 0 diff --git a/sdk/foobar2000/shared/filedialogs.cpp b/sdk/foobar2000/shared/filedialogs.cpp index 9629ac8..5a3f12a 100644 --- a/sdk/foobar2000/shared/filedialogs.cpp +++ b/sdk/foobar2000/shared/filedialogs.cpp @@ -48,7 +48,7 @@ BOOL SHARED_EXPORT uGetOpenFileName(HWND parent,const char * p_ext_mask,unsigned TRACK_CALL_TEXT("uGetOpenFileName"); try { if (UseVistaDialogs()) return Vista_GetOpenFileName(parent, p_ext_mask, def_ext_mask, p_def_ext, p_title, p_directory, p_filename, b_save); - } catch(pfc::exception_not_implemented) {} + } catch(pfc::exception_not_implemented const &) {} modal_dialog_scope scope; @@ -100,7 +100,7 @@ puGetOpenFileNameMultiResult SHARED_EXPORT uGetOpenFileNameMulti(HWND parent,con if (!Vista_GetOpenFileNameMulti(parent,p_ext_mask,def_ext_mask,p_def_ext,p_title,p_directory,result)) return NULL; return result.detach(); } - } catch(pfc::exception_not_implemented) {} + } catch(pfc::exception_not_implemented const &) {} modal_dialog_scope scope; @@ -276,7 +276,7 @@ BOOL SHARED_EXPORT uBrowseForFolder(HWND parent,const char * p_title,pfc::string if (UseVistaDialogs()) { return Vista_BrowseForFolder(parent,p_title,out); } - } catch(pfc::exception_not_implemented) {} + } catch(pfc::exception_not_implemented const &) {} TCHAR temp[MAX_PATH]; pfc::stringToBuffer(temp,dTEXT(out)); @@ -306,7 +306,7 @@ puGetOpenFileNameMultiResult SHARED_EXPORT uBrowseForFolderEx(HWND parent,const if (UseVistaDialogs()) { return Vista_BrowseForFolderEx(parent,title, initPath); } - } catch(pfc::exception_not_implemented) {} + } catch(pfc::exception_not_implemented const &) {} pfc::string8 temp; if (initPath) temp = initPath; diff --git a/sdk/foobar2000/shared/filedialogs_vista.cpp b/sdk/foobar2000/shared/filedialogs_vista.cpp index a1b7976..4110eb3 100644 --- a/sdk/foobar2000/shared/filedialogs_vista.cpp +++ b/sdk/foobar2000/shared/filedialogs_vista.cpp @@ -94,7 +94,7 @@ namespace { pfc::refcounted_object_ptr_t ptr; ptr.attach( reinterpret_cast( arg ) ); CoInitialize(0); - SFGAOF dummy; + SFGAOF dummy = {}; ptr->m_result = SHParseDisplayName(dTEXT(ptr->m_path),NULL,&ptr->m_idList.m_ptr,0,&dummy); CoUninitialize(); @@ -398,7 +398,7 @@ puGetOpenFileNameMultiResult Vista_BrowseForFolderEx(HWND parent,const char * p_ } if (result->GetCount() == 0) return NULL; return result.detach(); - } catch(exception_com) { + } catch(exception_com const &) { return NULL; } } @@ -445,7 +445,7 @@ puGetOpenFileNameMultiResult SHARED_EXPORT uEvalKnownFolder(REFKNOWNFOLDERID id) } if (result->get_count() == 0) return NULL; return result.detach(); - } catch(exception_com) { + } catch(exception_com const &) { //failed } @@ -459,7 +459,7 @@ puGetOpenFileNameMultiResult SHARED_EXPORT uEvalKnownFolder(REFKNOWNFOLDERID id) pfc::ptrholder_t result = new uGetOpenFileNameMultiResult_impl; result->AddItem(pfc::stringcvt::string_utf8_from_os(path.m_ptr)); return result.detach(); - } catch (exception_com) { + } catch (exception_com const &) { } @@ -477,7 +477,7 @@ puGetOpenFileNameMultiResult SHARED_EXPORT uEvalKnownFolder(REFKNOWNFOLDERID id) pfc::ptrholder_t result = new uGetOpenFileNameMultiResult_impl; result->AddItem(pfc::stringcvt::string_utf8_from_os_ex( path ) ); return result.detach(); - } catch(exception_com) { + } catch(exception_com const &) { //failed; } } @@ -489,7 +489,7 @@ puGetOpenFileNameMultiResult SHARED_EXPORT uEvalKnownFolder(REFKNOWNFOLDERID id) EH << SHGetKnownFolderPath(id, 0, NULL, nameBuf.Receive()); result->AddItem(pfc::stringcvt::string_utf8_from_os_ex( nameBuf.m_ptr ) ); return result.detach(); - } catch(exception_com) { + } catch(exception_com const &) { //failed } #endif diff --git a/sdk/foobar2000/shared/shared-apple.mm b/sdk/foobar2000/shared/shared-apple.mm index 6223656..ba615c8 100644 --- a/sdk/foobar2000/shared/shared-apple.mm +++ b/sdk/foobar2000/shared/shared-apple.mm @@ -29,3 +29,32 @@ bool uGetClipboardString(pfc::string_base & out) { } return rv; } + +void fb2k::crashOnException(std::function f, const char * context) { + auto fail = [context] ( const char * msg ) { + if (context) { + fb2k::crashWithMessage(pfc::format(context, ": ", msg)); + } else { + fb2k::crashWithMessage(msg); + } + }; + try { + @autoreleasepool { + @try { + f(); + } @catch(NSException * e) { + auto header = pfc::format("NSException: ", e.name.UTF8String, " reason: ", e.reason.UTF8String ); + uAddDebugEvent( header ); + uAddDebugEvent("Stack:"); + for(NSString * str in e.callStackSymbols ) { + uAddDebugEvent(str.UTF8String); + } + fail(header); + } + } + } catch(std::exception const & e) { + fail(pfc::format("C++ exception: ", e.what())); + } catch(...) { + fail("Invalid exception"); + } +} diff --git a/sdk/foobar2000/shared/shared-nix.cpp b/sdk/foobar2000/shared/shared-nix.cpp index de8d1c3..d87f918 100644 --- a/sdk/foobar2000/shared/shared-nix.cpp +++ b/sdk/foobar2000/shared/shared-nix.cpp @@ -191,7 +191,7 @@ pfc::string8 uGetTempFileName() { void fb2k::crashWithMessage [[noreturn]] ( const char * msg_ ) { - // there used to be code throwing Objective-C exceptions, but those were of no use, + uAddDebugEvent( msg_ ); pfc::crashWithMessageOnStack(msg_); } diff --git a/sdk/foobar2000/shared/shared.h b/sdk/foobar2000/shared/shared.h index b0b2494..c7d7b90 100644 --- a/sdk/foobar2000/shared/shared.h +++ b/sdk/foobar2000/shared/shared.h @@ -231,7 +231,7 @@ int SHARED_EXPORT uTabCtrl_SetItem(HWND wnd,t_size idx,const uTCITEM * item); int SHARED_EXPORT uGetKeyNameText(LONG lparam,pfc::string_base & out); -void SHARED_EXPORT uFixAmpersandChars(const char * src,pfc::string_base & out);//for notification area icon +void SHARED_EXPORT uFixAmpersandChars(const char * src,pfc::string_base & out);//for system tray icon void SHARED_EXPORT uFixAmpersandChars_v2(const char * src,pfc::string_base & out);//for other controls #if FB2K_SUPPORT_CRASH_LOGS diff --git a/sdk/foobar2000/shared/shared.vcxproj b/sdk/foobar2000/shared/shared.vcxproj index db8b677..72a5887 100644 --- a/sdk/foobar2000/shared/shared.vcxproj +++ b/sdk/foobar2000/shared/shared.vcxproj @@ -38,19 +38,20 @@ {054C606B-17BF-4540-AC4E-A9A7243628B8} shared Win32Proj + 10.0 DynamicLibrary Unicode true - v143 + v142 DynamicLibrary Unicode true - v143 + v142 DynamicLibrary @@ -67,12 +68,12 @@ DynamicLibrary Unicode - v143 + v142 DynamicLibrary Unicode - v143 + v142 DynamicLibrary @@ -365,24 +366,7 @@ - - - - - - - - - - - - - - - - - - + diff --git a/sdk/foobar2000/shared/shared.xcodeproj/project.pbxproj b/sdk/foobar2000/shared/shared.xcodeproj/project.pbxproj index 8b47996..02b8ee3 100644 --- a/sdk/foobar2000/shared/shared.xcodeproj/project.pbxproj +++ b/sdk/foobar2000/shared/shared.xcodeproj/project.pbxproj @@ -233,7 +233,7 @@ .., ); IPHONEOS_DEPLOYMENT_TARGET = 14.5; - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -293,7 +293,7 @@ .., ); IPHONEOS_DEPLOYMENT_TARGET = 14.5; - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 11.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = macosx; diff --git a/sdk/libPPUI/CEditWithButtons.h b/sdk/libPPUI/CEditWithButtons.h index 1646bd7..f5156f9 100644 --- a/sdk/libPPUI/CEditWithButtons.h +++ b/sdk/libPPUI/CEditWithButtons.h @@ -17,6 +17,7 @@ class CEditWithButtons : public CEditPPHooks { static constexpr LPARAM MSG_CHECKCONDITIONS_MAGIC2 = 0x180c2f35; BEGIN_MSG_MAP_EX(CEditWithButtons) + MSG_WM_CREATE(OnCreate) MSG_WM_SETFONT(OnSetFont) MSG_WM_WINDOWPOSCHANGED(OnPosChanged) MSG_WM_CTLCOLORBTN(OnColorBtn) @@ -36,6 +37,7 @@ class CEditWithButtons : public CEditPPHooks { BOOL SubclassWindow( HWND wnd ) { if (!CEditPPHooks::SubclassWindow(wnd)) return FALSE; + m_initialParent = GetParent(); this->ModifyStyle(0, WS_CLIPCHILDREN); RefreshButtons(); return TRUE; @@ -59,8 +61,8 @@ class CEditWithButtons : public CEditPPHooks { void Invalidate() { __super::Invalidate(); - for( auto i = m_buttons.begin(); i != m_buttons.end(); ++i ) { - if (i->wnd != NULL) i->wnd.Invalidate(); + for( auto & i : m_buttons ) { + if (i.wnd != NULL) i.wnd.Invalidate(); } } void SetShellFolderAutoComplete() { @@ -78,6 +80,11 @@ class CEditWithButtons : public CEditPPHooks { } void RefreshConditions(const wchar_t * newText = nullptr); private: + int OnCreate(LPCREATESTRUCT lpCreateStruct) { + m_initialParent = GetParent(); + SetMsgHandled(FALSE); + return 0; + } LRESULT OnCheckConditions( UINT msg, WPARAM wp, LPARAM lp ) { if ( msg == MSG_CHECKCONDITIONS && wp == MSG_CHECKCONDITIONS_MAGIC1 && lp == MSG_CHECKCONDITIONS_MAGIC2 ) { this->RefreshConditions(); @@ -108,9 +115,9 @@ class CEditWithButtons : public CEditPPHooks { return 0; } void OnEnable(BOOL bEnable) { - for( auto i = m_buttons.begin(); i != m_buttons.end(); ++ i ) { - if ( i->wnd != NULL ) { - i->wnd.EnableWindow( bEnable ); + for( auto & i : m_buttons ) { + if ( i.wnd != NULL ) { + i.wnd.EnableWindow( bEnable ); } } SetMsgHandled(FALSE); @@ -189,7 +196,11 @@ class CEditWithButtons : public CEditPPHooks { return (GetKeyState(VK_SHIFT) & 0x8000) ? true : false; } CWindow FindDialog() { - return GetParent(); + // Return a window that we can send WM_NEXTDLGCTL to + // PROBLEM: There is no clear way of obtaining one - something in our GetParent() hierarchy is usually a dialog, but we don't know which one + // Assume our initial parent window to be the right thing to talk to + PFC_ASSERT(m_initialParent != NULL); + return m_initialParent; } void TabFocusThis(HWND wnd) { FindDialog().PostMessage(WM_NEXTDLGCTL, (WPARAM) wnd, TRUE ); @@ -208,4 +219,5 @@ class CEditWithButtons : public CEditPPHooks { bool m_fixedWidthAuto = false; std::list< Button_t > m_buttons; bool m_hasAutoComplete = false; + CWindow m_initialParent; }; diff --git a/sdk/libPPUI/CListAccessible.cpp b/sdk/libPPUI/CListAccessible.cpp index 93a20e6..01f221d 100644 --- a/sdk/libPPUI/CListAccessible.cpp +++ b/sdk/libPPUI/CListAccessible.cpp @@ -70,7 +70,7 @@ HRESULT IEnumVARIANT_selection::Clone(IEnumVARIANT **ppEnum) IEnumVARIANT * var; try { var = new IEnumVARIANT_selection(m_data.get_ptr(), m_data.get_size(), m_pos); - } catch(std::bad_alloc) {return E_OUTOFMEMORY;} + } catch(std::bad_alloc const &) {return E_OUTOFMEMORY;} var->AddRef(); *ppEnum = var; @@ -475,7 +475,7 @@ HRESULT IAccessible_CListControl::get_accSelection(VARIANT *pvarChildren) pvarChildren->vt = VT_UNKNOWN; pvarChildren->punkVal = ptr; } - } catch(std::bad_alloc) { + } catch(std::bad_alloc const &) { return E_OUTOFMEMORY; } return S_OK; diff --git a/sdk/libPPUI/CListControl-Subst.cpp b/sdk/libPPUI/CListControl-Subst.cpp index 0c313ef..eaa9867 100644 --- a/sdk/libPPUI/CListControl-Subst.cpp +++ b/sdk/libPPUI/CListControl-Subst.cpp @@ -62,9 +62,18 @@ namespace { MESSAGE_HANDLER_EX(LVM_ENABLEGROUPVIEW, OnEnableGroupView) MESSAGE_HANDLER_EX(LVM_SCROLL, OnScroll) MESSAGE_HANDLER_EX(LVM_REDRAWITEMS, OnRedrawItems) + MSG_WM_KEYDOWN(OnKeyDown) + MSG_WM_SYSKEYDOWN(OnKeyDown) CHAIN_MSG_MAP(CListControlComplete) END_MSG_MAP() + void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { + NMLVKEYDOWN arg = {}; + arg.hdr = this->setupHdr(LVN_KEYDOWN); + arg.wVKey = nChar; + sendNotify(&arg); + SetMsgHandled(FALSE); + } LRESULT OnCreate(LPCREATESTRUCT) { SetMsgHandled(FALSE); // Adopt style flags of the original control to keep various ATL checks happy @@ -861,7 +870,7 @@ namespace { auto pItem = reinterpret_cast(lp); size_t item = (size_t)pItem->iItem; const size_t total = GetItemCount(); - if (item > total) return FALSE; + if (item >= total) return FALSE; size_t subItem = (size_t)pItem->iSubItem; if (subItem > 1024) return FALSE; // quick sanity auto& rec = m_content[item]; diff --git a/sdk/libPPUI/CListControlWithSelection.cpp b/sdk/libPPUI/CListControlWithSelection.cpp index 436e4f7..ed26a92 100644 --- a/sdk/libPPUI/CListControlWithSelection.cpp +++ b/sdk/libPPUI/CListControlWithSelection.cpp @@ -304,9 +304,14 @@ LRESULT CListControlWithSelectionBase::OnRButtonUp(UINT,WPARAM,LPARAM,BOOL& bHan return 0; } +bool CListControlWithSelectionBase::ShouldBeginDrag(CPoint ptRef, CPoint ptNow) const { + auto threshold = PP::queryDragThresholdForDPI(this->GetDPI()); + return abs(ptNow.x - ptRef.x) > threshold.cx || abs(ptNow.y - ptRef.y) > threshold.cy; +} + LRESULT CListControlWithSelectionBase::OnMouseMove(UINT,WPARAM,LPARAM p_lp,BOOL&) { if (m_prepareDragDropMode) { - if (CPoint(p_lp) != m_prepareDragDropOrigin) { + if (ShouldBeginDrag(m_prepareDragDropOrigin, CPoint(p_lp))) { AbortPrepareDragDropMode(); if (!m_ownDDActive) { pfc::vartoggle_t ownDD(m_ownDDActive,true); @@ -526,7 +531,7 @@ static HRGN FrameRectRgn(const CRect & rect) { void CListControlWithSelectionBase::HandleDragSel(const CPoint & p_pt) { const CPoint pt = PointClientToAbs(p_pt); - if (pt != m_selectDragCurrentAbs) { + if (m_selectDragMoved || ShouldBeginDrag(m_selectDragCurrentAbs, pt)) { if (!this->AllowRangeSelect()) { // simplified @@ -1541,6 +1546,7 @@ int CListControlWithSelectionBase::OnCreatePassThru(LPCREATESTRUCT) { return dda->dwEFfect; }; target->HookDrop = [this, flags] ( IDataObject * obj, CPoint pt ) { + this->ToggleDDScroll(false); this->ClearDropMark(); if ( this->m_ownDDActive ) { // Do not generate OnDrop for reorderings diff --git a/sdk/libPPUI/CListControlWithSelection.h b/sdk/libPPUI/CListControlWithSelection.h index 6ce20d6..9008fe7 100644 --- a/sdk/libPPUI/CListControlWithSelection.h +++ b/sdk/libPPUI/CListControlWithSelection.h @@ -220,6 +220,7 @@ class CListControlWithSelectionBase : public CListControl { bool m_prepareDragDropMode = false, m_prepareDragDropModeRightClick = false; bool m_noEnsureVisible = false; CPoint m_prepareDragDropOrigin; + bool ShouldBeginDrag(CPoint ptRef, CPoint ptNow) const; bool m_ownDDActive = false; bool m_drawThemeText = false; diff --git a/sdk/libPPUI/DarkMode.cpp b/sdk/libPPUI/DarkMode.cpp index 97f5830..deb2e3c 100644 --- a/sdk/libPPUI/DarkMode.cpp +++ b/sdk/libPPUI/DarkMode.cpp @@ -208,7 +208,7 @@ namespace DarkMode { return val; } bool IsSupportedSystem() { - return Win10BuildNumber() >= 17763; // require at least Win10 1809 / Server 2019 + return Win10BuildNumber() >= 17763 && !IsWine(); // require at least Win10 1809 / Server 2019 } bool IsWindows11() { return Win10BuildNumber() >= 22000; @@ -270,10 +270,18 @@ namespace DarkMode { } } + void ApplyDarkThemeCtrl2(HWND ctrl, bool bDark, const wchar_t* ThemeID_light, const wchar_t * ThemeID_dark) { + if (ctrl == NULL) return; + AllowDarkModeForWindow(ctrl, bDark); + if (bDark && IsSupportedSystem()) { + ::SetWindowTheme(ctrl, ThemeID_dark, NULL); + } else { + ::SetWindowTheme(ctrl, ThemeID_light, NULL); + } + } + void ApplyDarkThemeCtrl(HWND ctrl, bool bDark, const wchar_t* ThemeID) { if ( ctrl == NULL ) return; - // Both ways work - // DarkMode_Theme approach doesn't require evil undocumented MS API calls though AllowDarkModeForWindow(ctrl, bDark); if (bDark && IsSupportedSystem()) { std::wstring temp = L"DarkMode_"; temp += ThemeID; diff --git a/sdk/libPPUI/DarkMode.h b/sdk/libPPUI/DarkMode.h index de6fbb1..a6a50d3 100644 --- a/sdk/libPPUI/DarkMode.h +++ b/sdk/libPPUI/DarkMode.h @@ -13,6 +13,7 @@ namespace DarkMode { // Darken window title bar void UpdateTitleBar(HWND wnd, bool bDark ); void ApplyDarkThemeCtrl(HWND ctrl, bool bDark, const wchar_t * ThemeID = L"Explorer"); + void ApplyDarkThemeCtrl2(HWND ctrl, bool bDark, const wchar_t* ThemeID_light = L"Explorer", const wchar_t* ThemeID_dark = L"DarkMode_Explorer"); void AllowDarkModeForWindow(HWND wnd, bool bDark); // One-shot version of darkening function for editboxes diff --git a/sdk/libPPUI/IDataObjectUtils.cpp b/sdk/libPPUI/IDataObjectUtils.cpp index bfd673f..261cce9 100644 --- a/sdk/libPPUI/IDataObjectUtils.cpp +++ b/sdk/libPPUI/IDataObjectUtils.cpp @@ -50,9 +50,9 @@ HRESULT IDataObjectUtils::DataBlockToSTGMEDIUM(const void * blockPtr, t_size blo } return DV_E_TYMED; } - } catch(pfc::exception_not_implemented) { + } catch(pfc::exception_not_implemented const &) { return E_NOTIMPL; - } catch(std::bad_alloc) { + } catch(std::bad_alloc const &) { return E_OUTOFMEMORY; } catch(...) { return E_UNEXPECTED; diff --git a/sdk/libPPUI/ImageEncoder.cpp b/sdk/libPPUI/ImageEncoder.cpp index 1bfc955..9244f6a 100644 --- a/sdk/libPPUI/ImageEncoder.cpp +++ b/sdk/libPPUI/ImageEncoder.cpp @@ -40,9 +40,9 @@ int GetEncoderClsid(const WCHAR* format, CLSID* pClsid) void ConvertImage(const TCHAR * in, const TCHAR * out, const TCHAR * format, ULONG quality) { GdiplusScope scope; - std::unique_ptr< Bitmap > image ( new Bitmap(in) ); - EH << image->GetLastStatus(); - SaveImage(&*image, out, format, quality); + Bitmap image (in); + EH << image.GetLastStatus(); + SaveImage(&image, out, format, quality); } static void add16clip(uint16_t& v, int d) { diff --git a/sdk/libPPUI/PaintUtils.cpp b/sdk/libPPUI/PaintUtils.cpp index 15b1505..421fd16 100644 --- a/sdk/libPPUI/PaintUtils.cpp +++ b/sdk/libPPUI/PaintUtils.cpp @@ -169,15 +169,22 @@ namespace PaintUtils { } } void DrawTrack2(HDC p_dc, const CRect& rcTrack, const CRect& rcUpdate, COLORREF clrHighlight, COLORREF clrShadow) { - CMemoryDC dc(p_dc, rcUpdate); CRect rc(*rcTrack); - - WIN32_OP_D(dc.BitBlt(rcUpdate.left, rcUpdate.top, rcUpdate.Width(), rcUpdate.Height(), p_dc, rcUpdate.left, rcUpdate.top, SRCCOPY)); - +#if 1 + CDCHandle dc(p_dc); + SelectObjectScope scope(dc, GetStockObject(DC_PEN)); + dc.SetDCPenColor(clrHighlight); + dc.MoveTo(rc.left, rc.bottom); + dc.LineTo(rc.right, rc.bottom); + dc.LineTo(rc.right, rc.top); + dc.SetDCPenColor(clrShadow); + dc.LineTo(rc.left, rc.top); + dc.LineTo(rc.left, rc.bottom); +#else try { Gdiplus::Point points[] = { Gdiplus::Point(rc.left, rc.bottom), Gdiplus::Point(rc.right, rc.bottom), Gdiplus::Point(rc.right, rc.top), Gdiplus::Point(rc.left, rc.top)}; GdiplusErrorHandler eh; - Gdiplus::Graphics graphics(dc); + Gdiplus::Graphics graphics(p_dc); eh << graphics.GetLastStatus(); Gdiplus::Color c; c.SetFromCOLORREF(clrHighlight); @@ -194,17 +201,15 @@ namespace PaintUtils { PFC_ASSERT(!"???"); // console::print(e.what()); } +#endif } void DrawTrackVolume2(HDC p_dc, const CRect& rcTrack, const CRect& rcUpdate, COLORREF clrHighlight, COLORREF clrShadow) { - CMemoryDC dc(p_dc, rcUpdate); CRect rc(rcTrack); - WIN32_OP_D(dc.BitBlt(rcUpdate.left, rcUpdate.top, rcUpdate.Width(), rcUpdate.Height(), p_dc, rcUpdate.left, rcUpdate.top, SRCCOPY)); - try { Gdiplus::Point points[] = { Gdiplus::Point(rc.left, rc.bottom), Gdiplus::Point(rc.right, rc.bottom), Gdiplus::Point(rc.right, rc.top) }; GdiplusErrorHandler eh; - Gdiplus::Graphics graphics(dc); + Gdiplus::Graphics graphics(p_dc); eh << graphics.GetLastStatus(); Gdiplus::Color c; c.SetFromCOLORREF(clrHighlight); diff --git a/sdk/libPPUI/TreeMultiSel.h b/sdk/libPPUI/TreeMultiSel.h index 7268b75..1fd3617 100644 --- a/sdk/libPPUI/TreeMultiSel.h +++ b/sdk/libPPUI/TreeMultiSel.h @@ -159,9 +159,9 @@ class CTreeMultiSel : public CMessageMap { } else if (m_selection.size() > 0) { CTreeViewCtrl tree(hdr->hwndFrom); CRgn rgn; rgn.CreateRectRgn(0,0,0,0); - for(auto walk = m_selection.begin(); walk != m_selection.end(); ++walk) { + for(auto walk : m_selection) { CRect rc; - if (tree.GetItemRect(*walk, rc, TRUE)) { + if (tree.GetItemRect(walk, rc, TRUE)) { CRgn temp; temp.CreateRectRgnIndirect(rc); rgn.CombineRgn(temp, RGN_OR); } @@ -198,6 +198,29 @@ class CTreeMultiSel : public CMessageMap { SetMsgHandled(FALSE); return 0; } + + void FixFocusItem(CTreeViewCtrl tree, HTREEITEM item) { + if (this->IsItemSelected(item) || tree.GetSelectedItem() != item) return; + + auto scope = pfc::autoToggle(m_ownSelChange, true); + + for(;;) { + if (item == TVI_ROOT || item == NULL || this->IsItemSelected(item)) { + tree.SelectItem(item); return; + } + for (auto walk = tree.GetPrevSiblingItem(item); walk != NULL; walk = tree.GetPrevSiblingItem(walk)) { + if (this->IsItemSelected(walk)) { + tree.SelectItem(walk); return; + } + } + for (auto walk = tree.GetNextSiblingItem(item); walk != NULL; walk = tree.GetNextSiblingItem(walk)) { + if (this->IsItemSelected(walk)) { + tree.SelectItem(walk); return; + } + } + item = tree.GetParentItem(item); + } + } BOOL HandleClick(CTreeViewCtrl tree, CPoint pt) { UINT htFlags = 0; @@ -205,6 +228,7 @@ class CTreeMultiSel : public CMessageMap { if (item != NULL && (htFlags & TVHT_ONITEM) != 0) { if (IsKeyPressed(VK_CONTROL)) { SelectToggleItem(tree, item); + FixFocusItem(tree, item); return TRUE; } else if (item == tree.GetSelectedItem() && !IsItemSelected(item)) { SelectToggleItem(tree, item); @@ -252,7 +276,7 @@ class CTreeMultiSel : public CMessageMap { } selection_t newSel = GrabRange(tree, m_selStart, item ); - ApplySelection(tree, newSel); + ApplySelection(tree, std::move(newSel)); } static selection_t GrabRange(CTreeViewCtrl tree, HTREEITEM item1, HTREEITEM item2) { selection_t range1, range2; @@ -292,6 +316,7 @@ class CTreeMultiSel : public CMessageMap { NMTVCUSTOMDRAW* info = (NMTVCUSTOMDRAW*)hdr; switch (info->nmcd.dwDrawStage) { case CDDS_ITEMPREPAINT: + // NOTE: This doesn't work all the way. Unflagging CDIS_FOCUS isn't respected, causing weird behaviors when using ctrl+cursors or unselecting items. if (this->IsItemSelected((HTREEITEM)info->nmcd.dwItemSpec)) { info->nmcd.uItemState |= CDIS_SELECTED; } else { @@ -311,7 +336,7 @@ class CTreeMultiSel : public CMessageMap { DeselectAll(tree); SelectItem(tree, item); } - void ApplySelection(CTreeViewCtrl tree, selection_t const & newSel) { + void ApplySelection(CTreeViewCtrl tree, selection_t && newSel) { CRgn updateRgn; bool changed = false; if (newSel.size() != m_selection.size() && newSel.size() + m_selection.size() > 100) { @@ -319,21 +344,21 @@ class CTreeMultiSel : public CMessageMap { changed = true; } else { WIN32_OP_D(updateRgn.CreateRectRgn(0, 0, 0, 0) != NULL); - for (auto walk = m_selection.begin(); walk != m_selection.end(); ++walk) { - if (newSel.count(*walk) == 0) { + for (auto walk : m_selection) { + if (newSel.count(walk) == 0) { changed = true; CRect rc; - if (tree.GetItemRect(*walk, rc, TRUE)) { + if (tree.GetItemRect(walk, rc, TRUE)) { CRgn temp; WIN32_OP_D(temp.CreateRectRgnIndirect(rc)); WIN32_OP_D(updateRgn.CombineRgn(temp, RGN_OR) != ERROR); } } } - for (auto walk = newSel.begin(); walk != newSel.end(); ++walk) { - if (m_selection.count(*walk) == 0) { + for (auto walk : newSel) { + if (m_selection.count(walk) == 0) { changed = true; CRect rc; - if (tree.GetItemRect(*walk, rc, TRUE)) { + if (tree.GetItemRect(walk, rc, TRUE)) { CRgn temp; WIN32_OP_D(temp.CreateRectRgnIndirect(rc)); WIN32_OP_D(updateRgn.CombineRgn(temp, RGN_OR) != ERROR); } @@ -341,7 +366,7 @@ class CTreeMultiSel : public CMessageMap { } } if (changed) { - m_selection = newSel; + m_selection = std::move(newSel); tree.RedrawWindow(NULL, updateRgn); SendOnSelChanged(tree); } @@ -363,9 +388,9 @@ class CTreeMultiSel : public CMessageMap { CRgn updateRgn; if (m_selection.size() <= 100) { WIN32_OP_D(updateRgn.CreateRectRgn(0, 0, 0, 0) != NULL); - for (auto walk = m_selection.begin(); walk != m_selection.end(); ++walk) { + for (auto walk : m_selection) { CRect rc; - if (tree.GetItemRect(*walk, rc, TRUE)) { + if (tree.GetItemRect(walk, rc, TRUE)) { CRgn temp; WIN32_OP_D(temp.CreateRectRgnIndirect(rc)); WIN32_OP_D(updateRgn.CombineRgn(temp, RGN_OR) != ERROR); } diff --git a/sdk/libPPUI/gdiplus_helpers.cpp b/sdk/libPPUI/gdiplus_helpers.cpp index 43541f3..4130e96 100644 --- a/sdk/libPPUI/gdiplus_helpers.cpp +++ b/sdk/libPPUI/gdiplus_helpers.cpp @@ -32,22 +32,22 @@ HBITMAP GdiplusLoadBitmap(UINT id, const TCHAR* resType, CSize size) { auto stream = WinLoadResourceAsStream(GetThisModuleHandle(), MAKEINTRESOURCE(id), resType); GdiplusErrorHandler EH; - std::unique_ptr source ( new Image(stream) ); - EH << source->GetLastStatus(); + Image source ( stream ); + EH << source.GetLastStatus(); - std::unique_ptr resized ( new Bitmap(size.cx, size.cy, PixelFormat32bppARGB) ); - EH << resized->GetLastStatus(); + Bitmap resized (size.cx, size.cy, PixelFormat32bppARGB); + EH << resized.GetLastStatus(); { - std::unique_ptr target ( new Graphics(resized.get()) ); - EH << target->GetLastStatus(); - EH << target->SetInterpolationMode(InterpolationModeHighQuality); - EH << target->Clear(Color(0, 0, 0, 0)); - EH << target->DrawImage(source.get(), Rect(0, 0, size.cx, size.cy)); + Graphics target(&resized); + EH << target.GetLastStatus(); + EH << target.SetInterpolationMode(InterpolationModeHighQuality); + EH << target.Clear(Color(0, 0, 0, 0)); + EH << target.DrawImage(&source, Rect(0, 0, size.cx, size.cy)); } HBITMAP bmp = NULL; - EH << resized->GetHBITMAP(Gdiplus::Color::White, &bmp); + EH << resized.GetHBITMAP(Gdiplus::Color::White, &bmp); return bmp; } catch (...) { PFC_ASSERT(!"Should not get here"); @@ -73,11 +73,11 @@ std::unique_ptr< Gdiplus::Bitmap > GdiplusResizeImage(Gdiplus::Image* source, CS GdiplusErrorHandler EH; std::unique_ptr resized ( new Bitmap(size.cx, size.cy, pf) ); EH << resized->GetLastStatus(); - std::unique_ptr target ( new Graphics(resized.get()) ); - EH << target->GetLastStatus(); - EH << target->SetInterpolationMode(InterpolationModeHighQuality); - EH << target->Clear(Color(0, 0, 0, 0)); - EH << target->DrawImage(source, Rect(0, 0, size.cx, size.cy)); + Graphics target (resized.get() ); + EH << target.GetLastStatus(); + EH << target.SetInterpolationMode(InterpolationModeHighQuality); + EH << target.Clear(Color(0, 0, 0, 0)); + EH << target.DrawImage(source, Rect(0, 0, size.cx, size.cy)); return resized; } @@ -108,26 +108,26 @@ HICON GdiplusLoadIconEx(UINT id, const TCHAR* resType, GdiplusIconArg_t const& a auto stream = WinLoadResourceAsStream(GetThisModuleHandle(), MAKEINTRESOURCE(id), resType); GdiplusErrorHandler EH; - pfc::ptrholder_t source = new Image(stream); - EH << source->GetLastStatus(); - pfc::ptrholder_t resized = new Bitmap(arg.size.cx, arg.size.cy, PixelFormat32bppARGB); - EH << resized->GetLastStatus(); + Bitmap resized(arg.size.cx, arg.size.cy, PixelFormat32bppARGB); + EH << resized.GetLastStatus(); { - pfc::ptrholder_t target = new Graphics(resized.get_ptr()); - EH << target->GetLastStatus(); - EH << target->SetInterpolationMode(InterpolationModeHighQuality); - EH << target->Clear(Color(0, 0, 0, 0)); - EH << target->DrawImage(source.get_ptr(), Rect(0, 0, arg.size.cx, arg.size.cy)); + Image source(stream); + EH << source.GetLastStatus(); + + Graphics target(&resized); + EH << target.GetLastStatus(); + EH << target.SetInterpolationMode(InterpolationModeHighQuality); + EH << target.Clear(Color(0, 0, 0, 0)); + EH << target.DrawImage(&source, Rect(0, 0, arg.size.cx, arg.size.cy)); } - source = nullptr; - if (arg.transform) arg.transform(resized.get_ptr()); + if (arg.transform) arg.transform(&resized); HICON icon = NULL; - EH << resized->GetHICON(&icon); + EH << resized.GetHICON(&icon); return icon; } catch (...) { PFC_ASSERT(!"Should not get here"); diff --git a/sdk/libPPUI/libPPUI-license.txt b/sdk/libPPUI/libPPUI-license.txt index 0ab480d..dd237fe 100644 --- a/sdk/libPPUI/libPPUI-license.txt +++ b/sdk/libPPUI/libPPUI-license.txt @@ -1,4 +1,4 @@ -Copyright (C) 2002-2023 Peter Pawlowski +Copyright (C) 2002-2024 Peter Pawlowski This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/sdk/libPPUI/libPPUI.vcxproj b/sdk/libPPUI/libPPUI.vcxproj index 0420ed3..0c0024d 100644 --- a/sdk/libPPUI/libPPUI.vcxproj +++ b/sdk/libPPUI/libPPUI.vcxproj @@ -39,25 +39,26 @@ {7729EB82-4069-4414-964B-AD399091A03F} Win32Proj libPPUI + 10.0 StaticLibrary true - v143 + v142 Unicode StaticLibrary false - v143 + v142 true Unicode StaticLibrary true - v143 + v142 Unicode @@ -75,7 +76,7 @@ StaticLibrary false - v143 + v142 true Unicode @@ -161,6 +162,7 @@ Fast stdcpp17 true + MultiThreadedDebugDLL Windows @@ -179,6 +181,7 @@ stdcpp17 true ProgramDatabase + MultiThreadedDebugDLL Windows @@ -196,6 +199,7 @@ .. stdcpp17 true + MultiThreadedDebugDLL Windows @@ -234,7 +238,7 @@ Fast true /d2notypeopt %(AdditionalOptions) - NDEBUG;_UNICODE;UNICODE;%(PreprocessorDefinitions) + NDEBUG;%(PreprocessorDefinitions) stdcpp17 true @@ -258,7 +262,7 @@ false .. /d2notypeopt %(AdditionalOptions) - NDEBUG;_UNICODE;UNICODE;%(PreprocessorDefinitions) + NDEBUG;%(PreprocessorDefinitions) stdcpp17 true @@ -282,7 +286,7 @@ false .. /d2notypeopt %(AdditionalOptions) - NDEBUG;_UNICODE;UNICODE;%(PreprocessorDefinitions) + NDEBUG;%(PreprocessorDefinitions) stdcpp17 true @@ -306,7 +310,7 @@ false .. /d2notypeopt %(AdditionalOptions) - NDEBUG;_UNICODE;UNICODE;%(PreprocessorDefinitions) + NDEBUG;%(PreprocessorDefinitions) stdcpp17 true diff --git a/sdk/libPPUI/stdafx.h b/sdk/libPPUI/stdafx.h index c124a1f..0af3d4b 100644 --- a/sdk/libPPUI/stdafx.h +++ b/sdk/libPPUI/stdafx.h @@ -19,3 +19,8 @@ #include #include + + +#ifndef _UNICODE +#error seriously? +#endif \ No newline at end of file diff --git a/sdk/libPPUI/win32_utility.cpp b/sdk/libPPUI/win32_utility.cpp index 9f99e83..c54645b 100644 --- a/sdk/libPPUI/win32_utility.cpp +++ b/sdk/libPPUI/win32_utility.cpp @@ -173,6 +173,17 @@ void InjectParentEraseHandler(HWND wnd) { void InjectParentCtlColorHandler(HWND wnd) { WIN32_OP_D(SetWindowSubclass(wnd, CtlColorProc, 0, 0)); } +static LRESULT CALLBACK BounceNextDlgCtlProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) { + if (uMsg == WM_NEXTDLGCTL) { + return ::SendMessage((HWND)dwRefData, uMsg, wParam, lParam); + } + return DefSubclassProc(hWnd, uMsg, wParam, lParam); +} + +void BounceNextDlgCtl(HWND wnd, HWND wndTo) { + ::SetWindowSubclass(wnd, BounceNextDlgCtlProc, 0, (DWORD_PTR)wndTo); +} + pfc::string8 EscapeTooltipText(const char * src) { @@ -237,7 +248,7 @@ static void GetOSVersionStringAppend(pfc::string_base & out) { if (FetchWineInfoAppend(out)) return; OSVERSIONINFO ver = {}; ver.dwOSVersionInfoSize = sizeof(ver); - WIN32_OP(GetVersionEx(&ver)); + WIN32_OP_D(GetVersionEx(&ver)); SYSTEM_INFO info = {}; GetNativeSystemInfo(&info); @@ -348,3 +359,32 @@ void PP::hookWindowMessages(HWND wnd, CMessageMap* target, DWORD targetID, std:: void PP::hookWindowMessages(HWND wnd, messageHook_t h) { PP::subclassThisWindow< CWindowHook_Proc >(wnd, h); } + +namespace PP { + static LONG regReadHelper(HKEY root, const wchar_t* path, const wchar_t* value, LONG def) { + wchar_t buf[64] = {}; + DWORD cb = (DWORD)((std::size(buf) - 1) * sizeof(buf[0])); + if (RegGetValue(root, path, value, RRF_RT_REG_SZ, NULL, buf, &cb) == 0) { + return _wtol(buf); + } + return def; + } + + static SIZE querySystemDragThreshold() { + constexpr DWORD def = 1; + static constexpr wchar_t path[] = L"Control Panel\\Desktop"; + return { + (LONG)regReadHelper(HKEY_CURRENT_USER, path, L"DragWidth", def), + (LONG)regReadHelper(HKEY_CURRENT_USER, path, L"DragHeight", def) + }; + } + SIZE queryDragThresholdForDPI(SIZE dpi) { + PFC_ASSERT(dpi.cx > 0 && dpi.cy > 0); + static SIZE sys = {}; + if ( sys.cx == 0 || sys.cy == 0 ) sys = querySystemDragThreshold(); + return { MulDiv(sys.cx, dpi.cx, 96), MulDiv(sys.cy, dpi.cy, 96) }; + } + SIZE queryDragThreshold(HWND wndFor) { + return queryDragThresholdForDPI(QueryScreenDPIEx(wndFor)); + } +} diff --git a/sdk/libPPUI/win32_utility.h b/sdk/libPPUI/win32_utility.h index 80ee2c0..2a2b088 100644 --- a/sdk/libPPUI/win32_utility.h +++ b/sdk/libPPUI/win32_utility.h @@ -9,6 +9,12 @@ unsigned QueryScreenDPI_Y(HWND wnd = NULL); SIZE QueryScreenDPIEx(HWND wnd = NULL); SIZE QueryContextDPI(HDC dc); +namespace PP { + // Returns drag threshold, in actual pixels (DPI-corrected), for the specified window + SIZE queryDragThreshold(HWND wndFor); + SIZE queryDragThresholdForDPI(SIZE knownDPI); +} + void HeaderControl_SetSortIndicator(HWND header, int column, bool isUp); HINSTANCE GetThisModuleHandle(); diff --git a/sdk/libPPUI/wtl-pp.h b/sdk/libPPUI/wtl-pp.h index bf932d5..95c6c1f 100644 --- a/sdk/libPPUI/wtl-pp.h +++ b/sdk/libPPUI/wtl-pp.h @@ -73,6 +73,9 @@ LRESULT RelayEraseBkgnd(HWND p_from, HWND p_to, HDC p_dc); void InjectParentEraseHandler(HWND); void InjectEraseHandler(HWND, HWND sendTo); void InjectParentCtlColorHandler(HWND); +void BounceNextDlgCtl(HWND wnd, HWND wndTo); + + #define MSG_WM_ERASEBKGND_PARENT() \ if (uMsg == WM_ERASEBKGND) { \ diff --git a/sdk/pfc/CFObject.h b/sdk/pfc/CFObject.h new file mode 100644 index 0000000..7e30c53 --- /dev/null +++ b/sdk/pfc/CFObject.h @@ -0,0 +1,59 @@ +#pragma once + +#include + +namespace pfc { + template + class CFObject { + public: + typedef CFObject self_t; + type_t p = NULL; + + ~CFObject() { + if ( p ) CFRelease(p); + } + + void Retain(type_t arg) { + if ( p ) CFRelease(p); + p = arg; + if ( p ) CFRetain(p); + } + + void Attach(type_t arg) { + if ( p ) CFRelease(p); + p = arg; + } + + void operator=( self_t const & arg ) { + if ( p ) CFRelease(p); + p = arg.p; + if ( p ) CFRetain(p); + } + CFObject() {} + CFObject( self_t const & arg ) { + p = arg.p; + if ( p ) CFRetain(p); + } + + CFObject(self_t && arg ) { + p = arg.p; arg.p = NULL; + } + void operator=(self_t && arg) { + if ( p ) CFRelease(p); + p = arg.p; arg.p = NULL; + } + + operator bool() const { return p != NULL; } + operator type_t() const { return p;} + + + void reset() { + if ( p ) CFRelease(p); + p = NULL; + } + + void operator=(nullptr_t) { + reset(); + } + }; +} diff --git a/sdk/pfc/SmartStrStr-table.h b/sdk/pfc/SmartStrStr-table.h index 971af88..446da28 100644 --- a/sdk/pfc/SmartStrStr-table.h +++ b/sdk/pfc/SmartStrStr-table.h @@ -275,6 +275,7 @@ static constexpr mapping_t SmartStrStrTable[] = { {8216,39}, {8217,39}, {8218,44}, + {8219,39}, {8220,34}, {8221,34}, {8222,34}, diff --git a/sdk/pfc/SmartStrStr.cpp b/sdk/pfc/SmartStrStr.cpp index ee5cf31..25437ca 100644 --- a/sdk/pfc/SmartStrStr.cpp +++ b/sdk/pfc/SmartStrStr.cpp @@ -1,4 +1,4 @@ -#include "pfc-lite.h" +#include "pfc-lite.h" #include "string-conv-lite.h" #include "string_conv.h" @@ -94,133 +94,96 @@ SmartStrStr::SmartStrStr() { InitTwoCharMappings(); } -#ifdef _WIN32 -static_assert(sizeof(wchar_t) == sizeof(char16_t)); -const wchar_t * SmartStrStr::strStrEndW(const wchar_t * pString, const wchar_t * pSubString, size_t * outFoundAt) const { - return reinterpret_cast(strStrEnd16(reinterpret_cast(pString), reinterpret_cast(pSubString), outFoundAt)); +// == TEMPLATES == +template const char_t * SmartStrStr::matchHere_(const char_t * pString, const char_t * pUserString) const { + auto walkData = pString; + auto walkUser = pUserString; + for (;; ) { + if (*walkUser == 0) return walkData; + + uint32_t cData, cUser; + size_t dData = pfc::uni_decode_char(walkData, cData); + size_t dUser = pfc::uni_decode_char(walkUser, cUser); + if (dData == 0 || dUser == 0) return nullptr; + + if (cData != cUser) { + bool gotMulti = false; + { + const char * cDataSubst = m_twoCharMappings.query(cData); + if (cDataSubst != nullptr) { + PFC_ASSERT(strlen(cDataSubst) == 2); + if (matchOneChar(cUser, (uint32_t)cDataSubst[0])) { + auto walkUser2 = walkUser + dUser; + uint32_t cUser2; + auto dUser2 = pfc::uni_decode_char(walkUser2, cUser2); + if (matchOneChar(cUser2, (uint32_t)cDataSubst[1])) { + gotMulti = true; + dUser += dUser2; + } + } + } + } + if (!gotMulti) { + if (!matchOneChar(cUser, cData)) return nullptr; + } + } + + walkData += dData; + walkUser += dUser; + } +} +template bool SmartStrStr::equals_( const char_t * pString, const char_t * pUserString) const { + auto p = this->matchHere_(pString, pUserString); + if ( p == nullptr ) return false; + return *p == 0; +} + +template const char_t * SmartStrStr::strStrEnd_(const char_t * pString, const char_t * pSubString, size_t * outFoundAt) const { + size_t walk = 0; + for (;; ) { + if (pString[walk] == 0) return nullptr; + auto end = matchHere_(pString + walk, pSubString); + if (end != nullptr) { + if (outFoundAt != nullptr) * outFoundAt = walk; + return end; + } + + size_t delta = pfc::uni_char_length(pString + walk); + if (delta == 0) return nullptr; + walk += delta; + } +} +// == END TEMPLATES == + +const char16_t * SmartStrStr::matchHere16(const char16_t * pString, const char16_t * pUserString) const { + return this->matchHere_(pString, pUserString); } -const wchar_t * SmartStrStr::matchHereW(const wchar_t * pString, const wchar_t * pUserString) const { - return reinterpret_cast(matchHere16(reinterpret_cast(pString), reinterpret_cast(pUserString))); +const char * SmartStrStr::matchHere(const char * pString, const char * pUserString) const { + return this->matchHere_(pString, pUserString); } -#endif -const char16_t * SmartStrStr::matchHere16(const char16_t * pString, const char16_t * pUserString) const { - auto walkData = pString; - auto walkUser = pUserString; - for (;; ) { - if (*walkUser == 0) return walkData; - - uint32_t cData, cUser; - size_t dData = pfc::utf16_decode_char(walkData, &cData); - size_t dUser = pfc::utf16_decode_char(walkUser, &cUser); - if (dData == 0 || dUser == 0) return nullptr; - - if (cData != cUser) { - bool gotMulti = false; - { - const char * cDataSubst = m_twoCharMappings.query(cData); - if (cDataSubst != nullptr) { - PFC_ASSERT(strlen(cDataSubst) == 2); - if (matchOneChar(cUser, (uint32_t)cDataSubst[0])) { - auto walkUser2 = walkUser + dUser; - uint32_t cUser2; - auto dUser2 = pfc::utf16_decode_char(walkUser2, &cUser2); - if (matchOneChar(cUser2, (uint32_t)cDataSubst[1])) { - gotMulti = true; - dUser += dUser2; - } - } - } - } - if (!gotMulti) { - if (!matchOneChar(cUser, cData)) return nullptr; - } - } - - walkData += dData; - walkUser += dUser; - } +const wchar_t * SmartStrStr::matchHereW(const wchar_t * pString, const wchar_t * pUserString) const { + return this->matchHere_(pString, pUserString); } bool SmartStrStr::equals(const char * pString, const char * pUserString) const { - auto p = matchHere(pString, pUserString); - if ( p == nullptr ) return false; - return *p == 0; + return equals_(pString, pUserString); } bool SmartStrStr::equals16(const char16_t* pString, const char16_t* pUserString) const { - auto p = matchHere16(pString, pUserString); - if ( p == nullptr ) return false; - return *p == 0; + return equals_(pString, pUserString); } - -const char * SmartStrStr::matchHere(const char * pString, const char * pUserString) const { - const char * walkData = pString; - const char * walkUser = pUserString; - for (;; ) { - if (*walkUser == 0) return walkData; - - uint32_t cData, cUser; - size_t dData = pfc::utf8_decode_char(walkData, cData); - size_t dUser = pfc::utf8_decode_char(walkUser, cUser); - if (dData == 0 || dUser == 0) return nullptr; - - if (cData != cUser) { - bool gotMulti = false; - { - const char* cDataSubst = m_twoCharMappings.query(cData); - if (cDataSubst != nullptr) { - PFC_ASSERT(strlen(cDataSubst) == 2); - if (matchOneChar(cUser, (uint32_t)cDataSubst[0])) { - auto walkUser2 = walkUser + dUser; - uint32_t cUser2; - auto dUser2 = pfc::utf8_decode_char(walkUser2, cUser2); - if (matchOneChar(cUser2, (uint32_t)cDataSubst[1])) { - gotMulti = true; - dUser += dUser2; - } - } - } - } - if (!gotMulti) { - if (!matchOneChar(cUser, cData)) return nullptr; - } - } - - walkData += dData; - walkUser += dUser; - } +bool SmartStrStr::equalsW( const wchar_t * pString, const wchar_t * pUserString) const { + return equals_(pString, pUserString); } - const char * SmartStrStr::strStrEnd(const char * pString, const char * pSubString, size_t * outFoundAt) const { - size_t walk = 0; - for (;; ) { - if (pString[walk] == 0) return nullptr; - auto end = matchHere(pString+walk, pSubString); - if (end != nullptr) { - if ( outFoundAt != nullptr ) * outFoundAt = walk; - return end; - } - - size_t delta = pfc::utf8_char_len( pString + walk ); - if ( delta == 0 ) return nullptr; - walk += delta; - } + return strStrEnd_(pString, pSubString, outFoundAt); } const char16_t * SmartStrStr::strStrEnd16(const char16_t * pString, const char16_t * pSubString, size_t * outFoundAt) const { - size_t walk = 0; - for (;; ) { - if (pString[walk] == 0) return nullptr; - auto end = matchHere16(pString + walk, pSubString); - if (end != nullptr) { - if (outFoundAt != nullptr) * outFoundAt = walk; - return end; - } + return strStrEnd_(pString, pSubString, outFoundAt); +} - uint32_t dontcare; - size_t delta = pfc::utf16_decode_char(pString + walk, & dontcare); - if (delta == 0) return nullptr; - walk += delta; - } +const wchar_t * SmartStrStr::strStrEndW(const wchar_t * pString, const wchar_t * pSubString, size_t * outFoundAt) const { + return strStrEnd_(pString, pSubString, outFoundAt); } static bool wordBeginsHere(const char* base, size_t offset) { @@ -367,15 +330,16 @@ bool SmartStrStr::testSubString_prefix_subst(const char* str, const char* sub, u } bool SmartStrStr::testSubstring(const char* str, const char* sub) const { #if 1 + // optimized version for UTF-8 unsigned prefix; - const size_t skip = pfc::utf8_decode_char(sub, prefix); + const size_t skip = pfc::uni_decode_char(sub, prefix); if ( skip == 0 ) return false; sub += skip; if (testSubString_prefix_subst(str, sub, prefix)) return true; unsigned prefix2; - const size_t skip2 = pfc::utf8_decode_char(sub, prefix2); + const size_t skip2 = pfc::uni_decode_char(sub, prefix2); if (skip2 > 0 && prefix < 0x10000 && prefix2 < 0x10000) { sub += skip2; auto alt = m_twoCharMappingsReverse.query(prefix | (prefix2 << 16)); @@ -392,6 +356,9 @@ bool SmartStrStr::testSubstring(const char* str, const char* sub) const { bool SmartStrStr::testSubstring16(const char16_t* str, const char16_t* sub) const { return this->strStrEnd16(str, sub) != nullptr; } +bool SmartStrStr::testSubstringW( const wchar_t * str, const wchar_t * sub ) const { + return this->strStrEndW(str, sub) != nullptr; +} SmartStrStr& SmartStrStr::global() { static SmartStrStr g; @@ -429,7 +396,7 @@ void SmartStrFilter::init(const char* ptr, size_t len) { bool SmartStrFilter::test_disregardCounts(const char* src) const { - if (m_items.size() == 0) return false; + if (m_items.empty()) return false; for (auto& walk : m_items) { if (!dc->strStrEnd(src, walk.first.c_str())) return false; @@ -438,14 +405,14 @@ bool SmartStrFilter::test_disregardCounts(const char* src) const { } bool SmartStrFilter::testWords(const char* src) const { - if (m_items.size() == 0) return false; + if (m_items.empty()) return false; for (auto& walk : m_items) { - const t_size count = walk.second; - const std::string& str = walk.first; - const char* strWalk = src; - for (t_size walk = 0; walk < count; ++walk) { - const char* next = dc->strStrEndWord(strWalk, str.c_str()); + const auto count = walk.second; + const auto& str = walk.first; + const auto* strWalk = src; + for (size_t i = 0; i < count; ++i) { + auto next = dc->strStrEndWord(strWalk, str.c_str()); if (next == nullptr) return false; strWalk = next; } @@ -455,7 +422,7 @@ bool SmartStrFilter::testWords(const char* src) const { bool SmartStrFilter::test(const char* src) const { - if (m_items.size() == 0) return false; + if (m_items.empty()) return false; // Use the faster routine first, it can't be used to count occurances but nobody really knows about this feature for (auto& walk : m_items) { @@ -463,12 +430,12 @@ bool SmartStrFilter::test(const char* src) const { } // Have any items where specific number of occurances is wanted? for (auto & walk : m_items) { - const t_size count = walk.second; + const auto count = walk.second; if (count == 1) continue; - const std::string& str = walk.first; - const char* strWalk = src; - for (t_size walk = 0; walk < count; ++walk) { - const char* next = dc->strStrEnd(strWalk, str.c_str()); + const auto& str = walk.first; + const auto* strWalk = src; + for (size_t i = 0; i < count; ++i) { + auto next = dc->strStrEnd(strWalk, str.c_str()); if (next == nullptr) return false; strWalk = next; } diff --git a/sdk/pfc/SmartStrStr.h b/sdk/pfc/SmartStrStr.h index 073a572..0cdc131 100644 --- a/sdk/pfc/SmartStrStr.h +++ b/sdk/pfc/SmartStrStr.h @@ -25,24 +25,23 @@ class SmartStrStr { //! Returns ptr to the end of the string if positive (for continuing search), nullptr if negative. const char * strStrEnd(const char * pString, const char * pSubString, size_t * outFoundAt = nullptr) const; const char16_t * strStrEnd16(const char16_t * pString, const char16_t * pSubString, size_t * outFoundAt = nullptr) const; + const wchar_t * strStrEndW(const wchar_t * pString, const wchar_t * pSubString, size_t * outFoundAt = nullptr) const; const char* strStrEndWord(const char* pString, const char* pSubString, size_t* outFoundAt = nullptr) const; bool testSubstring( const char * str, const char * sub ) const; bool testSubstring16( const char16_t * str, const char16_t * sub ) const; -#ifdef _WIN32 - const wchar_t * strStrEndW(const wchar_t * pString, const wchar_t * pSubString, size_t * outFoundAt = nullptr) const; -#endif - //! Returns ptr to the end of the string if positive (for continuing search), nullptr if negative. + bool testSubstringW( const wchar_t * str, const wchar_t * sub ) const; + + //! Returns ptr to the end of the string if positive (for continuing search), nullptr if negative. const char * matchHere(const char * pString, const char * pUserString) const; const char16_t * matchHere16(const char16_t * pString, const char16_t * pUserString) const; -#ifdef _WIN32 const wchar_t * matchHereW( const wchar_t * pString, const wchar_t * pUserString) const; -#endif //! String-equals tool, compares strings rather than searching for occurance bool equals( const char * pString, const char * pUserString) const; bool equals16( const char16_t * pString, const char16_t * pUserString) const; + bool equalsW( const wchar_t * pString, const wchar_t * pUserString) const; //! One-char match. Doesn't use twoCharMappings, use only if you have to operate on char by char basis rather than call the other methods. bool matchOneChar(uint32_t cInput, uint32_t cData) const; @@ -53,6 +52,10 @@ class SmartStrStr { void transformStrHere(pfc::string8& out, const char* in) const; void transformStrHere(pfc::string8& out, const char* in, size_t inLen) const; private: + template const char_t * strStrEnd_(const char_t * pString, const char_t * pSubString, size_t * outFoundAt = nullptr) const; + template const char_t * matchHere_(const char_t * pString, const char_t * pUserString) const; + template bool equals_( const char_t * pString, const char_t * pUserString) const; + bool testSubString_prefix(const char* str, const char* sub, const char * prefix, size_t prefixLen) const; bool testSubString_prefix(const char* str, const char* sub, uint32_t c) const; bool testSubString_prefix_subst(const char* str, const char* sub, uint32_t c) const; @@ -84,6 +87,7 @@ class SmartStrFilter { static bool is_spacing(char c) { return c == ' ' || c == 10 || c == 13 || c == '\t'; } void init(const char* ptr, size_t len); + void init( const char * ptr ) { init(ptr, strlen(ptr)); } bool test(const char* src) const; bool testWords(const char* src) const; bool test_disregardCounts(const char* src) const; @@ -91,6 +95,8 @@ class SmartStrFilter { const t_stringlist& items() const { return m_items; } operator bool() const { return !m_items.empty(); } bool empty() const { return m_items.empty(); } + + SmartStrStr & _SmartStrStr() const { return *dc; } private: t_stringlist m_items; SmartStrStr * dc = &SmartStrStr::global(); diff --git a/sdk/pfc/alloc.h b/sdk/pfc/alloc.h index 53ba626..4f7a02e 100644 --- a/sdk/pfc/alloc.h +++ b/sdk/pfc/alloc.h @@ -125,7 +125,7 @@ namespace pfc { ~alloc_simple() {delete[] m_data;} - void move_from(t_self & other) { + void move_from(t_self & other) noexcept { delete[] m_data; m_data = replace_null_t(other.m_data); m_size = replace_null_t(other.m_size); diff --git a/sdk/pfc/array.h b/sdk/pfc/array.h index cc00c74..cbbae8c 100644 --- a/sdk/pfc/array.h +++ b/sdk/pfc/array.h @@ -159,7 +159,7 @@ namespace pfc { try { set_size(walk); return; - } catch(std::bad_alloc) { + } catch(std::bad_alloc const &) { if (walk <= minSize) throw; // go on } diff --git a/sdk/pfc/avltree.h b/sdk/pfc/avltree.h index 6287b09..0b7d942 100644 --- a/sdk/pfc/avltree.h +++ b/sdk/pfc/avltree.h @@ -9,15 +9,15 @@ namespace pfc { public: typedef _list_node t_node; typedef _avltree_node t_self; - template _avltree_node(t_param const& param) : t_node(param), m_left(), m_right(), m_depth() {} + template _avltree_node(t_param const& param) : t_node(param) {} typedef refcounted_object_ptr_t t_ptr; typedef t_self* t_rawptr; - t_ptr m_left, m_right; - t_rawptr m_parent; + t_ptr m_left, m_right; // smart ptr, no init + t_rawptr m_parent = nullptr; - t_size m_depth; + t_size m_depth = 0; void link_left(t_self* ptr) throw() { m_left = ptr; @@ -457,6 +457,7 @@ namespace pfc { _unlink_recur(m_root); m_root.release(); } + void clear() throw() { remove_all(); } bool remove(const_iterator const& iter) { PFC_ASSERT(iter.is_valid()); @@ -471,9 +472,8 @@ namespace pfc { return ret; } - t_size get_count() const throw() { - return calc_count(m_root.get_ptr()); - } + t_size get_count() const throw() { return calc_count(m_root.get_ptr()); } + size_t size() const throw() { return get_count(); } template void enumerate(t_callback && p_callback) const { diff --git a/sdk/pfc/bsearch_inline.h b/sdk/pfc/bsearch_inline.h index 92afed5..0d332d4 100644 --- a/sdk/pfc/bsearch_inline.h +++ b/sdk/pfc/bsearch_inline.h @@ -5,7 +5,7 @@ namespace pfc { //deprecated template -inline bool bsearch_inline_t(t_size p_count, const t_callback & p_callback,t_size & p_result) +inline bool bsearch_inline_t(t_size p_count, t_callback && p_callback,t_size & p_result) { t_size max = p_count; t_size min = 0; @@ -49,7 +49,7 @@ inline bool bsearch_simple_inline_t(t_buffer&& p_buffer, t_size p_count, t_value } template -inline bool bsearch_simple_inline_t(t_buffer && p_buffer,t_size p_count,t_value const & p_value,t_size & p_result) +inline bool bsearch_simple_inline_t(t_buffer && p_buffer,t_size p_count,t_value && p_value,t_size & p_result) { t_size max = p_count; t_size min = 0; diff --git a/sdk/pfc/charDownConvert.h b/sdk/pfc/charDownConvert.h index 536acda..33a87a2 100644 --- a/sdk/pfc/charDownConvert.h +++ b/sdk/pfc/charDownConvert.h @@ -25,7 +25,7 @@ namespace pfc { #endif } - char m_data[16]; + char m_data[16] = {}; }; class CharDownConvert { diff --git a/sdk/pfc/debug.h b/sdk/pfc/debug.h index f7fb1ee..cc7acfa 100644 --- a/sdk/pfc/debug.h +++ b/sdk/pfc/debug.h @@ -7,11 +7,16 @@ #endif namespace pfc { + void debugBreak(); [[noreturn]] void crash(); [[noreturn]] void crashWithMessageOnStack( const char * msg ); void outputDebugLine(const char * msg); - // Debug logger service. +#ifdef __APPLE__ + [[noreturn]] void appleThrowException( const char * name, const char * reason ); +#endif + + // Debug logger service. // It is up to the caller to ensure thread safety. You want to create debugLineReceiver instances on app startup and never destroy them. class debugLineReceiver { public: @@ -47,4 +52,4 @@ namespace pfc { #define PFC_DEBUG_PRINT(...) ::pfc::outputDebugLine(pfc::format(__VA_ARGS__)) #else #define PFC_DEBUG_PRINT(...) -#endif \ No newline at end of file +#endif diff --git a/sdk/pfc/event_std.h b/sdk/pfc/event_std.h new file mode 100644 index 0000000..19f12b9 --- /dev/null +++ b/sdk/pfc/event_std.h @@ -0,0 +1,49 @@ +#pragma once + +// Alternate lightweight implementation of pfc::event, with similar method sigantures but no support for multi-event-wait-for-any. +// It's a safe drop-in replacmeent for the regular event - code trying to use unsupported methods will fail to compile rather than behave incorrectly. + +// Rationale: +// Mac/Linux multi-wait-capable pipe-backed event is relatively expensive, in terms of CPU, memory and file descriptors opened. +// On Windows, event_std still outperforms regular win32 event but the difference is mostly insignificant in real life use cases. + +#include +#include +namespace pfc { + class event_std { + public: + void set_state(bool v = true) { + std::scoped_lock lock(m_mutex); + if (m_state != v) { + m_state = v; + if (v) m_condition.notify_all(); + } + } + bool is_set() const { return m_state; } + void wait() { + std::unique_lock lock(m_mutex); + m_condition.wait(lock, [this] { return this->m_state; }); + } + bool wait_for(double timeout) { + if (timeout < 0) { wait(); return true; } + std::unique_lock lock(m_mutex); + return m_condition.wait_for(lock, std::chrono::duration(timeout), [this] { return this->m_state; }); + } + void wait_and_clear() { + std::unique_lock lock(m_mutex); + m_condition.wait(lock, [this] { return this->m_state; }); + m_state = false; + } + bool wait_for_and_clear(double timeout) { + if ( timeout < 0 ) {wait_and_clear(); return true;} + std::unique_lock lock(m_mutex); + bool rv = m_condition.wait_for(lock, std::chrono::duration(timeout), [this] { return this->m_state; }); + if ( rv ) m_state = false; + return rv; + } + private: + volatile bool m_state = false; + std::condition_variable m_condition; + std::mutex m_mutex; + }; +} diff --git a/sdk/pfc/filehandle.cpp b/sdk/pfc/filehandle.cpp index f4cbc79..57359e2 100644 --- a/sdk/pfc/filehandle.cpp +++ b/sdk/pfc/filehandle.cpp @@ -6,7 +6,7 @@ #endif namespace pfc { -void fileHandleClose( fileHandle_t h ) { +void fileHandleClose( fileHandle_t h ) noexcept { if (h == fileHandleInvalid) return; #ifdef _WIN32 CloseHandle( h ); @@ -26,7 +26,7 @@ fileHandle_t fileHandleDup( fileHandle_t h ) { #endif } -void fileHandle::close() { +void fileHandle::close() noexcept { fileHandleClose( h ); clear(); } diff --git a/sdk/pfc/filehandle.h b/sdk/pfc/filehandle.h index b11a25d..c19f087 100644 --- a/sdk/pfc/filehandle.h +++ b/sdk/pfc/filehandle.h @@ -6,26 +6,26 @@ namespace pfc { const fileHandle_t fileHandleInvalid = INVALID_HANDLE_VALUE; #else typedef int fileHandle_t; - const fileHandle_t fileHandleInvalid = -1; + constexpr fileHandle_t fileHandleInvalid = -1; #endif - void fileHandleClose( fileHandle_t h ); + void fileHandleClose( fileHandle_t h ) noexcept; fileHandle_t fileHandleDup( fileHandle_t h ); class fileHandle { public: fileHandle( fileHandle_t val ) : h(val) {} fileHandle() : h ( fileHandleInvalid ) {} - ~fileHandle() { close(); } - fileHandle( fileHandle && other ) { h = other.h; other.clear(); } - void operator=( fileHandle && other ) { close(); h = other.h; other.clear(); } + ~fileHandle() noexcept { close(); } + fileHandle( fileHandle && other ) noexcept { h = other.h; other.clear(); } + void operator=( fileHandle && other ) noexcept { close(); h = other.h; other.clear(); } void operator=( fileHandle_t other ) { close(); h = other; } - void close(); - void clear() { h = fileHandleInvalid; } - bool isValid() { return h != fileHandleInvalid; } + void close() noexcept; + void clear() noexcept { h = fileHandleInvalid; } + bool isValid() noexcept { return h != fileHandleInvalid; } fileHandle_t h; private: - fileHandle( const fileHandle & ); - void operator=( const fileHandle & ); + fileHandle( const fileHandle & ) = delete; + void operator=( const fileHandle & ) = delete; }; } diff --git a/sdk/pfc/filetimetools.cpp b/sdk/pfc/filetimetools.cpp index 810d737..8f312ad 100644 --- a/sdk/pfc/filetimetools.cpp +++ b/sdk/pfc/filetimetools.cpp @@ -51,7 +51,7 @@ static t_filetimestamp ExportSystemTimeLocal(const SYSTEMTIME& st) { localtime_r(&t, &Local); return pfc::fileTimeUtoW(mktime(&Local)); } -static void SystemTimeFromNix(SYSTEMTIME& st, struct tm const& Time) { +static void SystemTimeFromNix(SYSTEMTIME& st, struct tm const& Time, t_filetimestamp origTS) { memset(&st, 0, sizeof(st)); st.wSecond = Time.tm_sec; st.wMinute = Time.tm_min; @@ -60,13 +60,14 @@ static void SystemTimeFromNix(SYSTEMTIME& st, struct tm const& Time) { st.wDayOfWeek = Time.tm_wday; st.wMonth = Time.tm_mon + 1; st.wYear = Time.tm_year + 1900; + st.wMilliseconds = (origTS % filetimestamp_1second_increment) / (filetimestamp_1second_increment/1000); } static bool MakeSystemTime(SYSTEMTIME& st, t_filetimestamp ts) { time_t t = (time_t)pfc::fileTimeWtoU(ts); struct tm Time; if (gmtime_r(&t, &Time) == NULL) return false; - SystemTimeFromNix(st, Time); + SystemTimeFromNix(st, Time, ts); return true; } @@ -74,7 +75,7 @@ static bool MakeSystemTimeLocal(SYSTEMTIME& st, t_filetimestamp ts) { time_t t = (time_t)pfc::fileTimeWtoU(ts); struct tm Time; if (localtime_r(&t, &Time) == NULL) return false; - SystemTimeFromNix(st, Time); + SystemTimeFromNix(st, Time, ts); return true; } @@ -182,7 +183,7 @@ static t_filetimestamp filetimestamp_from_string_internal(const char* date, bool } else { return ExportSystemTime(st); } - } catch (exception_time_error) { + } catch (exception_time_error const &) { return filetimestamp_invalid; } } diff --git a/sdk/pfc/iterators.h b/sdk/pfc/iterators.h index 6bc83b5..00bb424 100644 --- a/sdk/pfc/iterators.h +++ b/sdk/pfc/iterators.h @@ -53,6 +53,9 @@ namespace pfc { bool operator==(const t_self & other) const throw() {return this->m_content == other.m_content;} bool operator!=(const t_self & other) const throw() {return this->m_content != other.m_content;} + + // Returns pointer to referenced item - null if iterator isn't valid + const t_item* get() const noexcept { return this->m_content.is_valid() ? &this->m_content->m_content : nullptr; } protected: t_nodeptr m_content; }; @@ -82,6 +85,9 @@ namespace pfc { bool operator==(const t_self & other) const throw() {return this->m_content == other.m_content;} bool operator!=(const t_self & other) const throw() {return this->m_content != other.m_content;} + + // Returns pointer to referenced item - null if iterator isn't valid + t_item* get() const noexcept { return this->m_content.is_valid() ? &this->m_content->m_content : nullptr; } }; template class forward_iterator { diff --git a/sdk/pfc/list.h b/sdk/pfc/list.h index b3e94c0..6a1550b 100644 --- a/sdk/pfc/list.h +++ b/sdk/pfc/list.h @@ -394,11 +394,11 @@ class list_impl_t : public list_base_t T remove_by_idx(t_size idx) { - T ret = m_buffer[idx]; + T ret = std::move(m_buffer[idx]); t_size n; t_size max = m_buffer.get_size(); for(n=idx+1;n(p_key)); } + template + bool contains(key_t const& arg) const { return have_item(arg); } + template bool query(const _t_key & p_key,_t_value & p_value) const { const t_storage * storage = m_data.find_ptr(t_search_query<_t_key>(p_key)); @@ -135,8 +138,10 @@ namespace pfc { t_size get_count() const throw() {return m_data.get_count();} + size_t size() const throw() { return get_count(); } void remove_all() throw() {m_data.remove_all();} + void clear() throw() { remove_all(); } template void overwrite(const t_source & p_source) { diff --git a/sdk/pfc/nix-objects.cpp b/sdk/pfc/nix-objects.cpp index e35ed1c..01072f8 100644 --- a/sdk/pfc/nix-objects.cpp +++ b/sdk/pfc/nix-objects.cpp @@ -125,8 +125,7 @@ namespace pfc { pfc::array_t< pollfd > v; v.set_size_discard( count ); size_t walk = 0; - for( auto i = total.m_fds.begin(); i != total.m_fds.end(); ++ i ) { - const int fd = *i; + for( auto fd : total.m_fds) { auto & f = v[walk++]; f.fd = fd; f.events = (Reads[fd] ? POLLIN : 0) | (Writes[fd] ? POLLOUT : 0); @@ -166,19 +165,47 @@ namespace pfc { if (f.revents & POLLOUT) Writes += f.fd; if (f.revents & POLLERR) Errors += f.fd; } + PFC_ASSERT( !Reads.m_fds.empty() || !Writes.m_fds.empty() || !Errors.m_fds.empty() ); } return status; } - bool fdCanRead( int fd ) { - return fdWaitRead( fd, 0 ); + inline bool fdCanRead_select( int fdRead ) { + PFC_ASSERT( fdRead < FD_SETSIZE ); + timeval tv = {}; + fd_set set; + FD_ZERO(&set); + FD_SET(fdRead, &set); + + return select(fdRead + 1, &set, nullptr, nullptr, &tv) > 0; + } + inline bool fdCanRead_poll(int fdRead) { + pollfd arg = {fdRead, POLLIN }; + poll(&arg, 1, 0); + return (arg.revents & POLLIN) != 0; } + + bool fdCanRead( int fdRead ) { + if ( fdRead < 0 ) { + PFC_ASSERT( !"???" ); + return false; + } + #ifdef __APPLE__ + // BROKEN extremely inefficient implementation of poll() on Apple systems, avoid if possible + if ( fdRead < FD_SETSIZE ) { + return fdCanRead_select( fdRead ); + } + #endif + return fdCanRead_poll(fdRead); + } + bool fdCanWrite( int fd ) { return fdWaitWrite( fd, 0 ); } bool fdWaitRead( int fd, double timeOutSeconds ) { + if ( timeOutSeconds == 0 ) return fdCanRead( fd ); fdSelect sel; sel.Reads += fd; return sel.Select( timeOutSeconds ) > 0; } @@ -217,6 +244,9 @@ namespace pfc { bool nix_event::wait_for( double p_timeout_seconds ) { return fdWaitRead( m_fd[0], p_timeout_seconds ); } + bool nix_event::is_set() { + return fdCanRead(m_fd[0]); + } bool nix_event::g_wait_for( int p_event, double p_timeout_seconds ) { return fdWaitRead( p_event, p_timeout_seconds ); } @@ -300,14 +330,16 @@ namespace pfc { #endif } + static int openDevRand() { + int ret = open("/dev/urandom", O_RDONLY); + if ( ret < 0 ) throw exception_nix(); + return ret; + } void nixGetRandomData( void * outPtr, size_t outBytes ) { try { - fileHandle randomData; - randomData = open("/dev/urandom", O_RDONLY); - if (randomData.h < 0) throw exception_nix(); + static fileHandle randomData = openDevRand(); if (read(randomData.h, outPtr, outBytes) != outBytes) throw exception_nix(); - } - catch (std::exception const & e) { + } catch (std::exception const & e) { throw std::runtime_error("getRandomData failure"); } } diff --git a/sdk/pfc/nix-objects.h b/sdk/pfc/nix-objects.h index c795a64..d7d8bb7 100644 --- a/sdk/pfc/nix-objects.h +++ b/sdk/pfc/nix-objects.h @@ -82,8 +82,10 @@ namespace pfc { void set_state( bool state ); - bool is_set( ) {return wait_for(0); } + bool is_set( ); + void wait_and_clear() { wait(); set_state(false); } + void wait() { wait_for(-1); } bool wait_for( double p_timeout_seconds ); static bool g_wait_for( int p_event, double p_timeout_seconds ); diff --git a/sdk/pfc/obj-c.mm b/sdk/pfc/obj-c.mm index 529041f..e3dc734 100644 --- a/sdk/pfc/obj-c.mm +++ b/sdk/pfc/obj-c.mm @@ -16,6 +16,7 @@ #endif #include "pfc.h" +#include "sortstring.h" namespace pfc { @@ -119,6 +120,24 @@ int appleNaturalSortCompareI(const char* s1, const char* s2) { return (int) [str1 localizedCaseInsensitiveCompare: str2]; } } + [[noreturn]] void appleThrowException( const char * name, const char * reason ) { + @autoreleasepool { + @throw [NSException exceptionWithName: [NSString stringWithUTF8String: name] reason:[NSString stringWithUTF8String: reason] userInfo:nil]; + } + } +#ifndef PFC_SORTSTRING_GENERIC + sortString_t makeSortString(const char* str) { + sortString_t ret; + ret.Attach( CFStringCreateWithCString(NULL, str, kCFStringEncodingUTF8) ); + return ret; + } + int sortStringCompare(sortString_t const& s1, sortString_t const& s2) { + return (int) CFStringCompare(s1.p, s2.p, kCFCompareLocalized | kCFCompareNumerically ); + } + int sortStringCompareI(sortString_t const& s1, sortString_t const& s2) { + return (int) CFStringCompare(s1.p, s2.p, kCFCompareLocalized | kCFCompareNumerically | kCFCompareCaseInsensitive ); + } +#endif } #endif diff --git a/sdk/pfc/other.cpp b/sdk/pfc/other.cpp index 618c8c9..2fbc306 100644 --- a/sdk/pfc/other.cpp +++ b/sdk/pfc/other.cpp @@ -244,11 +244,19 @@ void pfc::outputDebugLine(const char * msg) { #endif } +void pfc::debugBreak() { +#ifdef _WIN32 + __debugbreak(); +#else + raise(SIGTRAP); +#endif +} + #if PFC_DEBUG #ifdef _WIN32 void pfc::myassert_win32(const wchar_t * _Message, const wchar_t *_File, unsigned _Line) { - if (IsDebuggerPresent()) pfc::crash(); + if (IsDebuggerPresent()) debugBreak(); PFC_DEBUGLOG << "PFC_ASSERT failure: " << _Message; PFC_DEBUGLOG << "PFC_ASSERT location: " << _File << " : " << _Line; _wassert(_Message,_File,_Line); @@ -258,11 +266,7 @@ void pfc::myassert_win32(const wchar_t * _Message, const wchar_t *_File, unsigne void pfc::myassert(const char * _Message, const char *_File, unsigned _Line) { PFC_DEBUGLOG << "Assert failure: \"" << _Message << "\" in: " << _File << " line " << _Line; -#ifdef _WIN32 - __debugbreak(); -#else - raise(SIGTRAP); -#endif + debugBreak(); } #endif diff --git a/sdk/pfc/pathUtils.cpp b/sdk/pfc/pathUtils.cpp index 68db25a..6f45664 100644 --- a/sdk/pfc/pathUtils.cpp +++ b/sdk/pfc/pathUtils.cpp @@ -183,8 +183,14 @@ string getIllegalNameChars(bool allowWC) { static const char * const specialIllegalNames[] = { "con", "aux", "lst", "prn", "nul", "eof", "inp", "out" }; +#endif // _WINDOWS + +#ifdef _WIN32 +static constexpr unsigned maxPathComponent = 255; +#else +static constexpr unsigned maxPathComponent = NAME_MAX; +#endif -enum { maxPathComponent = 255 }; static size_t safeTruncat( const char * str, size_t maxLen ) { size_t i = 0; size_t ret = 0; @@ -226,7 +232,6 @@ static string truncatePathComponent( string name, bool preserveExt ) { size_t truncat = safeTruncat( name.c_str(), maxPathComponent ); return name.subString(0, truncat); } -#endif // _WINDOWS static string trailingSanity(string name, bool preserveExt, const char * lstIllegal) { @@ -278,9 +283,9 @@ string validateFileName(string name, bool allowWC, bool preserveExt, charReplace name = trailingSanity(name, preserveExt, lstIllegal); } -#ifdef _WINDOWS name = truncatePathComponent(name, preserveExt); +#ifdef _WINDOWS for( auto p : specialIllegalNames ) { if (pfc::stringEqualsI_ascii( name.c_str(), p ) ) { name += "-"; diff --git a/sdk/pfc/pfc-license.txt b/sdk/pfc/pfc-license.txt index 0ab480d..dd237fe 100644 --- a/sdk/pfc/pfc-license.txt +++ b/sdk/pfc/pfc-license.txt @@ -1,4 +1,4 @@ -Copyright (C) 2002-2023 Peter Pawlowski +Copyright (C) 2002-2024 Peter Pawlowski This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/sdk/pfc/pfc.vcxproj b/sdk/pfc/pfc.vcxproj index 082eab7..a03c81c 100644 --- a/sdk/pfc/pfc.vcxproj +++ b/sdk/pfc/pfc.vcxproj @@ -75,19 +75,19 @@ StaticLibrary true - v143 + v142 Unicode StaticLibrary true - v143 + v142 Unicode StaticLibrary true - v143 + v142 Unicode @@ -105,7 +105,7 @@ StaticLibrary true - v143 + v142 Unicode @@ -122,17 +122,17 @@ StaticLibrary - v143 + v142 Unicode StaticLibrary - v143 + v142 Unicode StaticLibrary - v143 + v142 Unicode @@ -147,7 +147,7 @@ StaticLibrary - v143 + v142 Unicode @@ -429,6 +429,7 @@ stdcpp17 true true + MultiThreadedDLL NDEBUG;%(PreprocessorDefinitions) @@ -665,6 +666,7 @@ + @@ -703,6 +705,7 @@ + diff --git a/sdk/pfc/pfc.vcxproj.filters b/sdk/pfc/pfc.vcxproj.filters index d1a820d..4a94674 100644 --- a/sdk/pfc/pfc.vcxproj.filters +++ b/sdk/pfc/pfc.vcxproj.filters @@ -357,6 +357,12 @@ Header Files + + Header Files + + + Header Files + diff --git a/sdk/pfc/pfc.xcodeproj/project.pbxproj b/sdk/pfc/pfc.xcodeproj/project.pbxproj index 14c6c2a..8af4f46 100644 --- a/sdk/pfc/pfc.xcodeproj/project.pbxproj +++ b/sdk/pfc/pfc.xcodeproj/project.pbxproj @@ -16,6 +16,10 @@ 0F14904D242E44C300D0BD81 /* notifyList.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F14904C242E44C300D0BD81 /* notifyList.h */; }; 0F14904F242E44ED00D0BD81 /* autoref.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F14904E242E44ED00D0BD81 /* autoref.h */; }; 0F149051242E454C00D0BD81 /* weakRef.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F149050242E454C00D0BD81 /* weakRef.h */; }; + 0F22012C2B0CCEA60074C1FC /* sortstring.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2201292B0CCEA60074C1FC /* sortstring.h */; }; + 0F22012D2B0CCEA60074C1FC /* string_simple.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F22012A2B0CCEA60074C1FC /* string_simple.h */; }; + 0F22012E2B0CCEA60074C1FC /* sort2.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F22012B2B0CCEA60074C1FC /* sort2.h */; }; + 0F2201322B0CCF3D0074C1FC /* CFObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2201312B0CCF3D0074C1FC /* CFObject.h */; }; 0F2F4BF7250BFF660014812D /* pfc-fb2k-hooks.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2F4BEF250BFF660014812D /* pfc-fb2k-hooks.h */; }; 0F2F4BF8250BFF660014812D /* killswitch.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2F4BF0250BFF660014812D /* killswitch.h */; }; 0F2F4BF9250BFF660014812D /* pfc-fb2k-hooks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2F4BF1250BFF660014812D /* pfc-fb2k-hooks.cpp */; }; @@ -175,6 +179,11 @@ 0F14904C242E44C300D0BD81 /* notifyList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = notifyList.h; sourceTree = ""; }; 0F14904E242E44ED00D0BD81 /* autoref.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = autoref.h; sourceTree = ""; }; 0F149050242E454C00D0BD81 /* weakRef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = weakRef.h; sourceTree = ""; }; + 0F17B3DA2B5E8F0E00FC86C1 /* event_std.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = event_std.h; sourceTree = ""; }; + 0F2201292B0CCEA60074C1FC /* sortstring.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sortstring.h; sourceTree = ""; }; + 0F22012A2B0CCEA60074C1FC /* string_simple.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = string_simple.h; sourceTree = ""; }; + 0F22012B2B0CCEA60074C1FC /* sort2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sort2.h; sourceTree = ""; }; + 0F2201312B0CCF3D0074C1FC /* CFObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CFObject.h; sourceTree = ""; }; 0F2F4BEF250BFF660014812D /* pfc-fb2k-hooks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "pfc-fb2k-hooks.h"; sourceTree = ""; }; 0F2F4BF0250BFF660014812D /* killswitch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = killswitch.h; sourceTree = ""; }; 0F2F4BF1250BFF660014812D /* pfc-fb2k-hooks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "pfc-fb2k-hooks.cpp"; sourceTree = ""; }; @@ -340,6 +349,11 @@ B1DD35C2198A701100EF7043 /* Source */ = { isa = PBXGroup; children = ( + 0F17B3DA2B5E8F0E00FC86C1 /* event_std.h */, + 0F2201312B0CCF3D0074C1FC /* CFObject.h */, + 0F22012B2B0CCEA60074C1FC /* sort2.h */, + 0F2201292B0CCEA60074C1FC /* sortstring.h */, + 0F22012A2B0CCEA60074C1FC /* string_simple.h */, 0F7A1B682A692C88004F89FB /* filetimetools.cpp */, 0F7A1B692A692C88004F89FB /* filetimetools.h */, 0F0794D227C90AA4006BAD7F /* charDownConvert.cpp */, @@ -479,7 +493,9 @@ B1DD3635198A702E00EF7043 /* sort.h in Headers */, B1DD3648198A702E00EF7043 /* win-objects.h in Headers */, B1DD3607198A702E00EF7043 /* array.h in Headers */, + 0F2201322B0CCF3D0074C1FC /* CFObject.h in Headers */, B1DD360B198A702E00EF7043 /* binary_search.h in Headers */, + 0F22012D2B0CCEA60074C1FC /* string_simple.h in Headers */, B1DD3621198A702E00EF7043 /* memalign.h in Headers */, B1B502D6198FF75000525EAF /* wildcard.h in Headers */, B1DD361A198A702E00EF7043 /* guid.h in Headers */, @@ -507,11 +523,13 @@ B1DD3627198A702E00EF7043 /* other.h in Headers */, 0F2F4BFC250BFF660014812D /* suppress_fb2k_hooks.h in Headers */, B17EB26E1E85358D0057E2A4 /* pool.h in Headers */, + 0F22012E2B0CCEA60074C1FC /* sort2.h in Headers */, B17EB26F1E85358D0057E2A4 /* splitString.h in Headers */, 0F2F4BFF250BFF660014812D /* cmd_thread.h in Headers */, B1DD362B198A702E00EF7043 /* primitives_part2.h in Headers */, 0F2F4BFD250BFF660014812D /* platform-objects.h in Headers */, B1DD3632198A702E00EF7043 /* ref_counter.h in Headers */, + 0F22012C2B0CCEA60074C1FC /* sortstring.h in Headers */, B1DD3630198A702E00EF7043 /* ptr_list.h in Headers */, B17EB2701E85358D0057E2A4 /* wait_queue.h in Headers */, B1DD362C198A702E00EF7043 /* primitives.h in Headers */, @@ -773,7 +791,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 12.1; - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 11.0; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; SKIP_INSTALL = YES; @@ -825,7 +843,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 12.1; - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 11.0; SDKROOT = macosx; SKIP_INSTALL = YES; }; diff --git a/sdk/pfc/pocket_char_ops.h b/sdk/pfc/pocket_char_ops.h index b877ae9..d6f491c 100644 --- a/sdk/pfc/pocket_char_ops.h +++ b/sdk/pfc/pocket_char_ops.h @@ -138,22 +138,27 @@ size_t utf8_encode_char(unsigned wide, char * target) noexcept target[5] = 0x80 | (wide & 0x3F); wide = wide >> 6; wide |= 0x4000000; + [[fallthrough]]; case 5: target[4] = 0x80 | (wide & 0x3F); wide = wide >> 6; wide |= 0x200000; + [[fallthrough]]; case 4: target[3] = 0x80 | (wide & 0x3F); wide = wide >> 6; wide |= 0x10000; + [[fallthrough]]; case 3: target[2] = 0x80 | (wide & 0x3F); wide = wide >> 6; wide |= 0x800; + [[fallthrough]]; case 2: target[1] = 0x80 | (wide & 0x3F); wide = wide >> 6; wide |= 0xC0; + [[fallthrough]]; case 1: target[0] = wide & 0xFF; } diff --git a/sdk/pfc/primitives.h b/sdk/pfc/primitives.h index dc9f675..a4801dc 100644 --- a/sdk/pfc/primitives.h +++ b/sdk/pfc/primitives.h @@ -469,22 +469,12 @@ namespace pfc { } } - - - template - inline t_size append_t(t_array & p_array,const T & p_item) - { - t_size old_count = p_array.get_size(); - p_array.set_size(old_count + 1); - p_array[old_count] = p_item; - return old_count; - } template inline t_size append_t(t_array & p_array, T && p_item) { t_size old_count = p_array.get_size(); p_array.set_size(old_count + 1); - p_array[old_count] = std::move(p_item); + p_array[old_count] = std::forward(p_item); return old_count; } diff --git a/sdk/pfc/sortstring.h b/sdk/pfc/sortstring.h new file mode 100644 index 0000000..83a939a --- /dev/null +++ b/sdk/pfc/sortstring.h @@ -0,0 +1,30 @@ +#pragma once + +#ifdef _WIN32 +#include // std::unique_ptr<> +#endif +#ifdef __APPLE__ +#include "CFObject.h" +#endif + +namespace pfc { +#ifdef _WIN32 + typedef std::unique_ptr sortString_t; + sortString_t makeSortString(const char* str); + sortString_t makeSortString(const wchar_t* str); + int sortStringCompare(sortString_t const& s1, sortString_t const& s2); + int sortStringCompareI(sortString_t const& s1, sortString_t const& s2); +#elif defined(__APPLE__) + typedef CFObject sortString_t; + sortString_t makeSortString(const char* str); + int sortStringCompare(sortString_t const& s1, sortString_t const& s2); + int sortStringCompareI(sortString_t const& s1, sortString_t const& s2); +#else +#define PFC_SORTSTRING_GENERIC + typedef pfc::string8 sortString_t; + inline sortString_t makeSortString(const char* str) { return str; } + inline sortString_t makeSortString(pfc::string8&& str) { return std::move(str); } + int sortStringCompare(const char* str1, const char* str2); + int sortStringCompareI(const char* str1, const char* str2); +#endif +} diff --git a/sdk/pfc/string-compare.cpp b/sdk/pfc/string-compare.cpp index cd598dd..a0449d4 100644 --- a/sdk/pfc/string-compare.cpp +++ b/sdk/pfc/string-compare.cpp @@ -3,8 +3,25 @@ #include "string-compare.h" #include "string_base.h" #include "debug.h" +#include "bsearch_inline.h" +#include "sortstring.h" namespace pfc { + unsigned charToANSI(unsigned GotChar, unsigned fallback) { + if (GotChar < 128) return GotChar; + + static constexpr uint16_t from[] = {L'\u00C0', L'\u00C1', L'\u00C2', L'\u00C3', L'\u00C4', L'\u00C5', L'\u00C7', L'\u00C8', L'\u00C9', L'\u00CA', L'\u00CB', L'\u00CC', L'\u00CD', L'\u00CE', L'\u00CF', L'\u00D1', L'\u00D2', L'\u00D3', L'\u00D4', L'\u00D5', L'\u00D6', L'\u00D8', L'\u00D9', L'\u00DA', L'\u00DB', L'\u00DC', L'\u00DD', L'\u00E0', L'\u00E1', L'\u00E2', L'\u00E3', L'\u00E4', L'\u00E5', L'\u00E7', L'\u00E8', L'\u00E9', L'\u00EA', L'\u00EB', L'\u00EC', L'\u00ED', L'\u00EE', L'\u00EF', L'\u00F0', L'\u00F1', L'\u00F2', L'\u00F3', L'\u00F4', L'\u00F5', L'\u00F6', L'\u00F8', L'\u00F9', L'\u00FA', L'\u00FB', L'\u00FC', L'\u00FD', L'\u0100', L'\u0101', L'\u0102', L'\u0103', L'\u0104', L'\u0105', L'\u0106', L'\u0107', L'\u0108', L'\u0109', L'\u010A', L'\u010B', L'\u010C', L'\u010D', L'\u010E', L'\u010F', L'\u0110', L'\u0111', L'\u0112', L'\u0113', L'\u0114', L'\u0115', L'\u0116', L'\u0117', L'\u0118', L'\u0119', L'\u011A', L'\u011B', L'\u011C', L'\u011D', L'\u011E', L'\u011F', L'\u0120', L'\u0121', L'\u0122', L'\u0123', L'\u0128', L'\u0129', L'\u012A', L'\u012B', L'\u012C', L'\u012D', L'\u012E', L'\u012F', L'\u0130', L'\u0131', L'\u0134', L'\u0135', L'\u0136', L'\u0137', L'\u0139', L'\u013A', L'\u013B', L'\u013C', L'\u013D', L'\u013E', L'\u013F', L'\u0140', L'\u0141', L'\u0142', L'\u0143', L'\u0144', L'\u0145', L'\u0146', L'\u0147', L'\u0148', L'\u0149', L'\u014A', L'\u014B', L'\u014C', L'\u014D', L'\u014E', L'\u014F', L'\u0150', L'\u0151', L'\u0154', L'\u0155', L'\u0156', L'\u0157', L'\u0158', L'\u0159', L'\u015A', L'\u015B', L'\u015C', L'\u015D', L'\u015E', L'\u015F', L'\u0160', L'\u0161', L'\u0162', L'\u0163', L'\u0164', L'\u0165', L'\u0166', L'\u0167', L'\u0168', L'\u0169', L'\u016A', L'\u016B', L'\u016C', L'\u016D', L'\u016E', L'\u016F', L'\u0170', L'\u0171', L'\u0172', L'\u0173', L'\u0174', L'\u0175', L'\u0176', L'\u0177', L'\u0178', L'\u0179', L'\u017A', L'\u017B', L'\u017C', L'\u017D', L'\u017E'}; + static constexpr uint16_t to[] = {L'\u0041', L'\u0041', L'\u0041', L'\u0041', L'\u0041', L'\u0041', L'\u0043', L'\u0045', L'\u0045', L'\u0045', L'\u0045', L'\u0049', L'\u0049', L'\u0049', L'\u0049', L'\u004E', L'\u004F', L'\u004F', L'\u004F', L'\u004F', L'\u004F', L'\u004F', L'\u0055', L'\u0055', L'\u0055', L'\u0055', L'\u0059', L'\u0061', L'\u0061', L'\u0061', L'\u0061', L'\u0061', L'\u0061', L'\u0063', L'\u0065', L'\u0065', L'\u0065', L'\u0065', L'\u0069', L'\u0069', L'\u0069', L'\u0069', L'\u006F', L'\u006E', L'\u006F', L'\u006F', L'\u006F', L'\u006F', L'\u006F', L'\u006F', L'\u0075', L'\u0075', L'\u0075', L'\u0075', L'\u0079', L'\u0041', L'\u0061', L'\u0041', L'\u0061', L'\u0041', L'\u0061', L'\u0043', L'\u0063', L'\u0043', L'\u0063', L'\u0043', L'\u0063', L'\u0043', L'\u0063', L'\u0044', L'\u0064', L'\u0044', L'\u0064', L'\u0045', L'\u0065', L'\u0045', L'\u0065', L'\u0045', L'\u0065', L'\u0045', L'\u0065', L'\u0045', L'\u0065', L'\u0047', L'\u0067', L'\u0047', L'\u0067', L'\u0047', L'\u0067', L'\u0047', L'\u0067', L'\u0049', L'\u0069', L'\u0049', L'\u0069', L'\u0049', L'\u0069', L'\u0049', L'\u0069', L'\u0049', L'\u0069', L'\u004A', L'\u006A', L'\u004B', L'\u006B', L'\u004C', L'\u006C', L'\u004C', L'\u006C', L'\u004C', L'\u006C', L'\u004C', L'\u006C', L'\u004C', L'\u006C', L'\u004E', L'\u006E', L'\u004E', L'\u006E', L'\u004E', L'\u006E', L'\u006E', L'\u004E', L'\u006E', L'\u004F', L'\u006F', L'\u004F', L'\u006F', L'\u004F', L'\u006F', L'\u0052', L'\u0072', L'\u0052', L'\u0072', L'\u0052', L'\u0072', L'\u0053', L'\u0073', L'\u0053', L'\u0073', L'\u0053', L'\u0073', L'\u0053', L'\u0073', L'\u0054', L'\u0074', L'\u0054', L'\u0074', L'\u0054', L'\u0074', L'\u0055', L'\u0075', L'\u0055', L'\u0075', L'\u0055', L'\u0075', L'\u0055', L'\u0075', L'\u0055', L'\u0075', L'\u0055', L'\u0075', L'\u0057', L'\u0077', L'\u0059', L'\u0079', L'\u0059', L'\u005A', L'\u007A', L'\u005A', L'\u007A', L'\u005A', L'\u007A'}; + static_assert(std::size(from) == std::size(to)); + + size_t idx; + if (bsearch_simple_inline_t(from, std::size(from), GotChar, idx)) { + return to[idx]; + } + + return fallback; + } + int stricmp_ascii_partial(const char* str, const char* substr) throw() { size_t walk = 0; for (;;) { @@ -99,31 +116,38 @@ namespace pfc { while (char_is_numeric(s2[l2])) ++l2; size_t l = max_t(l1, l2); - for (size_t w = 0; w < l; ++w) { - char digit1, digit2; - - t_ssize off; - - off = w + l1 - l; - if (off >= 0) { - digit1 = s1[w - l + l1]; - } else { - digit1 = 0; + for (int pass = 0; pass < 2; ++pass) { + const char filler = pass ? 'z' : '0'; + for (size_t w = 0; w < l; ++w) { + char digit1 = filler, digit2 = filler; + + t_ssize off; + + off = w + l1 - l; + if (off >= 0) { + digit1 = s1[w - l + l1]; + } + off = w + l2 - l; + if (off >= 0) { + digit2 = s2[w - l + l2]; + } + if (digit1 < digit2) return -1; + if (digit1 > digit2) return 1; } - off = w + l2 - l; - if (off >= 0) { - digit2 = s2[w - l + l2]; - } else { - digit2 = 0; - } - if (digit1 < digit2) return -1; - if (digit1 > digit2) return 1; } - s1 += l1; s2 += l2; continue; } + unsigned alt1 = charToANSI(c1, c1), alt2 = charToANSI(c2, c2); + if (alt1 != c1 || alt2 != c2) { + if (insensitive) { + alt1 = charLower(alt1); + alt2 = charLower(alt2); + } + if (alt1 < alt2) return -1; + if (alt1 > alt2) return 1; + } if (insensitive) { c1 = charLower(c1); @@ -209,5 +233,12 @@ namespace pfc { s1 += d1; s2 += d2; } } +#ifdef PFC_SORTSTRING_GENERIC + int sortStringCompare(const char* str1, const char* str2) { + return naturalSortCompare(str1, str2); + } + int sortStringCompareI(const char* str1, const char* str2) { + return naturalSortCompareI(str1, str2); + } +#endif } - diff --git a/sdk/pfc/string_base.cpp b/sdk/pfc/string_base.cpp index 2c82abf..b3b743e 100644 --- a/sdk/pfc/string_base.cpp +++ b/sdk/pfc/string_base.cpp @@ -161,6 +161,19 @@ string8 string_filename(const char * fn) return ret; } +const char * extract_ext_v2( const char * filenameDotExt ) { + auto split = strrchr(filenameDotExt, '.'); + return split ? split+1 : ""; +} + +string8 remove_ext_v2( const char * filenameDotExt ) { + auto split = strrchr(filenameDotExt, '.'); + string8 ret; + if ( split ) ret.set_string_nc( filenameDotExt, split-filenameDotExt ); + else ret = filenameDotExt; + return ret; +} + const char * filename_ext_v2( const char * fn, char slash ) { if ( slash == 0 ) { slash = pfc::io::path::getDefaultSeparator(); @@ -1354,4 +1367,37 @@ void string_base::fix_dir_separator(char c) { return ret; } + pfc::string8 recover_invalid_utf8(const char* in, const char* subst) { + pfc::string8 ret; ret.prealloc(strlen(in)); + for (;;) { + char c = *in; + if (c == 0) break; + if (c < ' ') { + ret += subst; + } else { + ret.add_byte(c); + } + ++in; + } + return ret; + } + static bool is_spacing(char c) { + switch (c) { + case ' ': case '\n': case '\r': case '\t': return true; + default: return false; + } + } + pfc::string8 string_trim_spacing(const char* in) { + const char* temp_ptr = in; + while (is_spacing(*temp_ptr)) temp_ptr++; + const char* temp_start = temp_ptr; + const char* temp_end = temp_ptr; + while (*temp_ptr) + { + if (!is_spacing(*temp_ptr)) temp_end = temp_ptr + 1; + temp_ptr++; + } + + return string_part_ref { temp_start, (size_t)(temp_end - temp_start) }; + } } //namespace pfc diff --git a/sdk/pfc/string_base.h b/sdk/pfc/string_base.h index c68793c..12dfa4d 100644 --- a/sdk/pfc/string_base.h +++ b/sdk/pfc/string_base.h @@ -16,7 +16,6 @@ namespace pfc { bool is_lower_ascii(const char * param); bool is_multiline(const char * p_string,t_size p_len = SIZE_MAX); bool has_path_bad_chars(const char * param); - void recover_invalid_utf8(const char * src,char * out,unsigned replace);//out must be enough to hold strlen(char) + 1, or appropiately bigger if replace needs multiple chars void convert_to_lower_ascii(const char * src,t_size max,char * out,char replace = '?');//out should be at least strlen(src)+1 long template inline char_t ascii_tolower(char_t c) {if (c >= 'A' && c <= 'Z') c += 'a' - 'A'; return c;} @@ -107,7 +106,23 @@ namespace pfc { t_size wide_decode_char(const wchar_t * p_source,unsigned * p_out,t_size p_source_length = SIZE_MAX) noexcept; t_size wide_encode_char(unsigned c,wchar_t * out) noexcept; - + size_t uni_char_length(const char *); + size_t uni_char_length(const char16_t *); + size_t uni_char_length(const wchar_t *); + + size_t uni_decode_char(const char16_t * p_source, unsigned & p_out, size_t p_source_length = SIZE_MAX) noexcept; + size_t uni_decode_char(const char * p_source, unsigned & p_out, size_t p_source_length = SIZE_MAX) noexcept; + size_t uni_decode_char(const wchar_t * p_source, unsigned & p_out, size_t p_source_length = SIZE_MAX) noexcept; + + size_t uni_encode_char(unsigned c, char* out) noexcept; + size_t uni_encode_char(unsigned c, char16_t* out) noexcept; + size_t uni_encode_char(unsigned c, wchar_t* out) noexcept; + +#ifdef __cpp_char8_t + inline size_t uni_char_length(const char8_t* arg) { return uni_char_length(reinterpret_cast(arg)); } + inline size_t uni_decode_char(const char8_t* p_source, unsigned& p_out, size_t p_source_length = SIZE_MAX) noexcept { return uni_decode_char(reinterpret_cast(p_source), p_out, p_source_length); } + inline size_t uni_encode_char(unsigned c, char8_t* out) noexcept { return uni_encode_char(c, reinterpret_cast(out)); } +#endif t_size strstr_ex(const char * p_string,t_size p_string_len,const char * p_substring,t_size p_substring_len) noexcept; @@ -215,6 +230,8 @@ namespace pfc { string8 string_filename_ext(const char * fn); const char * filename_ext_v2 ( const char * fn, char slash = 0 ); + string8 remove_ext_v2( const char * fileNameDotExt ); // Just removes extension, assumes argument to hold just filename.ext, not whole path + const char * extract_ext_v2( const char * fileNameDotExt ); // Just extracts extension, assumes argument to hold just filename.ext, not whole path size_t find_extension_offset(const char * src); string8 string_extension(const char * src); @@ -413,4 +430,9 @@ namespace pfc { } pfc::string8 prefixLines(const char* str, const char* prefix, const char * setEOL = "\n"); + + + pfc::string8 recover_invalid_utf8(const char* in, const char* subst = "_"); + + pfc::string8 string_trim_spacing(const char* in); } diff --git a/sdk/pfc/string_list.h b/sdk/pfc/string_list.h index 75d047e..d7fe975 100644 --- a/sdk/pfc/string_list.h +++ b/sdk/pfc/string_list.h @@ -26,6 +26,8 @@ namespace pfc { template string_list_impl & operator+=(const t_what & p_source) {pfc::append_t(m_data, p_source); return *this;} void set_item(size_t idx, const char* str) { m_data[idx] = str; } + + void remove_mask(bit_array const& mask) { pfc::remove_mask_t(m_data, mask); } private: template void _append(const t_what & p_source) { const t_size toadd = p_source.get_size(), base = m_data.get_size(); diff --git a/sdk/pfc/syncd_storage.h b/sdk/pfc/syncd_storage.h index d38c72e..9b82a02 100644 --- a/sdk/pfc/syncd_storage.h +++ b/sdk/pfc/syncd_storage.h @@ -12,9 +12,9 @@ class syncd_storage { template syncd_storage(const t_source & p_source) : m_object(p_source) {} template - void set(t_source const & p_in) { + void set(t_source && p_in) { inWriteSync(m_sync); - m_object = p_in; + m_object = std::forward( p_in ); } template void get(t_destination & p_out) const { @@ -26,7 +26,7 @@ class syncd_storage { return m_object; } template - const t_self & operator=(t_source const & p_source) {set(p_source); return *this;} + const t_self & operator=(t_source && p_source) {set(std::forward(p_source)); return *this;} private: mutable ::pfc::readWriteLock m_sync; t_object m_object; @@ -47,13 +47,14 @@ class syncd_storage_flagged { m_changed_flag = p_flag; } template - void set(t_source const & p_in) { + void set(t_source && p_in) { inWriteSync(m_sync); - m_object = p_in; + m_object = std::forward(p_in); m_changed_flag = true; } bool has_changed() const { - inReadSync(m_sync); + // No point in locking here + // inReadSync(m_sync); return m_changed_flag; } t_object peek() const {inReadSync(m_sync); return m_object;} @@ -86,7 +87,19 @@ class syncd_storage_flagged { m_changed_flag = false; } template - const t_self & operator=(t_source const & p_source) {set(p_source); return *this;} + const t_self & operator=(t_source && p_source) {set(std::forward(p_source)); return *this;} + + template + bool compare_and_set(arg_t&& arg) { + inWriteSync(m_sync); + bool ret = false; + if (arg != m_object) { + m_object = std::forward(arg); + m_changed_flag = true; + ret = true; + } + return ret; + } private: mutable volatile bool m_changed_flag; mutable ::pfc::readWriteLock m_sync; diff --git a/sdk/pfc/threadSafeObj.h b/sdk/pfc/threadSafeObj.h new file mode 100644 index 0000000..dd96c21 --- /dev/null +++ b/sdk/pfc/threadSafeObj.h @@ -0,0 +1,39 @@ +#pragma once +namespace pfc { + + template + struct threadSafeObjCommon { + typedef mutex_t_ mutex_t; + typedef obj_t_ obj_t; + template threadSafeObjCommon( arg_t && ... arg ) : m_obj(std::forward(arg) ... ) {} + mutex_t m_mutex; + obj_t m_obj; + }; + + template + class threadSafeObjLock { + typedef threadSafeObjLock self_t; + common_t & m_common; + public: + typename common_t::obj_t & operator*() { return m_common.m_obj; } + typename common_t::obj_t * operator->() { return & m_common.m_obj; } + + threadSafeObjLock( common_t & arg ) : m_common(arg) { m_common.m_mutex.lock(); } + ~threadSafeObjLock( ) { m_common.m_mutex.unlock(); } + threadSafeObjLock( const self_t & ) = delete; + void operator=( const self_t & ) = delete; + }; + + template + class threadSafeObj { + typedef threadSafeObjCommon common_t; + typedef threadSafeObjLock lock_t; + common_t m_common; + public: + template + threadSafeObj( arg_t && ... arg ) : m_common( std::forward(arg) ... ) {} + + lock_t get() { return lock_t(m_common); } + }; + +} diff --git a/sdk/pfc/threads.cpp b/sdk/pfc/threads.cpp index ab23dce..1e0efc9 100644 --- a/sdk/pfc/threads.cpp +++ b/sdk/pfc/threads.cpp @@ -11,7 +11,7 @@ #include "threads.h" #include "debug.h" -#include "ptrholder.h" +#include #include @@ -180,9 +180,9 @@ namespace pfc { } void splitThread(thread::arg_t const & arg, std::function f) { - ptrholder_t< std::function > arg2 ( new std::function(f) ); + auto arg2 = std::make_unique >(f); #ifdef _WIN32 - HANDLE h = MyBeginThread(winSplitThreadProc, arg2.get_ptr(), NULL, arg.winThreadPriority ); + HANDLE h = MyBeginThread(winSplitThreadProc, arg2.get(), NULL, arg.winThreadPriority ); CloseHandle(h); #else #ifdef __APPLE__ @@ -194,11 +194,11 @@ namespace pfc { attr.apply( arg ); - if (pthread_create(&thread, &attr.a, nixSplitThreadProc, arg2.get_ptr()) != 0) thread::couldNotCreateThread(); + if (pthread_create(&thread, &attr.a, nixSplitThreadProc, arg2.get()) != 0) thread::couldNotCreateThread(); pthread_detach(thread); #endif - arg2.detach(); + arg2.release(); } #ifndef __APPLE__ // Stub for non Apple diff --git a/sdk/pfc/threads.h b/sdk/pfc/threads.h index 1338e34..5a5b8aa 100644 --- a/sdk/pfc/threads.h +++ b/sdk/pfc/threads.h @@ -62,7 +62,8 @@ namespace pfc { //! Valid thread object (created and not joined)? bool isActive() const; //! Joins the thread: blocks until complete, releases resources. \n - //! After waitTillDone() returns, isActive() becomes false. + //! After waitTillDone() returns, isActive() becomes false. \n + //! No-op if thread not started. void waitTillDone() {close();} #ifdef _WIN32 void winStart(int priority, DWORD * outThreadID); diff --git a/sdk/pfc/timers.h b/sdk/pfc/timers.h index 643e8d7..d0b50ea 100644 --- a/sdk/pfc/timers.h +++ b/sdk/pfc/timers.h @@ -70,19 +70,24 @@ class hires_timer { } private: double _query(t_uint64 p_val) const { - return (double)( p_val - m_start ) / (double) g_query_freq(); + return (double)( p_val - m_start ) * m_mul; } static t_uint64 g_query() { LARGE_INTEGER val; if (!QueryPerformanceCounter(&val)) throw pfc::exception_not_implemented(); return val.QuadPart; } + static double init_mul() { + return 1.0 / (double)g_query_freq(); + } static t_uint64 g_query_freq() { LARGE_INTEGER val; if (!QueryPerformanceFrequency(&val)) throw pfc::exception_not_implemented(); + PFC_ASSERT(val.QuadPart > 0); return val.QuadPart; } t_uint64 m_start; + double m_mul = init_mul(); }; class lores_timer { @@ -116,6 +121,34 @@ class lores_timer { } t_uint64 m_start = 0; }; + +class media_timer { + typedef DWORD val_t; + static val_t _now() { return timeGetTime(); } +public: + void start() { + _start(_now()); + } + double query() const { + return _query(_now()); + } + double query_reset() { + auto now = _now(); + double ret = _query(now); + _start(now); + return ret; + } + pfc::string8 queryString(unsigned precision = 3) const { + return pfc::format_time_ex(query(), precision).get_ptr(); + } + static media_timer create_and_start() { + media_timer t; t.start(); return t; + } +private: + void _start(val_t t) { m_start = t; } + double _query(val_t t) const { return (t - m_start) / 1000.0; } + val_t m_start = 0; +}; } #else // not _WIN32 @@ -137,6 +170,7 @@ class hires_timer { }; typedef hires_timer lores_timer; +typedef hires_timer media_timer; } diff --git a/sdk/pfc/utf8.cpp b/sdk/pfc/utf8.cpp index 27e189d..5a97c76 100644 --- a/sdk/pfc/utf8.cpp +++ b/sdk/pfc/utf8.cpp @@ -18,7 +18,7 @@ namespace pfc { t_size wide_decode_char(const wchar_t * p_source,unsigned * p_out,t_size p_source_length) throw() { PFC_STATIC_ASSERT( sizeof( wchar_t ) == sizeof( char16_t ) || sizeof( wchar_t ) == sizeof( unsigned ) ); - if (sizeof( wchar_t ) == sizeof( char16_t ) ) { + if constexpr (sizeof( wchar_t ) == sizeof( char16_t ) ) { return utf16_decode_char( reinterpret_cast< const char16_t *>(p_source), p_out, p_source_length ); } else { if (p_source_length == 0) { * p_out = 0; return 0; } @@ -28,7 +28,7 @@ namespace pfc { } t_size wide_encode_char(unsigned c,wchar_t * out) throw() { PFC_STATIC_ASSERT( sizeof( wchar_t ) == sizeof( char16_t ) || sizeof( wchar_t ) == sizeof( unsigned ) ); - if (sizeof( wchar_t ) == sizeof( char16_t ) ) { + if constexpr (sizeof( wchar_t ) == sizeof( char16_t ) ) { return utf16_encode_char( c, reinterpret_cast< char16_t * >(out) ); } else { * out = (wchar_t) c; @@ -36,6 +36,58 @@ namespace pfc { } } + size_t uni_decode_char(const char16_t * p_source, unsigned & p_out, size_t p_source_length) noexcept { + return utf16_decode_char(p_source, &p_out, p_source_length); + } + size_t uni_decode_char(const char * p_source, unsigned & p_out, size_t p_source_length) noexcept { + return utf8_decode_char(p_source, p_out, p_source_length); + } + size_t uni_decode_char(const wchar_t * p_source, unsigned & p_out, size_t p_source_length) noexcept { + if constexpr ( sizeof(wchar_t) == sizeof(char16_t)) { + return utf16_decode_char( reinterpret_cast(p_source), &p_out, p_source_length); + } else { + if (p_source_length > 0) { + unsigned c = (unsigned)*p_source; + if (c != 0) { + p_out = c; return 1; + } + } + p_out = 0; return 0; + } + } + + size_t uni_char_length(const char * arg) { + return utf8_char_len(arg); + } + size_t uni_char_length(const char16_t * arg) { + unsigned dontcare; + return utf16_decode_char(arg, &dontcare); + } + size_t uni_char_length(const wchar_t * arg) { + if constexpr ( sizeof(wchar_t) == sizeof(char16_t) ) { + unsigned dontcare; + return utf16_decode_char(reinterpret_cast(arg), &dontcare); + } else { + return *arg == 0 ? 0 : 1; + } + } + + size_t uni_encode_char(unsigned c, char* out) noexcept { + PFC_ASSERT(c != 0); + return utf8_encode_char(c, out); + } + size_t uni_encode_char(unsigned c, char16_t* out) noexcept { + PFC_ASSERT(c != 0); + return utf16_encode_char(c, out); + } + size_t uni_encode_char(unsigned c, wchar_t* out) noexcept { + PFC_ASSERT(c != 0); + if constexpr ( sizeof(wchar_t) == sizeof(char16_t)) { + return utf16_encode_char(c, reinterpret_cast(out)); + } else { + *out = c; return 1; + } + } bool is_lower_ascii(const char * param) diff --git a/sdk/pfc/wait_queue.h b/sdk/pfc/wait_queue.h index f4c557f..a7a98ce 100644 --- a/sdk/pfc/wait_queue.h +++ b/sdk/pfc/wait_queue.h @@ -98,7 +98,7 @@ namespace pfc { return m_canWrite.get_handle(); } - waitQueue2() : m_eof() { + waitQueue2() { m_canWrite.set_state(true); } @@ -133,6 +133,38 @@ namespace pfc { } } + typedef std::function receive_peek_t; + // Block until there's something to return + return multiple objects at once. + // Use peek function (optional) to stop reading / leave remaining items for the next call to pick up. + std::list receive(pfc::eventHandle_t hAbort, receive_peek_t peek = nullptr , bool* didAbort = nullptr) { + if (didAbort != nullptr) *didAbort = false; + std::list ret; + for (bool retry = false; ; retry = true ) { + // try without wait first, only place where this is really used can poll abort before/after without system calls + if (retry && pfc::event::g_twoEventWait(hAbort, m_canRead.get_handle(), -1) == 1) { + if (didAbort != nullptr) *didAbort = true; + break; + } + mutexScope guard(m_mutex); + auto i = m_list.begin(); + if (i == m_list.end()) { + if (m_eof) break; + continue; + } + bool bDidGet = false; + do { + if (peek && !peek(*i)) break; + auto n = i; ++n; + ret.splice(ret.end(), m_list, i); + i = std::move(n); + bDidGet = true; + } while (i != m_list.end()); + if ( bDidGet ) didGet(); + break; + } + return ret; + } + bool get(obj_t & out, pfc::eventHandle_t hAbort, bool * didAbort = nullptr) { if (didAbort != nullptr) * didAbort = false; for (;; ) { @@ -162,8 +194,9 @@ namespace pfc { } private: void didGet() { + // mutex assumed locked if (m_eof) return; - if (m_list.size() == 0) { + if (m_list.empty()) { m_canRead.set_state(false); m_canWrite.set_state(true); } else { @@ -171,9 +204,10 @@ namespace pfc { } } void refreshCanWrite() { + // mutex assumed locked m_canWrite.set_state( !m_eof && canWriteCheck(m_list)); } - bool m_eof; + bool m_eof = false; std::list m_list; mutex m_mutex; event m_canRead, m_canWrite; diff --git a/sdk/pfc/win-objects.cpp b/sdk/pfc/win-objects.cpp index 0ed07bb..7d67be4 100644 --- a/sdk/pfc/win-objects.cpp +++ b/sdk/pfc/win-objects.cpp @@ -11,6 +11,12 @@ #include "pfc-fb2k-hooks.h" +#include "sortstring.h" + +// StrCmpLogicalW() +#include +#pragma comment(lib, "Shlwapi.lib") + namespace pfc { BOOL winFormatSystemErrorMessageImpl(pfc::string_base & p_out,DWORD p_code) { @@ -515,19 +521,43 @@ namespace pfc { pfc::string8 unicodeNormalizeC(const char* str) { return winUnicodeNormalize(str, NormalizationC); } - int winNaturalSortCompare(const char* s1, const char* s2) { - return winNaturalSortCompare(wideFromUTF8(s1), wideFromUTF8(s2)); + int ret = winNaturalSortCompareI(s1, s2); + if (ret == 0) ret = strcmp(s1, s2); + return ret; } int winNaturalSortCompare(const wchar_t* s1, const wchar_t* s2) { - return lstrcmp(s1, s2); + int ret = winNaturalSortCompareI(s1, s2); + if (ret == 0) ret = wcscmp(s1, s2); + return ret; } int winNaturalSortCompareI(const char* s1, const char* s2) { return winNaturalSortCompareI(wideFromUTF8(s1), wideFromUTF8(s2)); } int winNaturalSortCompareI(const wchar_t* s1, const wchar_t* s2) { - return lstrcmpi(s1, s2); + return StrCmpLogicalW(s1, s2); + } + +#ifndef PFC_SORTSTRING_GENERIC + sortString_t makeSortString(const char* in) { + auto out = std::make_unique(pfc::stringcvt::estimate_utf8_to_wide(in)); + pfc::stringcvt::convert_utf8_to_wide_unchecked(out.get(), in); + return out; + } + sortString_t makeSortString(const wchar_t* in) { + size_t l = wcslen(in) + 1; + auto out = std::make_unique(l+1); + memcpy(out.get(), in, sizeof(wchar_t) * l); + return out; + } + int sortStringCompare(sortString_t const& s1, sortString_t const& s2) { + return winNaturalSortCompare(s1.get(), s2.get()); } + int sortStringCompareI(sortString_t const& s1, sortString_t const& s2) { + return winNaturalSortCompareI(s1.get(), s2.get()); + } +#endif } + #endif // _WIN32 diff --git a/sdk/pfc/win-objects.h b/sdk/pfc/win-objects.h index c7a78e9..63d89cc 100644 --- a/sdk/pfc/win-objects.h +++ b/sdk/pfc/win-objects.h @@ -138,7 +138,9 @@ class win32_event { //! Returns true when signaled, false on timeout bool wait_for(double p_timeout_seconds) {return g_wait_for(get(),p_timeout_seconds);} - + void wait() { wait_for(-1); } + void wait_and_clear() { wait(); set_state(false); } + static DWORD g_calculate_wait_time(double p_seconds); //! Returns true when signaled, false on timeout diff --git a/sdk/sdk-license.txt b/sdk/sdk-license.txt index 0824e77..2708c41 100644 --- a/sdk/sdk-license.txt +++ b/sdk/sdk-license.txt @@ -1,5 +1,5 @@ -foobar2000 2.0 SDK -Copyright (c) 2001-2023, Peter Pawlowski +foobar2000 2.x SDK +Copyright (c) 2002-2024, Peter Pawlowski All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/sdk/sdk-readme.html b/sdk/sdk-readme.html index 820aa52..2c6b5d4 100644 --- a/sdk/sdk-readme.html +++ b/sdk/sdk-readme.html @@ -8,12 +8,12 @@

-foobar2000 SDK, version 2023-09-23 +foobar2000 SDK, version 2024-08-07

Documentation:
-SDK Change Log
-foobar2000 Development Overview +SDK Change Log
+foobar2000 Development Overview

From 5be791c801d0e15adea6b69da62a73a401f296c4 Mon Sep 17 00:00:00 2001 From: Hyperblast Date: Wed, 12 Feb 2025 09:14:29 +0500 Subject: [PATCH 11/12] update to SDK-2024-12-03 --- cmake/FileLists.cmake | 1 + sdk/foobar2000/SDK/abort_callback.cpp | 21 +- sdk/foobar2000/SDK/abort_callback.h | 12 +- sdk/foobar2000/SDK/advconfig.cpp | 2 + sdk/foobar2000/SDK/advconfig.h | 2 +- sdk/foobar2000/SDK/album_art_helpers.h | 7 +- sdk/foobar2000/SDK/audio_chunk.cpp | 16 +- sdk/foobar2000/SDK/audio_chunk.h | 2 +- sdk/foobar2000/SDK/cfg_var.cpp | 2 + sdk/foobar2000/SDK/cfg_var_legacy.cpp | 1 + sdk/foobar2000/SDK/commandline.h | 2 +- sdk/foobar2000/SDK/commonObjects.cpp | 2 +- sdk/foobar2000/SDK/completion_notify.cpp | 4 +- sdk/foobar2000/SDK/completion_notify.h | 3 +- sdk/foobar2000/SDK/configStore.cpp | 8 +- sdk/foobar2000/SDK/configStore.h | 1 + sdk/foobar2000/SDK/config_object.cpp | 5 +- sdk/foobar2000/SDK/config_object_impl.h | 8 +- sdk/foobar2000/SDK/console_manager.h | 4 +- sdk/foobar2000/SDK/contextmenu.h | 45 +-- sdk/foobar2000/SDK/contextmenu_manager.h | 2 +- sdk/foobar2000/SDK/decode_postprocessor.h | 4 + sdk/foobar2000/SDK/dsp.cpp | 12 +- sdk/foobar2000/SDK/dsp.h | 9 +- sdk/foobar2000/SDK/file.h | 7 +- sdk/foobar2000/SDK/file_cached_impl.cpp | 4 +- sdk/foobar2000/SDK/file_info.cpp | 5 + sdk/foobar2000/SDK/file_info.h | 3 + sdk/foobar2000/SDK/file_info_const_impl.cpp | 6 +- sdk/foobar2000/SDK/file_info_const_impl.h | 24 +- sdk/foobar2000/SDK/file_info_filter_impl.h | 1 + sdk/foobar2000/SDK/file_info_impl.cpp | 2 +- sdk/foobar2000/SDK/file_operation_callback.h | 6 +- sdk/foobar2000/SDK/filesystem.cpp | 50 ++-- sdk/foobar2000/SDK/filesystem.h | 6 +- sdk/foobar2000/SDK/filesystem_helper.h | 12 +- sdk/foobar2000/SDK/foobar2000-versions.h | 2 +- sdk/foobar2000/SDK/foobar2000.h | 1 + .../foobar2000_SDK.xcodeproj/project.pbxproj | 4 + sdk/foobar2000/SDK/guids.cpp | 6 +- sdk/foobar2000/SDK/image.cpp | 8 +- sdk/foobar2000/SDK/input_file_type.h | 18 +- sdk/foobar2000/SDK/input_impl.h | 16 +- sdk/foobar2000/SDK/main_thread_callback.cpp | 15 +- sdk/foobar2000/SDK/menu.h | 42 +-- sdk/foobar2000/SDK/menu_common.h | 10 +- sdk/foobar2000/SDK/menu_helpers.cpp | 58 +++- sdk/foobar2000/SDK/menu_helpers.h | 6 + sdk/foobar2000/SDK/menu_manager.cpp | 2 +- sdk/foobar2000/SDK/message_loop.h | 2 +- sdk/foobar2000/SDK/metadb.h | 2 +- sdk/foobar2000/SDK/metadb_callbacks.h | 4 +- sdk/foobar2000/SDK/metadb_handle.h | 2 + sdk/foobar2000/SDK/metadb_handle_list.cpp | 53 ++-- sdk/foobar2000/SDK/noInfo.h | 48 ++-- sdk/foobar2000/SDK/output.h | 16 +- sdk/foobar2000/SDK/packet_decoder.h | 6 +- sdk/foobar2000/SDK/play_callback.h | 44 +-- sdk/foobar2000/SDK/playback_control.h | 9 + sdk/foobar2000/SDK/playlist.cpp | 122 ++++---- sdk/foobar2000/SDK/playlist.h | 79 +++--- sdk/foobar2000/SDK/playlist_loader.cpp | 12 +- sdk/foobar2000/SDK/preferences_page.h | 2 +- sdk/foobar2000/SDK/service.h | 49 ++-- sdk/foobar2000/SDK/system_time_keeper.h | 2 +- sdk/foobar2000/SDK/tag_processor.h | 2 +- sdk/foobar2000/SDK/threaded_process.h | 14 +- sdk/foobar2000/SDK/titleformat.cpp | 1 + sdk/foobar2000/SDK/titleformat.h | 24 +- sdk/foobar2000/SDK/ui.h | 2 +- sdk/foobar2000/SDK/ui_element.h | 24 +- sdk/foobar2000/SDK/ui_element_mac.h | 18 ++ .../helpers-mac/NSAttributedString+ppaddons.h | 10 - .../helpers-mac/NSAttributedString+ppaddons.m | 51 ---- sdk/foobar2000/helpers-mac/NSButton+checked.h | 7 - sdk/foobar2000/helpers-mac/NSButton+checked.m | 13 - sdk/foobar2000/helpers-mac/NSComboBox+fb2k.h | 8 +- sdk/foobar2000/helpers-mac/NSComboBox+fb2k.mm | 39 ++- sdk/foobar2000/helpers-mac/NSEvent+ppstuff.h | 8 +- sdk/foobar2000/helpers-mac/NSEvent+ppstuff.m | 12 +- sdk/foobar2000/helpers-mac/NSFont+pp.h | 16 ++ sdk/foobar2000/helpers-mac/NSFont+pp.m | 27 ++ sdk/foobar2000/helpers-mac/NSMenu+ppaddons.h | 16 +- sdk/foobar2000/helpers-mac/NSMenu+ppaddons.m | 32 +-- .../helpers-mac/NSTextField+grayed.h | 7 - .../helpers-mac/NSTextField+grayed.m | 14 - sdk/foobar2000/helpers-mac/NSView+embed.h | 15 +- sdk/foobar2000/helpers-mac/NSView+embed.m | 32 ++- .../helpers-mac/NSView+ppsubviews.h | 13 + .../helpers-mac/NSView+ppsubviews.m | 63 +++-- sdk/foobar2000/helpers-mac/fb2k-platform.h | 15 + sdk/foobar2000/helpers-mac/fb2k-platform.mm | 52 +++- .../helpers/CModelessDialogMessages.h | 2 +- sdk/foobar2000/helpers/VolumeMap.cpp | 4 +- sdk/foobar2000/helpers/albumArtCache.h | 2 +- sdk/foobar2000/helpers/cfg_obj.h | 4 +- sdk/foobar2000/helpers/mp3_utils.cpp | 4 +- sdk/foobar2000/shared/fb2kdebug.h | 1 + sdk/foobar2000/shared/shared-ARM64.lib | Bin 36632 -> 0 bytes sdk/foobar2000/shared/shared-apple.mm | 6 + sdk/libPPUI/CListAccessible.h | 8 +- sdk/libPPUI/CListControl-Subst.cpp | 2 +- sdk/libPPUI/CListControl.cpp | 30 +- sdk/libPPUI/CListControlHeaderImpl.cpp | 40 ++- sdk/libPPUI/CListControlHeaderImpl.h | 4 +- sdk/libPPUI/CListControlSimple.h | 49 +++- sdk/libPPUI/CListControlWithSelection.cpp | 2 +- sdk/libPPUI/CListControl_EditImpl.h | 1 + sdk/libPPUI/GDIUtils.h | 2 +- sdk/libPPUI/wtl-pp.h | 2 +- sdk/pfc/alloc.h | 10 +- sdk/pfc/audio_math.cpp | 266 +++++++++++++++++- sdk/pfc/audio_sample.cpp | 2 +- sdk/pfc/audio_sample.h | 10 +- sdk/pfc/byte_order.h | 8 +- sdk/pfc/charDownConvert.cpp | 6 +- sdk/pfc/debug.h | 4 +- sdk/pfc/event_std.h | 2 +- sdk/pfc/filetimetools.cpp | 12 +- sdk/pfc/list.h | 16 +- sdk/pfc/other.cpp | 2 +- sdk/pfc/pathUtils.cpp | 8 +- sdk/pfc/primitives.h | 16 +- sdk/pfc/selftest.cpp | 2 +- sdk/pfc/splitString.h | 2 +- sdk/pfc/splitString2.cpp | 2 +- sdk/pfc/string-compare.cpp | 2 +- sdk/pfc/string-compare.h | 4 +- sdk/pfc/string-interface.h | 9 +- sdk/pfc/string-lite.cpp | 4 +- sdk/pfc/string_base.cpp | 10 +- sdk/pfc/string_conv.cpp | 2 +- sdk/pfc/synchro.h | 38 +-- sdk/pfc/synchro_nix.h | 18 +- sdk/pfc/synchro_win.h | 30 +- sdk/pfc/timers.cpp | 19 +- sdk/pfc/utf8.cpp | 2 +- sdk/sdk-readme.html | 2 +- 138 files changed, 1337 insertions(+), 810 deletions(-) create mode 100644 sdk/foobar2000/SDK/ui_element_mac.h delete mode 100644 sdk/foobar2000/helpers-mac/NSAttributedString+ppaddons.h delete mode 100644 sdk/foobar2000/helpers-mac/NSAttributedString+ppaddons.m delete mode 100644 sdk/foobar2000/helpers-mac/NSButton+checked.h delete mode 100644 sdk/foobar2000/helpers-mac/NSButton+checked.m create mode 100644 sdk/foobar2000/helpers-mac/NSFont+pp.h create mode 100644 sdk/foobar2000/helpers-mac/NSFont+pp.m delete mode 100644 sdk/foobar2000/helpers-mac/NSTextField+grayed.h delete mode 100644 sdk/foobar2000/helpers-mac/NSTextField+grayed.m delete mode 100644 sdk/foobar2000/shared/shared-ARM64.lib diff --git a/cmake/FileLists.cmake b/cmake/FileLists.cmake index 53d6981..cf338ca 100644 --- a/cmake/FileLists.cmake +++ b/cmake/FileLists.cmake @@ -365,6 +365,7 @@ set( sdk/foobar2000/SDK/tracks.h sdk/foobar2000/SDK/ui_edit_context.h sdk/foobar2000/SDK/ui_element.h + sdk/foobar2000/SDK/ui_element_mac.h sdk/foobar2000/SDK/ui_element_typable_window_manager.h sdk/foobar2000/SDK/ui.h sdk/foobar2000/SDK/unpack.h diff --git a/sdk/foobar2000/SDK/abort_callback.cpp b/sdk/foobar2000/SDK/abort_callback.cpp index c59413b..dea973a 100644 --- a/sdk/foobar2000/SDK/abort_callback.cpp +++ b/sdk/foobar2000/SDK/abort_callback.cpp @@ -19,7 +19,7 @@ bool abort_callback::sleep_ex(double p_timeout_seconds) const { return !pfc::event::g_wait_for(get_abort_event(),p_timeout_seconds); } -bool abort_callback::waitForEvent( pfc::eventHandle_t evtHandle, double timeOut ) { +bool abort_callback::waitForEvent( pfc::eventHandle_t evtHandle, double timeOut ) const { int status = pfc::event::g_twoEventWait( this->get_abort_event(), evtHandle, timeOut ); switch(status) { case 1: throw exception_aborted(); @@ -33,20 +33,33 @@ bool abort_callback_usehandle::is_aborting() const { return pfc::event::g_wait_for( get_abort_event(), 0 ); } -bool abort_callback::waitForEvent(pfc::event& evt, double timeOut) { +bool abort_callback::waitForEvent(pfc::event& evt, double timeOut) const { return waitForEvent(evt.get_handle(), timeOut); } -void abort_callback::waitForEvent(pfc::eventHandle_t evtHandle) { +void abort_callback::waitForEvent(pfc::eventHandle_t evtHandle) const { bool status = waitForEvent(evtHandle, -1); (void)status; PFC_ASSERT(status); // should never return false } -void abort_callback::waitForEvent(pfc::event& evt) { +void abort_callback::waitForEvent(pfc::event& evt) const { bool status = waitForEvent(evt, -1); (void)status; PFC_ASSERT(status); // should never return false } +bool abort_callback::waitForEventNoThrow(pfc::eventHandle_t evtHandle) const { + int status = pfc::event::g_twoEventWait(this->get_abort_event(), evtHandle, -1); + switch (status) { + case 1: return false; + case 2: return true; + default: uBugCheck(); + } +} + +bool abort_callback::waitForEventNoThrow(pfc::event& evt) const { + return waitForEventNoThrow(evt.get_handle()); +} + namespace fb2k { abort_callback_dummy noAbort; } diff --git a/sdk/foobar2000/SDK/abort_callback.h b/sdk/foobar2000/SDK/abort_callback.h index c4497f1..f2519d5 100644 --- a/sdk/foobar2000/SDK/abort_callback.h +++ b/sdk/foobar2000/SDK/abort_callback.h @@ -38,18 +38,22 @@ class NOVTABLE abort_callback void sleep(double p_timeout_seconds) const; //! 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; + bool sleepNoThrow(double p_timeout_seconds) const { return sleep_ex(p_timeout_seconds); } //! 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 ); + bool waitForEvent( pfc::eventHandle_t evtHandle, double timeOut ) 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::event& evt, double timeOut); + bool waitForEvent(pfc::event& evt, double timeOut) const; //! Waits for an event. Returns once the event became signaled; throw exception_aborted if abort occurred first. - void waitForEvent(pfc::eventHandle_t evtHandle); + void waitForEvent(pfc::eventHandle_t evtHandle) const; //! Waits for an event. Returns once the event became signaled; throw exception_aborted if abort occurred first. - void waitForEvent(pfc::event& evt); + void waitForEvent(pfc::event& evt) const; + + bool waitForEventNoThrow(pfc::eventHandle_t evt) const; + bool waitForEventNoThrow(pfc::event& evt) const; abort_callback( const abort_callback & ) = delete; void operator=( const abort_callback & ) = delete; diff --git a/sdk/foobar2000/SDK/advconfig.cpp b/sdk/foobar2000/SDK/advconfig.cpp index 1034d22..e423eed 100644 --- a/sdk/foobar2000/SDK/advconfig.cpp +++ b/sdk/foobar2000/SDK/advconfig.cpp @@ -69,6 +69,7 @@ bool advconfig_entry_checkbox_impl::get_state_() const { #ifdef FOOBAR2000_HAVE_CFG_VAR_LEGACY void advconfig_entry_checkbox_impl::set_data_raw(stream_reader* p_stream, t_size p_sizehint, abort_callback& p_abort) { + (void)p_sizehint; uint8_t v; if (p_stream->read(&v, 1, p_abort) == 1) { set_state(v != 0); @@ -93,6 +94,7 @@ void advconfig_entry_string_impl::set_state(const char* p_string, t_size p_lengt #ifdef FOOBAR2000_HAVE_CFG_VAR_LEGACY void advconfig_entry_string_impl::set_data_raw(stream_reader* p_stream, t_size p_sizehint, abort_callback& p_abort) { + (void)p_sizehint; pfc::string8_fastalloc temp; p_stream->read_string_raw(temp, p_abort); this->set_state(temp); diff --git a/sdk/foobar2000/SDK/advconfig.h b/sdk/foobar2000/SDK/advconfig.h index 0ba8a96..714043d 100644 --- a/sdk/foobar2000/SDK/advconfig.h +++ b/sdk/foobar2000/SDK/advconfig.h @@ -88,6 +88,6 @@ class NOVTABLE advconfig_entry_string_v2 : public advconfig_entry_string { FB2K_MAKE_SERVICE_INTERFACE(advconfig_entry_string_v2, advconfig_entry_string) public: virtual void get_default_state(pfc::string_base & out) = 0; - virtual void validate(pfc::string_base & val) {} + virtual void validate(pfc::string_base& val) { (void)val; } virtual t_uint32 get_preferences_flags() {return 0;} //signals whether changing this setting should trigger playback restart or app restart; see: preferences_state::* constants }; diff --git a/sdk/foobar2000/SDK/album_art_helpers.h b/sdk/foobar2000/SDK/album_art_helpers.h index 09510f7..e3fc3aa 100644 --- a/sdk/foobar2000/SDK/album_art_helpers.h +++ b/sdk/foobar2000/SDK/album_art_helpers.h @@ -43,6 +43,7 @@ class album_art_extractor_instance_simple : public album_art_extractor_instance void set(const GUID & p_what,album_art_data_ptr p_content) {m_content.set(p_what,p_content);} bool have_item(const GUID & p_what) {return m_content.have_item(p_what);} album_art_data_ptr query(const GUID & p_what,abort_callback & p_abort) { + p_abort.check(); album_art_data_ptr temp; if (!m_content.query(p_what,temp)) throw exception_album_art_not_found(); return temp; @@ -67,6 +68,7 @@ class album_art_extractor_impl_stdtags : public album_art_extractor_v2 { } bool is_our_path(const char * p_path,const char * p_extension) override { + (void)p_path; return m_extensions.have_item(p_extension); } @@ -94,6 +96,7 @@ class album_art_editor_impl_stdtags : public album_art_editor_v2 { } bool is_our_path(const char * p_path,const char * p_extension) override { + (void)p_path; return m_extensions.have_item(p_extension); } @@ -161,6 +164,6 @@ class album_art_path_list_impl : public album_art_path_list { //! album_art_path_list implementation helper class album_art_path_list_dummy : public album_art_path_list { public: - const char * get_path(t_size index) const {FB2K_BugCheck();} - t_size get_count() const {return 0;} + const char * get_path(t_size) const override {FB2K_BugCheck();} + t_size get_count() const override {return 0;} }; diff --git a/sdk/foobar2000/SDK/audio_chunk.cpp b/sdk/foobar2000/SDK/audio_chunk.cpp index dc45e44..b1b6007 100644 --- a/sdk/foobar2000/SDK/audio_chunk.cpp +++ b/sdk/foobar2000/SDK/audio_chunk.cpp @@ -519,14 +519,14 @@ template class sampleToInt { clipHi = ( (int_t) 1 << (d.bpsValid-1)) - 1; scale = (float) ( (int64_t) 1 << (d.bpsValid - 1) ) * d.scale; if (d.useUpperBits) { - shift = d.bps - d.bpsValid; + shift = (int8_t)( d.bps - d.bpsValid ); } else { shift = 0; } } inline int_t operator() (audio_sample s) const { int_t v; - if (sizeof(int_t) > 4) v = (int_t) audio_math::rint64( s * scale ); + if constexpr (sizeof(int_t) > 4) v = (int_t) audio_math::rint64( s * scale ); else v = (int_t)audio_math::rint32( s * scale ); return pfc::clip_t( v, clipLo, clipHi) << shift; } @@ -676,10 +676,10 @@ WAVEFORMATEX audio_chunk::spec_t::toWFX() const { WAVEFORMATEX wfx = {}; wfx.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; - wfx.nChannels = chanCount; + wfx.nChannels = (WORD) chanCount; wfx.nSamplesPerSec = sampleRate; wfx.nAvgBytesPerSec = sampleRate * chanCount * sampleWidth; - wfx.nBlockAlign = chanCount * sampleWidth; + wfx.nBlockAlign = (WORD)( chanCount * sampleWidth ); wfx.wBitsPerSample = sampleWidth * 8; return wfx; } @@ -704,11 +704,11 @@ WAVEFORMATEX audio_chunk::spec_t::toWFXWithBPS(uint32_t bps) const { WAVEFORMATEX wfx = {}; wfx.wFormatTag = WAVE_FORMAT_PCM; - wfx.nChannels = chanCount; + wfx.nChannels = (WORD)chanCount; wfx.nSamplesPerSec = sampleRate; wfx.nAvgBytesPerSec = sampleRate * chanCount * sampleWidth; - wfx.nBlockAlign = chanCount * sampleWidth; - wfx.wBitsPerSample = sampleWidth * 8; + wfx.nBlockAlign = (WORD)( chanCount * sampleWidth ); + wfx.wBitsPerSample = (WORD)( sampleWidth * 8 ); return wfx; } @@ -720,7 +720,7 @@ WAVEFORMATEXTENSIBLE audio_chunk::spec_t::toWFXEXWithBPS(uint32_t bps) const { wfxe.Format = toWFXWithBPS(bps); wfxe.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; wfxe.Format.cbSize = sizeof(wfxe) - sizeof(wfxe.Format); - wfxe.Samples.wValidBitsPerSample = sampleWidth * 8; + wfxe.Samples.wValidBitsPerSample = (WORD)( sampleWidth * 8 ); wfxe.dwChannelMask = audio_chunk::g_channel_config_to_wfx(this->chanMask); wfxe.SubFormat = isFloat ? KSDATAFORMAT_SUBTYPE_IEEE_FLOAT : KSDATAFORMAT_SUBTYPE_PCM; diff --git a/sdk/foobar2000/SDK/audio_chunk.h b/sdk/foobar2000/SDK/audio_chunk.h index 2d705ac..4e22c88 100644 --- a/sdk/foobar2000/SDK/audio_chunk.h +++ b/sdk/foobar2000/SDK/audio_chunk.h @@ -156,7 +156,7 @@ class NOVTABLE audio_chunk { #if PFC_DEBUG void assert_valid(const char * ctx) const; #else - void assert_valid(const char * ctx) const {} + void assert_valid(const char* ctx) const { (void)ctx; } #endif diff --git a/sdk/foobar2000/SDK/cfg_var.cpp b/sdk/foobar2000/SDK/cfg_var.cpp index bc51083..ab14c9e 100644 --- a/sdk/foobar2000/SDK/cfg_var.cpp +++ b/sdk/foobar2000/SDK/cfg_var.cpp @@ -18,6 +18,7 @@ namespace cfg_var_modern { #ifdef FOOBAR2000_HAVE_CFG_VAR_LEGACY void cfg_string::set_data_raw(stream_reader* p_stream, t_size p_sizehint, abort_callback& p_abort) { + (void)p_sizehint; pfc::string8_fastalloc temp; p_stream->read_string_raw(temp, p_abort); this->set(temp); @@ -35,6 +36,7 @@ namespace cfg_var_modern { } void cfg_bool::set_data_raw(stream_reader* p_stream, t_size p_sizehint, abort_callback& p_abort) { + (void)p_sizehint; uint8_t b; if (p_stream->read(&b, 1, p_abort) == 1) { this->set(b != 0); diff --git a/sdk/foobar2000/SDK/cfg_var_legacy.cpp b/sdk/foobar2000/SDK/cfg_var_legacy.cpp index 670c248..44806bf 100644 --- a/sdk/foobar2000/SDK/cfg_var_legacy.cpp +++ b/sdk/foobar2000/SDK/cfg_var_legacy.cpp @@ -79,6 +79,7 @@ namespace cfg_var_legacy { } void cfg_string::set_data_raw(stream_reader* p_stream, t_size p_sizehint, abort_callback& p_abort) { + (void)p_sizehint; pfc::string8_fastalloc temp; p_stream->read_string_raw(temp, p_abort); set_string(temp); diff --git a/sdk/foobar2000/SDK/commandline.h b/sdk/foobar2000/SDK/commandline.h index a2cb741..6fadb7b 100644 --- a/sdk/foobar2000/SDK/commandline.h +++ b/sdk/foobar2000/SDK/commandline.h @@ -11,7 +11,7 @@ class NOVTABLE commandline_handler : public service_base RESULT_PROCESSED_EXPECT_FILES,//command processed, we want to takeover file urls after this command }; virtual result on_token(const char * token)=0; - virtual void on_file(const char * url) {};//optional + virtual void on_file(const char* url) { (void)url; };//optional virtual void on_files_done() {};//optional virtual bool want_directories() {return false;} diff --git a/sdk/foobar2000/SDK/commonObjects.cpp b/sdk/foobar2000/SDK/commonObjects.cpp index db1c930..41ab317 100644 --- a/sdk/foobar2000/SDK/commonObjects.cpp +++ b/sdk/foobar2000/SDK/commonObjects.cpp @@ -436,7 +436,7 @@ namespace fb2k { auto obj = this->itemAt( n ); if ( obj == item ) return n; } - return pfc_infinite; + return SIZE_MAX; } array::ptr array::subset( pfc::bit_array const & mask ) const { diff --git a/sdk/foobar2000/SDK/completion_notify.cpp b/sdk/foobar2000/SDK/completion_notify.cpp index 2d2700a..fa971eb 100644 --- a/sdk/foobar2000/SDK/completion_notify.cpp +++ b/sdk/foobar2000/SDK/completion_notify.cpp @@ -56,7 +56,7 @@ namespace { class completion_notify_func : public completion_notify { public: - void on_completion(unsigned p_code) { + void on_completion(unsigned p_code) noexcept override { m_func(p_code); } @@ -67,7 +67,7 @@ namespace { namespace fb2k { completion_notify::ptr makeCompletionNotify( completionNotifyFunc_t func ) { - service_ptr_t n = new service_impl_t< completion_notify_func >; + auto n = fb2k::service_new< completion_notify_func >(); n->m_func = func; return n; } diff --git a/sdk/foobar2000/SDK/completion_notify.h b/sdk/foobar2000/SDK/completion_notify.h index 6d92f56..eaefff6 100644 --- a/sdk/foobar2000/SDK/completion_notify.h +++ b/sdk/foobar2000/SDK/completion_notify.h @@ -7,6 +7,7 @@ class completion_notify : public service_base { public: //! Called when an async operation has been completed. Note that on_completion is always called from main thread. You can use on_completion_async() helper if you need to signal completion while your context is in another thread.\n //! IMPLEMENTATION WARNING: If process being completed creates a window taking caller's window as parent, you must not destroy the parent window inside on_completion(). If you need to do so, use PostMessage() or main_thread_callback to delay the deletion. + //! IMPLEMENTATION NOTE: on_completion() couldn't be declared noexcept in base class for historical reasons, but it's recommended that your overrides of on_completion() are noexcept. //! @param p_code Context-specific status code. Possible values depend on the operation being performed. virtual void on_completion(unsigned p_code) = 0; @@ -22,7 +23,7 @@ class completion_notify : public service_base { //! Implementation helper. class completion_notify_dummy : public completion_notify { public: - void on_completion(unsigned) {} + void on_completion(unsigned) override {} }; //! Implementation helper. diff --git a/sdk/foobar2000/SDK/configStore.cpp b/sdk/foobar2000/SDK/configStore.cpp index 85e92ce..a5544a1 100644 --- a/sdk/foobar2000/SDK/configStore.cpp +++ b/sdk/foobar2000/SDK/configStore.cpp @@ -80,7 +80,9 @@ configEventHandle_t configEvent::operator+=(std::function< void() > f) const { void configEvent::operator-=(configEventHandle_t h) const { auto obj = reinterpret_cast(h); - static_api_ptr_t()->removeNotify(m_name, obj); + if ( core_api::are_services_available() ) { + static_api_ptr_t()->removeNotify(m_name, obj); + } delete obj; } @@ -153,7 +155,9 @@ void appearanceChangeNotifyRef::set( std::function f ) { } void appearanceChangeNotifyRef::clear() { if (isSet()) { - static_api_ptr_t()->removeNotify2(handle); + if ( core_api::are_services_available() ) { + static_api_ptr_t()->removeNotify2(handle); + } handle = nullptr; } } diff --git a/sdk/foobar2000/SDK/configStore.h b/sdk/foobar2000/SDK/configStore.h index db912ee..4d57a04 100644 --- a/sdk/foobar2000/SDK/configStore.h +++ b/sdk/foobar2000/SDK/configStore.h @@ -78,6 +78,7 @@ class configStore : public service_base { virtual void callNotify(const char * name) = 0; fb2k::stringRef getConfigString( const char * name, const char * defVal ) { return getConfigString(name, defVal ? fb2k::makeString(defVal) : nullptr); } + fb2k::stringRef getConfigString( const char * name, std::nullptr_t ) { return getConfigString(name, fb2k::stringRef ( nullptr ) ); } }; struct configEventHandle_; diff --git a/sdk/foobar2000/SDK/config_object.cpp b/sdk/foobar2000/SDK/config_object.cpp index edf4b01..8315b2a 100644 --- a/sdk/foobar2000/SDK/config_object.cpp +++ b/sdk/foobar2000/SDK/config_object.cpp @@ -104,6 +104,7 @@ namespace { class stream_writer_string : public stream_writer { public: void write(const void * p_buffer,t_size p_bytes,abort_callback & p_abort) { + p_abort.check(); m_out.add_string((const char*)p_buffer,p_bytes); } stream_writer_string(pfc::string_base & p_out) : m_out(p_out) {m_out.reset();} @@ -114,6 +115,7 @@ namespace { class stream_writer_fixedbuffer : public stream_writer { public: void write(const void * p_buffer,t_size p_bytes,abort_callback & p_abort) { + p_abort.check(); if (p_bytes > 0) { if (p_bytes > m_bytes - m_bytes_read) throw pfc::exception_overflow(); memcpy((t_uint8*)m_out,p_buffer,p_bytes); @@ -131,7 +133,8 @@ namespace { class stream_writer_get_length : public stream_writer { public: - void write(const void * p_buffer,t_size p_bytes,abort_callback & p_abort) { + void write(const void * ,t_size p_bytes,abort_callback & p_abort) override { + p_abort.check(); m_length += p_bytes; } stream_writer_get_length(t_size & p_length) : m_length(p_length) {m_length = 0;} diff --git a/sdk/foobar2000/SDK/config_object_impl.h b/sdk/foobar2000/SDK/config_object_impl.h index 7a9fef3..59f3da5 100644 --- a/sdk/foobar2000/SDK/config_object_impl.h +++ b/sdk/foobar2000/SDK/config_object_impl.h @@ -39,7 +39,7 @@ class config_object_impl : public config_object, private cfg_var_legacy::cfg_var config_object_impl(const GUID & p_guid,const void * p_data,t_size p_bytes); private: #ifdef FOOBAR2000_HAVE_CFG_VAR_LEGACY - void set_data_raw(stream_reader * p_stream,t_size p_sizehint,abort_callback & p_abort) override {set_data(p_stream,p_abort,false);} + void set_data_raw(stream_reader * p_stream,t_size,abort_callback & p_abort) override {set_data(p_stream,p_abort,false);} #endif pfc::string8 formatName() const; @@ -82,9 +82,9 @@ class config_object_string_factory : public config_object_factory { class config_object_notify_impl_simple : public config_object_notify { public: - t_size get_watched_object_count() {return 1;} - GUID get_watched_object(t_size p_index) {return m_guid;} - void on_watched_object_changed(const service_ptr_t & p_object) {m_func(p_object);} + t_size get_watched_object_count() override {return 1;} + GUID get_watched_object(t_size) override {return m_guid;} + void on_watched_object_changed(const service_ptr_t & p_object) override {m_func(p_object);} typedef void (*t_func)(const service_ptr_t &); diff --git a/sdk/foobar2000/SDK/console_manager.h b/sdk/foobar2000/SDK/console_manager.h index d14ce0a..262684e 100644 --- a/sdk/foobar2000/SDK/console_manager.h +++ b/sdk/foobar2000/SDK/console_manager.h @@ -6,7 +6,7 @@ namespace fb2k { class NOVTABLE console_notify { public: virtual void onConsoleRefresh() = 0; - virtual void onConsoleLines(size_t oldLinesGone, arrayRef newLines, arrayRef newLinesTS) { onConsoleRefresh(); } + virtual void onConsoleLines(size_t oldLinesGone, arrayRef newLines, arrayRef newLinesTS) { (void)oldLinesGone; (void)newLines; (void)newLinesTS; onConsoleRefresh(); } }; //! \since 2.0 class NOVTABLE console_manager : public service_base { @@ -17,7 +17,9 @@ namespace fb2k { virtual fb2k::arrayRef getLinesTimestamped() = 0; virtual void addNotify(console_notify* notify) = 0; virtual void removeNotify(console_notify* notify) = 0; + //! Obsolete, done implicitly by toggling logging, do not use. virtual void saveBacklog() = 0; + //! Always true, reserved for future use. virtual bool isVerbose() = 0; }; } // namespace fb2k diff --git a/sdk/foobar2000/SDK/contextmenu.h b/sdk/foobar2000/SDK/contextmenu.h index d7da1b0..5a6d864 100644 --- a/sdk/foobar2000/SDK/contextmenu.h +++ b/sdk/foobar2000/SDK/contextmenu.h @@ -28,7 +28,7 @@ class NOVTABLE contextmenu_item_node { virtual bool get_display_data(pfc::string_base & p_out,unsigned & p_displayflags,metadb_handle_list_cref p_data,const GUID & p_caller) = 0; virtual t_type get_type() = 0; virtual void execute(metadb_handle_list_cref p_data,const GUID & p_caller) = 0; - virtual t_glyph get_glyph(metadb_handle_list_cref p_data,const GUID & p_caller) {return 0;}//RESERVED + virtual t_glyph get_glyph(metadb_handle_list_cref p_data, const GUID& p_caller) { (void)p_data; (void)p_caller; return 0; }//RESERVED virtual t_size get_children_count() = 0; virtual contextmenu_item_node * get_child(t_size p_index) = 0; virtual bool get_description(pfc::string_base & p_out) = 0; @@ -65,35 +65,36 @@ class NOVTABLE contextmenu_item_node_root_leaf : public contextmenu_item_node_ro class NOVTABLE contextmenu_item_node_popup : public contextmenu_item_node { public: - t_type get_type() {return TYPE_POPUP;} - void execute(metadb_handle_list_cref data,const GUID & caller) {} - bool get_description(pfc::string_base & p_out) {return false;} + t_type get_type() override {return TYPE_POPUP;} + void execute(metadb_handle_list_cref data, const GUID& caller) override { (void)data; (void)caller; } + bool get_description(pfc::string_base& p_out) override { (void)p_out; return false; } }; class NOVTABLE contextmenu_item_node_root_popup : public contextmenu_item_node_root { public: - t_type get_type() {return TYPE_POPUP;} - void execute(metadb_handle_list_cref data,const GUID & caller) {} - bool get_description(pfc::string_base & p_out) {return false;} + t_type get_type() override {return TYPE_POPUP;} + void execute(metadb_handle_list_cref data, const GUID& caller) override { (void)data; (void)caller; } + bool get_description(pfc::string_base& p_out) override { (void)p_out; return false; } }; class contextmenu_item_node_separator : public contextmenu_item_node { public: - t_type get_type() {return TYPE_SEPARATOR;} - void execute(metadb_handle_list_cref data,const GUID & caller) {} - bool get_description(pfc::string_base & p_out) {return false;} - t_size get_children_count() {return 0;} - bool get_display_data(pfc::string_base & p_out,unsigned & p_displayflags,metadb_handle_list_cref p_data,const GUID & p_caller) + t_type get_type() override {return TYPE_SEPARATOR;} + void execute(metadb_handle_list_cref data, const GUID& caller) override { (void)data; (void)caller; } + bool get_description(pfc::string_base& p_out) override { (void)p_out; return false; } + t_size get_children_count() override {return 0;} + bool get_display_data(pfc::string_base & p_out,unsigned & p_displayflags,metadb_handle_list_cref p_data,const GUID & p_caller) override { + (void)p_data; (void)p_caller; p_displayflags = 0; p_out = "---"; return true; } - contextmenu_item_node * get_child(t_size) {return NULL;} - GUID get_guid() {return pfc::guid_null;} - bool is_mappable_shortcut() {return false;} + contextmenu_item_node * get_child(t_size) override {return NULL;} + GUID get_guid() override {return pfc::guid_null;} + bool is_mappable_shortcut() override {return false;} }; /*! @@ -118,7 +119,7 @@ class NOVTABLE contextmenu_item : public service_base { //! Retrieves human-readable name of the context menu item. virtual void get_item_name(unsigned p_index,pfc::string_base & p_out) = 0; //! Obsolete since v1.0, don't use or override in new components. - virtual void get_item_default_path(unsigned p_index,pfc::string_base & p_out) {p_out = "";} + virtual void get_item_default_path(unsigned p_index, pfc::string_base& p_out) { (void)p_index; p_out = ""; } //! Retrieves item's description to show in the status bar. Set p_out to the string to be displayed and return true if you provide a description, return false otherwise. virtual bool get_item_description(unsigned p_index,pfc::string_base & p_out) = 0; //! Controls default state of context menu preferences for this item: \n @@ -170,11 +171,12 @@ class NOVTABLE contextmenu_item_simple : public contextmenu_item_v2 { // Functions to be overridden by implementers (some are not mandatory). - virtual t_enabled_state get_enabled_state(unsigned p_index) {return contextmenu_item::DEFAULT_ON;} + virtual t_enabled_state get_enabled_state(unsigned p_index) { (void)p_index; return contextmenu_item::DEFAULT_ON; } virtual unsigned get_num_items() = 0; virtual void get_item_name(unsigned p_index,pfc::string_base & p_out) = 0; virtual void context_command(unsigned p_index,metadb_handle_list_cref p_data,const GUID& p_caller) = 0; virtual bool context_get_display(unsigned p_index,metadb_handle_list_cref p_data,pfc::string_base & p_out,unsigned & p_displayflags,const GUID & p_caller) { + (void)p_caller; (void)p_data; (void)p_displayflags; PFC_ASSERT(p_index>=0 && p_index0 to signal that, after each flush(), you require of audio before your output becomes valid. \n + //! This causes decoder to seek to position- instead of then discard first of your output. virtual double get_buffer_ahead() = 0; }; diff --git a/sdk/foobar2000/SDK/dsp.cpp b/sdk/foobar2000/SDK/dsp.cpp index 6bb8fb3..1f596c7 100644 --- a/sdk/foobar2000/SDK/dsp.cpp +++ b/sdk/foobar2000/SDK/dsp.cpp @@ -229,7 +229,7 @@ size_t dsp_chain_config::find_first_of_type( const GUID & dspID ) const { for(size_t w = 0; w < count; ++w) { if (this->get_item(w).get_owner() == dspID) return w; } - return pfc_infinite; + return SIZE_MAX; } bool dsp_chain_config::contains_dsp( const GUID & dspID ) const { @@ -434,11 +434,15 @@ void dsp_preset_impl::set_data_from_stream(stream_reader * p_stream,t_size p_byt if (p_bytes > 0) p_stream->read_object(m_data.ptr(),p_bytes,p_abort); } +void dsp_chain_config::add_items(const dsp_chain_config & p_source) { + t_size n, m = p_source.get_count(); + for(n=0;n