/src/fwupd/libfwupdplugin/fu-stream-input-stream.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright 2026 Red Hat |
3 | | * |
4 | | * SPDX-License-Identifier: LGPL-2.1-or-later |
5 | | */ |
6 | | |
7 | 0 | #define G_LOG_DOMAIN "FuStreamInputStream" |
8 | | |
9 | | #include "config.h" |
10 | | |
11 | | #include "fu-stream-input-stream-private.h" |
12 | | #include "fu-stream-input-stream.h" |
13 | | |
14 | | /** |
15 | | * FuStreamInputStream: |
16 | | * |
17 | | * An input stream that wraps a #GInputStream (or subclass) into the |
18 | | * #FuInputStream type hierarchy. |
19 | | */ |
20 | | |
21 | | typedef struct { |
22 | | GInputStream *base_stream; /* nocheck:blocked */ |
23 | | } FuStreamInputStreamPrivate; |
24 | | |
25 | | static void |
26 | | fu_stream_input_stream_seekable_iface_init(GSeekableIface *iface); |
27 | | |
28 | 106k | G_DEFINE_TYPE_WITH_CODE(FuStreamInputStream, |
29 | 106k | fu_stream_input_stream, |
30 | 106k | FU_TYPE_INPUT_STREAM, |
31 | 106k | G_ADD_PRIVATE(FuStreamInputStream) |
32 | 106k | G_IMPLEMENT_INTERFACE(G_TYPE_SEEKABLE, |
33 | 106k | fu_stream_input_stream_seekable_iface_init)) |
34 | 106k | |
35 | 106k | static gssize |
36 | 106k | fu_stream_input_stream_read(GInputStream *stream, |
37 | 106k | void *buffer, |
38 | 106k | gsize count, |
39 | 106k | GCancellable *cancellable, |
40 | 106k | GError **error) |
41 | 106k | { |
42 | 39.5k | FuStreamInputStream *self = FU_STREAM_INPUT_STREAM(stream); |
43 | 39.5k | FuStreamInputStreamPrivate *priv = fu_stream_input_stream_get_instance_private(self); |
44 | | |
45 | 39.5k | g_return_val_if_fail(priv->base_stream != NULL, -1); |
46 | | |
47 | 39.5k | return g_input_stream_read(priv->base_stream, buffer, count, cancellable, error); |
48 | 39.5k | } |
49 | | |
50 | | static goffset |
51 | | fu_stream_input_stream_tell(GSeekable *seekable) |
52 | 0 | { |
53 | 0 | FuStreamInputStream *self = FU_STREAM_INPUT_STREAM(seekable); |
54 | 0 | FuStreamInputStreamPrivate *priv = fu_stream_input_stream_get_instance_private(self); |
55 | |
|
56 | 0 | if (!G_IS_SEEKABLE(priv->base_stream)) |
57 | 0 | return 0; |
58 | | |
59 | 0 | return g_seekable_tell(G_SEEKABLE(priv->base_stream)); |
60 | 0 | } |
61 | | |
62 | | static gboolean |
63 | | fu_stream_input_stream_can_seek(GSeekable *seekable) |
64 | 16.7k | { |
65 | 16.7k | FuStreamInputStream *self = FU_STREAM_INPUT_STREAM(seekable); |
66 | 16.7k | FuStreamInputStreamPrivate *priv = fu_stream_input_stream_get_instance_private(self); |
67 | | |
68 | 16.7k | if (!G_IS_SEEKABLE(priv->base_stream)) |
69 | 16.7k | return FALSE; |
70 | | |
71 | 0 | return g_seekable_can_seek(G_SEEKABLE(priv->base_stream)); |
72 | 16.7k | } |
73 | | |
74 | | static gboolean |
75 | | fu_stream_input_stream_seek(GSeekable *seekable, |
76 | | goffset offset, |
77 | | GSeekType type, |
78 | | GCancellable *cancellable, |
79 | | GError **error) |
80 | 0 | { |
81 | 0 | FuStreamInputStream *self = FU_STREAM_INPUT_STREAM(seekable); |
82 | 0 | FuStreamInputStreamPrivate *priv = fu_stream_input_stream_get_instance_private(self); |
83 | |
|
84 | 0 | if (!G_IS_SEEKABLE(priv->base_stream)) { |
85 | 0 | g_set_error_literal(error, |
86 | 0 | G_IO_ERROR, |
87 | 0 | G_IO_ERROR_NOT_SUPPORTED, |
88 | 0 | "base stream is not seekable"); /* nocheck:error */ |
89 | 0 | return FALSE; |
90 | 0 | } |
91 | | |
92 | 0 | return g_seekable_seek(G_SEEKABLE(priv->base_stream), offset, type, cancellable, error); |
93 | 0 | } |
94 | | |
95 | | static gboolean |
96 | | fu_stream_input_stream_can_truncate(GSeekable *seekable) |
97 | 0 | { |
98 | 0 | return FALSE; |
99 | 0 | } |
100 | | |
101 | | static gboolean |
102 | | fu_stream_input_stream_truncate(GSeekable *seekable, |
103 | | goffset offset, |
104 | | GCancellable *cancellable, |
105 | | GError **error) |
106 | 0 | { |
107 | 0 | g_set_error_literal(error, |
108 | 0 | FWUPD_ERROR, |
109 | 0 | FWUPD_ERROR_NOT_SUPPORTED, |
110 | 0 | "cannot truncate FuStreamInputStream"); |
111 | 0 | return FALSE; |
112 | 0 | } |
113 | | |
114 | | static void |
115 | | fu_stream_input_stream_seekable_iface_init(GSeekableIface *iface) |
116 | 4 | { |
117 | 4 | iface->tell = fu_stream_input_stream_tell; |
118 | 4 | iface->can_seek = fu_stream_input_stream_can_seek; |
119 | 4 | iface->seek = fu_stream_input_stream_seek; |
120 | 4 | iface->can_truncate = fu_stream_input_stream_can_truncate; |
121 | 4 | iface->truncate_fn = fu_stream_input_stream_truncate; |
122 | 4 | } |
123 | | |
124 | | static void |
125 | | fu_stream_input_stream_finalize(GObject *object) |
126 | 16.7k | { |
127 | 16.7k | FuStreamInputStream *self = FU_STREAM_INPUT_STREAM(object); |
128 | 16.7k | FuStreamInputStreamPrivate *priv = fu_stream_input_stream_get_instance_private(self); |
129 | 16.7k | g_clear_object(&priv->base_stream); |
130 | 16.7k | G_OBJECT_CLASS(fu_stream_input_stream_parent_class)->finalize(object); |
131 | 16.7k | } |
132 | | |
133 | | static void |
134 | | fu_stream_input_stream_class_init(FuStreamInputStreamClass *klass) |
135 | 4 | { |
136 | 4 | GObjectClass *object_class = G_OBJECT_CLASS(klass); |
137 | 4 | GInputStreamClass *istream_class = G_INPUT_STREAM_CLASS(klass); /* nocheck:blocked */ |
138 | 4 | object_class->finalize = fu_stream_input_stream_finalize; |
139 | 4 | istream_class->read_fn = fu_stream_input_stream_read; |
140 | 4 | } |
141 | | |
142 | | static void |
143 | | fu_stream_input_stream_init(FuStreamInputStream *self) |
144 | 16.7k | { |
145 | 16.7k | } |
146 | | |
147 | | /** |
148 | | * fu_stream_input_stream_set_base_stream: |
149 | | * @self: a #FuStreamInputStream |
150 | | * @base_stream: (transfer none): a #GInputStream |
151 | | * |
152 | | * Sets the underlying #GInputStream that this stream wraps. |
153 | | * The @base_stream is reffed. |
154 | | * This is intended for use by subclasses during construction. |
155 | | * |
156 | | * Since: 2.0.7 |
157 | | **/ |
158 | | void |
159 | | fu_stream_input_stream_set_base_stream(FuStreamInputStream *self, GInputStream *base_stream) |
160 | 16.7k | { |
161 | 16.7k | FuStreamInputStreamPrivate *priv = fu_stream_input_stream_get_instance_private(self); |
162 | | |
163 | 16.7k | g_return_if_fail(FU_IS_STREAM_INPUT_STREAM(self)); |
164 | 16.7k | g_return_if_fail(G_IS_INPUT_STREAM(base_stream)); |
165 | | |
166 | 16.7k | g_set_object(&priv->base_stream, base_stream); |
167 | 16.7k | } |
168 | | |
169 | | /** |
170 | | * fu_stream_input_stream_from_stream: |
171 | | * @stream: (transfer none): a #GInputStream |
172 | | * |
173 | | * Wraps a #GInputStream and returns a #FuStreamInputStream. The @stream |
174 | | * is reffed and future operations on this input stream apply to the |
175 | | * underlying #GInputStream. |
176 | | * |
177 | | * Returns: (transfer full): a #FuStreamInputStream, or %NULL on error |
178 | | * |
179 | | * Since: 2.0.7 |
180 | | **/ |
181 | | FuInputStream * |
182 | | fu_stream_input_stream_from_stream(GInputStream *stream) |
183 | 0 | { |
184 | 0 | g_autoptr(FuStreamInputStream) self = NULL; |
185 | |
|
186 | 0 | g_return_val_if_fail(G_IS_INPUT_STREAM(stream), NULL); |
187 | | |
188 | 0 | self = g_object_new(FU_TYPE_STREAM_INPUT_STREAM, NULL); |
189 | 0 | fu_stream_input_stream_set_base_stream(self, stream); |
190 | |
|
191 | 0 | return FU_INPUT_STREAM(g_steal_pointer(&self)); |
192 | 0 | } |