Compare commits

...

12 Commits

Author SHA1 Message Date
Max Kellermann
38a0d15190 release v0.18.17 2014-11-02 13:06:20 +01:00
Max Kellermann
ec3191f502 input/curl: fix curl_easy_setopt() parameter types 2014-11-02 11:55:48 +01:00
Max Kellermann
32b5654a6e Decoder, Playlist: ignore URI query string for plugin detection
Use the new uri_get_suffix() overload that removes the query string.
2014-11-02 11:54:26 +01:00
Max Kellermann
674091424e util/UriUtil: add uri_get_suffix() overload that ignores query string 2014-11-02 11:53:31 +01:00
Max Kellermann
6ad336743d PlaylistFile: don't allow empty playlist name 2014-11-02 11:52:48 +01:00
Max Kellermann
c882568ccd playlist/m3u: recognize the file suffix ".m3u8" 2014-11-02 11:50:56 +01:00
Max Kellermann
f6b2899dd2 decoder/faad: remove workaround for ancient libfaad2 ABI bug
Many years ago, FAAD had a serious ABI bug: the NeAACDecInit()
prototype in its header declared the "samplerate" parameter to be
"unsigned long *", but internally, the function assumed it was
"uint32_t *" instead.  On 32 bit machines, that was no difference, but
on 64 bit, this left one portion of the return value uninitialized;
and worse, on big-endian, the wrong word was filled.  This bug had to
be worked around in MPD (commit 9c4e97a6).

A few months later, the bug was fixed in the FAAD CVS in commit 1.117
on file libfaad/decoder.c; the commit message was:

 "Use public headers internally to prevent duplicate declarations"

The commit message was too brief at best; the problem was not
duplicate declarations, but a prototype mismatch.  No mention of the
bug fix in the ChangeLog.

The MPD project never learned about this bug fix, and so MPD would
always pass a "uin32_t *" dressed up as a "unsigned long *".  Nearly 6
years later, it's about time to fix this second ABI problem.  Let's
kill the workaround!
2014-11-02 11:50:56 +01:00
Steven OBrien
bccd4ef2f7 decoder/ffmpeg: recognize MIME type audio/aacp 2014-11-02 11:50:56 +01:00
Max Kellermann
94c240a026 configure.ac: show DSD in result 2014-11-02 11:50:56 +01:00
Max Kellermann
c50a0cf7bf output/roar: remove unnecessary "volatile" keyword
A mutex acts as a memory barrier, and thus "volatile" is not
necessary.
2014-11-02 11:50:56 +01:00
Max Kellermann
c37f7abb79 TagString: use g_strndup() for unterminated string
Fixes buffer overflow bug.
2014-11-02 11:48:13 +01:00
Max Kellermann
432ce9b1de configure.ac: prepare for 0.18.17 2014-11-02 11:41:40 +01:00
16 changed files with 84 additions and 55 deletions

9
NEWS
View File

@@ -1,3 +1,12 @@
ver 0.18.17 (2014/11/02)
* playlist
- don't allow empty playlist name
- m3u: recognize the file suffix ".m3u8"
* decoder
- ignore URI query string for plugin detection
- faad: remove workaround for ancient libfaad2 ABI bug
- ffmpeg: recognize MIME type audio/aacp
ver 0.18.16 (2014/09/26) ver 0.18.16 (2014/09/26)
* fix DSD breakage due to typo in configure.ac * fix DSD breakage due to typo in configure.ac

View File

@@ -1,10 +1,10 @@
AC_PREREQ(2.60) AC_PREREQ(2.60)
AC_INIT(mpd, 0.18.16, mpd-devel@musicpd.org) AC_INIT(mpd, 0.18.17, mpd-devel@musicpd.org)
VERSION_MAJOR=0 VERSION_MAJOR=0
VERSION_MINOR=18 VERSION_MINOR=18
VERSION_REVISION=0 VERSION_REVISION=17
VERSION_EXTRA=0 VERSION_EXTRA=0
AC_CONFIG_SRCDIR([src/Main.cxx]) AC_CONFIG_SRCDIR([src/Main.cxx])
@@ -1523,6 +1523,7 @@ results(un,[UNIX Domain Sockets])
printf '\nFile format support:\n\t' printf '\nFile format support:\n\t'
results(aac, [AAC]) results(aac, [AAC])
results(adplug, [AdPlug]) results(adplug, [AdPlug])
results(dsd, [DSD])
results(sidplay, [C64 SID]) results(sidplay, [C64 SID])
results(ffmpeg, [FFMPEG]) results(ffmpeg, [FFMPEG])
results(flac, [FLAC]) results(flac, [FLAC])

View File

@@ -62,36 +62,7 @@ int main() {
CPPFLAGS=$oldcppflags CPPFLAGS=$oldcppflags
fi fi
if test x$enable_aac = xyes; then if test x$enable_aac = xno; then
oldcflags=$CFLAGS
oldlibs=$LIBS
oldcppflags=$CPPFLAGS
CFLAGS="$CFLAGS $FAAD_CFLAGS -Werror"
LIBS="$LIBS $FAAD_LIBS"
CPPFLAGS=$CFLAGS
AC_MSG_CHECKING(for broken libfaad headers)
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
#include <faad.h>
#include <stddef.h>
#include <stdint.h>
int main() {
unsigned char channels;
uint32_t sample_rate;
NeAACDecInit2(NULL, NULL, 0, &sample_rate, &channels);
return 0;
}
])],
[AC_MSG_RESULT(correct)],
[AC_MSG_RESULT(broken);
AC_DEFINE(HAVE_FAAD_LONG, 1, [Define if faad.h uses the broken "unsigned long" pointers])])
CFLAGS=$oldcflags
LIBS=$oldlibs
CPPFLAGS=$oldcppflags
else
FAAD_LIBS="" FAAD_LIBS=""
FAAD_CFLAGS="" FAAD_CFLAGS=""
fi fi

View File

@@ -212,7 +212,8 @@ static bool
decoder_run_stream_locked(Decoder &decoder, InputStream &is, decoder_run_stream_locked(Decoder &decoder, InputStream &is,
const char *uri, bool &tried_r) const char *uri, bool &tried_r)
{ {
const char *const suffix = uri_get_suffix(uri); UriSuffixBuffer suffix_buffer;
const char *const suffix = uri_get_suffix(uri, suffix_buffer);
using namespace std::placeholders; using namespace std::placeholders;
const auto f = std::bind(decoder_run_stream_plugin, const auto f = std::bind(decoder_run_stream_plugin,

View File

@@ -69,6 +69,10 @@ spl_global_init(void)
bool bool
spl_valid_name(const char *name_utf8) spl_valid_name(const char *name_utf8)
{ {
if (*name_utf8 == 0)
/* empty name not allowed */
return false;
/* /*
* Not supporting '/' was done out of laziness, and we should * Not supporting '/' was done out of laziness, and we should
* really strive to support it in the future. * really strive to support it in the future.

View File

@@ -164,12 +164,12 @@ static SongEnumerator *
playlist_list_open_uri_suffix(const char *uri, Mutex &mutex, Cond &cond, playlist_list_open_uri_suffix(const char *uri, Mutex &mutex, Cond &cond,
const bool *tried) const bool *tried)
{ {
const char *suffix;
SongEnumerator *playlist = nullptr; SongEnumerator *playlist = nullptr;
assert(uri != nullptr); assert(uri != nullptr);
suffix = uri_get_suffix(uri); UriSuffixBuffer suffix_buffer;
const char *const suffix = uri_get_suffix(uri, suffix_buffer);
if (suffix == nullptr) if (suffix == nullptr)
return nullptr; return nullptr;
@@ -273,8 +273,6 @@ playlist_list_open_stream_suffix(InputStream &is, const char *suffix)
SongEnumerator * SongEnumerator *
playlist_list_open_stream(InputStream &is, const char *uri) playlist_list_open_stream(InputStream &is, const char *uri)
{ {
const char *suffix;
is.LockWaitReady(); is.LockWaitReady();
const char *const mime = is.GetMimeType(); const char *const mime = is.GetMimeType();
@@ -284,7 +282,10 @@ playlist_list_open_stream(InputStream &is, const char *uri)
return playlist; return playlist;
} }
suffix = uri != nullptr ? uri_get_suffix(uri) : nullptr; UriSuffixBuffer suffix_buffer;
const char *suffix = uri != nullptr
? uri_get_suffix(uri, suffix_buffer)
: nullptr;
if (suffix != nullptr) { if (suffix != nullptr) {
auto playlist = playlist_list_open_stream_suffix(is, suffix); auto playlist = playlist_list_open_stream_suffix(is, suffix);
if (playlist != nullptr) if (playlist != nullptr)

View File

@@ -277,20 +277,12 @@ faad_decoder_init(NeAACDecHandle decoder, DecoderBuffer *buffer,
} }
uint8_t channels; uint8_t channels;
uint32_t sample_rate; unsigned long sample_rate;
#ifdef HAVE_FAAD_LONG
/* neaacdec.h declares all arguments as "unsigned long", but
internally expects uint32_t pointers. To avoid gcc
warnings, use this workaround. */
unsigned long *sample_rate_p = (unsigned long *)(void *)&sample_rate;
#else
uint32_t *sample_rate_p = &sample_rate;
#endif
long nbytes = NeAACDecInit(decoder, long nbytes = NeAACDecInit(decoder,
/* deconst hack, libfaad requires this */ /* deconst hack, libfaad requires this */
const_cast<unsigned char *>(data), const_cast<unsigned char *>(data),
length, length,
sample_rate_p, &channels); &sample_rate, &channels);
if (nbytes < 0) { if (nbytes < 0) {
error.Set(faad_decoder_domain, "Not an AAC stream"); error.Set(faad_decoder_domain, "Not an AAC stream");
return false; return false;

View File

@@ -643,6 +643,7 @@ static const char *const ffmpeg_mime_types[] = {
"audio/8svx", "audio/8svx",
"audio/16sv", "audio/16sv",
"audio/aac", "audio/aac",
"audio/aacp",
"audio/ac3", "audio/ac3",
"audio/aiff" "audio/aiff"
"audio/amr", "audio/amr",

View File

@@ -983,10 +983,10 @@ input_curl_easy_init(struct input_curl *c, Error &error)
input_curl_writefunction); input_curl_writefunction);
curl_easy_setopt(c->easy, CURLOPT_WRITEDATA, c); curl_easy_setopt(c->easy, CURLOPT_WRITEDATA, c);
curl_easy_setopt(c->easy, CURLOPT_HTTP200ALIASES, http_200_aliases); curl_easy_setopt(c->easy, CURLOPT_HTTP200ALIASES, http_200_aliases);
curl_easy_setopt(c->easy, CURLOPT_FOLLOWLOCATION, 1); curl_easy_setopt(c->easy, CURLOPT_FOLLOWLOCATION, 1l);
curl_easy_setopt(c->easy, CURLOPT_NETRC, 1); curl_easy_setopt(c->easy, CURLOPT_NETRC, 1l);
curl_easy_setopt(c->easy, CURLOPT_MAXREDIRS, 5); curl_easy_setopt(c->easy, CURLOPT_MAXREDIRS, 5l);
curl_easy_setopt(c->easy, CURLOPT_FAILONERROR, true); curl_easy_setopt(c->easy, CURLOPT_FAILONERROR, 1l);
curl_easy_setopt(c->easy, CURLOPT_ERRORBUFFER, c->error); curl_easy_setopt(c->easy, CURLOPT_ERRORBUFFER, c->error);
curl_easy_setopt(c->easy, CURLOPT_NOPROGRESS, 1l); curl_easy_setopt(c->easy, CURLOPT_NOPROGRESS, 1l);
curl_easy_setopt(c->easy, CURLOPT_NOSIGNAL, 1l); curl_easy_setopt(c->easy, CURLOPT_NOSIGNAL, 1l);

View File

@@ -46,7 +46,7 @@ class RoarOutput {
struct roar_connection con; struct roar_connection con;
struct roar_audio_info info; struct roar_audio_info info;
mutable Mutex mutex; mutable Mutex mutex;
volatile bool alive; bool alive;
public: public:
RoarOutput() RoarOutput()

View File

@@ -135,7 +135,8 @@ ExtM3uPlaylist::NextSong()
static const char *const extm3u_suffixes[] = { static const char *const extm3u_suffixes[] = {
"m3u", "m3u",
NULL "m3u8",
nullptr
}; };
static const char *const extm3u_mime_types[] = { static const char *const extm3u_mime_types[] = {

View File

@@ -61,6 +61,7 @@ M3uPlaylist::NextSong()
static const char *const m3u_suffixes[] = { static const char *const m3u_suffixes[] = {
"m3u", "m3u",
"m3u8",
nullptr nullptr
}; };

View File

@@ -33,7 +33,7 @@ patch_utf8(const char *src, size_t length, const gchar *end)
{ {
/* duplicate the string, and replace invalid bytes in that /* duplicate the string, and replace invalid bytes in that
buffer */ buffer */
char *dest = g_strdup(src); char *dest = g_strndup(src, length);
do { do {
dest[end - src] = '?'; dest[end - src] = '?';

View File

@@ -44,6 +44,23 @@ uri_get_suffix(const char *uri)
return suffix; return suffix;
} }
const char *
uri_get_suffix(const char *uri, UriSuffixBuffer &buffer)
{
const char *suffix = uri_get_suffix(uri);
if (suffix == nullptr)
return nullptr;
const char *q = strchr(suffix, '?');
if (q != nullptr && size_t(q - suffix) < sizeof(buffer.data)) {
memcpy(buffer.data, suffix, q - suffix);
buffer.data[q - suffix] = 0;
suffix = buffer.data;
}
return suffix;
}
static const char * static const char *
verify_uri_segment(const char *p) verify_uri_segment(const char *p)
{ {

View File

@@ -35,6 +35,17 @@ gcc_pure
const char * const char *
uri_get_suffix(const char *uri); uri_get_suffix(const char *uri);
struct UriSuffixBuffer {
char data[8];
};
/**
* Returns the file name suffix, ignoring the query string.
*/
gcc_pure
const char *
uri_get_suffix(const char *uri, UriSuffixBuffer &buffer);
/** /**
* Returns true if this is a safe "local" URI: * Returns true if this is a safe "local" URI:
* *

View File

@@ -33,6 +33,25 @@ public:
uri_get_suffix(".jpg")); uri_get_suffix(".jpg"));
CPPUNIT_ASSERT_EQUAL((const char *)nullptr, CPPUNIT_ASSERT_EQUAL((const char *)nullptr,
uri_get_suffix("/foo/.jpg")); uri_get_suffix("/foo/.jpg"));
/* the first overload does not eliminate the query
string */
CPPUNIT_ASSERT_EQUAL(0, strcmp(uri_get_suffix("/foo/bar.jpg?query_string"),
"jpg?query_string"));
/* ... but the second one does */
UriSuffixBuffer buffer;
CPPUNIT_ASSERT_EQUAL(0, strcmp(uri_get_suffix("/foo/bar.jpg?query_string",
buffer),
"jpg"));
/* repeat some of the above tests with the second overload */
CPPUNIT_ASSERT_EQUAL((const char *)nullptr,
uri_get_suffix("/foo/bar", buffer));
CPPUNIT_ASSERT_EQUAL((const char *)nullptr,
uri_get_suffix("/foo.jpg/bar", buffer));
CPPUNIT_ASSERT_EQUAL(0, strcmp(uri_get_suffix("/foo/bar.jpg", buffer),
"jpg"));
} }
void TestRemoveAuth() { void TestRemoveAuth() {