Coverage Report

Created: 2025-06-13 06:55

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