summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Kellermann <max@musicpd.org>2018-01-11 19:25:46 +0100
committerMax Kellermann <max@musicpd.org>2018-01-11 19:25:46 +0100
commit8e29430f215f9c71f113604b2e640b0145929f78 (patch)
tree91046373ce0a23e08bca880afc4b9c4e0ffc8ef8
parent326488aeebe59299138da04854b91d4cad8d40e4 (diff)
lib/yajl/Handle: libyajl C++ bindings
-rw-r--r--Makefile.am4
-rw-r--r--src/lib/yajl/Handle.hxx93
-rw-r--r--src/playlist/plugins/SoundCloudPlaylistPlugin.cxx25
3 files changed, 104 insertions, 18 deletions
diff --git a/Makefile.am b/Makefile.am
index 95424c534..9c3d85dc2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -242,6 +242,9 @@ CURL_SOURCES = \
src/lib/curl/Multi.hxx \
src/lib/curl/Slist.hxx
+YAJL_SOURCES = \
+ src/lib/yajl/Handle.hxx
+
UPNP_SOURCES = \
src/lib/upnp/Compat.hxx \
src/lib/upnp/Init.cxx src/lib/upnp/Init.hxx \
@@ -1647,6 +1650,7 @@ endif
if ENABLE_SOUNDCLOUD
libplaylist_plugins_a_SOURCES += \
+ $(YAJL_SOURCES) \
src/playlist/plugins/SoundCloudPlaylistPlugin.cxx \
src/playlist/plugins/SoundCloudPlaylistPlugin.hxx
PLAYLIST_LIBS += $(YAJL_LIBS)
diff --git a/src/lib/yajl/Handle.hxx b/src/lib/yajl/Handle.hxx
new file mode 100644
index 000000000..c2a148639
--- /dev/null
+++ b/src/lib/yajl/Handle.hxx
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 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
+ * 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 YAJL_HANDLE_HXX
+#define YAJL_HANDLE_HXX
+
+#include "util/RuntimeError.hxx"
+#include "util/ScopeExit.hxx"
+
+#include <yajl/yajl_parse.h>
+
+#include <stdexcept>
+#include <algorithm>
+
+namespace Yajl {
+
+/**
+ * OO wrapper for "struct curl_slist *".
+ */
+class Handle {
+ yajl_handle handle = nullptr;
+
+public:
+ Handle() = default;
+
+ Handle(const yajl_callbacks *callbacks,
+ yajl_alloc_funcs *afs,
+ void *ctx) noexcept
+ :handle(yajl_alloc(callbacks, afs, ctx)) {}
+
+ Handle(Handle &&src) noexcept
+ :handle(std::exchange(src.handle, nullptr)) {}
+
+ ~Handle() noexcept {
+ if (handle != nullptr)
+ yajl_free(handle);
+ }
+
+ Handle &operator=(Handle &&src) noexcept {
+ std::swap(handle, src.handle);
+ return *this;
+ }
+
+ void Parse(const unsigned char *jsonText, size_t jsonTextLength) {
+ HandleStatus(yajl_parse(handle, jsonText, jsonTextLength));
+ }
+
+ void CompleteParse() {
+ HandleStatus(yajl_complete_parse(handle));
+ }
+
+private:
+ void HandleStatus(yajl_status status) {
+ if (status == yajl_status_error) {
+ unsigned char *str = yajl_get_error(handle, false,
+ nullptr, 0);
+ AtScopeExit(this, str) {
+ yajl_free_error(handle, str);
+ };
+ throw FormatRuntimeError("Failed to parse JSON: %s", str);
+ }
+ }
+};
+
+} // namespace Yajl
+
+#endif
diff --git a/src/playlist/plugins/SoundCloudPlaylistPlugin.cxx b/src/playlist/plugins/SoundCloudPlaylistPlugin.cxx
index 573f60281..276de5c52 100644
--- a/src/playlist/plugins/SoundCloudPlaylistPlugin.cxx
+++ b/src/playlist/plugins/SoundCloudPlaylistPlugin.cxx
@@ -21,6 +21,7 @@
#include "SoundCloudPlaylistPlugin.hxx"
#include "../PlaylistPlugin.hxx"
#include "../MemorySongEnumerator.hxx"
+#include "lib/yajl/Handle.hxx"
#include "config/Block.hxx"
#include "input/InputStream.hxx"
#include "tag/Builder.hxx"
@@ -30,8 +31,6 @@
#include "util/ScopeExit.hxx"
#include "Log.hxx"
-#include <yajl/yajl_parse.h>
-
#include <string>
#include <string.h>
@@ -221,18 +220,17 @@ static constexpr yajl_callbacks parse_callbacks = {
/**
* Read JSON data and parse it using the given YAJL parser.
* @param url URL of the JSON data.
- * @param hand YAJL parser handle.
+ * @param handle YAJL parser handle.
* @return -1 on error, 0 on success.
*/
static int
-soundcloud_parse_json(const char *url, yajl_handle hand,
+soundcloud_parse_json(const char *url, Yajl::Handle &handle,
Mutex &mutex, Cond &cond)
try {
auto input_stream = InputStream::OpenReady(url, mutex, cond);
const std::lock_guard<Mutex> protect(mutex);
- yajl_status stat;
bool done = false;
while (!done) {
@@ -243,16 +241,9 @@ try {
done = true;
if (done) {
- stat = yajl_complete_parse(hand);
+ handle.CompleteParse();
} else
- stat = yajl_parse(hand, buffer, nbytes);
-
- if (stat != yajl_status_ok) {
- unsigned char *str = yajl_get_error(hand, 1, buffer, nbytes);
- LogError(soundcloud_domain, (const char *)str);
- yajl_free_error(hand, str);
- break;
- }
+ handle.Parse(buffer, nbytes);
}
return 0;
@@ -310,10 +301,8 @@ soundcloud_open_uri(const char *uri, Mutex &mutex, Cond &cond)
}
SoundCloudJsonData data;
- yajl_handle hand = yajl_alloc(&parse_callbacks, nullptr, &data);
- AtScopeExit(hand, &data) { yajl_free(hand); };
-
- int ret = soundcloud_parse_json(u, hand, mutex, cond);
+ Yajl::Handle handle(&parse_callbacks, nullptr, &data);
+ int ret = soundcloud_parse_json(u, handle, mutex, cond);
if (ret == -1)
return nullptr;