Compare commits

...

28 Commits

Author SHA1 Message Date
Max Kellermann
eaf675dc92 release v0.18.14 2014-09-11 19:09:49 +02:00
Max Kellermann
57068e526c test/run_decoder: dump MixRamp data 2014-09-09 19:17:22 +02:00
Max Kellermann
c14a00eec9 decoder/ffmpeg: use memset() to initialize AVProbeData 2014-09-09 19:07:46 +02:00
Max Kellermann
219c42522f decoder/ffmpeg: pass MIME type to ffmpeg/libav version 11
That attribute was uninitialized before, which could crash
libavformat.

See Debian bug 760669
2014-09-07 22:05:33 +02:00
Max Kellermann
e3a0f15837 Decoder*: add more assertions 2014-09-07 21:52:34 +02:00
Max Kellermann
a6bb27483b DecoderThread: clear the pipe when handling late SEEK
See code comment.  Fixes assertion failure in
decoder_command_finished().
2014-09-07 21:50:00 +02:00
Max Kellermann
7ada7def9e decoder/audiofile: fix crash after seeking
Log call was added to the wrong branch.

Fixes regression by commit ca1a1149
2014-09-06 19:32:10 +02:00
Max Kellermann
421c4ae907 protocol/ArgParser: fix integer overflow in parse_range()
Casting std::numeric_limits<unsigned>::max() to "long" leads to an
overflow if sizeof(unsigned)==sizeof(long), and the result will be -1.

This happens on some 32 bit architectures, for example ARM and WIN32.

Workaround: use std::numeric_limits<int>::max(), which is the largest
signed integer.  Since sizeof(long)>=sizeof(int), this will never
overflow.

Fixes Mantis ticket 0004080.
2014-09-04 17:37:31 +02:00
Max Kellermann
4907f610d6 test/test_protocol: unit test for protocol/ArgParser.cxx 2014-09-04 17:10:30 +02:00
Max Kellermann
f9d1bbbffb configure.ac: prepare for 0.18.14 2014-09-03 19:59:26 +02:00
Max Kellermann
86e8b3b4bd release v0.18.13 2014-08-31 14:50:23 +02:00
Max Kellermann
a26ead035a PlaylistControl: use SeekSongOrder(current) to keep current song
The "current" attribute is a "song order", not a "song position".
This is usually the same - except in random mode.  Fixes Mantis ticket
0004073.
2014-08-31 14:44:20 +02:00
Max Kellermann
704be54c3a PlaylistControl: move code to new method SeekSongOrder() 2014-08-31 14:23:06 +02:00
Max Kellermann
2406152576 output/alsa: fix endless loop at end of file in dsd_usb mode 2014-08-31 14:01:57 +02:00
Max Kellermann
af260b5a64 output/{alsa,oss}: add assertions 2014-08-31 14:00:09 +02:00
Joachim Fasting
4efa96df21 doc/protocol: fix description of "stats" response
Fix incorrect description of the "songs" field and add missing
"albums" field.

Signed-off-by: Joachim Fasting <joachifm@fastmail.fm>
2014-08-31 13:16:39 +02:00
Max Kellermann
8b62127770 decoder/gme: fix song duration
The unit of gme_info_t::length is milliseconds, not centiseconds.
2014-08-29 23:03:29 +02:00
Max Kellermann
f06fe1ea98 event/TimeoutMonitor: really reset "active" flag before invoking OnTimeout()
The previous commit was broken.  D'oh!
2014-08-24 13:19:50 +02:00
Max Kellermann
d16fb79708 event/TimeoutMonitor: reset "active" flag before invoking OnTimeout()
The IsActive() method returned true even if the timer was not active,
after it completed once.  This broke the state file timer, and the
state file was not saved periodically.
2014-08-24 13:13:12 +02:00
Thomas Klausner
c38f29ce56 system/ByteOrder: <endian.h> is a non-standard header that only Linux provides. 2014-08-23 14:27:44 +02:00
Max Kellermann
78abcd7df7 decoer/dsdiff: fix endless loop on malformed file
Same bug as in the previous commit.
2014-08-21 12:48:03 +02:00
Max Kellermann
23dce21647 decoer/dsf: fix endless loop on malformed file
When the data chunk size is not a multiple of the frame size, the last
partial frame lead to an endless loop.  We fix this by checking
chunk_sze>=frame instead of chunk_sze>0.  This way, the partial frame
is simply skipped.
2014-08-21 12:37:22 +02:00
François Revol
40280fa6cf util: Fix header for strcasecmp
According to POSIX and both OSX and Linux manpages,
strcasecmp comes from strings.h, not string.h.

Most OSes also have them available in string.h,
but we just fixed the headers on Haiku and it now
only provides them in strings.h.

We might want to fall back to string.h for other
OSes though...

cf.
http://pubs.opengroup.org/onlinepubs/009695399/functions/strcasecmp.html
http://linux.die.net/man/3/strcasecmp
https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/strcasecmp.3.html
2014-08-16 06:51:13 +02:00
Max Kellermann
fe9299ceff decoder/ffmpeg: use avcodec_descriptor_get() to determine codec name
In version 11, both ffmpeg and libav deprecate
AVCodecContext::codec_name.  The function avcodec_descriptor_get() has
been introduced long ago.
2014-08-13 18:40:39 +02:00
Max Kellermann
c3f111a56c event/BufferedSocket: fix inversed buffer check
This was broken by commit 84d20d9e, which deleted the "!" from the
check.
2014-08-07 16:03:44 +02:00
François Revol
250318329f Makefile.am: fix dependencies for win32
It happened to me when doing the Haiku port, src/mpd failed to
be relinked properly when editing source files, and likely also
happens on win32, although I didn't try this change.

When building for windows, src_mpd_DEPENDENCIES is overriden.

Automake then disables the default version which contains all
the static libraries. In Makefile.in:
@HAVE_WINDOWS_FALSE@src_mpd_DEPENDENCIES = libmpd.a \

Instead we use EXTRA_src_mpd_DEPENDENCIES which is meant for this.
2014-08-02 08:48:44 +02:00
Max Kellermann
14c538c9c7 Win32Main: move to win32/ 2014-08-02 08:48:30 +02:00
Max Kellermann
abe4c57663 configure.ac: prepare for 0.18.13 2014-08-02 08:45:44 +02:00
27 changed files with 207 additions and 30 deletions

3
.gitignore vendored
View File

@@ -40,7 +40,7 @@ tags
.#* .#*
.stgit* .stgit*
src/dsd2pcm/dsd2pcm src/dsd2pcm/dsd2pcm
src/win/mpd_win32_rc.rc src/win32/mpd_win32_rc.rc
doc/doxygen.conf doc/doxygen.conf
doc/protocol.html doc/protocol.html
doc/protocol doc/protocol
@@ -63,6 +63,7 @@ test/run_normalize
test/tmp test/tmp
test/run_inotify test/run_inotify
test/test_queue_priority test/test_queue_priority
test/test_protocol
test/run_ntp_server test/run_ntp_server
test/run_resolver test/run_resolver
test/run_tcp_connect test/run_tcp_connect

View File

@@ -151,7 +151,7 @@ src_mpd_SOURCES = \
src/IOThread.cxx src/IOThread.hxx \ src/IOThread.cxx src/IOThread.hxx \
src/Main.cxx src/Main.hxx \ src/Main.cxx src/Main.hxx \
src/Instance.cxx src/Instance.hxx \ src/Instance.cxx src/Instance.hxx \
src/Win32Main.cxx \ src/win32/Win32Main.cxx \
src/GlobalEvents.cxx src/GlobalEvents.hxx \ src/GlobalEvents.cxx src/GlobalEvents.hxx \
src/Daemon.cxx src/Daemon.hxx \ src/Daemon.cxx src/Daemon.hxx \
src/AudioCompress/compress.c \ src/AudioCompress/compress.c \
@@ -211,14 +211,14 @@ src_mpd_SOURCES = \
# Windows resource file # Windows resource file
# #
src/win/mpd_win32_rc.$(OBJEXT): src/win/mpd_win32_rc.rc src/win32/mpd_win32_rc.$(OBJEXT): src/win32/mpd_win32_rc.rc
$(WINDRES) -i $< -o $@ $(WINDRES) -i $< -o $@
if HAVE_WINDOWS if HAVE_WINDOWS
noinst_DATA = src/win/mpd_win32_rc.rc noinst_DATA = src/win32/mpd_win32_rc.rc
src_mpd_DEPENDENCIES = src/win/mpd_win32_rc.$(OBJEXT) EXTRA_src_mpd_DEPENDENCIES = src/win32/mpd_win32_rc.$(OBJEXT)
src_mpd_LDFLAGS = -Wl,src/win/mpd_win32_rc.$(OBJEXT) src_mpd_LDFLAGS = -Wl,src/win32/mpd_win32_rc.$(OBJEXT)
endif endif
if ENABLE_DESPOTIFY if ENABLE_DESPOTIFY
@@ -1064,6 +1064,7 @@ C_TESTS = \
test/test_mixramp \ test/test_mixramp \
test/test_icy_parser \ test/test_icy_parser \
test/test_pcm \ test/test_pcm \
test/test_protocol \
test/test_queue_priority test/test_queue_priority
if ENABLE_ARCHIVE if ENABLE_ARCHIVE
@@ -1538,6 +1539,16 @@ test_test_archive_LDADD = \
$(GLIB_LIBS) \ $(GLIB_LIBS) \
$(CPPUNIT_LIBS) $(CPPUNIT_LIBS)
test_test_protocol_SOURCES = \
src/protocol/ArgParser.cxx \
test/test_protocol.cxx
test_test_protocol_CPPFLAGS = $(AM_CPPFLAGS) $(CPPUNIT_CFLAGS) -DCPPUNIT_HAVE_RTTI=0
test_test_protocol_CXXFLAGS = $(AM_CXXFLAGS) -Wno-error=deprecated-declarations
test_test_protocol_LDADD = \
libsystem.a \
libutil.a \
$(CPPUNIT_LIBS)
test_test_queue_priority_SOURCES = \ test_test_queue_priority_SOURCES = \
src/Queue.cxx \ src/Queue.cxx \
test/test_queue_priority.cxx test/test_queue_priority.cxx
@@ -1633,4 +1644,4 @@ EXTRA_DIST = $(doc_DATA) autogen.sh \
test/test_archive_zzip.sh \ test/test_archive_zzip.sh \
$(wildcard scripts/*.sh) \ $(wildcard scripts/*.sh) \
$(man_MANS) $(DOCBOOK_FILES) doc/mpdconf.example doc/doxygen.conf \ $(man_MANS) $(DOCBOOK_FILES) doc/mpdconf.example doc/doxygen.conf \
src/win/mpd_win32_rc.rc.in src/win/mpd.ico src/win32/mpd_win32_rc.rc.in src/win32/mpd.ico

20
NEWS
View File

@@ -1,3 +1,23 @@
ver 0.18.14 (2014/09/11)
* protocol
- fix range parser bug on certain 32 bit architectures
* decoder
- audiofile: fix crash after seeking
- ffmpeg: fix crash with ffmpeg/libav version 11
- fix assertion failure after seeking
ver 0.18.13 (2014/08/31)
* protocol
- don't change song on "seekcur" in random mode
* decoder
- dsdiff, dsf: fix endless loop on malformed file
- ffmpeg: support ffmpeg/libav version 11
- gme: fix song duration
* output
- alsa: fix endless loop at end of file in dsd_usb mode
* fix state file saver
* fix build failure on Darwin
ver 0.18.12 (2014/07/30) ver 0.18.12 (2014/07/30)
* database * database
- proxy: fix build failure with libmpdclient 2.2 - proxy: fix build failure with libmpdclient 2.2

View File

@@ -1,6 +1,6 @@
AC_PREREQ(2.60) AC_PREREQ(2.60)
AC_INIT(mpd, 0.18.12, mpd-devel@musicpd.org) AC_INIT(mpd, 0.18.14, mpd-devel@musicpd.org)
VERSION_MAJOR=0 VERSION_MAJOR=0
VERSION_MINOR=18 VERSION_MINOR=18
@@ -70,7 +70,7 @@ host_is_darwin=no
case "$host_os" in case "$host_os" in
mingw32* | windows*) mingw32* | windows*)
AC_CONFIG_FILES([ AC_CONFIG_FILES([
src/win/mpd_win32_rc.rc src/win32/mpd_win32_rc.rc
]) ])
AC_CHECK_TOOL(WINDRES, windres) AC_CHECK_TOOL(WINDRES, windres)
AM_CPPFLAGS="$AM_CPPFLAGS -DWIN32_LEAN_AND_MEAN" AM_CPPFLAGS="$AM_CPPFLAGS -DWIN32_LEAN_AND_MEAN"

View File

@@ -576,7 +576,12 @@
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
<varname>songs</varname>: number of albums <varname>albums</varname>: number of albums
</para>
</listitem>
<listitem>
<para>
<varname>songs</varname>: number of songs
</para> </para>
</listitem> </listitem>
<listitem> <listitem>

View File

@@ -47,6 +47,7 @@ decoder_initialized(Decoder &decoder,
assert(dc.state == DecoderState::START); assert(dc.state == DecoderState::START);
assert(dc.pipe != nullptr); assert(dc.pipe != nullptr);
assert(dc.pipe->IsEmpty());
assert(decoder.stream_tag == nullptr); assert(decoder.stream_tag == nullptr);
assert(decoder.decoder_tag == nullptr); assert(decoder.decoder_tag == nullptr);
assert(!decoder.seeking); assert(!decoder.seeking);
@@ -405,6 +406,9 @@ decoder_data(Decoder &decoder,
length == 0) length == 0)
return cmd; return cmd;
assert(!decoder.initial_seek_pending);
assert(!decoder.initial_seek_running);
/* send stream tags */ /* send stream tags */
if (update_stream_tag(decoder, is)) { if (update_stream_tag(decoder, is)) {

View File

@@ -83,6 +83,9 @@ void
decoder_flush_chunk(Decoder &decoder) decoder_flush_chunk(Decoder &decoder)
{ {
DecoderControl &dc = decoder.dc; DecoderControl &dc = decoder.dc;
assert(!decoder.seeking);
assert(!decoder.initial_seek_running);
assert(!decoder.initial_seek_pending);
assert(decoder.chunk != nullptr); assert(decoder.chunk != nullptr);

View File

@@ -26,6 +26,7 @@
#include "Song.hxx" #include "Song.hxx"
#include "system/FatalError.hxx" #include "system/FatalError.hxx"
#include "Mapper.hxx" #include "Mapper.hxx"
#include "MusicPipe.hxx"
#include "fs/Traits.hxx" #include "fs/Traits.hxx"
#include "fs/AllocatedPath.hxx" #include "fs/AllocatedPath.hxx"
#include "DecoderAPI.hxx" #include "DecoderAPI.hxx"
@@ -418,9 +419,18 @@ decoder_task(void *arg)
dc.replay_gain_prev_db = dc.replay_gain_db; dc.replay_gain_prev_db = dc.replay_gain_db;
dc.replay_gain_db = 0; dc.replay_gain_db = 0;
/* fall through */ decoder_run(dc);
break;
case DecoderCommand::SEEK: case DecoderCommand::SEEK:
/* this seek was too late, and the decoder had
already finished; start a new decoder */
/* we need to clear the pipe here; usually the
PlayerThread is responsible, but it is not
aware that the decoder has finished */
dc.pipe->Clear(*dc.buffer);
decoder_run(dc); decoder_run(dc);
break; break;

View File

@@ -234,6 +234,10 @@ public:
void PlayPrevious(PlayerControl &pc); void PlayPrevious(PlayerControl &pc);
PlaylistResult SeekSongOrder(PlayerControl &pc,
unsigned song_order,
float seek_time);
PlaylistResult SeekSongPosition(PlayerControl &pc, PlaylistResult SeekSongPosition(PlayerControl &pc,
unsigned song_position, unsigned song_position,
float seek_time); float seek_time);

View File

@@ -190,17 +190,12 @@ playlist::PlayPrevious(PlayerControl &pc)
} }
PlaylistResult PlaylistResult
playlist::SeekSongPosition(PlayerControl &pc, unsigned song, float seek_time) playlist::SeekSongOrder(PlayerControl &pc, unsigned i, float seek_time)
{ {
if (!queue.IsValidPosition(song)) assert(queue.IsValidOrder(i));
return PlaylistResult::BAD_RANGE;
const Song *queued_song = GetQueuedSong(); const Song *queued_song = GetQueuedSong();
unsigned i = queue.random
? queue.PositionToOrder(song)
: song;
pc.ClearError(); pc.ClearError();
stop_on_error = true; stop_on_error = true;
error_count = 0; error_count = 0;
@@ -228,6 +223,19 @@ playlist::SeekSongPosition(PlayerControl &pc, unsigned song, float seek_time)
return PlaylistResult::SUCCESS; return PlaylistResult::SUCCESS;
} }
PlaylistResult
playlist::SeekSongPosition(PlayerControl &pc, unsigned song, float seek_time)
{
if (!queue.IsValidPosition(song))
return PlaylistResult::BAD_RANGE;
unsigned i = queue.random
? queue.PositionToOrder(song)
: song;
return SeekSongOrder(pc, i, seek_time);
}
PlaylistResult PlaylistResult
playlist::SeekSongId(PlayerControl &pc, unsigned id, float seek_time) playlist::SeekSongId(PlayerControl &pc, unsigned id, float seek_time)
{ {
@@ -257,5 +265,5 @@ playlist::SeekCurrent(PlayerControl &pc, float seek_time, bool relative)
if (seek_time < 0) if (seek_time < 0)
seek_time = 0; seek_time = 0;
return SeekSongPosition(pc, current, seek_time); return SeekSongOrder(pc, current, seek_time);
} }

View File

@@ -110,9 +110,9 @@ audiofile_file_seek(AFvirtualfile *vfile, AFfileoffset offset, int is_relative)
Error error; Error error;
if (is.LockSeek(offset, whence, error)) { if (is.LockSeek(offset, whence, error)) {
LogError(error, "Seek failed");
return is.GetOffset(); return is.GetOffset();
} else { } else {
LogError(error, "Seek failed");
return -1; return -1;
} }
} }

View File

@@ -377,7 +377,7 @@ dsdiff_decode_chunk(Decoder &decoder, InputStream &is,
const unsigned buffer_samples = buffer_frames * frame_size; const unsigned buffer_samples = buffer_frames * frame_size;
const size_t buffer_size = buffer_samples * sample_size; const size_t buffer_size = buffer_samples * sample_size;
while (chunk_size > 0) { while (chunk_size >= frame_size) {
/* see how much aligned data from the remaining chunk /* see how much aligned data from the remaining chunk
fits into the local buffer */ fits into the local buffer */
size_t now_size = buffer_size; size_t now_size = buffer_size;

View File

@@ -238,7 +238,7 @@ dsf_decode_chunk(Decoder &decoder, InputStream &is,
const unsigned buffer_samples = buffer_frames * frame_size; const unsigned buffer_samples = buffer_frames * frame_size;
const size_t buffer_size = buffer_samples * sample_size; const size_t buffer_size = buffer_samples * sample_size;
while (chunk_size > 0) { while (chunk_size >= frame_size) {
/* see how much aligned data from the remaining chunk /* see how much aligned data from the remaining chunk
fits into the local buffer */ fits into the local buffer */
size_t now_size = buffer_size; size_t now_size = buffer_size;

View File

@@ -383,10 +383,23 @@ ffmpeg_probe(Decoder *decoder, InputStream &is)
nbytes -= PADDING; nbytes -= PADDING;
AVProbeData avpd; AVProbeData avpd;
/* new versions of ffmpeg may add new attributes, and leaving
them uninitialized may crash; hopefully, zero-initializing
everything we don't know is ok */
memset(&avpd, 0, sizeof(avpd));
avpd.buf = buffer; avpd.buf = buffer;
avpd.buf_size = nbytes; avpd.buf_size = nbytes;
avpd.filename = is.uri.c_str(); avpd.filename = is.uri.c_str();
#ifdef AVPROBE_SCORE_MIME
/* this attribute was added in libav/ffmpeg version 11, but
unfortunately it's "uint8_t" instead of "char", and it's
not "const" - wtf? */
avpd.mime_type = (uint8_t *)const_cast<char *>(is.GetMimeType());
#endif
return av_probe_input_format(&avpd, true); return av_probe_input_format(&avpd, true);
} }
@@ -433,9 +446,18 @@ ffmpeg_decode(Decoder &decoder, InputStream &input)
AVStream *av_stream = format_context->streams[audio_stream]; AVStream *av_stream = format_context->streams[audio_stream];
AVCodecContext *codec_context = av_stream->codec; AVCodecContext *codec_context = av_stream->codec;
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 25, 0)
const AVCodecDescriptor *codec_descriptor =
avcodec_descriptor_get(codec_context->codec_id);
if (codec_descriptor != nullptr)
FormatDebug(ffmpeg_domain, "codec '%s'",
codec_descriptor->name);
#else
if (codec_context->codec_name[0] != 0) if (codec_context->codec_name[0] != 0)
FormatDebug(ffmpeg_domain, "codec '%s'", FormatDebug(ffmpeg_domain, "codec '%s'",
codec_context->codec_name); codec_context->codec_name);
#endif
AVCodec *codec = avcodec_find_decoder(codec_context->codec_id); AVCodec *codec = avcodec_find_decoder(codec_context->codec_id);

View File

@@ -235,7 +235,7 @@ gme_scan_file(const char *path_fs,
if (ti->length > 0) if (ti->length > 0)
tag_handler_invoke_duration(handler, handler_ctx, tag_handler_invoke_duration(handler, handler_ctx,
ti->length / 100); ti->length / 1000);
if (ti->song != nullptr) { if (ti->song != nullptr) {
if (gme_track_count(emu) > 1) { if (gme_track_count(emu) > 1) {

View File

@@ -118,7 +118,7 @@ BufferedSocket::OnSocketReady(unsigned flags)
if (!ReadToBuffer() || !ResumeInput()) if (!ReadToBuffer() || !ResumeInput())
return false; return false;
if (input.IsFull()) if (!input.IsFull())
ScheduleRead(); ScheduleRead();
} }

View File

@@ -64,7 +64,9 @@ TimeoutMonitor::ScheduleSeconds(unsigned s)
void void
TimeoutMonitor::Run() TimeoutMonitor::Run()
{ {
#ifndef USE_EPOLL #ifdef USE_EPOLL
active = false;
#else
Cancel(); Cancel();
#endif #endif

View File

@@ -802,6 +802,7 @@ alsa_play(struct audio_output *ao, const void *chunk, size_t size,
{ {
AlsaOutput *ad = (AlsaOutput *)ao; AlsaOutput *ad = (AlsaOutput *)ao;
assert(size > 0);
assert(size % ad->in_frame_size == 0); assert(size % ad->in_frame_size == 0);
if (ad->must_prepare) { if (ad->must_prepare) {
@@ -814,11 +815,21 @@ alsa_play(struct audio_output *ao, const void *chunk, size_t size,
} }
} }
const size_t original_size = size;
chunk = ad->pcm_export->Export(chunk, size, size); chunk = ad->pcm_export->Export(chunk, size, size);
if (size == 0)
/* the DoP (DSD over PCM) filter converts two frames
at a time and ignores the last odd frame; if there
was only one frame (e.g. the last frame in the
file), the result is empty; to avoid an endless
loop, bail out here, and pretend the one frame has
been played */
return original_size;
assert(size % ad->out_frame_size == 0); assert(size % ad->out_frame_size == 0);
size /= ad->out_frame_size; size /= ad->out_frame_size;
assert(size > 0);
while (true) { while (true) {
snd_pcm_sframes_t ret = ad->writei(ad->pcm, chunk, size); snd_pcm_sframes_t ret = ad->writei(ad->pcm, chunk, size);

View File

@@ -727,6 +727,8 @@ oss_output_play(struct audio_output *ao, const void *chunk, size_t size,
OssOutput *od = (OssOutput *)ao; OssOutput *od = (OssOutput *)ao;
ssize_t ret; ssize_t ret;
assert(size > 0);
/* reopen the device since it was closed by dropBufferedAudio */ /* reopen the device since it was closed by dropBufferedAudio */
if (od->fd < 0 && !oss_reopen(od, error)) if (od->fd < 0 && !oss_reopen(od, error))
return 0; return 0;
@@ -735,6 +737,8 @@ oss_output_play(struct audio_output *ao, const void *chunk, size_t size,
chunk = od->pcm_export->Export(chunk, size, size); chunk = od->pcm_export->Export(chunk, size, size);
#endif #endif
assert(size > 0);
while (true) { while (true) {
ret = write(od->fd, chunk, size); ret = write(od->fd, chunk, size);
if (ret > 0) { if (ret > 0) {

View File

@@ -81,7 +81,7 @@ check_range(Client &client, unsigned *value_r1, unsigned *value_r2,
/* compatibility with older MPD versions: specifying /* compatibility with older MPD versions: specifying
"-1" makes MPD display the whole list */ "-1" makes MPD display the whole list */
*value_r1 = 0; *value_r1 = 0;
*value_r2 = std::numeric_limits<unsigned>::max(); *value_r2 = std::numeric_limits<int>::max();
return true; return true;
} }
@@ -108,7 +108,7 @@ check_range(Client &client, unsigned *value_r1, unsigned *value_r2,
} }
if (test == test2) if (test == test2)
value = std::numeric_limits<unsigned>::max(); value = std::numeric_limits<int>::max();
if (value < 0) { if (value < 0) {
command_error(client, ACK_ERROR_ARG, command_error(client, ACK_ERROR_ARG,

View File

@@ -40,6 +40,16 @@
/* well-known big-endian */ /* well-known big-endian */
# define IS_LITTLE_ENDIAN false # define IS_LITTLE_ENDIAN false
# define IS_BIG_ENDIAN true # define IS_BIG_ENDIAN true
#elif defined(__APPLE__)
/* compile-time check for MacOS */
# include <machine/endian.h>
# if BYTE_ORDER == LITTLE_ENDIAN
# define IS_LITTLE_ENDIAN true
# define IS_BIG_ENDIAN false
# else
# define IS_LITTLE_ENDIAN false
# define IS_BIG_ENDIAN true
# endif
#else #else
/* generic compile-time check */ /* generic compile-time check */
# include <endian.h> # include <endian.h>

View File

@@ -33,7 +33,7 @@
#include "Compiler.h" #include "Compiler.h"
#include <assert.h> #include <assert.h>
#include <string.h> #include <strings.h>
/** /**
* Determine whether two strings are equal, ignoring case for ASCII * Determine whether two strings are equal, ignoring case for ASCII

View File

Before

Width:  |  Height:  |  Size: 345 KiB

After

Width:  |  Height:  |  Size: 345 KiB

View File

@@ -3,7 +3,7 @@
#define VERSION_NUMBER @VERSION_MAJOR@,@VERSION_MINOR@,@VERSION_REVISION@,@VERSION_EXTRA@ #define VERSION_NUMBER @VERSION_MAJOR@,@VERSION_MINOR@,@VERSION_REVISION@,@VERSION_EXTRA@
#define VERSION_NUMBER_STR "@VERSION_MAJOR@,@VERSION_MINOR@,@VERSION_REVISION@,@VERSION_EXTRA@" #define VERSION_NUMBER_STR "@VERSION_MAJOR@,@VERSION_MINOR@,@VERSION_REVISION@,@VERSION_EXTRA@"
MPD_ICON ICON "@top_srcdir@/src/win/mpd.ico" MPD_ICON ICON "@top_srcdir@/src/win32/mpd.ico"
1 VERSIONINFO 1 VERSIONINFO
FILETYPE VFT_APP FILETYPE VFT_APP

View File

@@ -175,8 +175,10 @@ decoder_replay_gain(gcc_unused Decoder &decoder,
} }
void void
decoder_mixramp(gcc_unused Decoder &decoder, gcc_unused MixRampInfo &&mix_ramp) decoder_mixramp(gcc_unused Decoder &decoder, MixRampInfo &&mix_ramp)
{ {
fprintf(stderr, "MixRamp: start='%s' end='%s'\n",
mix_ramp.GetStart(), mix_ramp.GetEnd());
} }
int main(int argc, char **argv) int main(int argc, char **argv)

60
test/test_protocol.cxx Normal file
View File

@@ -0,0 +1,60 @@
#include "config.h"
#include "protocol/ArgParser.hxx"
#include "protocol/Result.hxx"
#include "Compiler.h"
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/ui/text/TestRunner.h>
#include <cppunit/extensions/HelperMacros.h>
static enum ack last_error = ack(-1);
void
command_error(gcc_unused Client &client, enum ack error,
gcc_unused const char *fmt, ...)
{
last_error = error;
}
class ArgParserTest : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(ArgParserTest);
CPPUNIT_TEST(TestRange);
CPPUNIT_TEST_SUITE_END();
public:
void TestRange();
};
void
ArgParserTest::TestRange()
{
Client &client = *(Client *)nullptr;
unsigned a, b;
CPPUNIT_ASSERT(check_range(client, &a, &b, "1"));
CPPUNIT_ASSERT_EQUAL(1u, a);
CPPUNIT_ASSERT_EQUAL(2u, b);
CPPUNIT_ASSERT(check_range(client, &a, &b, "1:5"));
CPPUNIT_ASSERT_EQUAL(1u, a);
CPPUNIT_ASSERT_EQUAL(5u, b);
CPPUNIT_ASSERT(check_range(client, &a, &b, "1:"));
CPPUNIT_ASSERT_EQUAL(1u, a);
CPPUNIT_ASSERT(b >= 999999u);
CPPUNIT_ASSERT(!check_range(client, &a, &b, "-2"));
CPPUNIT_ASSERT_EQUAL(ACK_ERROR_ARG, last_error);
}
CPPUNIT_TEST_SUITE_REGISTRATION(ArgParserTest);
int
main(gcc_unused int argc, gcc_unused char **argv)
{
CppUnit::TextUi::TestRunner runner;
auto &registry = CppUnit::TestFactoryRegistry::getRegistry();
runner.addTest(registry.makeTest());
return runner.run() ? EXIT_SUCCESS : EXIT_FAILURE;
}