[grilo-plugins] lua-factory: Add grl.unzip library function
- From: Bastien Nocera <hadess src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [grilo-plugins] lua-factory: Add grl.unzip library function
- Date: Wed, 7 May 2014 16:18:45 +0000 (UTC)
commit 714c03643329fcfd0518637d859336954699a28c
Author: Bastien Nocera <hadess hadess net>
Date: Fri Apr 18 21:14:28 2014 +0200
lua-factory: Add grl.unzip library function
Script developers can use this to fetch a zip file, and extract
particular files inside that zip file.
This also adds a libarchive dependency for the lua-factory plugin.
https://bugzilla.gnome.org/show_bug.cgi?id=728525
configure.ac | 11 ++-
src/lua-factory/grl-lua-library.c | 217 ++++++++++++++++++++++++++++++++++++-
2 files changed, 222 insertions(+), 6 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 5215451..50b4fda 100644
--- a/configure.ac
+++ b/configure.ac
@@ -140,6 +140,8 @@ PKG_CHECK_MODULES(LUA, lua >= 5.2.0,
HAVE_LUA=yes,
HAVE_LUA=no)])
+PKG_CHECK_MODULES(ARCHIVE, libarchive, HAVE_ARCHIVE=yes, HAVE_ARCHIVE=no)
+
PKG_CHECK_MODULES(GTHREAD, gthread-2.0, HAVE_GTHREAD=yes, HAVE_GTHREAD=no)
PKG_CHECK_MODULES(OAUTH, oauth, HAVE_OAUTH=yes, HAVE_OAUTH=no)
@@ -847,6 +849,9 @@ AC_ARG_ENABLE(lua_factory,
if test "x$HAVE_LUA" = "xno"; then
AC_MSG_ERROR([lua not found, install it or use --disable-lua-factory])
fi
+ if test "x$HAVE_ARCHIVE" = "xno"; then
+ AC_MSG_ERROR([libarchive not found, install it or use --disable-lua-factory])
+ fi
if test "x$HAVE_GRLNET" = "xno"; then
AC_MSG_ERROR([grilo-net not found, install it or use --disable-lua-factory])
fi
@@ -857,7 +862,7 @@ AC_ARG_ENABLE(lua_factory,
esac
],
[
- if test "x$HAVE_LUA" = "xyes" -a "x$HAVE_GRLNET" = "xyes" -a "x$HAVE_JSON_GLIB" = "xyes";
then
+ if test "x$HAVE_LUA" = "xyes" -a "x$HAVE_ARCHIVE" = "xyes" -a "x$HAVE_GRLNET" = "xyes" -a
"x$HAVE_JSON_GLIB" = "xyes"; then
enable_lua_factory=yes
else
enable_lua_factory=no
@@ -875,9 +880,9 @@ LUA_FACTORY_PLUGIN_ID="grl-lua-factory"
AC_SUBST(LUA_FACTORY_PLUGIN_ID)
AC_DEFINE_UNQUOTED([LUA_FACTORY_PLUGIN_ID], ["$LUA_FACTORY_PLUGIN_ID"], [Lua Factory plugin ID])
-DEPS_LUA_FACTORY_CFLAGS="$DEPS_CFLAGS $LUA_CFLAGS $GRLNET_CFLAGS $JSON_CFLAGS"
+DEPS_LUA_FACTORY_CFLAGS="$DEPS_CFLAGS $LUA_CFLAGS $ARCHIVE_CFLAGS $GRLNET_CFLAGS $JSON_CFLAGS"
AC_SUBST(DEPS_LUA_FACTORY_CFLAGS)
-DEPS_LUA_FACTORY_LIBS="$DEPS_LIBS $LUA_LIBS $GRLNET_LIBS $JSON_LIBS"
+DEPS_LUA_FACTORY_LIBS="$DEPS_LIBS $LUA_LIBS $ARCHIVE_LIBS $GRLNET_LIBS $JSON_LIBS"
AC_SUBST(DEPS_LUA_FACTORY_LIBS)
LUA_FACTORY_SOURCE_LOCATION="grilo-plugins/${LUA_FACTORY_PLUGIN_ID}"
diff --git a/src/lua-factory/grl-lua-library.c b/src/lua-factory/grl-lua-library.c
index 85fd22e..86337c4 100644
--- a/src/lua-factory/grl-lua-library.c
+++ b/src/lua-factory/grl-lua-library.c
@@ -24,6 +24,8 @@
#include <string.h>
#include <errno.h>
#include <stdlib.h>
+#include <archive.h>
+#include <archive_entry.h>
#include "grl-lua-common.h"
#include "grl-lua-library.h"
@@ -43,6 +45,14 @@ typedef struct {
gchar **results;
} FetchOperation;
+typedef struct {
+ lua_State *L;
+ guint operation_id;
+ gchar *lua_cb;
+ gchar *url;
+ gchar **filenames;
+} UnzipOperation;
+
/* ================== Lua-Library utils/helpers ============================ */
static gchar *
@@ -367,8 +377,145 @@ grl_util_fetch_done (GObject *source_object,
g_free (fo);
}
+static gboolean
+str_in_strv_at_index (const char **filenames,
+ const char *name,
+ guint *idx)
+{
+ guint i;
+
+ for (i = 0; filenames[i] != NULL; i++) {
+ if (g_strcmp0 (name, filenames[i]) == 0) {
+ *idx = i;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static char **
+get_zipped_contents (guchar *data,
+ gsize size,
+ const char **filenames)
+{
+ GPtrArray *results;
+ struct archive *a;
+ struct archive_entry *entry;
+ int r;
+
+ a = archive_read_new ();
+ archive_read_support_format_zip (a); //FIXME more formats?
+ r = archive_read_open_memory (a, data, size);
+ if (r != ARCHIVE_OK) {
+ g_print ("Failed to open archive\n");
+ return NULL;
+ }
+
+ results = g_ptr_array_new ();
+ g_ptr_array_set_size (results, g_strv_length ((gchar **) filenames) + 1);
+
+ while (1) {
+ const char *name;
+ guint idx;
+
+ r = archive_read_next_header(a, &entry);
+
+ if (r != ARCHIVE_OK) {
+ if (r != ARCHIVE_EOF && r == ARCHIVE_FATAL)
+ g_warning ("Fatal error handling archive: %s", archive_error_string (a));
+ break;
+ }
+
+ name = archive_entry_pathname (entry);
+ if (str_in_strv_at_index (filenames, name, &idx) != FALSE) {
+ size_t size = archive_entry_size (entry);
+ char *buf;
+ ssize_t read;
+
+ buf = g_malloc (size + 1);
+ buf[size] = 0;
+ read = archive_read_data (a, buf, size);
+ if (read <= 0) {
+ g_free (buf);
+ if (read < 0)
+ g_warning ("Fatal error reading '%s' in archive: %s", name, archive_error_string (a));
+ else
+ g_warning ("Read an empty file from the archive");
+ } else {
+ g_message ("Setting content for %s at %d", name, idx);
+ //FIXME check for validity?
+ results->pdata[idx] = buf;
+ }
+ }
+ archive_read_data_skip(a);
+ }
+ archive_read_free(a);
+
+ return (gchar **) g_ptr_array_free (results, FALSE);
+}
+
+static void
+grl_util_unzip_done (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ gchar *data;
+ gsize len;
+ guint i;
+ GError *err = NULL;
+ OperationSpec *os;
+ UnzipOperation *uo = (UnzipOperation *) user_data;
+ lua_State *L = uo->L;
+ char **results;
+
+ grl_net_wc_request_finish (GRL_NET_WC (source_object),
+ res, &data, &len, &err);
+
+ if (err != NULL) {
+ guint len, i;
+ GRL_WARNING ("Can't fetch zip file (URL: %s): '%s'", uo->url, err->message);
+ g_error_free (err);
+ len = g_strv_length (uo->filenames);
+ results = g_new0 (gchar *, len + 1);
+ for (i = 0; i < len; i++)
+ results[i] = g_strdup("");
+ } else {
+ GRL_DEBUG ("fetch_done element (URL: %s)", uo->url);
+ results = get_zipped_contents ((guchar *) data, len, (const gchar **) uo->filenames);
+ }
+
+ grl_lua_library_set_current_operation (L, uo->operation_id);
+ os = grl_lua_library_get_current_operation (L);
+ os->pending_ops--;
+
+ lua_getglobal (L, uo->lua_cb);
+
+ lua_newtable (L);
+ for (i = 0; results[i] != NULL; i++) {
+ lua_pushnumber (L, i + 1);
+ lua_pushlstring (L, results[i], strlen (results[i]));
+ lua_settable (L, -3);
+ }
+
+ if (lua_pcall (L, 1, 0, 0)) {
+ GRL_WARNING ("%s (%s) '%s'", "calling source callback function fail",
+ uo->lua_cb, lua_tolstring (L, -1, NULL));
+ }
+
+ grl_lua_library_set_current_operation (L, 0);
+
+ g_strfreev (results);
+
+ g_strfreev (uo->filenames);
+ g_free (uo->lua_cb);
+ g_free (uo->url);
+ g_free (uo);
+}
+
static GrlNetWc *
-net_wc_new_with_options(lua_State *L)
+net_wc_new_with_options(lua_State *L,
+ guint arg_offset)
{
GrlNetWc *wc;
@@ -376,7 +523,7 @@ net_wc_new_with_options(lua_State *L)
if (lua_istable (L, 3)) {
/* Set GrlNetWc options */
lua_pushnil (L);
- while (lua_next (L, 3) != 0) {
+ while (lua_next (L, arg_offset) != 0) {
const gchar *key = lua_tostring (L, -2);
if (g_strcmp0 (key, "user-agent") == 0 ||
g_strcmp0 (key, "user_agent") == 0) {
@@ -686,7 +833,7 @@ grl_l_fetch (lua_State *L)
lua_callback = lua_tolstring (L, 2, NULL);
- wc = net_wc_new_with_options(L);
+ wc = net_wc_new_with_options(L, 3);
/* shared data between urls */
results = g_new0 (gchar *, num_urls);
@@ -868,6 +1015,69 @@ grl_l_unescape (lua_State *L)
return 1;
}
+/**
+ * grl.unzip
+ *
+ * @url: (string) the URL of the zip file to fetch
+ * @filenames: (table) a table of filenames to get inside the zip file
+ * @callback: (string) The function to be called after fetch is complete.
+ * @netopts: (table) Options to set the GrlNetWc object.
+ * @return: Nothing.;
+ */
+static gint
+grl_l_unzip (lua_State *L)
+{
+ const gchar *lua_callback;
+ const gchar *url;
+ GrlNetWc *wc;
+ OperationSpec *os;
+ UnzipOperation *uo;
+ guint num_filenames, i;
+ gchar **filenames;
+
+ luaL_argcheck (L, lua_isstring (L, 1), 1,
+ "expecting url as string");
+ luaL_argcheck (L, lua_istable (L, 2), 2,
+ "expecting filenames as an array of filenames");
+ luaL_argcheck (L, lua_isstring (L, 3), 3,
+ "expecting callback function as string");
+
+ os = grl_lua_library_get_current_operation (L);
+ g_return_val_if_fail (os != NULL, 0);
+ os->pending_ops++;
+
+ url = lua_tolstring (L, 1, NULL);
+ num_filenames = luaL_len(L, 2);
+ filenames = g_new0 (gchar *, num_filenames + 1);
+ for (i = 0; i < num_filenames; i++) {
+ lua_pushinteger (L, i + 1);
+ lua_gettable (L, 2);
+ if (lua_isstring (L, -1)) {
+ filenames[i] = g_strdup (lua_tostring (L, -1));
+ } else {
+ luaL_error (L, "Array of urls expect strings only: at index %d is %s",
+ i + 1, luaL_typename (L, -1));
+ }
+ g_message ("grl.unzip() -> filenames[%d]: '%s'", i, filenames[i]);
+ lua_pop (L, 1);
+ }
+ GRL_DEBUG ("grl.unzip() -> '%s'", url);
+
+ lua_callback = lua_tolstring (L, 3, NULL);
+ wc = net_wc_new_with_options (L, 4);
+
+ uo = g_new0 (UnzipOperation, 1);
+ uo->L = L;
+ uo->operation_id = os->operation_id;
+ uo->lua_cb = g_strdup (lua_callback);
+ uo->url = g_strdup (url);
+ uo->filenames = filenames;
+
+ grl_net_wc_request_async (wc, url, NULL, grl_util_unzip_done, uo);
+ g_object_unref (wc);
+ return 1;
+}
+
/* ================== Lua-Library initialization =========================== */
gint
@@ -884,6 +1094,7 @@ luaopen_grilo (lua_State *L)
{"dgettext", &grl_l_dgettext},
{"decode", &grl_l_decode},
{"unescape", &grl_l_unescape},
+ {"unzip", &grl_l_unzip},
{NULL, NULL}
};
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]