diff --git a/src/decoder/plugins/OpusTags.cxx b/src/decoder/plugins/OpusTags.cxx index 931becbd1..eae4a12bd 100644 --- a/src/decoder/plugins/OpusTags.cxx +++ b/src/decoder/plugins/OpusTags.cxx @@ -19,6 +19,7 @@ #include "OpusTags.hxx" #include "OpusReader.hxx" +#include "lib/xiph/VorbisPicture.hxx" #include "lib/xiph/XiphTags.hxx" #include "tag/Handler.hxx" #include "tag/ParseName.hxx" @@ -45,6 +46,10 @@ ScanOneOpusTag(StringView name, StringView value, ReplayGainInfo *rgi, TagHandler &handler) noexcept { + if (handler.WantPicture() && + name.EqualsIgnoreCase("METADATA_BLOCK_PICTURE")) + return ScanVorbisPicture(value, handler); + if (value.size >= 4096) /* ignore large values */ return; diff --git a/src/decoder/plugins/meson.build b/src/decoder/plugins/meson.build index 50845e4df..0717ef30b 100644 --- a/src/decoder/plugins/meson.build +++ b/src/decoder/plugins/meson.build @@ -192,6 +192,7 @@ decoder_plugins = static_library( decoder_plugins_dep = declare_dependency( link_with: decoder_plugins, dependencies: [ + crypto_base64_dep, decoder_api_dep, pcm_dep, ], diff --git a/src/lib/xiph/VorbisComments.cxx b/src/lib/xiph/VorbisComments.cxx index f170b7462..dfa026000 100644 --- a/src/lib/xiph/VorbisComments.cxx +++ b/src/lib/xiph/VorbisComments.cxx @@ -18,6 +18,7 @@ */ #include "VorbisComments.hxx" +#include "VorbisPicture.hxx" #include "XiphTags.hxx" #include "tag/Table.hxx" #include "tag/Handler.hxx" @@ -84,6 +85,12 @@ vorbis_copy_comment(StringView comment, static void vorbis_scan_comment(StringView comment, TagHandler &handler) noexcept { + const auto picture_b64 = handler.WantPicture() + ? GetVorbisCommentValue(comment, "METADATA_BLOCK_PICTURE") + : nullptr; + if (!picture_b64.IsNull()) + return ScanVorbisPicture(picture_b64, handler); + if (handler.WantPair()) { const auto split = comment.Split('='); if (!split.first.empty() && !split.second.IsNull()) diff --git a/src/lib/xiph/VorbisPicture.cxx b/src/lib/xiph/VorbisPicture.cxx new file mode 100644 index 000000000..dfc745c3a --- /dev/null +++ b/src/lib/xiph/VorbisPicture.cxx @@ -0,0 +1,56 @@ +/* + * Copyright 2003-2019 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "VorbisPicture.hxx" +#include "lib/crypto/Base64.hxx" +#include "tag/Id3Picture.hxx" +#include "tag/Handler.hxx" +#include "util/StringView.hxx" +#include "util/WritableBuffer.hxx" +#include "config.h" + +#include + +void +ScanVorbisPicture(StringView value, TagHandler &handler) noexcept +{ +#ifdef HAVE_BASE64 + if (value.size > 1024 * 1024) + /* ignore image files which are too huge */ + return; + + size_t debase64_size = CalculateBase64OutputSize(value.size); + std::unique_ptr debase64_buffer; + debase64_buffer.reset(new uint8_t[debase64_size]); + + try { + debase64_size = + DecodeBase64({debase64_buffer.get(), debase64_size}, + value); + } catch (...) { + // TODO: log? + return; + } + + return ScanId3Apic({debase64_buffer.get(), debase64_size}, handler); +#else + (void)value; + (void)handler; +#endif +} diff --git a/src/lib/xiph/VorbisPicture.hxx b/src/lib/xiph/VorbisPicture.hxx new file mode 100644 index 000000000..b0efb48fb --- /dev/null +++ b/src/lib/xiph/VorbisPicture.hxx @@ -0,0 +1,29 @@ +/* + * Copyright 2003-2019 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_VORBIS_PICTURE_HXX +#define MPD_VORBIS_PICTURE_HXX + +struct StringView; +class TagHandler; + +void +ScanVorbisPicture(StringView value, TagHandler &handler) noexcept; + +#endif diff --git a/src/lib/xiph/meson.build b/src/lib/xiph/meson.build index 4f3f46e64..bdb489f9e 100644 --- a/src/lib/xiph/meson.build +++ b/src/lib/xiph/meson.build @@ -47,6 +47,7 @@ endif xiph = static_library( 'xiph', 'VorbisComments.cxx', + 'VorbisPicture.cxx', 'XiphTags.cxx', include_directories: inc, ) diff --git a/src/tag/Id3Picture.cxx b/src/tag/Id3Picture.cxx new file mode 100644 index 000000000..7c4aa666f --- /dev/null +++ b/src/tag/Id3Picture.cxx @@ -0,0 +1,80 @@ +/* + * Copyright 2003-2019 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "Id3Picture.hxx" +#include "Handler.hxx" +#include "util/ByteOrder.hxx" +#include "util/ConstBuffer.hxx" +#include "util/StringView.hxx" + +#include + +#include + +static StringView +ReadString(ConstBuffer &src) noexcept +{ + if (src.size < 4) + return nullptr; + + const size_t length = FromBE32(*(const uint32_t *)src.data); + src.skip_front(4); + + if (src.size < length) + return nullptr; + + StringView result((const char *)src.data, length); + src.skip_front(length); + return result; +} + +void +ScanId3Apic(ConstBuffer _buffer, TagHandler &handler) noexcept +{ + auto buffer = ConstBuffer::FromVoid(_buffer); + if (buffer.size < 4) + return; + + buffer.skip_front(4); /* picture type */ + + const auto mime_type = ReadString(buffer); + if (mime_type.IsNull()) + return; + + /* description */ + if (ReadString(buffer).IsNull()) + return; + + if (buffer.size < 20) + return; + + buffer.skip_front(16); + + const size_t image_size = FromBE32(*(const uint32_t *)buffer.data); + buffer.skip_front(4); + + if (buffer.size < image_size) + return; + + ConstBuffer image(buffer.data, image_size); + + // TODO: don't copy MIME type, pass StringView to TagHandler::OnPicture() + handler.OnPicture(std::string(mime_type.data, mime_type.size).c_str(), + image); +} diff --git a/src/tag/Id3Picture.hxx b/src/tag/Id3Picture.hxx new file mode 100644 index 000000000..950441672 --- /dev/null +++ b/src/tag/Id3Picture.hxx @@ -0,0 +1,32 @@ +/* + * Copyright 2003-2019 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_TAG_ID3_PICTURE_HXX +#define MPD_TAG_ID3_PICTURE_HXX + +template struct ConstBuffer; +class TagHandler; + +/** + * Scan an "APIC" value and call TagHandler::OnPicture(). + */ +void +ScanId3Apic(ConstBuffer buffer, TagHandler &handler) noexcept; + +#endif diff --git a/src/tag/meson.build b/src/tag/meson.build index 9767ba6ed..13e722f0b 100644 --- a/src/tag/meson.build +++ b/src/tag/meson.build @@ -15,6 +15,7 @@ tag_sources = [ 'MixRamp.cxx', 'Generic.cxx', 'Id3MusicBrainz.cxx', + 'Id3Picture.cxx', 'ApeLoader.cxx', 'ApeReplayGain.cxx', 'ApeTag.cxx',