/
githubmirror
/
fwupd
Обзор
Документация
Войти
/
githubmirror
/
fwupd
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
libfwupdplugin/fu-partial-input-stream.c
252 строки
7 KB
Peter Hutterer
libfwupdplugin: Make FuInputStream a GObject subclass
30 июл 2026, 14:23
30 июл 2026, 14:23
7d925c8
Код
Авторство
О чём код?
/* * Copyright 2023 Richard Hughes <richard@hughsie.com> * * SPDX-License-Identifier: LGPL-2.1-or-later */ #define G_LOG_DOMAIN "FuPartialInputStream" #include "config.h" #include "fwupd-codec.h" #include "fu-common.h" #include "fu-input-stream.h" #include "fu-partial-input-stream-private.h" /** * FuPartialInputStream: * * A input stream that is a slice of another input stream. * * off sz * [xxxxxxxxxxxx] * | 0x6 | * \ \ * \ \ * \ | * | | * [xxxxxx] * * xxx offset: 2, sz: 6 */ struct _FuPartialInputStream { FuInputStream parent_instance; FuInputStream *base_stream; gsize offset; gsize size; }; static void fu_partial_input_stream_codec_iface_init(FwupdCodecInterface *iface); G_DEFINE_TYPE_WITH_CODE(FuPartialInputStream, fu_partial_input_stream, FU_TYPE_INPUT_STREAM, G_IMPLEMENT_INTERFACE(FWUPD_TYPE_CODEC, fu_partial_input_stream_codec_iface_init)) static void fu_partial_input_stream_add_string(FwupdCodec *codec, guint idt, GString *str) { FuPartialInputStream *self = FU_PARTIAL_INPUT_STREAM(codec); fwupd_codec_string_append_hex(str, idt, "Offset", self->offset); fwupd_codec_string_append_hex(str, idt, "Size", self->size); } static void fu_partial_input_stream_codec_iface_init(FwupdCodecInterface *iface) { iface->add_string = fu_partial_input_stream_add_string; } static goffset fu_partial_input_stream_tell(FuInputStream *stream) { FuPartialInputStream *self = FU_PARTIAL_INPUT_STREAM(stream); return g_seekable_tell(G_SEEKABLE(self->base_stream)) - self->offset; } static gboolean fu_partial_input_stream_can_seek(FuInputStream *stream) { FuPartialInputStream *self = FU_PARTIAL_INPUT_STREAM(stream); return g_seekable_can_seek(G_SEEKABLE(self->base_stream)); } static gboolean fu_partial_input_stream_seek(FuInputStream *stream, goffset offset, GSeekType type, GCancellable *cancellable, GError **error) { FuPartialInputStream *self = FU_PARTIAL_INPUT_STREAM(stream); g_return_val_if_fail(FU_IS_PARTIAL_INPUT_STREAM(self), FALSE); g_return_val_if_fail(error == NULL || *error == NULL, FALSE); if (type == G_SEEK_CUR) { goffset pos = g_seekable_tell(G_SEEKABLE(self->base_stream)); return g_seekable_seek(G_SEEKABLE(self->base_stream), self->offset + pos + offset, G_SEEK_SET, cancellable, error); } if (type == G_SEEK_END) { return g_seekable_seek(G_SEEKABLE(self->base_stream), self->offset + self->size + offset, G_SEEK_SET, cancellable, error); } return g_seekable_seek(G_SEEKABLE(self->base_stream), self->offset + offset, G_SEEK_SET, cancellable, error); } /** * fu_partial_input_stream_new: * @stream: a base #FuInputStream * @offset: offset into @stream * @size: size of @stream in bytes, or %G_MAXSIZE for the "rest" of the stream * @error: (nullable): optional return location for an error * * Creates a partial input stream where content is read from the donor stream. * * Returns: (transfer full): a #FuPartialInputStream, or %NULL on error * * Since: 2.0.0 **/ FuInputStream * fu_partial_input_stream_new(FuInputStream *stream, gsize offset, gsize size, GError **error) { gsize base_sz = 0; g_autoptr(FuPartialInputStream) self = g_object_new(FU_TYPE_PARTIAL_INPUT_STREAM, NULL); g_return_val_if_fail(FU_IS_INPUT_STREAM(stream), NULL); g_return_val_if_fail(error == NULL || *error == NULL, NULL); self->base_stream = g_object_ref(stream); self->offset = offset; /* sanity check */ if (!fu_input_stream_size(stream, &base_sz, error)) { g_prefix_error_literal(error, "failed to get size: "); return NULL; } if (size == G_MAXSIZE) { if (offset > base_sz) { g_set_error(error, FWUPD_ERROR, FWUPD_ERROR_INVALID_DATA, "base stream was 0x%x bytes in size " "and tried to create partial stream @0x%x", (guint)base_sz, (guint)offset); return NULL; } self->size = base_sz - offset; } else { if (fu_size_checked_add(offset, size) > base_sz) { g_set_error(error, FWUPD_ERROR, FWUPD_ERROR_INVALID_DATA, "base stream was 0x%x bytes in size, and tried to create " "partial stream @0x%x of 0x%x bytes", (guint)base_sz, (guint)offset, (guint)size); return NULL; } self->size = size; } /* success */ return FU_INPUT_STREAM(g_steal_pointer(&self)); } /** * fu_partial_input_stream_get_offset: * @self: a #FuPartialInputStream * * Gets the offset of the stream. * * Returns: integer * * Since: 2.0.0 **/ gsize fu_partial_input_stream_get_offset(FuPartialInputStream *self) { g_return_val_if_fail(FU_IS_PARTIAL_INPUT_STREAM(self), G_MAXSIZE); return self->offset; } /** * fu_partial_input_stream_get_size: * @self: a #FuPartialInputStream * * Gets the offset of the stream. * * Returns: integer * * Since: 2.0.0 **/ gsize fu_partial_input_stream_get_size(FuPartialInputStream *self) { g_return_val_if_fail(FU_IS_PARTIAL_INPUT_STREAM(self), G_MAXSIZE); return self->size; } static gssize fu_partial_input_stream_read_fn(FuInputStream *stream, void *buffer, gsize count, GCancellable *cancellable, GError **error) { FuPartialInputStream *self = FU_PARTIAL_INPUT_STREAM(stream); g_return_val_if_fail(FU_IS_PARTIAL_INPUT_STREAM(self), -1); g_return_val_if_fail(error == NULL || *error == NULL, -1); if (self->size < (gsize)g_seekable_tell(G_SEEKABLE(stream))) { g_set_error_literal(error, FWUPD_ERROR, FWUPD_ERROR_INVALID_DATA, "base stream is outside seekable range"); return -1; } count = MIN(count, self->size - g_seekable_tell(G_SEEKABLE(stream))); return fu_input_stream_read(self->base_stream, buffer, count, cancellable, error); } static void fu_partial_input_stream_finalize(GObject *object) { FuPartialInputStream *self = FU_PARTIAL_INPUT_STREAM(object); if (self->base_stream != NULL) g_object_unref(self->base_stream); G_OBJECT_CLASS(fu_partial_input_stream_parent_class)->finalize(object); } static void fu_partial_input_stream_class_init(FuPartialInputStreamClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS(klass); FuInputStreamClass *istream_class = FU_INPUT_STREAM_CLASS(klass); istream_class->read_fn = fu_partial_input_stream_read_fn; istream_class->tell = fu_partial_input_stream_tell; istream_class->can_seek = fu_partial_input_stream_can_seek; istream_class->seek = fu_partial_input_stream_seek; object_class->finalize = fu_partial_input_stream_finalize; } static void fu_partial_input_stream_init(FuPartialInputStream *self) { }