Coverage Report

Created: 2025-07-23 08:13

/src/pango/subprojects/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
 * 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
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
g_data_output_stream_class_init (GDataOutputStreamClass *klass)
82
0
{
83
0
  GObjectClass *object_class;
84
85
0
  object_class = G_OBJECT_CLASS (klass);
86
0
  object_class->get_property = g_data_output_stream_get_property;
87
0
  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
0
  g_object_class_install_property (object_class,
96
0
                                   PROP_BYTE_ORDER,
97
0
                                   g_param_spec_enum ("byte-order", NULL, NULL,
98
0
                                                      G_TYPE_DATA_STREAM_BYTE_ORDER,
99
0
                                                      G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN,
100
0
                                                      G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_BLURB));
101
102
0
}
103
104
static void
105
g_data_output_stream_set_property (GObject     *object,
106
          guint         prop_id,
107
          const GValue *value,
108
          GParamSpec   *pspec)
109
0
{
110
0
  GDataOutputStream *dstream;
111
112
0
  dstream = G_DATA_OUTPUT_STREAM (object);
113
114
0
  switch (prop_id) 
115
0
    {
116
0
    case PROP_BYTE_ORDER:
117
0
      g_data_output_stream_set_byte_order (dstream, g_value_get_enum (value));
118
0
      break;
119
120
0
    default:
121
0
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
122
0
      break;
123
0
    }
124
0
}
125
126
static void
127
g_data_output_stream_get_property (GObject    *object,
128
           guint       prop_id,
129
           GValue     *value,
130
           GParamSpec *pspec)
131
0
{
132
0
  GDataOutputStreamPrivate *priv;
133
0
  GDataOutputStream        *dstream;
134
135
0
  dstream = G_DATA_OUTPUT_STREAM (object);
136
0
  priv = dstream->priv;
137
138
0
  switch (prop_id)
139
0
    {
140
0
    case PROP_BYTE_ORDER:
141
0
      g_value_set_enum (value, priv->byte_order);
142
0
      break;
143
144
0
    default:
145
0
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
146
0
      break;
147
0
    }
148
0
}
149
150
static void
151
g_data_output_stream_init (GDataOutputStream *stream)
152
0
{
153
0
  stream->priv = g_data_output_stream_get_instance_private (stream);
154
0
  stream->priv->byte_order = G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN;
155
0
}
156
157
static void
158
g_data_output_stream_seekable_iface_init (GSeekableIface *iface)
159
0
{
160
0
  iface->tell         = g_data_output_stream_tell;
161
0
  iface->can_seek     = g_data_output_stream_can_seek;
162
0
  iface->seek         = g_data_output_stream_seek;
163
0
  iface->can_truncate = g_data_output_stream_can_truncate;
164
0
  iface->truncate_fn  = g_data_output_stream_truncate;
165
0
}
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
g_data_output_stream_new (GOutputStream *base_stream)
177
0
{
178
0
  GDataOutputStream *stream;
179
180
0
  g_return_val_if_fail (G_IS_OUTPUT_STREAM (base_stream), NULL);
181
182
0
  stream = g_object_new (G_TYPE_DATA_OUTPUT_STREAM,
183
0
                         "base-stream", base_stream,
184
0
                         NULL);
185
186
0
  return stream;
187
0
}
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
g_data_output_stream_set_byte_order (GDataOutputStream    *stream,
198
                                     GDataStreamByteOrder  order)
199
0
{
200
0
  GDataOutputStreamPrivate *priv;
201
0
  g_return_if_fail (G_IS_DATA_OUTPUT_STREAM (stream));
202
0
  priv = stream->priv;
203
0
  if (priv->byte_order != order)
204
0
    {
205
0
      priv->byte_order = order;
206
0
      g_object_notify (G_OBJECT (stream), "byte-order");
207
0
    }
208
0
}
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
g_data_output_stream_get_byte_order (GDataOutputStream *stream)
220
0
{
221
0
  g_return_val_if_fail (G_IS_DATA_OUTPUT_STREAM (stream), G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN);
222
223
0
  return stream->priv->byte_order;
224
0
}
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
g_data_output_stream_put_byte (GDataOutputStream  *stream,
239
             guchar              data,
240
             GCancellable       *cancellable,
241
             GError            **error)
242
0
{
243
0
  gsize bytes_written;
244
  
245
0
  g_return_val_if_fail (G_IS_DATA_OUTPUT_STREAM (stream), FALSE);
246
247
0
  return g_output_stream_write_all (G_OUTPUT_STREAM (stream),
248
0
            &data, 1,
249
0
            &bytes_written,
250
0
            cancellable, error);
251
0
}
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
g_data_output_stream_put_int16 (GDataOutputStream  *stream,
266
        gint16              data,
267
        GCancellable       *cancellable,
268
        GError            **error)
269
0
{
270
0
  gsize bytes_written;
271
  
272
0
  g_return_val_if_fail (G_IS_DATA_OUTPUT_STREAM (stream), FALSE);
273
274
0
  switch (stream->priv->byte_order)
275
0
    {
276
0
    case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
277
0
      data = GINT16_TO_BE (data);
278
0
      break;
279
0
    case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
280
0
      data = GINT16_TO_LE (data);
281
0
      break;
282
0
    case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
283
0
    default:
284
0
      break;
285
0
    }
286
  
287
0
  return g_output_stream_write_all (G_OUTPUT_STREAM (stream),
288
0
            &data, 2,
289
0
            &bytes_written,
290
0
            cancellable, error);
291
0
}
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
g_data_output_stream_put_uint16 (GDataOutputStream  *stream,
306
         guint16             data,
307
         GCancellable       *cancellable,
308
         GError            **error)
309
0
{
310
0
  gsize bytes_written;
311
  
312
0
  g_return_val_if_fail (G_IS_DATA_OUTPUT_STREAM (stream), FALSE);
313
314
0
  switch (stream->priv->byte_order)
315
0
    {
316
0
    case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
317
0
      data = GUINT16_TO_BE (data);
318
0
      break;
319
0
    case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
320
0
      data = GUINT16_TO_LE (data);
321
0
      break;
322
0
    case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
323
0
    default:
324
0
      break;
325
0
    }
326
  
327
0
  return g_output_stream_write_all (G_OUTPUT_STREAM (stream),
328
0
            &data, 2,
329
0
            &bytes_written,
330
0
            cancellable, error);
331
0
}
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
g_data_output_stream_put_int32 (GDataOutputStream  *stream,
346
        gint32              data,
347
        GCancellable       *cancellable,
348
        GError            **error)
349
0
{
350
0
  gsize bytes_written;
351
  
352
0
  g_return_val_if_fail (G_IS_DATA_OUTPUT_STREAM (stream), FALSE);
353
354
0
  switch (stream->priv->byte_order)
355
0
    {
356
0
    case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
357
0
      data = GINT32_TO_BE (data);
358
0
      break;
359
0
    case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
360
0
      data = GINT32_TO_LE (data);
361
0
      break;
362
0
    case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
363
0
    default:
364
0
      break;
365
0
    }
366
  
367
0
  return g_output_stream_write_all (G_OUTPUT_STREAM (stream),
368
0
            &data, 4,
369
0
            &bytes_written,
370
0
            cancellable, error);
371
0
}
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
g_data_output_stream_put_uint32 (GDataOutputStream  *stream,
386
         guint32             data,
387
         GCancellable       *cancellable,
388
         GError            **error)
389
0
{
390
0
  gsize bytes_written;
391
  
392
0
  g_return_val_if_fail (G_IS_DATA_OUTPUT_STREAM (stream), FALSE);
393
394
0
  switch (stream->priv->byte_order)
395
0
    {
396
0
    case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
397
0
      data = GUINT32_TO_BE (data);
398
0
      break;
399
0
    case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
400
0
      data = GUINT32_TO_LE (data);
401
0
      break;
402
0
    case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
403
0
    default:
404
0
      break;
405
0
    }
406
  
407
0
  return g_output_stream_write_all (G_OUTPUT_STREAM (stream),
408
0
            &data, 4,
409
0
            &bytes_written,
410
0
            cancellable, error);
411
0
}
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
g_data_output_stream_put_int64 (GDataOutputStream  *stream,
426
        gint64              data,
427
        GCancellable       *cancellable,
428
        GError            **error)
429
0
{
430
0
  gsize bytes_written;
431
  
432
0
  g_return_val_if_fail (G_IS_DATA_OUTPUT_STREAM (stream), FALSE);
433
434
0
  switch (stream->priv->byte_order)
435
0
    {
436
0
    case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
437
0
      data = GINT64_TO_BE (data);
438
0
      break;
439
0
    case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
440
0
      data = GINT64_TO_LE (data);
441
0
      break;
442
0
    case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
443
0
    default:
444
0
      break;
445
0
    }
446
  
447
0
  return g_output_stream_write_all (G_OUTPUT_STREAM (stream),
448
0
            &data, 8,
449
0
            &bytes_written,
450
0
            cancellable, error);
451
0
}
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
g_data_output_stream_put_uint64 (GDataOutputStream  *stream,
466
         guint64             data,
467
         GCancellable       *cancellable,
468
         GError            **error)
469
0
{
470
0
  gsize bytes_written;
471
  
472
0
  g_return_val_if_fail (G_IS_DATA_OUTPUT_STREAM (stream), FALSE);
473
474
0
  switch (stream->priv->byte_order)
475
0
    {
476
0
    case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
477
0
      data = GUINT64_TO_BE (data);
478
0
      break;
479
0
    case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
480
0
      data = GUINT64_TO_LE (data);
481
0
      break;
482
0
    case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
483
0
    default:
484
0
      break;
485
0
    }
486
  
487
0
  return g_output_stream_write_all (G_OUTPUT_STREAM (stream),
488
0
            &data, 8,
489
0
            &bytes_written,
490
0
            cancellable, error);
491
0
}
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
g_data_output_stream_put_string (GDataOutputStream  *stream,
506
         const char         *str,
507
         GCancellable       *cancellable,
508
         GError            **error)
509
0
{
510
0
  gsize bytes_written;
511
  
512
0
  g_return_val_if_fail (G_IS_DATA_OUTPUT_STREAM (stream), FALSE);
513
0
  g_return_val_if_fail (str != NULL, FALSE);
514
515
0
  return g_output_stream_write_all (G_OUTPUT_STREAM (stream),
516
0
            str, strlen (str),
517
0
            &bytes_written,
518
0
            cancellable, error);
519
0
}
520
521
static goffset
522
g_data_output_stream_tell (GSeekable *seekable)
523
0
{
524
0
  GOutputStream *base_stream;
525
0
  GSeekable *base_stream_seekable;
526
527
0
  base_stream = G_FILTER_OUTPUT_STREAM (seekable)->base_stream;
528
0
  if (!G_IS_SEEKABLE (base_stream))
529
0
    return 0;
530
0
  base_stream_seekable = G_SEEKABLE (base_stream);
531
0
  return g_seekable_tell (base_stream_seekable);
532
0
}
533
534
static gboolean
535
g_data_output_stream_can_seek (GSeekable *seekable)
536
0
{
537
0
  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
0
}
542
543
static gboolean
544
g_data_output_stream_seek (GSeekable     *seekable,
545
         goffset        offset,
546
         GSeekType      type,
547
         GCancellable  *cancellable,
548
         GError       **error)
549
0
{
550
0
  GOutputStream *base_stream;
551
0
  GSeekable *base_stream_seekable;
552
553
0
  base_stream = G_FILTER_OUTPUT_STREAM (seekable)->base_stream;
554
0
  if (!G_IS_SEEKABLE (base_stream))
555
0
    {
556
0
      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
557
0
                           _("Seek not supported on base stream"));
558
0
      return FALSE;
559
0
    }
560
561
0
  base_stream_seekable = G_SEEKABLE (base_stream);
562
0
  return g_seekable_seek (base_stream_seekable, offset, type, cancellable, error);
563
0
}
564
565
static gboolean
566
g_data_output_stream_can_truncate (GSeekable *seekable)
567
0
{
568
0
  GOutputStream *base_stream;
569
  
570
0
  base_stream = G_FILTER_OUTPUT_STREAM (seekable)->base_stream;
571
0
  return G_IS_SEEKABLE (base_stream) && g_seekable_can_truncate (G_SEEKABLE (base_stream));
572
0
}
573
574
static gboolean
575
g_data_output_stream_truncate (GSeekable     *seekable,
576
           goffset        offset,
577
           GCancellable  *cancellable,
578
           GError       **error)
579
0
{
580
0
  GOutputStream *base_stream;
581
0
  GSeekable *base_stream_seekable;
582
583
0
  base_stream = G_FILTER_OUTPUT_STREAM (seekable)->base_stream;
584
0
  if (!G_IS_SEEKABLE (base_stream))
585
0
    {
586
0
      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
587
0
                           _("Truncate not supported on base stream"));
588
0
      return FALSE;
589
0
    }
590
591
0
  base_stream_seekable = G_SEEKABLE (base_stream);
592
0
  return g_seekable_truncate (base_stream_seekable, offset, cancellable, error);
593
0
}