From aa877a29d7241f148a82433fccef26152b3e344a Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 22 Nov 2016 10:15:23 +0100 Subject: [PATCH] decoder/Thread: repair container decoder support Catch ENOTDIR exceptions and in that case, try all matching decoder plugins which implement the "container_scan" method. https://bugs.musicpd.org/view.php?id=4561 --- src/decoder/DecoderThread.cxx | 54 ++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/src/decoder/DecoderThread.cxx b/src/decoder/DecoderThread.cxx index 1bba9e30f..603140009 100644 --- a/src/decoder/DecoderThread.cxx +++ b/src/decoder/DecoderThread.cxx @@ -31,6 +31,7 @@ #include "input/InputStream.hxx" #include "input/LocalOpen.hxx" #include "DecoderList.hxx" +#include "system/Error.hxx" #include "util/MimeType.hxx" #include "util/UriUtil.hxx" #include "util/RuntimeError.hxx" @@ -309,6 +310,44 @@ TryDecoderFile(DecoderBridge &bridge, Path path_fs, const char *suffix, return false; } +/** + * Decode a container file with the given decoder plugin. + * + * DecoderControl::mutex is not locked by caller. + */ +static bool +TryContainerDecoder(DecoderBridge &bridge, Path path_fs, const char *suffix, + const DecoderPlugin &plugin) +{ + if (plugin.container_scan == nullptr || + plugin.file_decode == nullptr || + !plugin.SupportsSuffix(suffix)) + return false; + + bridge.error = nullptr; + + DecoderControl &dc = bridge.dc; + const ScopeLock protect(dc.mutex); + return decoder_file_decode(plugin, bridge, path_fs); +} + +/** + * Decode a container file. + * + * DecoderControl::mutex is not locked by caller. + */ +static bool +TryContainerDecoder(DecoderBridge &bridge, Path path_fs, const char *suffix) +{ + return decoder_plugins_try([&bridge, path_fs, + suffix](const DecoderPlugin &plugin){ + return TryContainerDecoder(bridge, + path_fs, + suffix, + plugin); + }); +} + /** * Try decoding a file. * @@ -321,7 +360,20 @@ decoder_run_file(DecoderBridge &bridge, const char *uri_utf8, Path path_fs) if (suffix == nullptr) return false; - auto input_stream = decoder_input_stream_open(bridge.dc, path_fs); + InputStreamPtr input_stream; + + try { + input_stream = decoder_input_stream_open(bridge.dc, path_fs); + } catch (const std::system_error &e) { + if (IsPathNotFound(e) && + /* ENOTDIR means this may be a path inside a + "container" file */ + TryContainerDecoder(bridge, path_fs, suffix)) + return true; + + throw; + } + assert(input_stream); LoadReplayGain(bridge, *input_stream);