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 { 86 GObjectClass *object_class; 87 88 object_class = G_OBJECT_CLASS (klass); 89 object_class->get_property = g_data_output_stream_get_property; 90 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 g_object_class_install_property (object_class, 99 PROP_BYTE_ORDER, 100 g_param_spec_enum ("byte-order", 101 P_("Byte order"), 102 P_("The byte order"), 103 G_TYPE_DATA_STREAM_BYTE_ORDER, 104 G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN, 105 G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_BLURB)); 106 107 } 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 { 115 GDataOutputStream *dstream; 116 117 dstream = G_DATA_OUTPUT_STREAM (object); 118 119 switch (prop_id) 120 { 121 case PROP_BYTE_ORDER: 122 g_data_output_stream_set_byte_order (dstream, g_value_get_enum (value)); 123 break; 124 125 default: 126 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); 127 break; 128 } 129 } 130 131 static void 132 g_data_output_stream_get_property (GObject *object, 133 guint prop_id, 134 GValue *value, 135 GParamSpec *pspec) 136 { 137 GDataOutputStreamPrivate *priv; 138 GDataOutputStream *dstream; 139 140 dstream = G_DATA_OUTPUT_STREAM (object); 141 priv = dstream->priv; 142 143 switch (prop_id) 144 { 145 case PROP_BYTE_ORDER: 146 g_value_set_enum (value, priv->byte_order); 147 break; 148 149 default: 150 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); 151 break; 152 } 153 } 154 155 static void 156 g_data_output_stream_init (GDataOutputStream *stream) 157 { 158 stream->priv = g_data_output_stream_get_instance_private (stream); 159 stream->priv->byte_order = G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN; 160 } 161 162 static void 163 g_data_output_stream_seekable_iface_init (GSeekableIface *iface) 164 { 165 iface->tell = g_data_output_stream_tell; 166 iface->can_seek = g_data_output_stream_can_seek; 167 iface->seek = g_data_output_stream_seek; 168 iface->can_truncate = g_data_output_stream_can_truncate; 169 iface->truncate_fn = g_data_output_stream_truncate; 170 } 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 { 183 GDataOutputStream *stream; 184 185 g_return_val_if_fail (G_IS_OUTPUT_STREAM (base_stream), NULL); 186 187 stream = g_object_new (G_TYPE_DATA_OUTPUT_STREAM, 188 "base-stream", base_stream, 189 NULL); 190 191 return stream; 192 } 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 { 205 GDataOutputStreamPrivate *priv; 206 g_return_if_fail (G_IS_DATA_OUTPUT_STREAM (stream)); 207 priv = stream->priv; 208 if (priv->byte_order != order) 209 { 210 priv->byte_order = order; 211 g_object_notify (G_OBJECT (stream), "byte-order"); 212 } 213 } 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 { 226 g_return_val_if_fail (G_IS_DATA_OUTPUT_STREAM (stream), G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN); 227 228 return stream->priv->byte_order; 229 } 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 { 248 gsize bytes_written; 249 250 g_return_val_if_fail (G_IS_DATA_OUTPUT_STREAM (stream), FALSE); 251 252 return g_output_stream_write_all (G_OUTPUT_STREAM (stream), 253 &data, 1, 254 &bytes_written, 255 cancellable, error); 256 } 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 { 275 gsize bytes_written; 276 277 g_return_val_if_fail (G_IS_DATA_OUTPUT_STREAM (stream), FALSE); 278 279 switch (stream->priv->byte_order) 280 { 281 case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN: 282 data = GINT16_TO_BE (data); 283 break; 284 case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN: 285 data = GINT16_TO_LE (data); 286 break; 287 case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN: 288 default: 289 break; 290 } 291 292 return g_output_stream_write_all (G_OUTPUT_STREAM (stream), 293 &data, 2, 294 &bytes_written, 295 cancellable, error); 296 } 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 { 315 gsize bytes_written; 316 317 g_return_val_if_fail (G_IS_DATA_OUTPUT_STREAM (stream), FALSE); 318 319 switch (stream->priv->byte_order) 320 { 321 case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN: 322 data = GUINT16_TO_BE (data); 323 break; 324 case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN: 325 data = GUINT16_TO_LE (data); 326 break; 327 case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN: 328 default: 329 break; 330 } 331 332 return g_output_stream_write_all (G_OUTPUT_STREAM (stream), 333 &data, 2, 334 &bytes_written, 335 cancellable, error); 336 } 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 { 355 gsize bytes_written; 356 357 g_return_val_if_fail (G_IS_DATA_OUTPUT_STREAM (stream), FALSE); 358 359 switch (stream->priv->byte_order) 360 { 361 case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN: 362 data = GINT32_TO_BE (data); 363 break; 364 case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN: 365 data = GINT32_TO_LE (data); 366 break; 367 case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN: 368 default: 369 break; 370 } 371 372 return g_output_stream_write_all (G_OUTPUT_STREAM (stream), 373 &data, 4, 374 &bytes_written, 375 cancellable, error); 376 } 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 { 395 gsize bytes_written; 396 397 g_return_val_if_fail (G_IS_DATA_OUTPUT_STREAM (stream), FALSE); 398 399 switch (stream->priv->byte_order) 400 { 401 case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN: 402 data = GUINT32_TO_BE (data); 403 break; 404 case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN: 405 data = GUINT32_TO_LE (data); 406 break; 407 case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN: 408 default: 409 break; 410 } 411 412 return g_output_stream_write_all (G_OUTPUT_STREAM (stream), 413 &data, 4, 414 &bytes_written, 415 cancellable, error); 416 } 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 { 435 gsize bytes_written; 436 437 g_return_val_if_fail (G_IS_DATA_OUTPUT_STREAM (stream), FALSE); 438 439 switch (stream->priv->byte_order) 440 { 441 case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN: 442 data = GINT64_TO_BE (data); 443 break; 444 case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN: 445 data = GINT64_TO_LE (data); 446 break; 447 case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN: 448 default: 449 break; 450 } 451 452 return g_output_stream_write_all (G_OUTPUT_STREAM (stream), 453 &data, 8, 454 &bytes_written, 455 cancellable, error); 456 } 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 { 475 gsize bytes_written; 476 477 g_return_val_if_fail (G_IS_DATA_OUTPUT_STREAM (stream), FALSE); 478 479 switch (stream->priv->byte_order) 480 { 481 case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN: 482 data = GUINT64_TO_BE (data); 483 break; 484 case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN: 485 data = GUINT64_TO_LE (data); 486 break; 487 case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN: 488 default: 489 break; 490 } 491 492 return g_output_stream_write_all (G_OUTPUT_STREAM (stream), 493 &data, 8, 494 &bytes_written, 495 cancellable, error); 496 } 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 { 515 gsize bytes_written; 516 517 g_return_val_if_fail (G_IS_DATA_OUTPUT_STREAM (stream), FALSE); 518 g_return_val_if_fail (str != NULL, FALSE); 519 520 return g_output_stream_write_all (G_OUTPUT_STREAM (stream), 521 str, strlen (str), 522 &bytes_written, 523 cancellable, error); 524 } 525 526 static goffset 527 g_data_output_stream_tell (GSeekable *seekable) 528 { 529 GOutputStream *base_stream; 530 GSeekable *base_stream_seekable; 531 532 base_stream = G_FILTER_OUTPUT_STREAM (seekable)->base_stream; 533 if (!G_IS_SEEKABLE (base_stream)) 534 return 0; 535 base_stream_seekable = G_SEEKABLE (base_stream); 536 return g_seekable_tell (base_stream_seekable); 537 } 538 539 static gboolean 540 g_data_output_stream_can_seek (GSeekable *seekable) 541 { 542 GOutputStream *base_stream; 543 544 base_stream = G_FILTER_OUTPUT_STREAM (seekable)->base_stream; 545 return G_IS_SEEKABLE (base_stream) && g_seekable_can_seek (G_SEEKABLE (base_stream)); 546 } 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 { 555 GOutputStream *base_stream; 556 GSeekable *base_stream_seekable; 557 558 base_stream = G_FILTER_OUTPUT_STREAM (seekable)->base_stream; 559 if (!G_IS_SEEKABLE (base_stream)) 560 { 561 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, 562 _("Seek not supported on base stream")); 563 return FALSE; 564 } 565 566 base_stream_seekable = G_SEEKABLE (base_stream); 567 return g_seekable_seek (base_stream_seekable, offset, type, cancellable, error); 568 } 569 570 static gboolean 571 g_data_output_stream_can_truncate (GSeekable *seekable) 572 { 573 GOutputStream *base_stream; 574 575 base_stream = G_FILTER_OUTPUT_STREAM (seekable)->base_stream; 576 return G_IS_SEEKABLE (base_stream) && g_seekable_can_truncate (G_SEEKABLE (base_stream)); 577 } 578 579 static gboolean 580 g_data_output_stream_truncate (GSeekable *seekable, 581 goffset offset, 582 GCancellable *cancellable, 583 GError **error) 584 { 585 GOutputStream *base_stream; 586 GSeekable *base_stream_seekable; 587 588 base_stream = G_FILTER_OUTPUT_STREAM (seekable)->base_stream; 589 if (!G_IS_SEEKABLE (base_stream)) 590 { 591 g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, 592 _("Truncate not supported on base stream")); 593 return FALSE; 594 } 595 596 base_stream_seekable = G_SEEKABLE (base_stream); 597 return g_seekable_truncate (base_stream_seekable, offset, cancellable, error); 598 } 599