Compare commits
41 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
98afae2520 | ||
![]() |
ddc85c620f | ||
![]() |
12bc625fe1 | ||
![]() |
6b407356b9 | ||
![]() |
a4e0b52468 | ||
![]() |
98efb4f6d5 | ||
![]() |
36edb4886c | ||
![]() |
76290f786d | ||
![]() |
c6299c26b5 | ||
![]() |
fb5f9baf9c | ||
![]() |
dee591d970 | ||
![]() |
a5cc13b0c5 | ||
![]() |
aaf588aeaa | ||
![]() |
533a3def9f | ||
![]() |
fcf487f4e0 | ||
![]() |
906972973e | ||
![]() |
116edf5fce | ||
![]() |
8581013911 | ||
![]() |
b1e073bacd | ||
![]() |
501e48daba | ||
![]() |
643ecd1edd | ||
![]() |
7393e1cba1 | ||
![]() |
ceee47fda8 | ||
![]() |
6f3c0d0a60 | ||
![]() |
466625f7ad | ||
![]() |
b8259e604a | ||
![]() |
86e2075c63 | ||
![]() |
30900b2fe2 | ||
![]() |
fd7ae7ea4c | ||
![]() |
60d5bf0240 | ||
![]() |
41cdc4e14b | ||
![]() |
87dfca0477 | ||
![]() |
e1ee8e7812 | ||
![]() |
63406efcd8 | ||
![]() |
d5c132fca0 | ||
![]() |
5f082a2739 | ||
![]() |
7d6a762845 | ||
![]() |
8dcb1f805d | ||
![]() |
a8b9e5b9b9 | ||
![]() |
04f928e2b0 | ||
![]() |
c7a803c922 |
Makefile.amNEWS
android
configure.acdoc
python/build
src
AudioFormat.cxxAudioFormat.hxxLocateUri.cxx
db
plugins
update
decoder
fs
input
lib
ls.cxxoutput
pcm
playlist
protocol
storage
system
tag
thread
util
win32
13
Makefile.am
13
Makefile.am
@@ -234,6 +234,7 @@ libmpd_a_SOURCES += \
|
||||
endif
|
||||
|
||||
CURL_SOURCES = \
|
||||
src/lib/curl/Error.hxx \
|
||||
src/lib/curl/Version.cxx src/lib/curl/Version.hxx \
|
||||
src/lib/curl/Global.cxx src/lib/curl/Global.hxx \
|
||||
src/lib/curl/Request.cxx src/lib/curl/Request.hxx \
|
||||
@@ -293,7 +294,7 @@ libmpd.so: $(filter %.a,$(src_mpd_LDADD)) libmain.a
|
||||
$(AM_V_CXXLD)$(CXXLD) -shared -Wl,--no-undefined,-shared,-Bsymbolic -llog -lz -o $@ $(AM_CXXFLAGS) $(CXXFLAGS) $(LDFLAGS) src/libmain_a-Main.o $(src_mpd_LDADD) $(LIBS)
|
||||
|
||||
ANDROID_SDK_BUILD_TOOLS_VERSION = 27.0.0
|
||||
ANDROID_SDK_PLATFORM = android-17
|
||||
ANDROID_SDK_PLATFORM = android-21
|
||||
|
||||
ANDROID_BUILD_TOOLS_DIR = $(ANDROID_SDK)/build-tools/$(ANDROID_SDK_BUILD_TOOLS_VERSION)
|
||||
ANDROID_SDK_PLATFORM_DIR = $(ANDROID_SDK)/platforms/$(ANDROID_SDK_PLATFORM)
|
||||
@@ -340,7 +341,7 @@ android/build/include/org_musicpd_Bridge.h: android/build/classes.dex
|
||||
|
||||
BUILT_SOURCES = android/build/include/org_musicpd_Bridge.h
|
||||
|
||||
android/build/lib/armeabi-v7a/libmpd.so: libmpd.so
|
||||
android/build/lib/$(ANDROID_ABI)/libmpd.so: libmpd.so
|
||||
mkdir -p $(@D)
|
||||
rm -f $@
|
||||
$(STRIP) -o $@ $<
|
||||
@@ -350,7 +351,7 @@ android/build/res/drawable/icon.png: mpd.svg
|
||||
rsvg-convert --width=48 --height=48 $< -o $@
|
||||
|
||||
.DELETE_ON_ERROR: android/build/unsigned.apk
|
||||
android/build/unsigned.apk: android/build/classes.dex android/build/resources.apk android/build/lib/armeabi-v7a/libmpd.so
|
||||
android/build/unsigned.apk: android/build/classes.dex android/build/resources.apk android/build/lib/$(ANDROID_ABI)/libmpd.so
|
||||
cp android/build/resources.apk $@
|
||||
cd $(dir $@) && zip -q -r $(notdir $@) classes.dex lib
|
||||
|
||||
@@ -444,6 +445,7 @@ libutil_a_SOURCES = \
|
||||
src/util/NumberParser.hxx \
|
||||
src/util/MimeType.cxx src/util/MimeType.hxx \
|
||||
src/util/StringBuffer.hxx \
|
||||
src/util/StringFormat.hxx \
|
||||
src/util/StringPointer.hxx \
|
||||
src/util/StringView.cxx src/util/StringView.hxx \
|
||||
src/util/AllocatedString.cxx src/util/AllocatedString.hxx \
|
||||
@@ -712,6 +714,7 @@ NFS_SOURCES = \
|
||||
src/lib/nfs/Cancellable.hxx \
|
||||
src/lib/nfs/Lease.hxx \
|
||||
src/lib/nfs/Connection.cxx src/lib/nfs/Connection.hxx \
|
||||
src/lib/nfs/Error.cxx src/lib/nfs/Error.hxx \
|
||||
src/lib/nfs/Manager.cxx src/lib/nfs/Manager.hxx \
|
||||
src/lib/nfs/Glue.cxx src/lib/nfs/Glue.hxx \
|
||||
src/lib/nfs/Base.cxx src/lib/nfs/Base.hxx \
|
||||
@@ -734,6 +737,8 @@ libstorage_a_SOURCES = \
|
||||
src/storage/FileInfo.hxx
|
||||
|
||||
libstorage_a_CPPFLAGS = $(AM_CPPFLAGS) \
|
||||
$(CURL_CFLAGS) \
|
||||
$(EXPAT_CFLAGS) \
|
||||
$(NFS_CFLAGS) \
|
||||
$(SMBCLIENT_CFLAGS)
|
||||
|
||||
@@ -1292,7 +1297,7 @@ endif
|
||||
#
|
||||
|
||||
libinput_a_SOURCES = \
|
||||
src/input/Domain.cxx src/input/Domain.hxx \
|
||||
src/input/Error.cxx src/input/Error.hxx \
|
||||
src/input/Init.cxx src/input/Init.hxx \
|
||||
src/input/Registry.cxx src/input/Registry.hxx \
|
||||
src/input/Open.cxx \
|
||||
|
13
NEWS
13
NEWS
@@ -1,3 +1,16 @@
|
||||
ver 0.20.21 (2018/08/17)
|
||||
* database
|
||||
- proxy: add "password" setting
|
||||
- proxy: support tags "ArtistSort", "AlbumArtistSort", "AlbumSort"
|
||||
- simple: allow .mpdignore comments only at start of line
|
||||
* output
|
||||
- httpd: remove broken DLNA support code
|
||||
* playlist
|
||||
- cue: support file type declaration "FLAC" (non-standard)
|
||||
* URI schemes are case insensitive
|
||||
* Android, Windows
|
||||
- enable the "curl" storage plugin
|
||||
|
||||
ver 0.20.20 (2018/05/22)
|
||||
* protocol
|
||||
- fix "modified-since" filter regression
|
||||
|
@@ -2,10 +2,10 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.musicpd"
|
||||
android:installLocation="auto"
|
||||
android:versionCode="19"
|
||||
android:versionName="0.20.20">
|
||||
android:versionCode="20"
|
||||
android:versionName="0.20.21">
|
||||
|
||||
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="17"/>
|
||||
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="21"/>
|
||||
|
||||
<application android:icon="@drawable/icon" android:label="@string/app_name">
|
||||
<activity android:name=".Main"
|
||||
|
@@ -29,6 +29,15 @@ android_abis = {
|
||||
'cflags': '-march=armv7-a -mfpu=vfp -mfloat-abi=softfp',
|
||||
},
|
||||
|
||||
'arm64-v8a': {
|
||||
'android_api_level': '21',
|
||||
'arch': 'aarch64-linux-android',
|
||||
'ndk_arch': 'arm64',
|
||||
'toolchain_arch': 'aarch64-linux-android',
|
||||
'llvm_triple': 'aarch64-none-linux-android',
|
||||
'cflags': '',
|
||||
},
|
||||
|
||||
'x86': {
|
||||
'arch': 'i686-linux-android',
|
||||
'ndk_arch': 'x86',
|
||||
@@ -65,7 +74,8 @@ class AndroidNdkToolchain:
|
||||
self.build_path = build_path
|
||||
|
||||
ndk_arch = abi_info['ndk_arch']
|
||||
ndk_platform = 'android-14'
|
||||
android_api_level = '21'
|
||||
ndk_platform = 'android-' + android_api_level
|
||||
|
||||
# select the NDK compiler
|
||||
gcc_version = '4.9'
|
||||
@@ -106,7 +116,7 @@ class AndroidNdkToolchain:
|
||||
self.cppflags = '--sysroot=' + sysroot + \
|
||||
' -isystem ' + os.path.join(install_prefix, 'include') + \
|
||||
' -isystem ' + os.path.join(sysroot, 'usr', 'include', arch) + \
|
||||
' -D__ANDROID_API__=14'
|
||||
' -D__ANDROID_API__=' + android_api_level
|
||||
self.ldflags = '--sysroot=' + sysroot + \
|
||||
' -L' + os.path.join(install_prefix, 'lib') + \
|
||||
' -L' + os.path.join(target_root, 'usr', 'lib') + \
|
||||
@@ -116,6 +126,7 @@ class AndroidNdkToolchain:
|
||||
|
||||
self.is_arm = ndk_arch == 'arm'
|
||||
self.is_armv7 = self.is_arm and 'armv7' in self.cflags
|
||||
self.is_aarch64 = ndk_arch == 'arm64'
|
||||
self.is_windows = False
|
||||
|
||||
libcxx_path = os.path.join(ndk_path, 'sources/cxx-stl/llvm-libc++')
|
||||
@@ -146,6 +157,7 @@ thirdparty_libs = [
|
||||
libid3tag,
|
||||
ffmpeg,
|
||||
curl,
|
||||
libexpat,
|
||||
libnfs,
|
||||
boost,
|
||||
]
|
||||
|
@@ -49,7 +49,7 @@ public class Main extends Activity implements Runnable {
|
||||
TextView tv = new TextView(this);
|
||||
tv.setText("Failed to load the native MPD libary.\n" +
|
||||
"Report this problem to us, and include the following information:\n" +
|
||||
"ABI=" + Build.CPU_ABI + "\n" +
|
||||
"SUPPORTED_ABIS=" + String.join(", ", Build.SUPPORTED_ABIS) + "\n" +
|
||||
"PRODUCT=" + Build.PRODUCT + "\n" +
|
||||
"FINGERPRINT=" + Build.FINGERPRINT + "\n" +
|
||||
"error=" + Loader.error);
|
||||
|
24
configure.ac
24
configure.ac
@@ -1,10 +1,10 @@
|
||||
AC_PREREQ(2.60)
|
||||
|
||||
AC_INIT(mpd, 0.20.20, musicpd-dev-team@lists.sourceforge.net)
|
||||
AC_INIT(mpd, 0.20.21, musicpd-dev-team@lists.sourceforge.net)
|
||||
|
||||
VERSION_MAJOR=0
|
||||
VERSION_MINOR=20
|
||||
VERSION_REVISION=20
|
||||
VERSION_REVISION=21
|
||||
VERSION_EXTRA=0
|
||||
|
||||
AC_CONFIG_SRCDIR([src/Main.cxx])
|
||||
@@ -16,7 +16,7 @@ AC_CONFIG_MACRO_DIR([m4])
|
||||
|
||||
AC_DEFINE(PROTOCOL_VERSION, "0.20.0", [The MPD protocol version])
|
||||
|
||||
GIT_COMMIT=`GIT_DIR="$srcdir/.git" git describe --dirty --always 2>/dev/null`
|
||||
GIT_COMMIT=`cd "$srcdir" && git describe --dirty --always 2>/dev/null`
|
||||
if test x$GIT_COMMIT != x; then
|
||||
AC_DEFINE_UNQUOTED(GIT_COMMIT, ["$GIT_COMMIT"], [The current git commit])
|
||||
fi
|
||||
@@ -186,6 +186,7 @@ AC_ARG_WITH([android-sdk],
|
||||
[Directory for Android SDK]),
|
||||
[], [with_android_sdk=no])
|
||||
|
||||
android_abi=""
|
||||
if test x$host_is_android = xyes; then
|
||||
if test x$with_android_sdk = xno; then
|
||||
AC_MSG_ERROR([Android build requires option --with-android-sdk=DIR])
|
||||
@@ -194,9 +195,15 @@ if test x$host_is_android = xyes; then
|
||||
if ! test -x $with_android_sdk/tools/android; then
|
||||
AC_MSG_ERROR([Android SDK not found in $with_android_sdk])
|
||||
fi
|
||||
|
||||
AS_CASE([$host_cpu],
|
||||
[i686], [android_abi="x86"],
|
||||
[aarch64], [android_abi="arm64-v8a"],
|
||||
[android_abi="armeabi-v7a"])
|
||||
fi
|
||||
|
||||
AC_SUBST(ANDROID_SDK, [$with_android_sdk])
|
||||
AC_SUBST(ANDROID_ABI, [$android_abi])
|
||||
|
||||
dnl ---------------------------------------------------------------------------
|
||||
dnl Language Checks
|
||||
@@ -315,7 +322,7 @@ else
|
||||
fi
|
||||
|
||||
default_enable_daemon=yes
|
||||
if test x$host_is_android = xyes || test x$host_is_android = xyes; then
|
||||
if test x$host_is_android = xyes || test x$host_is_windows = xyes; then
|
||||
default_enable_daemon=no
|
||||
fi
|
||||
AC_ARG_ENABLE(daemon,
|
||||
@@ -402,7 +409,7 @@ AC_ARG_ENABLE(recorder-output,
|
||||
|
||||
AC_ARG_ENABLE(sidplay,
|
||||
AS_HELP_STRING([--enable-sidplay],
|
||||
[enable C64 SID support via libsidplay2]),,
|
||||
[enable C64 SID support via libsidplayfp or libsidplay2]),,
|
||||
enable_sidplay=auto)
|
||||
|
||||
AC_ARG_ENABLE(shout,
|
||||
@@ -1005,7 +1012,7 @@ if test x$enable_sidplay != xno && test x$found_sidplayfp = xno; then
|
||||
[found_sidplay=no])
|
||||
|
||||
MPD_AUTO_PRE(sidplay, [sidplay decoder plugin],
|
||||
[libsidplay2 not found])
|
||||
[libsidplay2 or libsidutils not found])
|
||||
fi
|
||||
|
||||
if test x$enable_sidplay != xno && test x$found_sidplayfp = xno; then
|
||||
@@ -1017,10 +1024,11 @@ if test x$enable_sidplay != xno && test x$found_sidplayfp = xno; then
|
||||
fi
|
||||
|
||||
if test x$enable_sidplay = xyes; then
|
||||
SIDPLAY_LIBS="$SIDPLAY_LIBS -lresid-builder"
|
||||
AC_DEFINE(ENABLE_SIDPLAY, 1, [Define for libsidplay2 support])
|
||||
AC_DEFINE(ENABLE_SIDPLAY, 1, [Define for libsidplayfp or libsidplay2 support])
|
||||
if test x$found_sidplayfp = xyes; then
|
||||
AC_DEFINE(HAVE_SIDPLAYFP, 1, [Define if libsidplayfp is used instead of libsidplay2])
|
||||
else
|
||||
SIDPLAY_LIBS="$SIDPLAY_LIBS -lresid-builder"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
16
doc/user.xml
16
doc/user.xml
@@ -2087,13 +2087,6 @@ run</programlisting>
|
||||
database.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Note that unless overridden by the below settings (e.g. by
|
||||
setting them to a blank value), general curl configuration
|
||||
from environment variables such as http_proxy or specified
|
||||
in ~/.curlrc will be in effect.
|
||||
</para>
|
||||
|
||||
<informaltable>
|
||||
<tgroup cols="2">
|
||||
<thead>
|
||||
@@ -2121,6 +2114,15 @@ run</programlisting>
|
||||
<application>MPD</application> instance.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<varname>password</varname>
|
||||
</entry>
|
||||
<entry>
|
||||
The password used to log in to the "master"
|
||||
<application>MPD</application> instance.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>
|
||||
<varname>keepalive</varname>
|
||||
|
@@ -21,6 +21,8 @@ class FfmpegProject(Project):
|
||||
|
||||
if toolchain.is_arm:
|
||||
arch = 'arm'
|
||||
elif toolchain.is_aarch64:
|
||||
arch = 'aarch64'
|
||||
else:
|
||||
arch = 'x86'
|
||||
|
||||
|
@@ -112,8 +112,8 @@ liblame = AutotoolsProject(
|
||||
)
|
||||
|
||||
ffmpeg = FfmpegProject(
|
||||
'http://ffmpeg.org/releases/ffmpeg-4.0.tar.xz',
|
||||
'ed945daf40b124e77a685893cc025d086f638bc703183460aff49508edb3a43f',
|
||||
'http://ffmpeg.org/releases/ffmpeg-4.0.2.tar.xz',
|
||||
'a95c0cc9eb990e94031d2183f2e6e444cc61c99f6f182d1575c433d62afb2f97',
|
||||
'lib/libavcodec.a',
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
@@ -341,8 +341,8 @@ ffmpeg = FfmpegProject(
|
||||
)
|
||||
|
||||
curl = AutotoolsProject(
|
||||
'http://curl.haxx.se/download/curl-7.60.0.tar.xz',
|
||||
'8736ff8ded89ddf7e926eec7b16f82597d029fc1469f3a551f1fafaac164e6a0',
|
||||
'http://curl.haxx.se/download/curl-7.61.0.tar.xz',
|
||||
'ef6e55192d04713673b4409ccbcb4cb6cd723137d6e10ca45b0c593a454e1720',
|
||||
'lib/libcurl.a',
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
@@ -364,9 +364,19 @@ curl = AutotoolsProject(
|
||||
patches='src/lib/curl/patches',
|
||||
)
|
||||
|
||||
libexpat = AutotoolsProject(
|
||||
'https://github.com/libexpat/libexpat/releases/download/R_2_2_6/expat-2.2.6.tar.bz2',
|
||||
'17b43c2716d521369f82fc2dc70f359860e90fa440bea65b3b85f0b246ea81f2',
|
||||
'lib/libexpat.a',
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
'--without-docbook',
|
||||
],
|
||||
)
|
||||
|
||||
libnfs = AutotoolsProject(
|
||||
'https://github.com/sahlberg/libnfs/archive/libnfs-2.0.0.tar.gz',
|
||||
'7ea6cd8fa6c461d01091e584d424d28e137d23ff4b65b95d01a3fd0ef95d120e',
|
||||
'https://github.com/sahlberg/libnfs/archive/libnfs-3.0.0.tar.gz',
|
||||
'445d92c5fc55e4a5b115e358e60486cf8f87ee50e0103d46a02e7fb4618566a5',
|
||||
'lib/libnfs.a',
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
@@ -374,13 +384,15 @@ libnfs = AutotoolsProject(
|
||||
|
||||
# work around -Wtautological-compare
|
||||
'--disable-werror',
|
||||
|
||||
'--disable-utils', '--disable-examples',
|
||||
],
|
||||
base='libnfs-libnfs-2.0.0',
|
||||
base='libnfs-libnfs-3.0.0',
|
||||
autoreconf=True,
|
||||
)
|
||||
|
||||
boost = BoostProject(
|
||||
'http://downloads.sourceforge.net/project/boost/boost/1.66.0/boost_1_66_0.tar.bz2',
|
||||
'5721818253e6a0989583192f96782c4a98eb6204965316df9f5ad75819225ca9',
|
||||
'http://downloads.sourceforge.net/project/boost/boost/1.68.0/boost_1_68_0.tar.bz2',
|
||||
'7f6130bc3cf65f56a618888ce9d5ea704fa10b462be126ad053e80e553d6d8b7',
|
||||
'include/boost/version.hpp',
|
||||
)
|
||||
|
@@ -20,6 +20,9 @@ class MesonProject(Project):
|
||||
cpu = 'armv7'
|
||||
else:
|
||||
cpu = 'armv6'
|
||||
elif toolchain.is_aarch64:
|
||||
cpu_family = 'aarch64'
|
||||
cpu = 'arm64-v8a'
|
||||
else:
|
||||
cpu_family = 'x86'
|
||||
if 'x86_64' in toolchain.arch:
|
||||
@@ -51,6 +54,9 @@ c_link_args = %s
|
||||
cpp_args = %s
|
||||
cpp_link_args = %s
|
||||
|
||||
# Keep Meson from executing Android-x86 test binariees
|
||||
needs_exe_wrapper = true
|
||||
|
||||
[host_machine]
|
||||
system = '%s'
|
||||
cpu_family = '%s'
|
||||
|
@@ -19,9 +19,9 @@
|
||||
|
||||
#include "AudioFormat.hxx"
|
||||
#include "util/StringBuffer.hxx"
|
||||
#include "util/StringFormat.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void
|
||||
AudioFormat::ApplyMask(AudioFormat mask) noexcept
|
||||
@@ -44,21 +44,16 @@ AudioFormat::ApplyMask(AudioFormat mask) noexcept
|
||||
StringBuffer<24>
|
||||
ToString(const AudioFormat af) noexcept
|
||||
{
|
||||
StringBuffer<24> buffer;
|
||||
|
||||
if (af.format == SampleFormat::DSD && af.sample_rate > 0 &&
|
||||
af.sample_rate % 44100 == 0) {
|
||||
/* use shortcuts such as "dsd64" which implies the
|
||||
sample rate */
|
||||
snprintf(buffer.data(), buffer.capacity(), "dsd%u:%u",
|
||||
af.sample_rate * 8 / 44100,
|
||||
af.channels);
|
||||
return buffer;
|
||||
return StringFormat<24>("dsd%u:%u",
|
||||
af.sample_rate * 8 / 44100,
|
||||
af.channels);
|
||||
}
|
||||
|
||||
snprintf(buffer.data(), buffer.capacity(), "%u:%s:%u",
|
||||
af.sample_rate, sample_format_to_string(af.format),
|
||||
af.channels);
|
||||
|
||||
return buffer;
|
||||
return StringFormat<24>("%u:%s:%u",
|
||||
af.sample_rate, sample_format_to_string(af.format),
|
||||
af.channels);
|
||||
}
|
||||
|
@@ -23,7 +23,6 @@
|
||||
#include "pcm/SampleFormat.hxx"
|
||||
#include "Compiler.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
@@ -23,7 +23,7 @@
|
||||
#include "fs/AllocatedPath.hxx"
|
||||
#include "ls.hxx"
|
||||
#include "util/UriUtil.hxx"
|
||||
#include "util/StringCompare.hxx"
|
||||
#include "util/ASCII.hxx"
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
#include "storage/StorageInterface.hxx"
|
||||
@@ -83,7 +83,7 @@ LocateUri(const char *uri, const Client *client
|
||||
)
|
||||
{
|
||||
/* skip the obsolete "file://" prefix */
|
||||
const char *path_utf8 = StringAfterPrefix(uri, "file://");
|
||||
const char *path_utf8 = StringAfterPrefixCaseASCII(uri, "file://");
|
||||
if (path_utf8 != nullptr) {
|
||||
if (!PathTraitsUTF8::IsAbsolute(path_utf8))
|
||||
throw std::runtime_error("Malformed file:// URI");
|
||||
|
@@ -82,6 +82,7 @@ class ProxyDatabase final : public Database, SocketMonitor, IdleMonitor {
|
||||
DatabaseListener &listener;
|
||||
|
||||
const std::string host;
|
||||
const std::string password;
|
||||
const unsigned port;
|
||||
const bool keepalive;
|
||||
|
||||
@@ -169,6 +170,13 @@ static constexpr struct {
|
||||
#if LIBMPDCLIENT_CHECK_VERSION(2,10,0)
|
||||
{ TAG_MUSICBRAINZ_RELEASETRACKID,
|
||||
MPD_TAG_MUSICBRAINZ_RELEASETRACKID },
|
||||
#endif
|
||||
#if LIBMPDCLIENT_CHECK_VERSION(2,11,0)
|
||||
{ TAG_ARTIST_SORT, MPD_TAG_ARTIST_SORT },
|
||||
{ TAG_ALBUM_ARTIST_SORT, MPD_TAG_ALBUM_ARTIST_SORT },
|
||||
#endif
|
||||
#if LIBMPDCLIENT_CHECK_VERSION(2,12,0)
|
||||
{ TAG_ALBUM_SORT, MPD_TAG_ALBUM_SORT },
|
||||
#endif
|
||||
{ TAG_NUM_OF_ITEM_TYPES, MPD_TAG_COUNT }
|
||||
};
|
||||
@@ -359,6 +367,7 @@ ProxyDatabase::ProxyDatabase(EventLoop &_loop, DatabaseListener &_listener,
|
||||
SocketMonitor(_loop), IdleMonitor(_loop),
|
||||
listener(_listener),
|
||||
host(block.GetBlockValue("host", "")),
|
||||
password(block.GetBlockValue("password", "")),
|
||||
port(block.GetBlockValue("port", 0u)),
|
||||
keepalive(block.GetBlockValue("keepalive", false))
|
||||
{
|
||||
@@ -402,6 +411,10 @@ ProxyDatabase::Connect()
|
||||
|
||||
try {
|
||||
CheckError(connection);
|
||||
|
||||
if (!password.empty() &&
|
||||
!mpd_run_password(connection, password.c_str()))
|
||||
ThrowError(connection);
|
||||
} catch (...) {
|
||||
mpd_connection_free(connection);
|
||||
connection = nullptr;
|
||||
|
@@ -27,6 +27,7 @@
|
||||
#include "util/UriUtil.hxx"
|
||||
#include "util/RuntimeError.hxx"
|
||||
#include "util/ScopeExit.hxx"
|
||||
#include "util/StringFormat.hxx"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
@@ -47,10 +48,6 @@ ContentDirectoryService::readDirSlice(UpnpClient_Handle hdl,
|
||||
unsigned &didreadp,
|
||||
unsigned &totalp) const
|
||||
{
|
||||
// Create request
|
||||
char ofbuf[100], cntbuf[100];
|
||||
sprintf(ofbuf, "%u", offset);
|
||||
sprintf(cntbuf, "%u", count);
|
||||
// Some devices require an empty SortCriteria, else bad params
|
||||
IXML_Document *request =
|
||||
MakeActionHelper("Browse", m_serviceType.c_str(),
|
||||
@@ -58,8 +55,10 @@ ContentDirectoryService::readDirSlice(UpnpClient_Handle hdl,
|
||||
"BrowseFlag", "BrowseDirectChildren",
|
||||
"Filter", "*",
|
||||
"SortCriteria", "",
|
||||
"StartingIndex", ofbuf,
|
||||
"RequestedCount", cntbuf);
|
||||
"StartingIndex",
|
||||
StringFormat<32>("%u", offset).c_str(),
|
||||
"RequestedCount",
|
||||
StringFormat<32>("%u", count).c_str());
|
||||
if (request == nullptr)
|
||||
throw std::runtime_error("UpnpMakeAction() failed");
|
||||
|
||||
@@ -112,15 +111,13 @@ ContentDirectoryService::search(UpnpClient_Handle hdl,
|
||||
unsigned offset = 0, total = -1, count;
|
||||
|
||||
do {
|
||||
char ofbuf[100];
|
||||
sprintf(ofbuf, "%d", offset);
|
||||
|
||||
UniqueIxmlDocument request(MakeActionHelper("Search", m_serviceType.c_str(),
|
||||
"ContainerID", objectId,
|
||||
"SearchCriteria", ss,
|
||||
"Filter", "*",
|
||||
"SortCriteria", "",
|
||||
"StartingIndex", ofbuf,
|
||||
"StartingIndex",
|
||||
StringFormat<32>("%u", offset).c_str(),
|
||||
"RequestedCount", "0")); // Setting a value here gets twonky into fits
|
||||
if (!request)
|
||||
throw std::runtime_error("UpnpMakeAction() failed");
|
||||
|
@@ -26,8 +26,8 @@
|
||||
#include "ExcludeList.hxx"
|
||||
#include "fs/Path.hxx"
|
||||
#include "fs/NarrowPath.hxx"
|
||||
#include "fs/io/TextFile.hxx"
|
||||
#include "system/Error.hxx"
|
||||
#include "input/TextInputStream.hxx"
|
||||
#include "util/StringUtil.hxx"
|
||||
#include "Log.hxx"
|
||||
|
||||
#include <stdexcept>
|
||||
@@ -35,35 +35,29 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
inline void
|
||||
ExcludeList::ParseLine(char *line) noexcept
|
||||
{
|
||||
char *p = Strip(line);
|
||||
if (*p != 0 && *p != '#')
|
||||
patterns.emplace_front(p);
|
||||
}
|
||||
|
||||
bool
|
||||
ExcludeList::LoadFile(Path path_fs) noexcept
|
||||
try {
|
||||
ExcludeList::Load(InputStreamPtr is)
|
||||
{
|
||||
#ifdef HAVE_CLASS_GLOB
|
||||
TextFile file(path_fs);
|
||||
TextInputStream tis(std::move(is));
|
||||
|
||||
char *line;
|
||||
while ((line = file.ReadLine()) != nullptr) {
|
||||
char *p = strchr(line, '#');
|
||||
if (p != nullptr)
|
||||
*p = 0;
|
||||
|
||||
p = Strip(line);
|
||||
if (*p != 0)
|
||||
patterns.emplace_front(p);
|
||||
}
|
||||
while ((line = tis.ReadLine()) != nullptr)
|
||||
ParseLine(line);
|
||||
#else
|
||||
/* not implemented */
|
||||
(void)path_fs;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
} catch (const std::system_error &e) {
|
||||
if (!IsFileNotFound(e))
|
||||
LogError(e);
|
||||
return false;
|
||||
} catch (const std::exception &e) {
|
||||
LogError(e);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@@ -28,6 +28,7 @@
|
||||
#include "check.h"
|
||||
#include "Compiler.h"
|
||||
#include "fs/Glob.hxx"
|
||||
#include "input/Ptr.hxx"
|
||||
|
||||
#ifdef HAVE_CLASS_GLOB
|
||||
#include <forward_list>
|
||||
@@ -62,13 +63,16 @@ public:
|
||||
/**
|
||||
* Loads and parses a .mpdignore file.
|
||||
*/
|
||||
bool LoadFile(Path path_fs) noexcept;
|
||||
bool Load(InputStreamPtr is);
|
||||
|
||||
/**
|
||||
* Checks whether one of the patterns in the .mpdignore file matches
|
||||
* the specified file name.
|
||||
*/
|
||||
bool Check(Path name_fs) const noexcept;
|
||||
|
||||
private:
|
||||
void ParseLine(char *line) noexcept;
|
||||
};
|
||||
|
||||
|
||||
|
@@ -36,6 +36,9 @@
|
||||
#include "fs/Traits.hxx"
|
||||
#include "fs/FileSystem.hxx"
|
||||
#include "storage/FileInfo.hxx"
|
||||
#include "input/InputStream.hxx"
|
||||
#include "input/Error.hxx"
|
||||
#include "thread/Cond.hxx"
|
||||
#include "util/Alloc.hxx"
|
||||
#include "util/StringCompare.hxx"
|
||||
#include "util/UriUtil.hxx"
|
||||
@@ -345,11 +348,16 @@ UpdateWalk::UpdateDirectory(Directory &directory,
|
||||
|
||||
ExcludeList child_exclude_list(exclude_list);
|
||||
|
||||
{
|
||||
const auto exclude_path_fs =
|
||||
storage.MapChildFS(directory.GetPath(), ".mpdignore");
|
||||
if (!exclude_path_fs.IsNull())
|
||||
child_exclude_list.LoadFile(exclude_path_fs);
|
||||
try {
|
||||
Mutex mutex;
|
||||
Cond cond;
|
||||
auto is = InputStream::OpenReady(PathTraitsUTF8::Build(storage.MapUTF8(directory.GetPath()).c_str(),
|
||||
".mpdignore").c_str(),
|
||||
mutex, cond);
|
||||
child_exclude_list.Load(std::move(is));
|
||||
} catch (...) {
|
||||
if (!IsFileNotFound(std::current_exception()))
|
||||
LogError(std::current_exception());
|
||||
}
|
||||
|
||||
if (!child_exclude_list.IsEmpty())
|
||||
|
@@ -28,7 +28,7 @@
|
||||
#include "fs/Path.hxx"
|
||||
#include "fs/AllocatedPath.hxx"
|
||||
#include "util/ScopeExit.hxx"
|
||||
#include "util/FormatString.hxx"
|
||||
#include "util/StringFormat.hxx"
|
||||
#include "util/UriUtil.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "Log.hxx"
|
||||
@@ -38,7 +38,6 @@
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define SUBTUNE_PREFIX "tune_"
|
||||
|
||||
@@ -191,20 +190,17 @@ ScanGmeInfo(const gme_info_t &info, unsigned song_num, int track_count,
|
||||
tag_handler_invoke_duration(handler, handler_ctx,
|
||||
SongTime::FromMS(info.play_length));
|
||||
|
||||
if (track_count > 1) {
|
||||
char track[16];
|
||||
sprintf(track, "%u", song_num + 1);
|
||||
tag_handler_invoke_tag(handler, handler_ctx, TAG_TRACK, track);
|
||||
}
|
||||
if (track_count > 1)
|
||||
tag_handler_invoke_tag(handler, handler_ctx, TAG_TRACK,
|
||||
StringFormat<16>("%u", song_num + 1));
|
||||
|
||||
if (info.song != nullptr) {
|
||||
if (track_count > 1) {
|
||||
/* start numbering subtunes from 1 */
|
||||
char tag_title[1024];
|
||||
snprintf(tag_title, sizeof(tag_title),
|
||||
"%s (%u/%d)",
|
||||
info.song, song_num + 1,
|
||||
track_count);
|
||||
const auto tag_title =
|
||||
StringFormat<1024>("%s (%u/%d)",
|
||||
info.song, song_num + 1,
|
||||
track_count);
|
||||
tag_handler_invoke_tag(handler, handler_ctx,
|
||||
TAG_TITLE, tag_title);
|
||||
} else
|
||||
@@ -297,9 +293,9 @@ gme_container_scan(Path path_fs)
|
||||
ScanMusicEmu(emu, i,
|
||||
add_tag_handler, &tag_builder);
|
||||
|
||||
char track_name[64];
|
||||
snprintf(track_name, sizeof(track_name),
|
||||
SUBTUNE_PREFIX "%03u.%s", i+1, subtune_suffix);
|
||||
const auto track_name =
|
||||
StringFormat<64>(SUBTUNE_PREFIX "%03u.%s", i+1,
|
||||
subtune_suffix);
|
||||
tail = list.emplace_after(tail, track_name,
|
||||
tag_builder.Commit());
|
||||
}
|
||||
|
@@ -26,7 +26,7 @@
|
||||
#include "fs/Path.hxx"
|
||||
#include "fs/AllocatedPath.hxx"
|
||||
#include "util/Macros.hxx"
|
||||
#include "util/FormatString.hxx"
|
||||
#include "util/StringFormat.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "system/ByteOrder.hxx"
|
||||
#include "Log.hxx"
|
||||
@@ -413,10 +413,9 @@ ScanSidTuneInfo(const SidTuneInfo &info, unsigned track, unsigned n_tracks,
|
||||
title = "";
|
||||
|
||||
if (n_tracks > 1) {
|
||||
char tag_title[1024];
|
||||
snprintf(tag_title, sizeof(tag_title),
|
||||
"%s (%u/%u)",
|
||||
title, track, n_tracks);
|
||||
const auto tag_title =
|
||||
StringFormat<1024>("%s (%u/%u)",
|
||||
title, track, n_tracks);
|
||||
tag_handler_invoke_tag(handler, handler_ctx,
|
||||
TAG_TITLE, tag_title);
|
||||
} else
|
||||
@@ -435,9 +434,8 @@ ScanSidTuneInfo(const SidTuneInfo &info, unsigned track, unsigned n_tracks,
|
||||
date);
|
||||
|
||||
/* track */
|
||||
char track_buffer[16];
|
||||
sprintf(track_buffer, "%d", track);
|
||||
tag_handler_invoke_tag(handler, handler_ctx, TAG_TRACK, track_buffer);
|
||||
tag_handler_invoke_tag(handler, handler_ctx, TAG_TRACK,
|
||||
StringFormat<16>("%u", track));
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@@ -20,6 +20,7 @@
|
||||
#include "config.h"
|
||||
#include "FileOutputStream.hxx"
|
||||
#include "system/Error.hxx"
|
||||
#include "util/StringFormat.hxx"
|
||||
|
||||
FileOutputStream::FileOutputStream(Path _path, Mode _mode)
|
||||
:path(_path), mode(_mode)
|
||||
@@ -212,10 +213,9 @@ FileOutputStream::Commit()
|
||||
unlink(GetPath().c_str());
|
||||
|
||||
/* hard-link the temporary file to the final path */
|
||||
char fd_path[64];
|
||||
snprintf(fd_path, sizeof(fd_path), "/proc/self/fd/%d",
|
||||
fd.Get());
|
||||
if (linkat(AT_FDCWD, fd_path, AT_FDCWD, path.c_str(),
|
||||
if (linkat(AT_FDCWD,
|
||||
StringFormat<64>("/proc/self/fd/%d", fd.Get()),
|
||||
AT_FDCWD, path.c_str(),
|
||||
AT_SYMLINK_FOLLOW) < 0)
|
||||
throw FormatErrno("Failed to commit %s",
|
||||
path.c_str());
|
||||
|
@@ -19,7 +19,6 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "AsyncInputStream.hxx"
|
||||
#include "Domain.hxx"
|
||||
#include "tag/Tag.hxx"
|
||||
#include "thread/Cond.hxx"
|
||||
#include "IOThread.hxx"
|
||||
|
53
src/input/Error.cxx
Normal file
53
src/input/Error.cxx
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 2003-2018 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 "config.h"
|
||||
#include "Error.hxx"
|
||||
#include "system/Error.hxx"
|
||||
|
||||
#ifdef ENABLE_CURL
|
||||
#include "lib/curl/Error.hxx"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_NFS
|
||||
#include "lib/nfs/Error.hxx"
|
||||
#include <nfsc/libnfs-raw-nfs.h>
|
||||
#endif
|
||||
|
||||
bool
|
||||
IsFileNotFound(std::exception_ptr ep)
|
||||
{
|
||||
try {
|
||||
std::rethrow_exception(ep);
|
||||
} catch (const std::system_error &e) {
|
||||
return IsFileNotFound(e);
|
||||
#ifdef ENABLE_CURL
|
||||
} catch (const HttpStatusError &e) {
|
||||
return e.GetStatus() == 404;
|
||||
#endif
|
||||
#ifdef ENABLE_NFS
|
||||
} catch (const NfsClientError &e) {
|
||||
return e.GetCode() == NFS3ERR_NOENT;
|
||||
#endif
|
||||
} catch (...) {
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -17,11 +17,21 @@
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MPD_INPUT_DOMAIN_HXX
|
||||
#define MPD_INPUT_DOMAIN_HXX
|
||||
#ifndef INPUT_ERROR_HXX
|
||||
#define INPUT_ERROR_HXX
|
||||
|
||||
class Domain;
|
||||
#include "check.h"
|
||||
#include "Compiler.h"
|
||||
|
||||
extern const Domain input_domain;
|
||||
#include <exception>
|
||||
|
||||
/**
|
||||
* Was this exception thrown because the requested file does not
|
||||
* exist? This function attempts to recognize exceptions thrown by
|
||||
* various input plugins.
|
||||
*/
|
||||
gcc_pure
|
||||
bool
|
||||
IsFileNotFound(std::exception_ptr e);
|
||||
|
||||
#endif
|
@@ -20,7 +20,7 @@
|
||||
#include "config.h"
|
||||
#include "InputStream.hxx"
|
||||
#include "thread/Cond.hxx"
|
||||
#include "util/StringCompare.hxx"
|
||||
#include "util/ASCII.hxx"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
@@ -77,8 +77,8 @@ gcc_pure
|
||||
static bool
|
||||
ExpensiveSeeking(const char *uri) noexcept
|
||||
{
|
||||
return StringStartsWith(uri, "http://") ||
|
||||
StringStartsWith(uri, "https://");
|
||||
return StringStartsWithCaseASCII(uri, "http://") ||
|
||||
StringStartsWithCaseASCII(uri, "https://");
|
||||
}
|
||||
|
||||
bool
|
||||
|
@@ -29,4 +29,10 @@
|
||||
*/
|
||||
typedef uint64_t offset_type;
|
||||
|
||||
/**
|
||||
* To format an offset_type with printf(). To use this, include
|
||||
* <cinttypes>.
|
||||
*/
|
||||
#define PRIoffset PRIu64
|
||||
|
||||
#endif
|
||||
|
@@ -22,7 +22,6 @@
|
||||
#include "Registry.hxx"
|
||||
#include "InputPlugin.hxx"
|
||||
#include "LocalOpen.hxx"
|
||||
#include "Domain.hxx"
|
||||
#include "plugins/RewindInputPlugin.hxx"
|
||||
#include "fs/Traits.hxx"
|
||||
#include "fs/AllocatedPath.hxx"
|
||||
|
@@ -33,7 +33,7 @@
|
||||
#include "util/RuntimeError.hxx"
|
||||
#include "util/StringCompare.hxx"
|
||||
#include "util/ReusableArray.hxx"
|
||||
|
||||
#include "util/ASCII.hxx"
|
||||
#include "Log.hxx"
|
||||
#include "event/MultiSocketMonitor.hxx"
|
||||
#include "event/DeferredMonitor.hxx"
|
||||
@@ -147,7 +147,7 @@ private:
|
||||
inline InputStream *
|
||||
AlsaInputStream::Create(const char *uri, Mutex &mutex, Cond &cond)
|
||||
{
|
||||
const char *device = StringAfterPrefix(uri, "alsa://");
|
||||
const char *device = StringAfterPrefixCaseASCII(uri, "alsa://");
|
||||
if (device == nullptr)
|
||||
return nullptr;
|
||||
|
||||
|
@@ -26,7 +26,7 @@
|
||||
#include "../InputStream.hxx"
|
||||
#include "../InputPlugin.hxx"
|
||||
#include "util/StringUtil.hxx"
|
||||
#include "util/StringCompare.hxx"
|
||||
#include "util/ASCII.hxx"
|
||||
#include "util/RuntimeError.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "system/ByteOrder.hxx"
|
||||
@@ -128,7 +128,7 @@ struct cdio_uri {
|
||||
static bool
|
||||
parse_cdio_uri(struct cdio_uri *dest, const char *src)
|
||||
{
|
||||
if (!StringStartsWith(src, "cdda://"))
|
||||
if (!StringStartsWithCaseASCII(src, "cdda://"))
|
||||
return false;
|
||||
|
||||
src += 7;
|
||||
|
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "CurlInputPlugin.hxx"
|
||||
#include "lib/curl/Error.hxx"
|
||||
#include "lib/curl/Easy.hxx"
|
||||
#include "lib/curl/Global.hxx"
|
||||
#include "lib/curl/Request.hxx"
|
||||
@@ -34,12 +35,15 @@
|
||||
#include "IOThread.hxx"
|
||||
#include "util/ASCII.hxx"
|
||||
#include "util/StringUtil.hxx"
|
||||
#include "util/StringFormat.hxx"
|
||||
#include "util/NumberParser.hxx"
|
||||
#include "util/RuntimeError.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "Log.hxx"
|
||||
#include "PluginUnavailable.hxx"
|
||||
|
||||
#include <cinttypes>
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -185,7 +189,9 @@ CurlInputStream::OnHeaders(unsigned status,
|
||||
assert(!postponed_exception);
|
||||
|
||||
if (status < 200 || status >= 300)
|
||||
throw FormatRuntimeError("got HTTP status %ld", status);
|
||||
throw HttpStatusError(status,
|
||||
StringFormat<40>("got HTTP status %u",
|
||||
status).c_str());
|
||||
|
||||
const std::lock_guard<Mutex> protect(mutex);
|
||||
|
||||
@@ -371,13 +377,10 @@ CurlInputStream::InitEasy()
|
||||
if (proxy_port > 0)
|
||||
request->SetOption(CURLOPT_PROXYPORT, (long)proxy_port);
|
||||
|
||||
if (proxy_user != nullptr && proxy_password != nullptr) {
|
||||
char proxy_auth_str[1024];
|
||||
snprintf(proxy_auth_str, sizeof(proxy_auth_str),
|
||||
"%s:%s",
|
||||
proxy_user, proxy_password);
|
||||
request->SetOption(CURLOPT_PROXYUSERPWD, proxy_auth_str);
|
||||
}
|
||||
if (proxy_user != nullptr && proxy_password != nullptr)
|
||||
request->SetOption(CURLOPT_PROXYUSERPWD,
|
||||
StringFormat<1024>("%s:%s", proxy_user,
|
||||
proxy_password).c_str());
|
||||
|
||||
request->SetOption(CURLOPT_SSL_VERIFYPEER, verify_peer ? 1l : 0l);
|
||||
request->SetOption(CURLOPT_SSL_VERIFYHOST, verify_host ? 2l : 0l);
|
||||
@@ -414,16 +417,10 @@ CurlInputStream::SeekInternal(offset_type new_offset)
|
||||
|
||||
/* send the "Range" header */
|
||||
|
||||
if (offset > 0) {
|
||||
char range[32];
|
||||
#ifdef _WIN32
|
||||
// TODO: what can we use on Windows to format 64 bit?
|
||||
sprintf(range, "%lu-", (long)offset);
|
||||
#else
|
||||
sprintf(range, "%llu-", (unsigned long long)offset);
|
||||
#endif
|
||||
request->SetOption(CURLOPT_RANGE, range);
|
||||
}
|
||||
if (offset > 0)
|
||||
request->SetOption(CURLOPT_RANGE,
|
||||
StringFormat<40>("%" PRIoffset "-",
|
||||
offset).c_str());
|
||||
|
||||
StartRequest();
|
||||
}
|
||||
@@ -461,8 +458,8 @@ CurlInputStream::Open(const char *url, Mutex &mutex, Cond &cond)
|
||||
static InputStream *
|
||||
input_curl_open(const char *url, Mutex &mutex, Cond &cond)
|
||||
{
|
||||
if (strncmp(url, "http://", 7) != 0 &&
|
||||
strncmp(url, "https://", 8) != 0)
|
||||
if (!StringStartsWithCaseASCII(url, "http://") &&
|
||||
!StringStartsWithCaseASCII(url, "https://"))
|
||||
return nullptr;
|
||||
|
||||
return CurlInputStream::Open(url, mutex, cond);
|
||||
|
@@ -28,7 +28,7 @@
|
||||
#include "../InputStream.hxx"
|
||||
#include "../InputPlugin.hxx"
|
||||
#include "PluginUnavailable.hxx"
|
||||
#include "util/StringCompare.hxx"
|
||||
#include "util/ASCII.hxx"
|
||||
|
||||
extern "C" {
|
||||
#include <libavformat/avio.h>
|
||||
@@ -85,12 +85,12 @@ static InputStream *
|
||||
input_ffmpeg_open(const char *uri,
|
||||
Mutex &mutex, Cond &cond)
|
||||
{
|
||||
if (!StringStartsWith(uri, "gopher://") &&
|
||||
!StringStartsWith(uri, "rtp://") &&
|
||||
!StringStartsWith(uri, "rtsp://") &&
|
||||
!StringStartsWith(uri, "rtmp://") &&
|
||||
!StringStartsWith(uri, "rtmpt://") &&
|
||||
!StringStartsWith(uri, "rtmps://"))
|
||||
if (!StringStartsWithCaseASCII(uri, "gopher://") &&
|
||||
!StringStartsWithCaseASCII(uri, "rtp://") &&
|
||||
!StringStartsWithCaseASCII(uri, "rtsp://") &&
|
||||
!StringStartsWithCaseASCII(uri, "rtmp://") &&
|
||||
!StringStartsWithCaseASCII(uri, "rtmpt://") &&
|
||||
!StringStartsWithCaseASCII(uri, "rtmps://"))
|
||||
return nullptr;
|
||||
|
||||
AVIOContext *h;
|
||||
|
@@ -65,12 +65,9 @@ OpenFileInputStream(Path path,
|
||||
throw FormatRuntimeError("Not a regular file: %s",
|
||||
path.c_str());
|
||||
|
||||
#if !defined(__BIONIC__) || __ANDROID_API__ >= 21
|
||||
/* posix_fadvise() requires Android API 21 */
|
||||
#ifdef POSIX_FADV_SEQUENTIAL
|
||||
posix_fadvise(reader.GetFD().Get(), (off_t)0, info.GetSize(),
|
||||
POSIX_FADV_SEQUENTIAL);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return InputStreamPtr(new FileInputStream(path.ToUTF8().c_str(),
|
||||
|
@@ -22,7 +22,7 @@
|
||||
#include "input/ThreadInputStream.hxx"
|
||||
#include "input/InputPlugin.hxx"
|
||||
#include "system/Error.hxx"
|
||||
#include "util/StringCompare.hxx"
|
||||
#include "util/ASCII.hxx"
|
||||
|
||||
#include <libmms/mmsx.h>
|
||||
|
||||
@@ -74,10 +74,10 @@ static InputStream *
|
||||
input_mms_open(const char *url,
|
||||
Mutex &mutex, Cond &cond)
|
||||
{
|
||||
if (!StringStartsWith(url, "mms://") &&
|
||||
!StringStartsWith(url, "mmsh://") &&
|
||||
!StringStartsWith(url, "mmst://") &&
|
||||
!StringStartsWith(url, "mmsu://"))
|
||||
if (!StringStartsWithCaseASCII(url, "mms://") &&
|
||||
!StringStartsWithCaseASCII(url, "mmsh://") &&
|
||||
!StringStartsWithCaseASCII(url, "mmst://") &&
|
||||
!StringStartsWithCaseASCII(url, "mmsu://"))
|
||||
return nullptr;
|
||||
|
||||
auto m = new MmsInputStream(url, mutex, cond);
|
||||
|
@@ -23,9 +23,7 @@
|
||||
#include "../InputPlugin.hxx"
|
||||
#include "lib/nfs/Glue.hxx"
|
||||
#include "lib/nfs/FileReader.hxx"
|
||||
#include "util/StringCompare.hxx"
|
||||
|
||||
#include <string.h>
|
||||
#include "util/ASCII.hxx"
|
||||
|
||||
/**
|
||||
* Do not buffer more than this number of bytes. It should be a
|
||||
@@ -219,7 +217,7 @@ static InputStream *
|
||||
input_nfs_open(const char *uri,
|
||||
Mutex &mutex, Cond &cond)
|
||||
{
|
||||
if (!StringStartsWith(uri, "nfs://"))
|
||||
if (!StringStartsWithCaseASCII(uri, "nfs://"))
|
||||
return nullptr;
|
||||
|
||||
NfsInputStream *is = new NfsInputStream(uri, mutex, cond);
|
||||
|
@@ -25,7 +25,7 @@
|
||||
#include "../InputPlugin.hxx"
|
||||
#include "PluginUnavailable.hxx"
|
||||
#include "system/Error.hxx"
|
||||
#include "util/StringCompare.hxx"
|
||||
#include "util/ASCII.hxx"
|
||||
|
||||
#include <libsmbclient.h>
|
||||
|
||||
@@ -87,7 +87,7 @@ static InputStream *
|
||||
input_smbclient_open(const char *uri,
|
||||
Mutex &mutex, Cond &cond)
|
||||
{
|
||||
if (!StringStartsWith(uri, "smb://"))
|
||||
if (!StringStartsWithCaseASCII(uri, "smb://"))
|
||||
return nullptr;
|
||||
|
||||
const std::lock_guard<Mutex> protect(smbclient_mutex);
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* Copyright 2003-2018 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -17,8 +17,26 @@
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "Domain.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#ifndef CURL_ERROR_HXX
|
||||
#define CURL_ERROR_HXX
|
||||
|
||||
const Domain input_domain("input");
|
||||
#include <stdexcept>
|
||||
|
||||
/**
|
||||
* Thrown when an unsuccessful status was received from the HTTP
|
||||
* server.
|
||||
*/
|
||||
class HttpStatusError : public std::runtime_error {
|
||||
unsigned status;
|
||||
|
||||
public:
|
||||
template<typename M>
|
||||
explicit HttpStatusError(unsigned _status, M &&_msg) noexcept
|
||||
:std::runtime_error(std::forward<M>(_msg)), status(_status) {}
|
||||
|
||||
unsigned GetStatus() const noexcept {
|
||||
return status;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
@@ -25,6 +25,7 @@
|
||||
#include "Domain.hxx"
|
||||
#include "LogV.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "util/StringFormat.hxx"
|
||||
|
||||
extern "C" {
|
||||
#include <libavutil/log.h>
|
||||
@@ -57,9 +58,10 @@ FfmpegLogCallback(gcc_unused void *ptr, int level, const char *fmt, va_list vl)
|
||||
cls = *(const AVClass *const*)ptr;
|
||||
|
||||
if (cls != nullptr) {
|
||||
char domain[64];
|
||||
snprintf(domain, sizeof(domain), "%s/%s",
|
||||
ffmpeg_domain.GetName(), cls->item_name(ptr));
|
||||
const auto domain =
|
||||
StringFormat<64>("%s/%s",
|
||||
ffmpeg_domain.GetName(),
|
||||
cls->item_name(ptr));
|
||||
const Domain d(domain);
|
||||
LogFormatV(d, FfmpegImportLogLevel(level), fmt, vl);
|
||||
}
|
||||
|
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "Connection.hxx"
|
||||
#include "Error.hxx"
|
||||
#include "Lease.hxx"
|
||||
#include "Callback.hxx"
|
||||
#include "event/Loop.hxx"
|
||||
@@ -139,7 +140,7 @@ NfsConnection::CancellableCallback::Callback(int err, void *data)
|
||||
if (err >= 0)
|
||||
cb.OnNfsCallback((unsigned)err, data);
|
||||
else
|
||||
cb.OnNfsError(std::make_exception_ptr(std::runtime_error((const char *)data)));
|
||||
cb.OnNfsError(std::make_exception_ptr(NfsClientError(-err, (const char *)data)));
|
||||
} else {
|
||||
if (open) {
|
||||
/* a nfs_open_async() call was cancelled - to
|
||||
|
76
src/lib/nfs/Error.cxx
Normal file
76
src/lib/nfs/Error.cxx
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2007-2017 Content Management AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* author: Max Kellermann <mk@cm4all.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "Error.hxx"
|
||||
#include "util/StringFormat.hxx"
|
||||
|
||||
extern "C" {
|
||||
#include <nfsc/libnfs.h>
|
||||
}
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
static StringBuffer<256>
|
||||
FormatNfsClientError(struct nfs_context *nfs, const char *msg) noexcept
|
||||
{
|
||||
assert(msg != nullptr);
|
||||
|
||||
const char *msg2 = nfs_get_error(nfs);
|
||||
return StringFormat<256>("%s: %s", msg, msg2);
|
||||
}
|
||||
|
||||
NfsClientError::NfsClientError(struct nfs_context *nfs, const char *msg) noexcept
|
||||
:std::runtime_error(FormatNfsClientError(nfs, msg).c_str()),
|
||||
code(0) {}
|
||||
|
||||
static StringBuffer<256>
|
||||
FormatNfsClientError(int err, struct nfs_context *nfs, void *data,
|
||||
const char *msg) noexcept
|
||||
{
|
||||
assert(msg != nullptr);
|
||||
assert(err < 0);
|
||||
|
||||
const char *msg2 = (const char *)data;
|
||||
if (data == nullptr || *(const char *)data == 0) {
|
||||
msg2 = nfs_get_error(nfs);
|
||||
if (msg2 == nullptr)
|
||||
msg2 = strerror(-err);
|
||||
}
|
||||
|
||||
return StringFormat<256>("%s: %s", msg, msg2);
|
||||
}
|
||||
|
||||
NfsClientError::NfsClientError(int err, struct nfs_context *nfs, void *data,
|
||||
const char *msg) noexcept
|
||||
:std::runtime_error(FormatNfsClientError(err, nfs, data, msg).c_str()),
|
||||
code(-err) {}
|
58
src/lib/nfs/Error.hxx
Normal file
58
src/lib/nfs/Error.hxx
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2007-2017 Content Management AG
|
||||
* All rights reserved.
|
||||
*
|
||||
* author: Max Kellermann <mk@cm4all.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef NFS_ERROR_HXX
|
||||
#define NFS_ERROR_HXX
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
class NfsClientError : public std::runtime_error {
|
||||
int code;
|
||||
|
||||
public:
|
||||
explicit NfsClientError(const char *_msg) noexcept
|
||||
:std::runtime_error(_msg), code(0) {}
|
||||
|
||||
NfsClientError(int _code, const char *_msg) noexcept
|
||||
:std::runtime_error(_msg), code(_code) {}
|
||||
|
||||
NfsClientError(struct nfs_context *nfs, const char *msg) noexcept;
|
||||
|
||||
NfsClientError(int err, struct nfs_context *nfs, void *data,
|
||||
const char *msg) noexcept;
|
||||
|
||||
int GetCode() const noexcept {
|
||||
return code;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
@@ -24,7 +24,7 @@
|
||||
#include "Connection.hxx"
|
||||
#include "event/Call.hxx"
|
||||
#include "IOThread.hxx"
|
||||
#include "util/StringCompare.hxx"
|
||||
#include "util/ASCII.hxx"
|
||||
|
||||
#include <utility>
|
||||
|
||||
@@ -93,7 +93,7 @@ NfsFileReader::Open(const char *uri)
|
||||
{
|
||||
assert(state == State::INITIAL);
|
||||
|
||||
if (!StringStartsWith(uri, "nfs://"))
|
||||
if (!StringStartsWithCaseASCII(uri, "nfs://"))
|
||||
throw std::runtime_error("Malformed nfs:// URI");
|
||||
|
||||
uri += 6;
|
||||
|
@@ -20,7 +20,7 @@
|
||||
#include "config.h"
|
||||
#include "ls.hxx"
|
||||
#include "client/Response.hxx"
|
||||
#include "util/StringCompare.hxx"
|
||||
#include "util/ASCII.hxx"
|
||||
#include "util/UriUtil.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
@@ -97,7 +97,7 @@ uri_supported_scheme(const char *uri) noexcept
|
||||
assert(uri_has_scheme(uri));
|
||||
|
||||
while (*urlPrefixes) {
|
||||
if (StringStartsWith(uri, *urlPrefixes))
|
||||
if (StringStartsWithCaseASCII(uri, *urlPrefixes))
|
||||
return true;
|
||||
urlPrefixes++;
|
||||
}
|
||||
|
@@ -37,6 +37,7 @@
|
||||
#include "config/ConfigGlobal.hxx"
|
||||
#include "config/Block.hxx"
|
||||
#include "util/RuntimeError.hxx"
|
||||
#include "util/StringFormat.hxx"
|
||||
#include "Log.hxx"
|
||||
|
||||
#include <stdexcept>
|
||||
|
@@ -36,6 +36,8 @@
|
||||
#include <roaraudio.h>
|
||||
#undef new
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
class RoarOutput {
|
||||
friend struct AudioOutputWrapper<RoarOutput>;
|
||||
|
||||
|
@@ -122,15 +122,6 @@ HttpdClient::HandleLine(const char *line)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (StringEqualsCaseASCII(line, "transferMode.dlna.org: Streaming", 32)) {
|
||||
/* Send as dlna */
|
||||
dlna_streaming_requested = true;
|
||||
/* metadata is not supported by dlna streaming, so disable it */
|
||||
metadata_supported = false;
|
||||
metadata_requested = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* expect more request headers */
|
||||
return true;
|
||||
}
|
||||
@@ -148,22 +139,7 @@ HttpdClient::SendResponse()
|
||||
|
||||
assert(state == RESPONSE);
|
||||
|
||||
if (dlna_streaming_requested) {
|
||||
snprintf(buffer, sizeof(buffer),
|
||||
"HTTP/1.1 206 OK\r\n"
|
||||
"Content-Type: %s\r\n"
|
||||
"Content-Length: 10000\r\n"
|
||||
"Content-RangeX: 0-1000000/1000000\r\n"
|
||||
"transferMode.dlna.org: Streaming\r\n"
|
||||
"Accept-Ranges: bytes\r\n"
|
||||
"Connection: close\r\n"
|
||||
"realTimeInfo.dlna.org: DLNA.ORG_TLAG=*\r\n"
|
||||
"contentFeatures.dlna.org: DLNA.ORG_OP=01;DLNA.ORG_CI=0\r\n"
|
||||
"\r\n",
|
||||
httpd.content_type);
|
||||
response = buffer;
|
||||
|
||||
} else if (metadata_requested) {
|
||||
if (metadata_requested) {
|
||||
allocated =
|
||||
icy_server_metadata_header(httpd.name, httpd.genre,
|
||||
httpd.website,
|
||||
@@ -202,7 +178,6 @@ HttpdClient::HttpdClient(HttpdOutput &_httpd, int _fd, EventLoop &_loop,
|
||||
state(REQUEST),
|
||||
queue_size(0),
|
||||
head_method(false),
|
||||
dlna_streaming_requested(false),
|
||||
metadata_supported(_metadata_supported),
|
||||
metadata_requested(false), metadata_sent(true),
|
||||
metaint(8192), /*TODO: just a std value */
|
||||
|
@@ -82,11 +82,6 @@ class HttpdClient final
|
||||
*/
|
||||
bool head_method;
|
||||
|
||||
/**
|
||||
* If DLNA streaming was an option.
|
||||
*/
|
||||
bool dlna_streaming_requested;
|
||||
|
||||
/* ICY */
|
||||
|
||||
/**
|
||||
|
@@ -35,6 +35,7 @@
|
||||
#include "SoxrResampler.hxx"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
enum class SelectedResampler {
|
||||
|
@@ -32,6 +32,8 @@
|
||||
#include "PcmDop.hxx"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
void
|
||||
PcmExport::Open(SampleFormat sample_format, unsigned _channels,
|
||||
Params params)
|
||||
|
@@ -202,6 +202,7 @@ CueParser::Feed2(char *p) noexcept
|
||||
return;
|
||||
|
||||
if (strcmp(type, "WAVE") != 0 &&
|
||||
strcmp(type, "FLAC") != 0 && /* non-standard */
|
||||
strcmp(type, "MP3") != 0 &&
|
||||
strcmp(type, "AIFF") != 0) {
|
||||
state = IGNORE_FILE;
|
||||
|
@@ -24,6 +24,7 @@
|
||||
#include "config/Block.hxx"
|
||||
#include "input/InputStream.hxx"
|
||||
#include "tag/TagBuilder.hxx"
|
||||
#include "util/ASCII.hxx"
|
||||
#include "util/StringCompare.hxx"
|
||||
#include "util/Alloc.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
@@ -68,7 +69,7 @@ soundcloud_resolve(const char* uri)
|
||||
{
|
||||
char *u, *ru;
|
||||
|
||||
if (StringStartsWith(uri, "https://")) {
|
||||
if (StringStartsWithCaseASCII(uri, "https://")) {
|
||||
u = xstrdup(uri);
|
||||
} else if (StringStartsWith(uri, "soundcloud.com")) {
|
||||
u = xstrcatdup("https://", uri);
|
||||
@@ -273,7 +274,7 @@ try {
|
||||
static SongEnumerator *
|
||||
soundcloud_open_uri(const char *uri, Mutex &mutex, Cond &cond)
|
||||
{
|
||||
assert(strncmp(uri, "soundcloud://", 13) == 0);
|
||||
assert(StringEqualsCaseASCII(uri, "soundcloud://", 13));
|
||||
uri += 13;
|
||||
|
||||
char *u = nullptr;
|
||||
|
@@ -20,9 +20,9 @@
|
||||
#ifndef MPD_ACK_H
|
||||
#define MPD_ACK_H
|
||||
|
||||
#include <stdexcept>
|
||||
#include "util/StringFormat.hxx"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdexcept>
|
||||
|
||||
class Domain;
|
||||
|
||||
@@ -60,9 +60,9 @@ template<typename... Args>
|
||||
static inline ProtocolError
|
||||
FormatProtocolError(enum ack code, const char *fmt, Args&&... args) noexcept
|
||||
{
|
||||
char buffer[256];
|
||||
snprintf(buffer, sizeof(buffer), fmt, std::forward<Args>(args)...);
|
||||
return ProtocolError(code, buffer);
|
||||
return ProtocolError(code,
|
||||
StringFormat<256>(fmt,
|
||||
std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -33,8 +33,10 @@
|
||||
#include "event/DeferredMonitor.hxx"
|
||||
#include "thread/Mutex.hxx"
|
||||
#include "thread/Cond.hxx"
|
||||
#include "util/ASCII.hxx"
|
||||
#include "util/RuntimeError.hxx"
|
||||
#include "util/StringCompare.hxx"
|
||||
#include "util/StringFormat.hxx"
|
||||
#include "util/TimeParser.hxx"
|
||||
#include "util/UriUtil.hxx"
|
||||
|
||||
@@ -296,9 +298,7 @@ public:
|
||||
{
|
||||
request.SetOption(CURLOPT_CUSTOMREQUEST, "PROPFIND");
|
||||
|
||||
char buffer[40];
|
||||
sprintf(buffer, "depth: %u", depth);
|
||||
request_headers.Append(buffer);
|
||||
request_headers.Append(StringFormat<40>("depth: %u", depth));
|
||||
|
||||
request.SetOption(CURLOPT_HTTPHEADER, request_headers.Get());
|
||||
|
||||
@@ -591,8 +591,8 @@ CurlStorage::OpenDirectory(const char *uri_utf8)
|
||||
static Storage *
|
||||
CreateCurlStorageURI(EventLoop &event_loop, const char *uri)
|
||||
{
|
||||
if (strncmp(uri, "http://", 7) != 0 &&
|
||||
strncmp(uri, "https://", 8) != 0)
|
||||
if (!StringStartsWithCaseASCII(uri, "http://") &&
|
||||
!StringStartsWithCaseASCII(uri, "https://"))
|
||||
return nullptr;
|
||||
|
||||
return new CurlStorage(event_loop, uri);
|
||||
|
@@ -35,6 +35,7 @@
|
||||
#include "event/Call.hxx"
|
||||
#include "event/DeferredMonitor.hxx"
|
||||
#include "event/TimeoutMonitor.hxx"
|
||||
#include "util/ASCII.hxx"
|
||||
#include "util/StringCompare.hxx"
|
||||
|
||||
extern "C" {
|
||||
@@ -401,11 +402,10 @@ NfsStorage::OpenDirectory(const char *uri_utf8)
|
||||
static Storage *
|
||||
CreateNfsStorageURI(EventLoop &event_loop, const char *base)
|
||||
{
|
||||
if (strncmp(base, "nfs://", 6) != 0)
|
||||
const char *p = StringAfterPrefixCaseASCII(base, "nfs://");
|
||||
if (p == nullptr)
|
||||
return nullptr;
|
||||
|
||||
const char *p = base + 6;
|
||||
|
||||
const char *mount = strchr(p, '/');
|
||||
if (mount == nullptr)
|
||||
throw std::runtime_error("Malformed nfs:// URI");
|
||||
|
@@ -27,6 +27,7 @@
|
||||
#include "fs/Traits.hxx"
|
||||
#include "thread/Mutex.hxx"
|
||||
#include "system/Error.hxx"
|
||||
#include "util/ASCII.hxx"
|
||||
#include "util/StringCompare.hxx"
|
||||
#include "util/ScopeExit.hxx"
|
||||
|
||||
@@ -182,7 +183,7 @@ SmbclientDirectoryReader::GetInfo(gcc_unused bool follow)
|
||||
static Storage *
|
||||
CreateSmbclientStorageURI(gcc_unused EventLoop &event_loop, const char *base)
|
||||
{
|
||||
if (strncmp(base, "smb://", 6) != 0)
|
||||
if (!StringStartsWithCaseASCII(base, "smb://"))
|
||||
return nullptr;
|
||||
|
||||
SmbclientInit();
|
||||
|
@@ -22,21 +22,6 @@
|
||||
#include "EPollFD.hxx"
|
||||
#include "FatalError.hxx"
|
||||
|
||||
#if defined(__BIONIC__) && __ANDROID_API__ < 21
|
||||
|
||||
#include <sys/syscall.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define EPOLL_CLOEXEC O_CLOEXEC
|
||||
|
||||
static inline int
|
||||
epoll_create1(int flags)
|
||||
{
|
||||
return syscall(__NR_epoll_create1, flags);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
EPollFD::EPollFD()
|
||||
:fd(::epoll_create1(EPOLL_CLOEXEC))
|
||||
{
|
||||
|
@@ -21,8 +21,8 @@
|
||||
#include "TagHandler.hxx"
|
||||
#include "TagBuilder.hxx"
|
||||
#include "util/ASCII.hxx"
|
||||
#include "util/StringFormat.hxx"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static void
|
||||
@@ -42,11 +42,8 @@ add_tag_tag(TagType type, const char *value, void *ctx)
|
||||
/* filter out this extra data and leading zeroes */
|
||||
char *end;
|
||||
unsigned n = strtoul(value, &end, 10);
|
||||
if (value != end) {
|
||||
char s[21];
|
||||
if (snprintf(s, 21, "%u", n) > 0)
|
||||
tag.AddItem(type, s);
|
||||
}
|
||||
if (value != end)
|
||||
tag.AddItem(type, StringFormat<21>("%u", n));
|
||||
} else
|
||||
tag.AddItem(type, value);
|
||||
}
|
||||
|
@@ -31,7 +31,7 @@
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_THREAD_NAME
|
||||
# include <stdio.h>
|
||||
#include "util/StringFormat.hxx"
|
||||
#endif
|
||||
|
||||
static inline void
|
||||
@@ -59,9 +59,7 @@ static inline void
|
||||
FormatThreadName(const char *fmt, gcc_unused Args&&... args)
|
||||
{
|
||||
#ifdef HAVE_THREAD_NAME
|
||||
char buffer[16];
|
||||
snprintf(buffer, sizeof(buffer), fmt, args...);
|
||||
SetThreadName(buffer);
|
||||
SetThreadName(StringFormat<16>(fmt, args...));
|
||||
#else
|
||||
(void)fmt;
|
||||
#endif
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Max Kellermann <max.kellermann@gmail.com>
|
||||
* Copyright (C) 2013-2018 Max Kellermann <max.kellermann@gmail.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -30,6 +30,7 @@
|
||||
#ifndef ASCII_HXX
|
||||
#define ASCII_HXX
|
||||
|
||||
#include "StringView.hxx"
|
||||
#include "Compiler.h"
|
||||
|
||||
#include <assert.h>
|
||||
@@ -69,4 +70,20 @@ StringEqualsCaseASCII(const char *a, const char *b, size_t n) noexcept
|
||||
return strncasecmp(a, b, n) == 0;
|
||||
}
|
||||
|
||||
gcc_pure gcc_nonnull_all
|
||||
static inline bool
|
||||
StringStartsWithCaseASCII(const char *haystack, StringView needle) noexcept
|
||||
{
|
||||
return StringEqualsCaseASCII(haystack, needle.data, needle.size);
|
||||
}
|
||||
|
||||
gcc_pure gcc_nonnull_all
|
||||
static inline const char *
|
||||
StringAfterPrefixCaseASCII(const char *haystack, StringView needle) noexcept
|
||||
{
|
||||
return StringStartsWithCaseASCII(haystack, needle)
|
||||
? haystack + needle.size
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -23,14 +23,9 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
AllocatedString<>
|
||||
FormatStringV(const char *fmt, va_list args)
|
||||
{
|
||||
#ifndef _WIN32
|
||||
va_list tmp;
|
||||
va_copy(tmp, args);
|
||||
const int length = vsnprintf(NULL, 0, fmt, tmp);
|
||||
@@ -43,22 +38,6 @@ FormatStringV(const char *fmt, va_list args)
|
||||
char *buffer = new char[length + 1];
|
||||
vsnprintf(buffer, length + 1, fmt, args);
|
||||
return AllocatedString<>::Donate(buffer);
|
||||
#else
|
||||
/* On mingw32, snprintf() expects a 64 bit integer instead of
|
||||
a "long int" for "%li". This is not consistent with our
|
||||
expectation, so we're using plain sprintf() here, hoping
|
||||
the static buffer is large enough. Sorry for this hack,
|
||||
but WIN32 development is so painful, I'm not in the mood to
|
||||
do it properly now. */
|
||||
|
||||
char buffer[16384];
|
||||
vsprintf(buffer, fmt, args);
|
||||
|
||||
const size_t length = strlen(buffer);
|
||||
char *p = new char[length + 1];
|
||||
memcpy(p, buffer, length + 1);
|
||||
return AllocatedString<>::Donate(p);
|
||||
#endif
|
||||
}
|
||||
|
||||
AllocatedString<>
|
||||
|
69
src/util/StringFormat.hxx
Normal file
69
src/util/StringFormat.hxx
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2015 Max Kellermann <max.kellermann@gmail.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef STRING_FORMAT_HXX
|
||||
#define STRING_FORMAT_HXX
|
||||
|
||||
#include "StringBuffer.hxx"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
template<typename... Args>
|
||||
static inline void
|
||||
StringFormat(char *buffer, size_t size,
|
||||
const char *fmt, Args&&... args) noexcept
|
||||
{
|
||||
snprintf(buffer, size, fmt, args...);
|
||||
}
|
||||
|
||||
template<size_t CAPACITY, typename... Args>
|
||||
static inline void
|
||||
StringFormat(StringBuffer<CAPACITY> &buffer,
|
||||
const char *fmt, Args&&... args) noexcept
|
||||
{
|
||||
StringFormat(buffer.data(), buffer.capacity(), fmt, args...);
|
||||
}
|
||||
|
||||
template<size_t CAPACITY, typename... Args>
|
||||
static inline StringBuffer<CAPACITY>
|
||||
StringFormat(const char *fmt, Args&&... args) noexcept
|
||||
{
|
||||
StringBuffer<CAPACITY> result;
|
||||
StringFormat(result, fmt, args...);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
static inline void
|
||||
StringFormatUnsafe(char *buffer, const char *fmt, Args&&... args) noexcept
|
||||
{
|
||||
sprintf(buffer, fmt, args...);
|
||||
}
|
||||
|
||||
#endif
|
@@ -18,7 +18,7 @@
|
||||
*/
|
||||
|
||||
#include "UriUtil.hxx"
|
||||
#include "StringCompare.hxx"
|
||||
#include "ASCII.hxx"
|
||||
#include "CharUtil.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
@@ -169,7 +169,7 @@ SkipUriScheme(const char *uri) noexcept
|
||||
{
|
||||
const char *const schemes[] = { "http://", "https://", "ftp://" };
|
||||
for (auto scheme : schemes) {
|
||||
auto result = StringAfterPrefix(uri, scheme);
|
||||
auto result = StringAfterPrefixCaseASCII(uri, scheme);
|
||||
if (result != nullptr)
|
||||
return result;
|
||||
}
|
||||
|
@@ -65,6 +65,7 @@ class CrossGccToolchain:
|
||||
|
||||
self.is_arm = arch.startswith('arm')
|
||||
self.is_armv7 = self.is_arm and 'armv7' in self.cflags
|
||||
self.is_aarch64 = arch == 'aarch64'
|
||||
self.is_windows = 'mingw32' in arch
|
||||
|
||||
self.env = dict(os.environ)
|
||||
@@ -86,6 +87,7 @@ thirdparty_libs = [
|
||||
liblame,
|
||||
ffmpeg,
|
||||
curl,
|
||||
libexpat,
|
||||
libnfs,
|
||||
boost,
|
||||
]
|
||||
|
Reference in New Issue
Block a user