nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* GIO - GLib Input, Output and Streaming Library |
2 | * |
||
3 | * Copyright (C) 2006-2007 Red Hat, Inc. |
||
4 | * |
||
5 | * This library is free software; you can redistribute it and/or |
||
6 | * modify it under the terms of the GNU Lesser General Public |
||
7 | * License as published by the Free Software Foundation; either |
||
8 | * version 2 of the License, or (at your option) any later version. |
||
9 | * |
||
10 | * This library is distributed in the hope that it will be useful, |
||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||
13 | * Lesser General Public License for more details. |
||
14 | * |
||
15 | * You should have received a copy of the GNU Lesser General |
||
16 | * Public License along with this library; if not, see <http://www.gnu.org/licenses/>. |
||
17 | * |
||
18 | * Author: Christian Kellner <gicmo@gnome.org> |
||
19 | */ |
||
20 | |||
21 | #include "config.h" |
||
22 | #include "gmemoryinputstream.h" |
||
23 | #include "gpollableinputstream.h" |
||
24 | #include "ginputstream.h" |
||
25 | #include "gseekable.h" |
||
26 | #include "string.h" |
||
27 | #include "gtask.h" |
||
28 | #include "gioerror.h" |
||
29 | #include "glibintl.h" |
||
30 | |||
31 | |||
32 | /** |
||
33 | * SECTION:gmemoryinputstream |
||
34 | * @short_description: Streaming input operations on memory chunks |
||
35 | * @include: gio/gio.h |
||
36 | * @see_also: #GMemoryOutputStream |
||
37 | * |
||
38 | * #GMemoryInputStream is a class for using arbitrary |
||
39 | * memory chunks as input for GIO streaming input operations. |
||
40 | * |
||
41 | * As of GLib 2.34, #GMemoryInputStream implements |
||
42 | * #GPollableInputStream. |
||
43 | */ |
||
44 | |||
45 | struct _GMemoryInputStreamPrivate { |
||
46 | GSList *chunks; |
||
47 | gsize len; |
||
48 | gsize pos; |
||
49 | }; |
||
50 | |||
51 | static gssize g_memory_input_stream_read (GInputStream *stream, |
||
52 | void *buffer, |
||
53 | gsize count, |
||
54 | GCancellable *cancellable, |
||
55 | GError **error); |
||
56 | static gssize g_memory_input_stream_skip (GInputStream *stream, |
||
57 | gsize count, |
||
58 | GCancellable *cancellable, |
||
59 | GError **error); |
||
60 | static gboolean g_memory_input_stream_close (GInputStream *stream, |
||
61 | GCancellable *cancellable, |
||
62 | GError **error); |
||
63 | static void g_memory_input_stream_skip_async (GInputStream *stream, |
||
64 | gsize count, |
||
65 | int io_priority, |
||
66 | GCancellable *cancellabl, |
||
67 | GAsyncReadyCallback callback, |
||
68 | gpointer datae); |
||
69 | static gssize g_memory_input_stream_skip_finish (GInputStream *stream, |
||
70 | GAsyncResult *result, |
||
71 | GError **error); |
||
72 | static void g_memory_input_stream_close_async (GInputStream *stream, |
||
73 | int io_priority, |
||
74 | GCancellable *cancellabl, |
||
75 | GAsyncReadyCallback callback, |
||
76 | gpointer data); |
||
77 | static gboolean g_memory_input_stream_close_finish (GInputStream *stream, |
||
78 | GAsyncResult *result, |
||
79 | GError **error); |
||
80 | |||
81 | static void g_memory_input_stream_seekable_iface_init (GSeekableIface *iface); |
||
82 | static goffset g_memory_input_stream_tell (GSeekable *seekable); |
||
83 | static gboolean g_memory_input_stream_can_seek (GSeekable *seekable); |
||
84 | static gboolean g_memory_input_stream_seek (GSeekable *seekable, |
||
85 | goffset offset, |
||
86 | GSeekType type, |
||
87 | GCancellable *cancellable, |
||
88 | GError **error); |
||
89 | static gboolean g_memory_input_stream_can_truncate (GSeekable *seekable); |
||
90 | static gboolean g_memory_input_stream_truncate (GSeekable *seekable, |
||
91 | goffset offset, |
||
92 | GCancellable *cancellable, |
||
93 | GError **error); |
||
94 | |||
95 | static void g_memory_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface); |
||
96 | static gboolean g_memory_input_stream_is_readable (GPollableInputStream *stream); |
||
97 | static GSource *g_memory_input_stream_create_source (GPollableInputStream *stream, |
||
98 | GCancellable *cancellable); |
||
99 | |||
100 | static void g_memory_input_stream_finalize (GObject *object); |
||
101 | |||
102 | G_DEFINE_TYPE_WITH_CODE (GMemoryInputStream, g_memory_input_stream, G_TYPE_INPUT_STREAM, |
||
103 | G_ADD_PRIVATE (GMemoryInputStream) |
||
104 | G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE, |
||
105 | g_memory_input_stream_seekable_iface_init); |
||
106 | G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_INPUT_STREAM, |
||
107 | g_memory_input_stream_pollable_iface_init); |
||
108 | ) |
||
109 | |||
110 | |||
111 | static void |
||
112 | g_memory_input_stream_class_init (GMemoryInputStreamClass *klass) |
||
113 | { |
||
114 | GObjectClass *object_class; |
||
115 | GInputStreamClass *istream_class; |
||
116 | |||
117 | object_class = G_OBJECT_CLASS (klass); |
||
118 | object_class->finalize = g_memory_input_stream_finalize; |
||
119 | |||
120 | istream_class = G_INPUT_STREAM_CLASS (klass); |
||
121 | istream_class->read_fn = g_memory_input_stream_read; |
||
122 | istream_class->skip = g_memory_input_stream_skip; |
||
123 | istream_class->close_fn = g_memory_input_stream_close; |
||
124 | |||
125 | istream_class->skip_async = g_memory_input_stream_skip_async; |
||
126 | istream_class->skip_finish = g_memory_input_stream_skip_finish; |
||
127 | istream_class->close_async = g_memory_input_stream_close_async; |
||
128 | istream_class->close_finish = g_memory_input_stream_close_finish; |
||
129 | } |
||
130 | |||
131 | static void |
||
132 | g_memory_input_stream_finalize (GObject *object) |
||
133 | { |
||
134 | GMemoryInputStream *stream; |
||
135 | GMemoryInputStreamPrivate *priv; |
||
136 | |||
137 | stream = G_MEMORY_INPUT_STREAM (object); |
||
138 | priv = stream->priv; |
||
139 | |||
140 | g_slist_free_full (priv->chunks, (GDestroyNotify)g_bytes_unref); |
||
141 | |||
142 | G_OBJECT_CLASS (g_memory_input_stream_parent_class)->finalize (object); |
||
143 | } |
||
144 | |||
145 | static void |
||
146 | g_memory_input_stream_seekable_iface_init (GSeekableIface *iface) |
||
147 | { |
||
148 | iface->tell = g_memory_input_stream_tell; |
||
149 | iface->can_seek = g_memory_input_stream_can_seek; |
||
150 | iface->seek = g_memory_input_stream_seek; |
||
151 | iface->can_truncate = g_memory_input_stream_can_truncate; |
||
152 | iface->truncate_fn = g_memory_input_stream_truncate; |
||
153 | } |
||
154 | |||
155 | static void |
||
156 | g_memory_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface) |
||
157 | { |
||
158 | iface->is_readable = g_memory_input_stream_is_readable; |
||
159 | iface->create_source = g_memory_input_stream_create_source; |
||
160 | } |
||
161 | |||
162 | static void |
||
163 | g_memory_input_stream_init (GMemoryInputStream *stream) |
||
164 | { |
||
165 | stream->priv = g_memory_input_stream_get_instance_private (stream); |
||
166 | } |
||
167 | |||
168 | /** |
||
169 | * g_memory_input_stream_new: |
||
170 | * |
||
171 | * Creates a new empty #GMemoryInputStream. |
||
172 | * |
||
173 | * Returns: a new #GInputStream |
||
174 | */ |
||
175 | GInputStream * |
||
176 | g_memory_input_stream_new (void) |
||
177 | { |
||
178 | GInputStream *stream; |
||
179 | |||
180 | stream = g_object_new (G_TYPE_MEMORY_INPUT_STREAM, NULL); |
||
181 | |||
182 | return stream; |
||
183 | } |
||
184 | |||
185 | /** |
||
186 | * g_memory_input_stream_new_from_data: |
||
187 | * @data: (array length=len) (element-type guint8) (transfer full): input data |
||
188 | * @len: length of the data, may be -1 if @data is a nul-terminated string |
||
189 | * @destroy: (allow-none): function that is called to free @data, or %NULL |
||
190 | * |
||
191 | * Creates a new #GMemoryInputStream with data in memory of a given size. |
||
192 | * |
||
193 | * Returns: new #GInputStream read from @data of @len bytes. |
||
194 | **/ |
||
195 | GInputStream * |
||
196 | g_memory_input_stream_new_from_data (const void *data, |
||
197 | gssize len, |
||
198 | GDestroyNotify destroy) |
||
199 | { |
||
200 | GInputStream *stream; |
||
201 | |||
202 | stream = g_memory_input_stream_new (); |
||
203 | |||
204 | g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (stream), |
||
205 | data, len, destroy); |
||
206 | |||
207 | return stream; |
||
208 | } |
||
209 | |||
210 | /** |
||
211 | * g_memory_input_stream_new_from_bytes: |
||
212 | * @bytes: a #GBytes |
||
213 | * |
||
214 | * Creates a new #GMemoryInputStream with data from the given @bytes. |
||
215 | * |
||
216 | * Returns: new #GInputStream read from @bytes |
||
217 | * |
||
218 | * Since: 2.34 |
||
219 | **/ |
||
220 | GInputStream * |
||
221 | g_memory_input_stream_new_from_bytes (GBytes *bytes) |
||
222 | { |
||
223 | |||
224 | GInputStream *stream; |
||
225 | |||
226 | stream = g_memory_input_stream_new (); |
||
227 | |||
228 | g_memory_input_stream_add_bytes (G_MEMORY_INPUT_STREAM (stream), |
||
229 | bytes); |
||
230 | |||
231 | return stream; |
||
232 | } |
||
233 | |||
234 | /** |
||
235 | * g_memory_input_stream_add_data: |
||
236 | * @stream: a #GMemoryInputStream |
||
237 | * @data: (array length=len) (element-type guint8) (transfer full): input data |
||
238 | * @len: length of the data, may be -1 if @data is a nul-terminated string |
||
239 | * @destroy: (allow-none): function that is called to free @data, or %NULL |
||
240 | * |
||
241 | * Appends @data to data that can be read from the input stream |
||
242 | */ |
||
243 | void |
||
244 | g_memory_input_stream_add_data (GMemoryInputStream *stream, |
||
245 | const void *data, |
||
246 | gssize len, |
||
247 | GDestroyNotify destroy) |
||
248 | { |
||
249 | GBytes *bytes; |
||
250 | |||
251 | if (len == -1) |
||
252 | len = strlen (data); |
||
253 | |||
254 | /* It's safe to discard the const here because we're chaining the |
||
255 | * destroy callback. |
||
256 | */ |
||
257 | bytes = g_bytes_new_with_free_func (data, len, destroy, (void*)data); |
||
258 | |||
259 | g_memory_input_stream_add_bytes (stream, bytes); |
||
260 | |||
261 | g_bytes_unref (bytes); |
||
262 | } |
||
263 | |||
264 | /** |
||
265 | * g_memory_input_stream_add_bytes: |
||
266 | * @stream: a #GMemoryInputStream |
||
267 | * @bytes: input data |
||
268 | * |
||
269 | * Appends @bytes to data that can be read from the input stream. |
||
270 | * |
||
271 | * Since: 2.34 |
||
272 | */ |
||
273 | void |
||
274 | g_memory_input_stream_add_bytes (GMemoryInputStream *stream, |
||
275 | GBytes *bytes) |
||
276 | { |
||
277 | GMemoryInputStreamPrivate *priv; |
||
278 | |||
279 | g_return_if_fail (G_IS_MEMORY_INPUT_STREAM (stream)); |
||
280 | g_return_if_fail (bytes != NULL); |
||
281 | |||
282 | priv = stream->priv; |
||
283 | |||
284 | priv->chunks = g_slist_append (priv->chunks, g_bytes_ref (bytes)); |
||
285 | priv->len += g_bytes_get_size (bytes); |
||
286 | } |
||
287 | |||
288 | static gssize |
||
289 | g_memory_input_stream_read (GInputStream *stream, |
||
290 | void *buffer, |
||
291 | gsize count, |
||
292 | GCancellable *cancellable, |
||
293 | GError **error) |
||
294 | { |
||
295 | GMemoryInputStream *memory_stream; |
||
296 | GMemoryInputStreamPrivate *priv; |
||
297 | GSList *l; |
||
298 | GBytes *chunk; |
||
299 | gsize len; |
||
300 | gsize offset, start, rest, size; |
||
301 | |||
302 | memory_stream = G_MEMORY_INPUT_STREAM (stream); |
||
303 | priv = memory_stream->priv; |
||
304 | |||
305 | count = MIN (count, priv->len - priv->pos); |
||
306 | |||
307 | offset = 0; |
||
308 | for (l = priv->chunks; l; l = l->next) |
||
309 | { |
||
310 | chunk = (GBytes *)l->data; |
||
311 | len = g_bytes_get_size (chunk); |
||
312 | |||
313 | if (offset + len > priv->pos) |
||
314 | break; |
||
315 | |||
316 | offset += len; |
||
317 | } |
||
318 | |||
319 | start = priv->pos - offset; |
||
320 | rest = count; |
||
321 | |||
322 | for (; l && rest > 0; l = l->next) |
||
323 | { |
||
324 | const guint8* chunk_data; |
||
325 | chunk = (GBytes *)l->data; |
||
326 | |||
327 | chunk_data = g_bytes_get_data (chunk, &len); |
||
328 | |||
329 | size = MIN (rest, len - start); |
||
330 | |||
331 | memcpy ((guint8 *)buffer + (count - rest), chunk_data + start, size); |
||
332 | rest -= size; |
||
333 | |||
334 | start = 0; |
||
335 | } |
||
336 | |||
337 | priv->pos += count; |
||
338 | |||
339 | return count; |
||
340 | } |
||
341 | |||
342 | static gssize |
||
343 | g_memory_input_stream_skip (GInputStream *stream, |
||
344 | gsize count, |
||
345 | GCancellable *cancellable, |
||
346 | GError **error) |
||
347 | { |
||
348 | GMemoryInputStream *memory_stream; |
||
349 | GMemoryInputStreamPrivate *priv; |
||
350 | |||
351 | memory_stream = G_MEMORY_INPUT_STREAM (stream); |
||
352 | priv = memory_stream->priv; |
||
353 | |||
354 | count = MIN (count, priv->len - priv->pos); |
||
355 | priv->pos += count; |
||
356 | |||
357 | return count; |
||
358 | } |
||
359 | |||
360 | static gboolean |
||
361 | g_memory_input_stream_close (GInputStream *stream, |
||
362 | GCancellable *cancellable, |
||
363 | GError **error) |
||
364 | { |
||
365 | return TRUE; |
||
366 | } |
||
367 | |||
368 | static void |
||
369 | g_memory_input_stream_skip_async (GInputStream *stream, |
||
370 | gsize count, |
||
371 | int io_priority, |
||
372 | GCancellable *cancellable, |
||
373 | GAsyncReadyCallback callback, |
||
374 | gpointer user_data) |
||
375 | { |
||
376 | GTask *task; |
||
377 | gssize nskipped; |
||
378 | GError *error = NULL; |
||
379 | |||
380 | nskipped = G_INPUT_STREAM_GET_CLASS (stream)->skip (stream, count, cancellable, &error); |
||
381 | task = g_task_new (stream, cancellable, callback, user_data); |
||
382 | if (error) |
||
383 | g_task_return_error (task, error); |
||
384 | else |
||
385 | g_task_return_int (task, nskipped); |
||
386 | g_object_unref (task); |
||
387 | } |
||
388 | |||
389 | static gssize |
||
390 | g_memory_input_stream_skip_finish (GInputStream *stream, |
||
391 | GAsyncResult *result, |
||
392 | GError **error) |
||
393 | { |
||
394 | g_return_val_if_fail (g_task_is_valid (result, stream), -1); |
||
395 | |||
396 | return g_task_propagate_int (G_TASK (result), error); |
||
397 | } |
||
398 | |||
399 | static void |
||
400 | g_memory_input_stream_close_async (GInputStream *stream, |
||
401 | int io_priority, |
||
402 | GCancellable *cancellable, |
||
403 | GAsyncReadyCallback callback, |
||
404 | gpointer user_data) |
||
405 | { |
||
406 | GTask *task; |
||
407 | |||
408 | task = g_task_new (stream, cancellable, callback, user_data); |
||
409 | g_task_return_boolean (task, TRUE); |
||
410 | g_object_unref (task); |
||
411 | } |
||
412 | |||
413 | static gboolean |
||
414 | g_memory_input_stream_close_finish (GInputStream *stream, |
||
415 | GAsyncResult *result, |
||
416 | GError **error) |
||
417 | { |
||
418 | return TRUE; |
||
419 | } |
||
420 | |||
421 | static goffset |
||
422 | g_memory_input_stream_tell (GSeekable *seekable) |
||
423 | { |
||
424 | GMemoryInputStream *memory_stream; |
||
425 | GMemoryInputStreamPrivate *priv; |
||
426 | |||
427 | memory_stream = G_MEMORY_INPUT_STREAM (seekable); |
||
428 | priv = memory_stream->priv; |
||
429 | |||
430 | return priv->pos; |
||
431 | } |
||
432 | |||
433 | static |
||
434 | gboolean g_memory_input_stream_can_seek (GSeekable *seekable) |
||
435 | { |
||
436 | return TRUE; |
||
437 | } |
||
438 | |||
439 | static gboolean |
||
440 | g_memory_input_stream_seek (GSeekable *seekable, |
||
441 | goffset offset, |
||
442 | GSeekType type, |
||
443 | GCancellable *cancellable, |
||
444 | GError **error) |
||
445 | { |
||
446 | GMemoryInputStream *memory_stream; |
||
447 | GMemoryInputStreamPrivate *priv; |
||
448 | goffset absolute; |
||
449 | |||
450 | memory_stream = G_MEMORY_INPUT_STREAM (seekable); |
||
451 | priv = memory_stream->priv; |
||
452 | |||
453 | switch (type) |
||
454 | { |
||
455 | case G_SEEK_CUR: |
||
456 | absolute = priv->pos + offset; |
||
457 | break; |
||
458 | |||
459 | case G_SEEK_SET: |
||
460 | absolute = offset; |
||
461 | break; |
||
462 | |||
463 | case G_SEEK_END: |
||
464 | absolute = priv->len + offset; |
||
465 | break; |
||
466 | |||
467 | default: |
||
468 | g_set_error_literal (error, |
||
469 | G_IO_ERROR, |
||
470 | G_IO_ERROR_INVALID_ARGUMENT, |
||
471 | _("Invalid GSeekType supplied")); |
||
472 | |||
473 | return FALSE; |
||
474 | } |
||
475 | |||
476 | if (absolute < 0 || absolute > priv->len) |
||
477 | { |
||
478 | g_set_error_literal (error, |
||
479 | G_IO_ERROR, |
||
480 | G_IO_ERROR_INVALID_ARGUMENT, |
||
481 | _("Invalid seek request")); |
||
482 | return FALSE; |
||
483 | } |
||
484 | |||
485 | priv->pos = absolute; |
||
486 | |||
487 | return TRUE; |
||
488 | } |
||
489 | |||
490 | static gboolean |
||
491 | g_memory_input_stream_can_truncate (GSeekable *seekable) |
||
492 | { |
||
493 | return FALSE; |
||
494 | } |
||
495 | |||
496 | static gboolean |
||
497 | g_memory_input_stream_truncate (GSeekable *seekable, |
||
498 | goffset offset, |
||
499 | GCancellable *cancellable, |
||
500 | GError **error) |
||
501 | { |
||
502 | g_set_error_literal (error, |
||
503 | G_IO_ERROR, |
||
504 | G_IO_ERROR_NOT_SUPPORTED, |
||
505 | _("Cannot truncate GMemoryInputStream")); |
||
506 | return FALSE; |
||
507 | } |
||
508 | |||
509 | static gboolean |
||
510 | g_memory_input_stream_is_readable (GPollableInputStream *stream) |
||
511 | { |
||
512 | return TRUE; |
||
513 | } |
||
514 | |||
515 | static GSource * |
||
516 | g_memory_input_stream_create_source (GPollableInputStream *stream, |
||
517 | GCancellable *cancellable) |
||
518 | { |
||
519 | GSource *base_source, *pollable_source; |
||
520 | |||
521 | base_source = g_timeout_source_new (0); |
||
522 | pollable_source = g_pollable_source_new_full (stream, base_source, |
||
523 | cancellable); |
||
524 | g_source_unref (base_source); |
||
525 | |||
526 | return pollable_source; |
||
527 | } |