Coverage Report

Created: 2025-07-01 07:09

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