Files
sysprof/src/libsysprof-analyze/sysprof-document-file.c
Christian Hergert 957cec9843 libsysprof-analyze: decompress if necessary in dup_bytes()
If we are trying to get the file bytes and they are compressed, we may need
to transparently decompress those bytes. That way if the API requested
"/proc/cpuinfo" but really got "/proc/cpuinfo.gz" it still gets the same
bytes to consume.
2023-05-30 13:19:57 -07:00

242 lines
6.8 KiB
C

/* sysprof-document-file.c
*
* Copyright 2023 Christian Hergert <chergert@redhat.com>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "config.h"
#include "sysprof-document-file-chunk.h"
#include "sysprof-document-file-private.h"
#include "sysprof-document-frame-private.h"
struct _SysprofDocumentFile
{
GObject parent_instance;
char *path;
GPtrArray *file_chunks;
guint compressed : 1;
};
enum {
PROP_0,
PROP_BYTES,
PROP_PATH,
N_PROPS
};
G_DEFINE_FINAL_TYPE (SysprofDocumentFile, sysprof_document_file, G_TYPE_OBJECT)
static GParamSpec *properties [N_PROPS];
static void
sysprof_document_file_finalize (GObject *object)
{
SysprofDocumentFile *self = (SysprofDocumentFile *)object;
g_clear_pointer (&self->path, g_free);
g_clear_pointer (&self->file_chunks, g_ptr_array_unref);
G_OBJECT_CLASS (sysprof_document_file_parent_class)->finalize (object);
}
static void
sysprof_document_file_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
SysprofDocumentFile *self = SYSPROF_DOCUMENT_FILE (object);
switch (prop_id)
{
case PROP_PATH:
g_value_set_string (value, sysprof_document_file_get_path (self));
break;
case PROP_BYTES:
g_value_take_boxed (value, sysprof_document_file_dup_bytes (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
sysprof_document_file_class_init (SysprofDocumentFileClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = sysprof_document_file_finalize;
object_class->get_property = sysprof_document_file_get_property;
properties [PROP_PATH] =
g_param_spec_string ("path", NULL, NULL,
NULL,
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
properties [PROP_BYTES] =
g_param_spec_boxed ("bytes", NULL, NULL,
G_TYPE_BYTES,
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, N_PROPS, properties);
}
static void
sysprof_document_file_init (SysprofDocumentFile *self)
{
}
SysprofDocumentFile *
_sysprof_document_file_new (const char *path,
GPtrArray *file_chunks,
gboolean compressed)
{
SysprofDocumentFile *self;
g_return_val_if_fail (path != NULL, NULL);
g_return_val_if_fail (file_chunks != NULL, NULL);
self = g_object_new (SYSPROF_TYPE_DOCUMENT_FILE, NULL);
self->path = g_strdup (path);
self->file_chunks = file_chunks;
self->compressed = !!compressed;
return self;
}
const char *
sysprof_document_file_get_path (SysprofDocumentFile *self)
{
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_FILE (self), NULL);
return self->path;
}
/**
* sysprof_document_file_dup_contents:
* @self: a #SysprofDocumentFile
*
* Creates a new #GBytes containing the contents of the file.
*
* Returns: (transfer full): a #GBytes
*/
GBytes *
sysprof_document_file_dup_bytes (SysprofDocumentFile *self)
{
GArray *ar;
guint len;
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_FILE (self), NULL);
ar = g_array_new (TRUE, FALSE, sizeof (char));
for (guint i = 0; i < self->file_chunks->len; i++)
{
SysprofDocumentFileChunk *file_chunk = g_ptr_array_index (self->file_chunks, i);
const guint8 *data = sysprof_document_file_chunk_get_data (file_chunk, &len);
g_array_append_vals (ar, data, len);
}
len = ar->len;
if (self->compressed)
{
guint8 *data = (guint8 *)g_array_free (ar, FALSE);
g_autoptr(GInputStream) input = g_memory_input_stream_new_from_data (data, len, g_free);
g_autoptr(GOutputStream) memory_output = g_memory_output_stream_new_resizable ();
g_autoptr(GZlibDecompressor) zlib = g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP);
g_autoptr(GOutputStream) zlib_output = g_converter_output_stream_new (memory_output, G_CONVERTER (zlib));
g_output_stream_splice (zlib_output,
input,
(G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET),
NULL, NULL);
return g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (memory_output));
}
return g_bytes_new_take (g_array_free (ar, FALSE), len);
}
/**
* sysprof_document_file_read:
* @self: a #SysprofDocumentFile
*
* Creates a new input stream containing the contents of the file
* within the document.
*
* Returns: (transfer full): a #GInputstream
*/
GInputStream *
sysprof_document_file_read (SysprofDocumentFile *self)
{
g_autoptr(GInputStream) input = NULL;
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_FILE (self), NULL);
input = g_memory_input_stream_new ();
for (guint i = 0; i < self->file_chunks->len; i++)
{
g_autoptr(GBytes) bytes = NULL;
SysprofDocumentFileChunk *file_chunk;
const guint8 *data;
guint len;
file_chunk = g_ptr_array_index (self->file_chunks, i);
data = sysprof_document_file_chunk_get_data (file_chunk, &len);
bytes = g_bytes_new_with_free_func (data,
len,
(GDestroyNotify)g_mapped_file_unref,
g_mapped_file_ref (SYSPROF_DOCUMENT_FRAME (file_chunk)->mapped_file));
g_memory_input_stream_add_bytes (G_MEMORY_INPUT_STREAM (input), bytes);
}
if (self->compressed)
{
g_autoptr(GZlibDecompressor) zlib = g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP);
return g_converter_input_stream_new (input, G_CONVERTER (zlib));
}
return g_steal_pointer (&input);
}
gsize
sysprof_document_file_get_size (SysprofDocumentFile *self)
{
gsize size = 0;
g_return_val_if_fail (SYSPROF_IS_DOCUMENT_FILE (self), 0);
for (guint i = 0; i < self->file_chunks->len; i++)
{
SysprofDocumentFileChunk *file_chunk = g_ptr_array_index (self->file_chunks, i);
size += sysprof_document_file_chunk_get_size (file_chunk);
}
return size;
}