Branch data Line data Source code
1 : : /* GIO - GLib Input, Output and Streaming Library
2 : : *
3 : : * Copyright (C) 2006-2007 Red Hat, Inc.
4 : : *
5 : : * SPDX-License-Identifier: LGPL-2.1-or-later
6 : : *
7 : : * This library is free software; you can redistribute it and/or
8 : : * modify it under the terms of the GNU Lesser General Public
9 : : * License as published by the Free Software Foundation; either
10 : : * version 2.1 of the License, or (at your option) any later version.
11 : : *
12 : : * This library is distributed in the hope that it will be useful,
13 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : * Lesser General Public License for more details.
16 : : *
17 : : * You should have received a copy of the GNU Lesser General
18 : : * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 : : *
20 : : * Author: Alexander Larsson <alexl@redhat.com>
21 : : */
22 : :
23 : : #include "config.h"
24 : : #include <string.h>
25 : : #include "gdataoutputstream.h"
26 : : #include "gseekable.h"
27 : : #include "gioenumtypes.h"
28 : : #include "gioerror.h"
29 : : #include "glibintl.h"
30 : :
31 : :
32 : : /**
33 : : * GDataOutputStream:
34 : : *
35 : : * Data output stream implements [class@Gio.OutputStream] and includes functions
36 : : * for writing data directly to an output stream.
37 : : */
38 : :
39 : :
40 : : struct _GDataOutputStreamPrivate {
41 : : GDataStreamByteOrder byte_order;
42 : : };
43 : :
44 : : enum {
45 : : PROP_0,
46 : : PROP_BYTE_ORDER
47 : : };
48 : :
49 : : static void g_data_output_stream_set_property (GObject *object,
50 : : guint prop_id,
51 : : const GValue *value,
52 : : GParamSpec *pspec);
53 : : static void g_data_output_stream_get_property (GObject *object,
54 : : guint prop_id,
55 : : GValue *value,
56 : : GParamSpec *pspec);
57 : :
58 : : static void g_data_output_stream_seekable_iface_init (GSeekableIface *iface);
59 : : static goffset g_data_output_stream_tell (GSeekable *seekable);
60 : : static gboolean g_data_output_stream_can_seek (GSeekable *seekable);
61 : : static gboolean g_data_output_stream_seek (GSeekable *seekable,
62 : : goffset offset,
63 : : GSeekType type,
64 : : GCancellable *cancellable,
65 : : GError **error);
66 : : static gboolean g_data_output_stream_can_truncate (GSeekable *seekable);
67 : : static gboolean g_data_output_stream_truncate (GSeekable *seekable,
68 : : goffset offset,
69 : : GCancellable *cancellable,
70 : : GError **error);
71 : :
72 : 113450 : G_DEFINE_TYPE_WITH_CODE (GDataOutputStream,
73 : : g_data_output_stream,
74 : : G_TYPE_FILTER_OUTPUT_STREAM,
75 : : G_ADD_PRIVATE (GDataOutputStream)
76 : : G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,
77 : : g_data_output_stream_seekable_iface_init))
78 : :
79 : :
80 : : static void
81 : 101 : g_data_output_stream_class_init (GDataOutputStreamClass *klass)
82 : : {
83 : : GObjectClass *object_class;
84 : :
85 : 101 : object_class = G_OBJECT_CLASS (klass);
86 : 101 : object_class->get_property = g_data_output_stream_get_property;
87 : 101 : object_class->set_property = g_data_output_stream_set_property;
88 : :
89 : : /**
90 : : * GDataOutputStream:byte-order:
91 : : *
92 : : * Determines the byte ordering that is used when writing
93 : : * multi-byte entities (such as integers) to the stream.
94 : : */
95 : 101 : g_object_class_install_property (object_class,
96 : : PROP_BYTE_ORDER,
97 : : g_param_spec_enum ("byte-order", NULL, NULL,
98 : : G_TYPE_DATA_STREAM_BYTE_ORDER,
99 : : G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN,
100 : : G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_BLURB));
101 : :
102 : 101 : }
103 : :
104 : : static void
105 : 1 : g_data_output_stream_set_property (GObject *object,
106 : : guint prop_id,
107 : : const GValue *value,
108 : : GParamSpec *pspec)
109 : : {
110 : : GDataOutputStream *dstream;
111 : :
112 : 1 : dstream = G_DATA_OUTPUT_STREAM (object);
113 : :
114 : 1 : switch (prop_id)
115 : : {
116 : 1 : case PROP_BYTE_ORDER:
117 : 1 : g_data_output_stream_set_byte_order (dstream, g_value_get_enum (value));
118 : 1 : break;
119 : :
120 : 0 : default:
121 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
122 : 0 : break;
123 : : }
124 : 1 : }
125 : :
126 : : static void
127 : 1 : g_data_output_stream_get_property (GObject *object,
128 : : guint prop_id,
129 : : GValue *value,
130 : : GParamSpec *pspec)
131 : : {
132 : : GDataOutputStreamPrivate *priv;
133 : : GDataOutputStream *dstream;
134 : :
135 : 1 : dstream = G_DATA_OUTPUT_STREAM (object);
136 : 1 : priv = dstream->priv;
137 : :
138 : 1 : switch (prop_id)
139 : : {
140 : 1 : case PROP_BYTE_ORDER:
141 : 1 : g_value_set_enum (value, priv->byte_order);
142 : 1 : break;
143 : :
144 : 0 : default:
145 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
146 : 0 : break;
147 : : }
148 : 1 : }
149 : :
150 : : static void
151 : 2256 : g_data_output_stream_init (GDataOutputStream *stream)
152 : : {
153 : 2256 : stream->priv = g_data_output_stream_get_instance_private (stream);
154 : 2256 : stream->priv->byte_order = G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN;
155 : 2256 : }
156 : :
157 : : static void
158 : 101 : g_data_output_stream_seekable_iface_init (GSeekableIface *iface)
159 : : {
160 : 101 : iface->tell = g_data_output_stream_tell;
161 : 101 : iface->can_seek = g_data_output_stream_can_seek;
162 : 101 : iface->seek = g_data_output_stream_seek;
163 : 101 : iface->can_truncate = g_data_output_stream_can_truncate;
164 : 101 : iface->truncate_fn = g_data_output_stream_truncate;
165 : 101 : }
166 : :
167 : : /**
168 : : * g_data_output_stream_new:
169 : : * @base_stream: a #GOutputStream.
170 : : *
171 : : * Creates a new data output stream for @base_stream.
172 : : *
173 : : * Returns: #GDataOutputStream.
174 : : **/
175 : : GDataOutputStream *
176 : 2256 : g_data_output_stream_new (GOutputStream *base_stream)
177 : : {
178 : : GDataOutputStream *stream;
179 : :
180 : 2256 : g_return_val_if_fail (G_IS_OUTPUT_STREAM (base_stream), NULL);
181 : :
182 : 2256 : stream = g_object_new (G_TYPE_DATA_OUTPUT_STREAM,
183 : : "base-stream", base_stream,
184 : : NULL);
185 : :
186 : 2256 : return stream;
187 : : }
188 : :
189 : : /**
190 : : * g_data_output_stream_set_byte_order:
191 : : * @stream: a #GDataOutputStream.
192 : : * @order: a %GDataStreamByteOrder.
193 : : *
194 : : * Sets the byte order of the data output stream to @order.
195 : : **/
196 : : void
197 : 30 : g_data_output_stream_set_byte_order (GDataOutputStream *stream,
198 : : GDataStreamByteOrder order)
199 : : {
200 : : GDataOutputStreamPrivate *priv;
201 : 30 : g_return_if_fail (G_IS_DATA_OUTPUT_STREAM (stream));
202 : 30 : priv = stream->priv;
203 : 30 : if (priv->byte_order != order)
204 : : {
205 : 18 : priv->byte_order = order;
206 : 18 : g_object_notify (G_OBJECT (stream), "byte-order");
207 : : }
208 : : }
209 : :
210 : : /**
211 : : * g_data_output_stream_get_byte_order:
212 : : * @stream: a #GDataOutputStream.
213 : : *
214 : : * Gets the byte order for the stream.
215 : : *
216 : : * Returns: the #GDataStreamByteOrder for the @stream.
217 : : **/
218 : : GDataStreamByteOrder
219 : 7 : g_data_output_stream_get_byte_order (GDataOutputStream *stream)
220 : : {
221 : 7 : g_return_val_if_fail (G_IS_DATA_OUTPUT_STREAM (stream), G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN);
222 : :
223 : 7 : return stream->priv->byte_order;
224 : : }
225 : :
226 : : /**
227 : : * g_data_output_stream_put_byte:
228 : : * @stream: a #GDataOutputStream.
229 : : * @data: a #guchar.
230 : : * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
231 : : * @error: a #GError, %NULL to ignore.
232 : : *
233 : : * Puts a byte into the output stream.
234 : : *
235 : : * Returns: %TRUE if @data was successfully added to the @stream.
236 : : **/
237 : : gboolean
238 : 70515 : g_data_output_stream_put_byte (GDataOutputStream *stream,
239 : : guchar data,
240 : : GCancellable *cancellable,
241 : : GError **error)
242 : : {
243 : : gsize bytes_written;
244 : :
245 : 70515 : g_return_val_if_fail (G_IS_DATA_OUTPUT_STREAM (stream), FALSE);
246 : :
247 : 70515 : return g_output_stream_write_all (G_OUTPUT_STREAM (stream),
248 : : &data, 1,
249 : : &bytes_written,
250 : : cancellable, error);
251 : : }
252 : :
253 : : /**
254 : : * g_data_output_stream_put_int16:
255 : : * @stream: a #GDataOutputStream.
256 : : * @data: a #gint16.
257 : : * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
258 : : * @error: a #GError, %NULL to ignore.
259 : : *
260 : : * Puts a signed 16-bit integer into the output stream.
261 : : *
262 : : * Returns: %TRUE if @data was successfully added to the @stream.
263 : : **/
264 : : gboolean
265 : 96 : g_data_output_stream_put_int16 (GDataOutputStream *stream,
266 : : gint16 data,
267 : : GCancellable *cancellable,
268 : : GError **error)
269 : : {
270 : : gsize bytes_written;
271 : :
272 : 96 : g_return_val_if_fail (G_IS_DATA_OUTPUT_STREAM (stream), FALSE);
273 : :
274 : 96 : switch (stream->priv->byte_order)
275 : : {
276 : 32 : case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
277 : 32 : data = GINT16_TO_BE (data);
278 : 32 : break;
279 : 32 : case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
280 : 32 : data = GINT16_TO_LE (data);
281 : 32 : break;
282 : 32 : case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
283 : : default:
284 : 32 : break;
285 : : }
286 : :
287 : 96 : return g_output_stream_write_all (G_OUTPUT_STREAM (stream),
288 : : &data, 2,
289 : : &bytes_written,
290 : : cancellable, error);
291 : : }
292 : :
293 : : /**
294 : : * g_data_output_stream_put_uint16:
295 : : * @stream: a #GDataOutputStream.
296 : : * @data: a #guint16.
297 : : * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
298 : : * @error: a #GError, %NULL to ignore.
299 : : *
300 : : * Puts an unsigned 16-bit integer into the output stream.
301 : : *
302 : : * Returns: %TRUE if @data was successfully added to the @stream.
303 : : **/
304 : : gboolean
305 : 104 : g_data_output_stream_put_uint16 (GDataOutputStream *stream,
306 : : guint16 data,
307 : : GCancellable *cancellable,
308 : : GError **error)
309 : : {
310 : : gsize bytes_written;
311 : :
312 : 104 : g_return_val_if_fail (G_IS_DATA_OUTPUT_STREAM (stream), FALSE);
313 : :
314 : 104 : switch (stream->priv->byte_order)
315 : : {
316 : 40 : case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
317 : 40 : data = GUINT16_TO_BE (data);
318 : 40 : break;
319 : 32 : case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
320 : 32 : data = GUINT16_TO_LE (data);
321 : 32 : break;
322 : 32 : case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
323 : : default:
324 : 32 : break;
325 : : }
326 : :
327 : 104 : return g_output_stream_write_all (G_OUTPUT_STREAM (stream),
328 : : &data, 2,
329 : : &bytes_written,
330 : : cancellable, error);
331 : : }
332 : :
333 : : /**
334 : : * g_data_output_stream_put_int32:
335 : : * @stream: a #GDataOutputStream.
336 : : * @data: a #gint32.
337 : : * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
338 : : * @error: a #GError, %NULL to ignore.
339 : : *
340 : : * Puts a signed 32-bit integer into the output stream.
341 : : *
342 : : * Returns: %TRUE if @data was successfully added to the @stream.
343 : : **/
344 : : gboolean
345 : 96 : g_data_output_stream_put_int32 (GDataOutputStream *stream,
346 : : gint32 data,
347 : : GCancellable *cancellable,
348 : : GError **error)
349 : : {
350 : : gsize bytes_written;
351 : :
352 : 96 : g_return_val_if_fail (G_IS_DATA_OUTPUT_STREAM (stream), FALSE);
353 : :
354 : 96 : switch (stream->priv->byte_order)
355 : : {
356 : 32 : case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
357 : 32 : data = GINT32_TO_BE (data);
358 : 32 : break;
359 : 32 : case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
360 : 32 : data = GINT32_TO_LE (data);
361 : 32 : break;
362 : 32 : case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
363 : : default:
364 : 32 : break;
365 : : }
366 : :
367 : 96 : return g_output_stream_write_all (G_OUTPUT_STREAM (stream),
368 : : &data, 4,
369 : : &bytes_written,
370 : : cancellable, error);
371 : : }
372 : :
373 : : /**
374 : : * g_data_output_stream_put_uint32:
375 : : * @stream: a #GDataOutputStream.
376 : : * @data: a #guint32.
377 : : * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
378 : : * @error: a #GError, %NULL to ignore.
379 : : *
380 : : * Puts an unsigned 32-bit integer into the stream.
381 : : *
382 : : * Returns: %TRUE if @data was successfully added to the @stream.
383 : : **/
384 : : gboolean
385 : 96 : g_data_output_stream_put_uint32 (GDataOutputStream *stream,
386 : : guint32 data,
387 : : GCancellable *cancellable,
388 : : GError **error)
389 : : {
390 : : gsize bytes_written;
391 : :
392 : 96 : g_return_val_if_fail (G_IS_DATA_OUTPUT_STREAM (stream), FALSE);
393 : :
394 : 96 : switch (stream->priv->byte_order)
395 : : {
396 : 32 : case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
397 : 32 : data = GUINT32_TO_BE (data);
398 : 32 : break;
399 : 32 : case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
400 : 32 : data = GUINT32_TO_LE (data);
401 : 32 : break;
402 : 32 : case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
403 : : default:
404 : 32 : break;
405 : : }
406 : :
407 : 96 : return g_output_stream_write_all (G_OUTPUT_STREAM (stream),
408 : : &data, 4,
409 : : &bytes_written,
410 : : cancellable, error);
411 : : }
412 : :
413 : : /**
414 : : * g_data_output_stream_put_int64:
415 : : * @stream: a #GDataOutputStream.
416 : : * @data: a #gint64.
417 : : * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
418 : : * @error: a #GError, %NULL to ignore.
419 : : *
420 : : * Puts a signed 64-bit integer into the stream.
421 : : *
422 : : * Returns: %TRUE if @data was successfully added to the @stream.
423 : : **/
424 : : gboolean
425 : 96 : g_data_output_stream_put_int64 (GDataOutputStream *stream,
426 : : gint64 data,
427 : : GCancellable *cancellable,
428 : : GError **error)
429 : : {
430 : : gsize bytes_written;
431 : :
432 : 96 : g_return_val_if_fail (G_IS_DATA_OUTPUT_STREAM (stream), FALSE);
433 : :
434 : 96 : switch (stream->priv->byte_order)
435 : : {
436 : 32 : case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
437 : 32 : data = GINT64_TO_BE (data);
438 : 32 : break;
439 : 32 : case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
440 : 32 : data = GINT64_TO_LE (data);
441 : 32 : break;
442 : 32 : case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
443 : : default:
444 : 32 : break;
445 : : }
446 : :
447 : 96 : return g_output_stream_write_all (G_OUTPUT_STREAM (stream),
448 : : &data, 8,
449 : : &bytes_written,
450 : : cancellable, error);
451 : : }
452 : :
453 : : /**
454 : : * g_data_output_stream_put_uint64:
455 : : * @stream: a #GDataOutputStream.
456 : : * @data: a #guint64.
457 : : * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
458 : : * @error: a #GError, %NULL to ignore.
459 : : *
460 : : * Puts an unsigned 64-bit integer into the stream.
461 : : *
462 : : * Returns: %TRUE if @data was successfully added to the @stream.
463 : : **/
464 : : gboolean
465 : 96 : g_data_output_stream_put_uint64 (GDataOutputStream *stream,
466 : : guint64 data,
467 : : GCancellable *cancellable,
468 : : GError **error)
469 : : {
470 : : gsize bytes_written;
471 : :
472 : 96 : g_return_val_if_fail (G_IS_DATA_OUTPUT_STREAM (stream), FALSE);
473 : :
474 : 96 : switch (stream->priv->byte_order)
475 : : {
476 : 32 : case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
477 : 32 : data = GUINT64_TO_BE (data);
478 : 32 : break;
479 : 32 : case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
480 : 32 : data = GUINT64_TO_LE (data);
481 : 32 : break;
482 : 32 : case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
483 : : default:
484 : 32 : break;
485 : : }
486 : :
487 : 96 : return g_output_stream_write_all (G_OUTPUT_STREAM (stream),
488 : : &data, 8,
489 : : &bytes_written,
490 : : cancellable, error);
491 : : }
492 : :
493 : : /**
494 : : * g_data_output_stream_put_string:
495 : : * @stream: a #GDataOutputStream.
496 : : * @str: a string.
497 : : * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
498 : : * @error: a #GError, %NULL to ignore.
499 : : *
500 : : * Puts a string into the output stream.
501 : : *
502 : : * Returns: %TRUE if @string was successfully added to the @stream.
503 : : **/
504 : : gboolean
505 : 21708 : g_data_output_stream_put_string (GDataOutputStream *stream,
506 : : const char *str,
507 : : GCancellable *cancellable,
508 : : GError **error)
509 : : {
510 : : gsize bytes_written;
511 : :
512 : 21708 : g_return_val_if_fail (G_IS_DATA_OUTPUT_STREAM (stream), FALSE);
513 : 21708 : g_return_val_if_fail (str != NULL, FALSE);
514 : :
515 : 21708 : return g_output_stream_write_all (G_OUTPUT_STREAM (stream),
516 : : str, strlen (str),
517 : : &bytes_written,
518 : : cancellable, error);
519 : : }
520 : :
521 : : static goffset
522 : 10 : g_data_output_stream_tell (GSeekable *seekable)
523 : : {
524 : : GOutputStream *base_stream;
525 : : GSeekable *base_stream_seekable;
526 : :
527 : 10 : base_stream = G_FILTER_OUTPUT_STREAM (seekable)->base_stream;
528 : 10 : if (!G_IS_SEEKABLE (base_stream))
529 : 0 : return 0;
530 : 10 : base_stream_seekable = G_SEEKABLE (base_stream);
531 : 10 : return g_seekable_tell (base_stream_seekable);
532 : : }
533 : :
534 : : static gboolean
535 : 0 : g_data_output_stream_can_seek (GSeekable *seekable)
536 : : {
537 : : GOutputStream *base_stream;
538 : :
539 : 0 : base_stream = G_FILTER_OUTPUT_STREAM (seekable)->base_stream;
540 : 0 : return G_IS_SEEKABLE (base_stream) && g_seekable_can_seek (G_SEEKABLE (base_stream));
541 : : }
542 : :
543 : : static gboolean
544 : 4 : g_data_output_stream_seek (GSeekable *seekable,
545 : : goffset offset,
546 : : GSeekType type,
547 : : GCancellable *cancellable,
548 : : GError **error)
549 : : {
550 : : GOutputStream *base_stream;
551 : : GSeekable *base_stream_seekable;
552 : :
553 : 4 : base_stream = G_FILTER_OUTPUT_STREAM (seekable)->base_stream;
554 : 4 : if (!G_IS_SEEKABLE (base_stream))
555 : : {
556 : 0 : g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
557 : : _("Seek not supported on base stream"));
558 : 0 : return FALSE;
559 : : }
560 : :
561 : 4 : base_stream_seekable = G_SEEKABLE (base_stream);
562 : 4 : return g_seekable_seek (base_stream_seekable, offset, type, cancellable, error);
563 : : }
564 : :
565 : : static gboolean
566 : 2 : g_data_output_stream_can_truncate (GSeekable *seekable)
567 : : {
568 : : GOutputStream *base_stream;
569 : :
570 : 2 : base_stream = G_FILTER_OUTPUT_STREAM (seekable)->base_stream;
571 : 2 : return G_IS_SEEKABLE (base_stream) && g_seekable_can_truncate (G_SEEKABLE (base_stream));
572 : : }
573 : :
574 : : static gboolean
575 : 3 : g_data_output_stream_truncate (GSeekable *seekable,
576 : : goffset offset,
577 : : GCancellable *cancellable,
578 : : GError **error)
579 : : {
580 : : GOutputStream *base_stream;
581 : : GSeekable *base_stream_seekable;
582 : :
583 : 3 : base_stream = G_FILTER_OUTPUT_STREAM (seekable)->base_stream;
584 : 3 : if (!G_IS_SEEKABLE (base_stream))
585 : : {
586 : 0 : g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
587 : : _("Truncate not supported on base stream"));
588 : 0 : return FALSE;
589 : : }
590 : :
591 : 3 : base_stream_seekable = G_SEEKABLE (base_stream);
592 : 3 : return g_seekable_truncate (base_stream_seekable, offset, cancellable, error);
593 : : }
|