mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-07-10 12:38:54 +02:00
file: add g_file_load_bytes()
This adds g_file_load_bytes() to make it more convenient to load the contents of a GFile as GBytes. It includes a special casing for gresources to increase the chances that the GBytes directly references the embedded data instead of copying to the heap. https://bugzilla.gnome.org/show_bug.cgi?id=790272
This commit is contained in:
@ -184,6 +184,9 @@ g_file_mount_enclosing_volume_finish
|
|||||||
g_file_monitor_directory
|
g_file_monitor_directory
|
||||||
g_file_monitor_file
|
g_file_monitor_file
|
||||||
g_file_monitor
|
g_file_monitor
|
||||||
|
g_file_load_bytes
|
||||||
|
g_file_load_bytes_async
|
||||||
|
g_file_load_bytes_finish
|
||||||
g_file_load_contents
|
g_file_load_contents
|
||||||
g_file_load_contents_async
|
g_file_load_contents_async
|
||||||
g_file_load_contents_finish
|
g_file_load_contents_finish
|
||||||
|
188
gio/gfile.c
188
gio/gfile.c
@ -8092,3 +8092,191 @@ g_file_supports_thread_contexts (GFile *file)
|
|||||||
iface = G_FILE_GET_IFACE (file);
|
iface = G_FILE_GET_IFACE (file);
|
||||||
return iface->supports_thread_contexts;
|
return iface->supports_thread_contexts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* g_file_load_bytes:
|
||||||
|
* @file: a #GFile
|
||||||
|
* @cancellable: (nullable): a #GCancellable or %NULL
|
||||||
|
* @etag_out: (out) (nullable) (optional): a location to place the current
|
||||||
|
* entity tag for the file, or %NULL if the entity tag is not needed
|
||||||
|
* @error: a location for a #GError or %NULL
|
||||||
|
*
|
||||||
|
* Loads the contents of @file and returns it as #GBytes.
|
||||||
|
*
|
||||||
|
* If @file is a resource:// based URI, the resulting bytes will reference the
|
||||||
|
* embedded resource instead of a copy. Otherwise, this is equivalent to calling
|
||||||
|
* g_file_load_contents() and g_bytes_new_take().
|
||||||
|
*
|
||||||
|
* For resources, @etag_out will be set to %NULL.
|
||||||
|
*
|
||||||
|
* The data contained in the resulting #GBytes is always zero-terminated, but
|
||||||
|
* this is not included in the #GBytes length. The resulting #GBytes should be
|
||||||
|
* freed with g_bytes_unref() when no longer in use.
|
||||||
|
*
|
||||||
|
* Returns: (transfer full): a #GBytes or %NULL and @error is set
|
||||||
|
*
|
||||||
|
* Since: 2.56
|
||||||
|
*/
|
||||||
|
GBytes *
|
||||||
|
g_file_load_bytes (GFile *file,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
gchar **etag_out,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gchar *contents;
|
||||||
|
gsize len;
|
||||||
|
|
||||||
|
g_return_val_if_fail (G_IS_FILE (file), NULL);
|
||||||
|
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
|
||||||
|
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
||||||
|
|
||||||
|
if (etag_out != NULL)
|
||||||
|
*etag_out = NULL;
|
||||||
|
|
||||||
|
if (g_file_has_uri_scheme (file, "resource"))
|
||||||
|
{
|
||||||
|
GBytes *bytes;
|
||||||
|
gchar *uri, *unescaped;
|
||||||
|
|
||||||
|
uri = g_file_get_uri (file);
|
||||||
|
unescaped = g_uri_unescape_string (uri + strlen ("resource://"), NULL);
|
||||||
|
g_free (uri);
|
||||||
|
|
||||||
|
bytes = g_resources_lookup_data (unescaped, G_RESOURCE_LOOKUP_FLAGS_NONE, error);
|
||||||
|
g_free (unescaped);
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* contents is guaranteed to be \0 terminated */
|
||||||
|
if (g_file_load_contents (file, cancellable, &contents, &len, etag_out, error))
|
||||||
|
return g_bytes_new_take (g_steal_pointer (&contents), len);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
g_file_load_bytes_cb (GObject *object,
|
||||||
|
GAsyncResult *result,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GFile *file = G_FILE (object);
|
||||||
|
GTask *task = user_data;
|
||||||
|
GError *error = NULL;
|
||||||
|
gchar *etag = NULL;
|
||||||
|
gchar *contents = NULL;
|
||||||
|
gsize len = 0;
|
||||||
|
|
||||||
|
g_file_load_contents_finish (file, result, &contents, &len, &etag, &error);
|
||||||
|
g_task_set_task_data (task, g_steal_pointer (&etag), g_free);
|
||||||
|
|
||||||
|
if (error != NULL)
|
||||||
|
g_task_return_error (task, g_steal_pointer (&error));
|
||||||
|
else
|
||||||
|
g_task_return_pointer (task,
|
||||||
|
g_bytes_new_take (g_steal_pointer (&contents), len),
|
||||||
|
(GDestroyNotify)g_bytes_unref);
|
||||||
|
|
||||||
|
g_object_unref (task);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* g_file_load_bytes_async:
|
||||||
|
* @file: a #GFile
|
||||||
|
* @cancellable: (nullable): a #GCancellable or %NULL
|
||||||
|
* @callback: (scope async): a #GAsyncReadyCallback to call when the
|
||||||
|
* request is satisfied
|
||||||
|
* @user_data: (closure): the data to pass to callback function
|
||||||
|
*
|
||||||
|
* Asynchronously loads the contents of @file as #GBytes.
|
||||||
|
*
|
||||||
|
* If @file is a resource:// based URI, the resulting bytes will reference the
|
||||||
|
* embedded resource instead of a copy. Otherwise, this is equivalent to calling
|
||||||
|
* g_file_load_contents_async() and g_bytes_new_take().
|
||||||
|
*
|
||||||
|
* @callback should call g_file_load_bytes_finish() to get the result of this
|
||||||
|
* asynchronous operation.
|
||||||
|
*
|
||||||
|
* See g_file_load_bytes() for more information.
|
||||||
|
*
|
||||||
|
* Since: 2.56
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
g_file_load_bytes_async (GFile *file,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
GBytes *bytes;
|
||||||
|
GTask *task;
|
||||||
|
|
||||||
|
g_return_if_fail (G_IS_FILE (file));
|
||||||
|
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
|
||||||
|
|
||||||
|
task = g_task_new (file, cancellable, callback, user_data);
|
||||||
|
g_task_set_source_tag (task, g_file_load_bytes_async);
|
||||||
|
|
||||||
|
if (!g_file_has_uri_scheme (file, "resource"))
|
||||||
|
{
|
||||||
|
g_file_load_contents_async (file,
|
||||||
|
cancellable,
|
||||||
|
g_file_load_bytes_cb,
|
||||||
|
g_steal_pointer (&task));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes = g_file_load_bytes (file, cancellable, NULL, &error);
|
||||||
|
|
||||||
|
if (bytes == NULL)
|
||||||
|
g_task_return_error (task, g_steal_pointer (&error));
|
||||||
|
else
|
||||||
|
g_task_return_pointer (task,
|
||||||
|
g_steal_pointer (&bytes),
|
||||||
|
(GDestroyNotify)g_bytes_unref);
|
||||||
|
|
||||||
|
g_object_unref (task);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* g_file_load_bytes_finish:
|
||||||
|
* @file: a #GFile
|
||||||
|
* @result: a #GAsyncResult provided to the callback
|
||||||
|
* @etag_out: (out) (nullable) (optional): a location to place the current
|
||||||
|
* entity tag for the file, or %NULL if the entity tag is not needed
|
||||||
|
* @error: a location for a #GError, or %NULL
|
||||||
|
*
|
||||||
|
* Completes an asynchronous request to g_file_load_bytes_async().
|
||||||
|
*
|
||||||
|
* For resources, @etag_out will be set to %NULL.
|
||||||
|
*
|
||||||
|
* The data contained in the resulting #GBytes is always zero-terminated, but
|
||||||
|
* this is not included in the #GBytes length. The resulting #GBytes should be
|
||||||
|
* freed with g_bytes_unref() when no longer in use.
|
||||||
|
*
|
||||||
|
* See g_file_load_bytes() for more information.
|
||||||
|
*
|
||||||
|
* Returns: (transfer full): a #GBytes or %NULL and @error is set
|
||||||
|
*
|
||||||
|
* Since: 2.56
|
||||||
|
*/
|
||||||
|
GBytes *
|
||||||
|
g_file_load_bytes_finish (GFile *file,
|
||||||
|
GAsyncResult *result,
|
||||||
|
gchar **etag_out,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
GBytes *bytes;
|
||||||
|
|
||||||
|
g_return_val_if_fail (G_IS_FILE (file), NULL);
|
||||||
|
g_return_val_if_fail (G_IS_TASK (result), NULL);
|
||||||
|
g_return_val_if_fail (g_task_is_valid (G_TASK (result), file), NULL);
|
||||||
|
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
||||||
|
|
||||||
|
bytes = g_task_propagate_pointer (G_TASK (result), error);
|
||||||
|
|
||||||
|
if (etag_out != NULL)
|
||||||
|
*etag_out = g_strdup (g_task_get_task_data (G_TASK (result)));
|
||||||
|
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
16
gio/gfile.h
16
gio/gfile.h
@ -1251,6 +1251,22 @@ gboolean g_file_replace_contents_finish (GFile *file,
|
|||||||
GLIB_AVAILABLE_IN_ALL
|
GLIB_AVAILABLE_IN_ALL
|
||||||
gboolean g_file_supports_thread_contexts (GFile *file);
|
gboolean g_file_supports_thread_contexts (GFile *file);
|
||||||
|
|
||||||
|
GLIB_AVAILABLE_IN_2_56
|
||||||
|
GBytes *g_file_load_bytes (GFile *file,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
gchar **etag_out,
|
||||||
|
GError **error);
|
||||||
|
GLIB_AVAILABLE_IN_2_56
|
||||||
|
void g_file_load_bytes_async (GFile *file,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data);
|
||||||
|
GLIB_AVAILABLE_IN_2_56
|
||||||
|
GBytes *g_file_load_bytes_finish (GFile *file,
|
||||||
|
GAsyncResult *result,
|
||||||
|
gchar **etag_out,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __G_FILE_H__ */
|
#endif /* __G_FILE_H__ */
|
||||||
|
Reference in New Issue
Block a user