/*
* Copyright (C) 2018 Richard Hughes <richard@hughsie.com>
*
* SPDX-License-Identifier: LGPL-2.1+
*/
#define G_LOG_DOMAIN "XbSilo"
#include "config.h"
#include <gio/gio.h>
#include "xb-builder-source-ctx-private.h"
typedef struct {
GObject parent_instance;
GInputStream *istream;
gchar *filename;
gchar *content_type;
} XbBuilderSourceCtxPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (XbBuilderSourceCtx, xb_builder_source_ctx, G_TYPE_OBJECT)
#define GET_PRIVATE(o) (xb_builder_source_ctx_get_instance_private (o))
/**
* xb_builder_source_ctx_get_stream:
* @self: a #XbBuilderSourceCtx
*
* Returns the input stream currently being processed.
*
* Returns: (transfer none): a #GInputStream
*
* Since: 0.1.7
**/
GInputStream *
xb_builder_source_ctx_get_stream (XbBuilderSourceCtx *self)
{
XbBuilderSourceCtxPrivate *priv = GET_PRIVATE (self);
g_return_val_if_fail (XB_IS_BUILDER_SOURCE_CTX (self), NULL);
return priv->istream;
}
/**
* xb_builder_source_ctx_get_bytes:
* @self: a #XbBuilderSourceCtx
* @cancellable: a #GCancellable, or %NULL
* @error: the #GError, or %NULL
*
* Returns the data currently being processed.
*
* Returns: (transfer none): a #GInputStream
*
* Since: 0.1.7
**/
GBytes *
xb_builder_source_ctx_get_bytes (XbBuilderSourceCtx *self,
GCancellable *cancellable,
GError **error)
{
XbBuilderSourceCtxPrivate *priv = GET_PRIVATE (self);
g_return_val_if_fail (XB_IS_BUILDER_SOURCE_CTX (self), NULL);
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
return g_input_stream_read_bytes (priv->istream,
128 * 1024 * 1024, /* 128Mb */
cancellable, error);
}
/**
* xb_builder_source_ctx_get_filename:
* @self: a #XbBuilderSourceCtx
*
* Returns the basename of the file currently being processed.
*
* Returns: a filename, or %NULL if unset
*
* Since: 0.1.7
**/
const gchar *
xb_builder_source_ctx_get_filename (XbBuilderSourceCtx *self)
{
XbBuilderSourceCtxPrivate *priv = GET_PRIVATE (self);
g_return_val_if_fail (XB_IS_BUILDER_SOURCE_CTX (self), NULL);
return priv->filename;
}
/**
* xb_builder_source_ctx_get_content_type:
* @self: a #XbBuilderSourceCtx
*
* Returns the content type of the input stream currently being
* processed.
*
* Returns: (transfer full): a content type (e.g. `application/x-desktop`), or %NULL
*
* Since: 0.1.7
**/
gchar *
xb_builder_source_ctx_get_content_type (XbBuilderSourceCtx *self,
GCancellable *cancellable,
GError **error)
{
XbBuilderSourceCtxPrivate *priv = GET_PRIVATE (self);
g_autofree gchar *content_type = NULL;
g_return_val_if_fail (XB_IS_BUILDER_SOURCE_CTX (self), NULL);
if (G_IS_SEEKABLE (priv->istream)) {
gsize bufsz = 0;
guchar buf[4096] = { 0x00 };
if (!g_input_stream_read_all (priv->istream, buf, sizeof(buf),
&bufsz, cancellable, error))
return NULL;
if (!g_seekable_seek (G_SEEKABLE (priv->istream), 0, G_SEEK_SET,
cancellable, error))
return NULL;
if (bufsz > 0)
content_type = g_content_type_guess (priv->filename, buf, bufsz, NULL);
}
/* either unseekable, or empty */
if (content_type == NULL)
content_type = g_content_type_guess (priv->filename, NULL, 0, NULL);
#ifdef _WIN32
/* map Windows "mime-type" to a content type */
if (g_strcmp0 (content_type, ".gz") == 0)
return g_strdup ("application/gzip");
if (g_strcmp0 (content_type, ".txt") == 0 ||
g_strcmp0 (content_type, ".xml") == 0)
return g_strdup ("application/xml");
if (g_strcmp0 (content_type, ".desktop") == 0)
return g_strdup ("application/x-desktop");
#endif
return g_steal_pointer (&content_type);
}
/* private */
void
xb_builder_source_ctx_set_filename (XbBuilderSourceCtx *self, const gchar *filename)
{
XbBuilderSourceCtxPrivate *priv = GET_PRIVATE (self);
g_return_if_fail (XB_IS_BUILDER_SOURCE_CTX (self));
g_return_if_fail (filename != NULL);
g_free (priv->filename);
priv->filename = g_strdup (filename);
}
static void
xb_builder_source_ctx_init (XbBuilderSourceCtx *self)
{
}
static void
xb_builder_source_ctx_finalize (GObject *obj)
{
XbBuilderSourceCtx *self = XB_BUILDER_SOURCE_CTX (obj);
XbBuilderSourceCtxPrivate *priv = GET_PRIVATE (self);
g_free (priv->filename);
g_object_unref (priv->istream);
G_OBJECT_CLASS (xb_builder_source_ctx_parent_class)->finalize (obj);
}
static void
xb_builder_source_ctx_class_init (XbBuilderSourceCtxClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = xb_builder_source_ctx_finalize;
}
/**
* xb_builder_source_ctx_new:
* @element: An element name, e.g. "component"
*
* Creates a new builder source_ctx.
*
* Returns: (transfer full): a new #XbBuilderSourceCtx
*
* Since: 0.1.7
**/
XbBuilderSourceCtx *
xb_builder_source_ctx_new (GInputStream *istream)
{
XbBuilderSourceCtx *self = g_object_new (XB_TYPE_BUILDER_SOURCE_CTX, NULL);
XbBuilderSourceCtxPrivate *priv = GET_PRIVATE (self);
priv->istream = g_object_ref (istream);
return self;
}