1/* GIO - GLib Input, Output and Streaming Library
2 *
3 * Copyright (C) 2006-2007 Red Hat, Inc.
4 * Copyright (C) 2007 Jürg Billeter
5 * Copyright © 2009 Codethink Limited
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 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, write to the
19 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20 * Boston, MA 02111-1307, USA.
21 *
22 * Author: Alexander Larsson <alexl@redhat.com>
23 */
24
25#include "config.h"
26#include "gdatainputstream.h"
27#include "gsimpleasyncresult.h"
28#include "gcancellable.h"
29#include "gioenumtypes.h"
30#include "gioerror.h"
31#include "glibintl.h"
32
33#include "gioalias.h"
34
35/**
36 * SECTION:gdatainputstream
37 * @short_description: Data Input Stream
38 * @include: gio/gio.h
39 * @see_also: #GInputStream
40 *
41 * Data input stream implements #GInputStream and includes functions for
42 * reading structured data directly from a binary input stream.
43 *
44 **/
45
46struct _GDataInputStreamPrivate {
47  GDataStreamByteOrder byte_order;
48  GDataStreamNewlineType newline_type;
49};
50
51enum {
52  PROP_0,
53  PROP_BYTE_ORDER,
54  PROP_NEWLINE_TYPE
55};
56
57static void g_data_input_stream_set_property (GObject      *object,
58					      guint         prop_id,
59					      const GValue *value,
60					      GParamSpec   *pspec);
61static void g_data_input_stream_get_property (GObject      *object,
62					      guint         prop_id,
63					      GValue       *value,
64					      GParamSpec   *pspec);
65
66G_DEFINE_TYPE (GDataInputStream,
67               g_data_input_stream,
68               G_TYPE_BUFFERED_INPUT_STREAM)
69
70
71static void
72g_data_input_stream_class_init (GDataInputStreamClass *klass)
73{
74  GObjectClass *object_class;
75
76  g_type_class_add_private (klass, sizeof (GDataInputStreamPrivate));
77
78  object_class = G_OBJECT_CLASS (klass);
79  object_class->get_property = g_data_input_stream_get_property;
80  object_class->set_property = g_data_input_stream_set_property;
81
82  /**
83   * GDataStream:byte-order:
84   *
85   * The ::byte-order property determines the byte ordering that
86   * is used when reading multi-byte entities (such as integers)
87   * from the stream.
88   */
89  g_object_class_install_property (object_class,
90                                   PROP_BYTE_ORDER,
91                                   g_param_spec_enum ("byte-order",
92                                                      P_("Byte order"),
93                                                      P_("The byte order"),
94                                                      G_TYPE_DATA_STREAM_BYTE_ORDER,
95                                                      G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN,
96                                                      G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_BLURB));
97
98  /**
99   * GDataStream:newline-type:
100   *
101   * The :newline-type property determines what is considered
102   * as a line ending when reading complete lines from the stream.
103   */
104  g_object_class_install_property (object_class,
105                                   PROP_NEWLINE_TYPE,
106                                   g_param_spec_enum ("newline-type",
107                                                      P_("Newline type"),
108                                                      P_("The accepted types of line ending"),
109                                                      G_TYPE_DATA_STREAM_NEWLINE_TYPE,
110                                                      G_DATA_STREAM_NEWLINE_TYPE_LF,
111                                                      G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_BLURB));
112}
113
114static void
115g_data_input_stream_set_property (GObject      *object,
116				  guint         prop_id,
117				  const GValue *value,
118				  GParamSpec   *pspec)
119{
120  GDataInputStreamPrivate *priv;
121  GDataInputStream        *dstream;
122
123  dstream = G_DATA_INPUT_STREAM (object);
124  priv = dstream->priv;
125
126   switch (prop_id)
127    {
128    case PROP_BYTE_ORDER:
129      g_data_input_stream_set_byte_order (dstream, g_value_get_enum (value));
130      break;
131
132    case PROP_NEWLINE_TYPE:
133      g_data_input_stream_set_newline_type (dstream, g_value_get_enum (value));
134      break;
135
136    default:
137      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
138      break;
139    }
140
141}
142
143static void
144g_data_input_stream_get_property (GObject    *object,
145                                  guint       prop_id,
146                                  GValue     *value,
147                                  GParamSpec *pspec)
148{
149  GDataInputStreamPrivate *priv;
150  GDataInputStream        *dstream;
151
152  dstream = G_DATA_INPUT_STREAM (object);
153  priv = dstream->priv;
154
155  switch (prop_id)
156    {
157    case PROP_BYTE_ORDER:
158      g_value_set_enum (value, priv->byte_order);
159      break;
160
161    case PROP_NEWLINE_TYPE:
162      g_value_set_enum (value, priv->newline_type);
163      break;
164
165    default:
166      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
167      break;
168    }
169
170}
171static void
172g_data_input_stream_init (GDataInputStream *stream)
173{
174  stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
175                                              G_TYPE_DATA_INPUT_STREAM,
176                                              GDataInputStreamPrivate);
177
178  stream->priv->byte_order = G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN;
179  stream->priv->newline_type = G_DATA_STREAM_NEWLINE_TYPE_LF;
180}
181
182/**
183 * g_data_input_stream_new:
184 * @base_stream: a #GInputStream.
185 *
186 * Creates a new data input stream for the @base_stream.
187 *
188 * Returns: a new #GDataInputStream.
189 **/
190GDataInputStream *
191g_data_input_stream_new (GInputStream *base_stream)
192{
193  GDataInputStream *stream;
194
195  g_return_val_if_fail (G_IS_INPUT_STREAM (base_stream), NULL);
196
197  stream = g_object_new (G_TYPE_DATA_INPUT_STREAM,
198                         "base-stream", base_stream,
199                         NULL);
200
201  return stream;
202}
203
204/**
205 * g_data_input_stream_set_byte_order:
206 * @stream: a given #GDataInputStream.
207 * @order: a #GDataStreamByteOrder to set.
208 *
209 * This function sets the byte order for the given @stream. All subsequent
210 * reads from the @stream will be read in the given @order.
211 *
212 **/
213void
214g_data_input_stream_set_byte_order (GDataInputStream     *stream,
215				    GDataStreamByteOrder  order)
216{
217  GDataInputStreamPrivate *priv;
218
219  g_return_if_fail (G_IS_DATA_INPUT_STREAM (stream));
220
221  priv = stream->priv;
222
223  if (priv->byte_order != order)
224    {
225      priv->byte_order = order;
226
227      g_object_notify (G_OBJECT (stream), "byte-order");
228    }
229}
230
231/**
232 * g_data_input_stream_get_byte_order:
233 * @stream: a given #GDataInputStream.
234 *
235 * Gets the byte order for the data input stream.
236 *
237 * Returns: the @stream's current #GDataStreamByteOrder.
238 **/
239GDataStreamByteOrder
240g_data_input_stream_get_byte_order (GDataInputStream *stream)
241{
242  g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN);
243
244  return stream->priv->byte_order;
245}
246
247/**
248 * g_data_input_stream_set_newline_type:
249 * @stream: a #GDataInputStream.
250 * @type: the type of new line return as #GDataStreamNewlineType.
251 *
252 * Sets the newline type for the @stream.
253 *
254 * Note that using G_DATA_STREAM_NEWLINE_TYPE_ANY is slightly unsafe. If a read
255 * chunk ends in "CR" we must read an additional byte to know if this is "CR" or
256 * "CR LF", and this might block if there is no more data availible.
257 *
258 **/
259void
260g_data_input_stream_set_newline_type (GDataInputStream       *stream,
261				      GDataStreamNewlineType  type)
262{
263  GDataInputStreamPrivate *priv;
264
265  g_return_if_fail (G_IS_DATA_INPUT_STREAM (stream));
266
267  priv = stream->priv;
268
269  if (priv->newline_type != type)
270    {
271      priv->newline_type = type;
272
273      g_object_notify (G_OBJECT (stream), "newline-type");
274    }
275}
276
277/**
278 * g_data_input_stream_get_newline_type:
279 * @stream: a given #GDataInputStream.
280 *
281 * Gets the current newline type for the @stream.
282 *
283 * Returns: #GDataStreamNewlineType for the given @stream.
284 **/
285GDataStreamNewlineType
286g_data_input_stream_get_newline_type (GDataInputStream *stream)
287{
288  g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), G_DATA_STREAM_NEWLINE_TYPE_ANY);
289
290  return stream->priv->newline_type;
291}
292
293static gboolean
294read_data (GDataInputStream  *stream,
295           void              *buffer,
296           gsize              size,
297           GCancellable      *cancellable,
298           GError           **error)
299{
300  gsize available;
301  gssize res;
302
303  while ((available = g_buffered_input_stream_get_available (G_BUFFERED_INPUT_STREAM (stream))) < size)
304    {
305      res = g_buffered_input_stream_fill (G_BUFFERED_INPUT_STREAM (stream),
306					  size - available,
307					  cancellable, error);
308      if (res < 0)
309	return FALSE;
310      if (res == 0)
311	{
312	  g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
313                               _("Unexpected early end-of-stream"));
314	  return FALSE;
315	}
316    }
317
318  /* This should always succeed, since it's in the buffer */
319  res = g_input_stream_read (G_INPUT_STREAM (stream),
320			     buffer, size,
321			     NULL, NULL);
322  g_warn_if_fail (res == size);
323  return TRUE;
324}
325
326
327/**
328 * g_data_input_stream_read_byte:
329 * @stream: a given #GDataInputStream.
330 * @cancellable: optional #GCancellable object, %NULL to ignore.
331 * @error: #GError for error reporting.
332 *
333 * Reads an unsigned 8-bit/1-byte value from @stream.
334 *
335 * Returns: an unsigned 8-bit/1-byte value read from the @stream or %0
336 * if an error occurred.
337 **/
338guchar
339g_data_input_stream_read_byte (GDataInputStream  *stream,
340			       GCancellable       *cancellable,
341			       GError            **error)
342{
343  guchar c;
344
345  g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), '\0');
346
347  if (read_data (stream, &c, 1, cancellable, error))
348      return c;
349
350  return 0;
351}
352
353
354/**
355 * g_data_input_stream_read_int16:
356 * @stream: a given #GDataInputStream.
357 * @cancellable: optional #GCancellable object, %NULL to ignore.
358 * @error: #GError for error reporting.
359 *
360 * Reads a 16-bit/2-byte value from @stream.
361 *
362 * In order to get the correct byte order for this read operation,
363 * see g_data_stream_get_byte_order() and g_data_stream_set_byte_order().
364 *
365 * Returns: a signed 16-bit/2-byte value read from @stream or %0 if
366 * an error occurred.
367 **/
368gint16
369g_data_input_stream_read_int16 (GDataInputStream  *stream,
370			       GCancellable       *cancellable,
371			       GError            **error)
372{
373  gint16 v;
374
375  g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), 0);
376
377  if (read_data (stream, &v, 2, cancellable, error))
378    {
379      switch (stream->priv->byte_order)
380	{
381	case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
382	  v = GINT16_FROM_BE (v);
383	  break;
384	case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
385	  v = GINT16_FROM_LE (v);
386	  break;
387	case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
388	default:
389	  break;
390	}
391      return v;
392    }
393
394  return 0;
395}
396
397
398/**
399 * g_data_input_stream_read_uint16:
400 * @stream: a given #GDataInputStream.
401 * @cancellable: optional #GCancellable object, %NULL to ignore.
402 * @error: #GError for error reporting.
403 *
404 * Reads an unsigned 16-bit/2-byte value from @stream.
405 *
406 * In order to get the correct byte order for this read operation,
407 * see g_data_stream_get_byte_order() and g_data_stream_set_byte_order().
408 *
409 * Returns: an unsigned 16-bit/2-byte value read from the @stream or %0 if
410 * an error occurred.
411 **/
412guint16
413g_data_input_stream_read_uint16 (GDataInputStream  *stream,
414				 GCancellable       *cancellable,
415				 GError            **error)
416{
417  guint16 v;
418
419  g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), 0);
420
421  if (read_data (stream, &v, 2, cancellable, error))
422    {
423      switch (stream->priv->byte_order)
424	{
425	case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
426	  v = GUINT16_FROM_BE (v);
427	  break;
428	case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
429	  v = GUINT16_FROM_LE (v);
430	  break;
431	case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
432	default:
433	  break;
434	}
435      return v;
436    }
437
438  return 0;
439}
440
441
442/**
443 * g_data_input_stream_read_int32:
444 * @stream: a given #GDataInputStream.
445 * @cancellable: optional #GCancellable object, %NULL to ignore.
446 * @error: #GError for error reporting.
447 *
448 * Reads a signed 32-bit/4-byte value from @stream.
449 *
450 * In order to get the correct byte order for this read operation,
451 * see g_data_stream_get_byte_order() and g_data_stream_set_byte_order().
452 *
453 * If @cancellable is not %NULL, then the operation can be cancelled by
454 * triggering the cancellable object from another thread. If the operation
455 * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned.
456 *
457 * Returns: a signed 32-bit/4-byte value read from the @stream or %0 if
458 * an error occurred.
459 **/
460gint32
461g_data_input_stream_read_int32 (GDataInputStream  *stream,
462				GCancellable       *cancellable,
463				GError            **error)
464{
465  gint32 v;
466
467  g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), 0);
468
469  if (read_data (stream, &v, 4, cancellable, error))
470    {
471      switch (stream->priv->byte_order)
472	{
473	case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
474	  v = GINT32_FROM_BE (v);
475	  break;
476	case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
477	  v = GINT32_FROM_LE (v);
478	  break;
479	case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
480	default:
481	  break;
482	}
483      return v;
484    }
485
486  return 0;
487}
488
489
490/**
491 * g_data_input_stream_read_uint32:
492 * @stream: a given #GDataInputStream.
493 * @cancellable: optional #GCancellable object, %NULL to ignore.
494 * @error: #GError for error reporting.
495 *
496 * Reads an unsigned 32-bit/4-byte value from @stream.
497 *
498 * In order to get the correct byte order for this read operation,
499 * see g_data_stream_get_byte_order() and g_data_stream_set_byte_order().
500 *
501 * If @cancellable is not %NULL, then the operation can be cancelled by
502 * triggering the cancellable object from another thread. If the operation
503 * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned.
504 *
505 * Returns: an unsigned 32-bit/4-byte value read from the @stream or %0 if
506 * an error occurred.
507 **/
508guint32
509g_data_input_stream_read_uint32 (GDataInputStream  *stream,
510				 GCancellable       *cancellable,
511				 GError            **error)
512{
513  guint32 v;
514
515  g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), 0);
516
517  if (read_data (stream, &v, 4, cancellable, error))
518    {
519      switch (stream->priv->byte_order)
520	{
521	case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
522	  v = GUINT32_FROM_BE (v);
523	  break;
524	case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
525	  v = GUINT32_FROM_LE (v);
526	  break;
527	case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
528	default:
529	  break;
530	}
531      return v;
532    }
533
534  return 0;
535}
536
537
538/**
539 * g_data_input_stream_read_int64:
540 * @stream: a given #GDataInputStream.
541 * @cancellable: optional #GCancellable object, %NULL to ignore.
542 * @error: #GError for error reporting.
543 *
544 * Reads a 64-bit/8-byte value from @stream.
545 *
546 * In order to get the correct byte order for this read operation,
547 * see g_data_stream_get_byte_order() and g_data_stream_set_byte_order().
548 *
549 * If @cancellable is not %NULL, then the operation can be cancelled by
550 * triggering the cancellable object from another thread. If the operation
551 * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned.
552 *
553 * Returns: a signed 64-bit/8-byte value read from @stream or %0 if
554 * an error occurred.
555 **/
556gint64
557g_data_input_stream_read_int64 (GDataInputStream  *stream,
558			       GCancellable       *cancellable,
559			       GError            **error)
560{
561  gint64 v;
562
563  g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), 0);
564
565  if (read_data (stream, &v, 8, cancellable, error))
566    {
567      switch (stream->priv->byte_order)
568	{
569	case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
570	  v = GINT64_FROM_BE (v);
571	  break;
572	case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
573	  v = GINT64_FROM_LE (v);
574	  break;
575	case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
576	default:
577	  break;
578	}
579      return v;
580    }
581
582  return 0;
583}
584
585
586/**
587 * g_data_input_stream_read_uint64:
588 * @stream: a given #GDataInputStream.
589 * @cancellable: optional #GCancellable object, %NULL to ignore.
590 * @error: #GError for error reporting.
591 *
592 * Reads an unsigned 64-bit/8-byte value from @stream.
593 *
594 * In order to get the correct byte order for this read operation,
595 * see g_data_stream_get_byte_order().
596 *
597 * If @cancellable is not %NULL, then the operation can be cancelled by
598 * triggering the cancellable object from another thread. If the operation
599 * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned.
600 *
601 * Returns: an unsigned 64-bit/8-byte read from @stream or %0 if
602 * an error occurred.
603 **/
604guint64
605g_data_input_stream_read_uint64 (GDataInputStream  *stream,
606				GCancellable       *cancellable,
607				GError            **error)
608{
609  guint64 v;
610
611  g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), 0);
612
613  if (read_data (stream, &v, 8, cancellable, error))
614    {
615      switch (stream->priv->byte_order)
616	{
617	case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
618	  v = GUINT64_FROM_BE (v);
619	  break;
620	case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
621	  v = GUINT64_FROM_LE (v);
622	  break;
623	case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
624	default:
625	  break;
626	}
627      return v;
628    }
629
630  return 0;
631}
632
633static gssize
634scan_for_newline (GDataInputStream *stream,
635		  gsize            *checked_out,
636		  gboolean         *last_saw_cr_out,
637		  int              *newline_len_out)
638{
639  GBufferedInputStream *bstream;
640  GDataInputStreamPrivate *priv;
641  const char *buffer;
642  gsize start, end, peeked;
643  int i;
644  gssize found_pos;
645  int newline_len;
646  gsize available, checked;
647  gboolean last_saw_cr;
648
649  priv = stream->priv;
650
651  bstream = G_BUFFERED_INPUT_STREAM (stream);
652
653  checked = *checked_out;
654  last_saw_cr = *last_saw_cr_out;
655  found_pos = -1;
656  newline_len = 0;
657
658  start = checked;
659  buffer = (const char*)g_buffered_input_stream_peek_buffer (bstream, &available) + start;
660  end = available;
661  peeked = end - start;
662
663  for (i = 0; checked < available && i < peeked; i++)
664    {
665      switch (priv->newline_type)
666	{
667	case G_DATA_STREAM_NEWLINE_TYPE_LF:
668	  if (buffer[i] == 10)
669	    {
670	      found_pos = start + i;
671	      newline_len = 1;
672	    }
673	  break;
674	case G_DATA_STREAM_NEWLINE_TYPE_CR:
675	  if (buffer[i] == 13)
676	    {
677	      found_pos = start + i;
678	      newline_len = 1;
679	    }
680	  break;
681	case G_DATA_STREAM_NEWLINE_TYPE_CR_LF:
682	  if (last_saw_cr && buffer[i] == 10)
683	    {
684	      found_pos = start + i - 1;
685	      newline_len = 2;
686	    }
687	  break;
688	default:
689	case G_DATA_STREAM_NEWLINE_TYPE_ANY:
690	  if (buffer[i] == 10) /* LF */
691	    {
692	      if (last_saw_cr)
693		{
694		  /* CR LF */
695		  found_pos = start + i - 1;
696		  newline_len = 2;
697		}
698	      else
699		{
700		  /* LF */
701		  found_pos = start + i;
702		  newline_len = 1;
703		}
704	    }
705	  else if (last_saw_cr)
706	    {
707	      /* Last was cr, this is not LF, end is CR */
708	      found_pos = start + i - 1;
709	      newline_len = 1;
710	    }
711	  /* Don't check for CR here, instead look at last_saw_cr on next byte */
712	  break;
713	}
714
715      last_saw_cr = (buffer[i] == 13);
716
717      if (found_pos != -1)
718	{
719	  *newline_len_out = newline_len;
720	  return found_pos;
721	}
722    }
723
724  checked = end;
725
726  *checked_out = checked;
727  *last_saw_cr_out = last_saw_cr;
728  return -1;
729}
730
731
732/**
733 * g_data_input_stream_read_line:
734 * @stream: a given #GDataInputStream.
735 * @length: a #gsize to get the length of the data read in.
736 * @cancellable: optional #GCancellable object, %NULL to ignore.
737 * @error: #GError for error reporting.
738 *
739 * Reads a line from the data input stream.
740 *
741 * If @cancellable is not %NULL, then the operation can be cancelled by
742 * triggering the cancellable object from another thread. If the operation
743 * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned.
744 *
745 * Returns: a string with the line that was read in (without the newlines).
746 *     Set @length to a #gsize to get the length of the read line.
747 *     On an error, it will return %NULL and @error will be set. If there's no
748 *     content to read, it will still return %NULL, but @error won't be set.
749 **/
750char *
751g_data_input_stream_read_line (GDataInputStream  *stream,
752			       gsize             *length,
753			       GCancellable      *cancellable,
754			       GError           **error)
755{
756  GBufferedInputStream *bstream;
757  gsize checked;
758  gboolean last_saw_cr;
759  gssize found_pos;
760  gssize res;
761  int newline_len;
762  char *line;
763
764  g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), NULL);
765
766  bstream = G_BUFFERED_INPUT_STREAM (stream);
767
768  newline_len = 0;
769  checked = 0;
770  last_saw_cr = FALSE;
771
772  while ((found_pos = scan_for_newline (stream, &checked, &last_saw_cr, &newline_len)) == -1)
773    {
774      if (g_buffered_input_stream_get_available (bstream) ==
775	  g_buffered_input_stream_get_buffer_size (bstream))
776	g_buffered_input_stream_set_buffer_size (bstream,
777						 2 * g_buffered_input_stream_get_buffer_size (bstream));
778
779      res = g_buffered_input_stream_fill (bstream, -1, cancellable, error);
780      if (res < 0)
781	return NULL;
782      if (res == 0)
783	{
784	  /* End of stream */
785	  if (g_buffered_input_stream_get_available (bstream) == 0)
786	    {
787	      if (length)
788		*length = 0;
789	      return NULL;
790	    }
791	  else
792	    {
793	      found_pos = checked;
794	      newline_len = 0;
795	      break;
796	    }
797	}
798    }
799
800  line = g_malloc (found_pos + newline_len + 1);
801
802  res = g_input_stream_read (G_INPUT_STREAM (stream),
803			     line,
804			     found_pos + newline_len,
805			     NULL, NULL);
806  if (length)
807    *length = (gsize)found_pos;
808  g_warn_if_fail (res == found_pos + newline_len);
809  line[found_pos] = 0;
810
811  return line;
812}
813
814static gssize
815scan_for_chars (GDataInputStream *stream,
816		gsize            *checked_out,
817		const char       *stop_chars)
818{
819  GBufferedInputStream *bstream;
820  GDataInputStreamPrivate *priv;
821  const char *buffer;
822  gsize start, end, peeked;
823  int i;
824  gssize found_pos;
825  gsize available, checked;
826  const char *stop_char;
827
828  priv = stream->priv;
829
830  bstream = G_BUFFERED_INPUT_STREAM (stream);
831
832  checked = *checked_out;
833  found_pos = -1;
834
835  start = checked;
836  buffer = (const char *)g_buffered_input_stream_peek_buffer (bstream, &available) + start;
837  end = available;
838  peeked = end - start;
839
840  for (i = 0; checked < available && i < peeked; i++)
841    {
842      for (stop_char = stop_chars; *stop_char != '\0'; stop_char++)
843	{
844	  if (buffer[i] == *stop_char)
845	    return (start + i);
846	}
847    }
848
849  checked = end;
850
851  *checked_out = checked;
852  return -1;
853}
854
855/**
856 * g_data_input_stream_read_until:
857 * @stream: a given #GDataInputStream.
858 * @stop_chars: characters to terminate the read.
859 * @length: a #gsize to get the length of the data read in.
860 * @cancellable: optional #GCancellable object, %NULL to ignore.
861 * @error: #GError for error reporting.
862 *
863 * Reads a string from the data input stream, up to the first
864 * occurrence of any of the stop characters.
865 *
866 * Returns: a string with the data that was read before encountering
867 *     any of the stop characters. Set @length to a #gsize to get the length
868 *     of the string. This function will return %NULL on an error.
869 */
870char *
871g_data_input_stream_read_until (GDataInputStream  *stream,
872			       const gchar        *stop_chars,
873			       gsize              *length,
874			       GCancellable       *cancellable,
875			       GError            **error)
876{
877  GBufferedInputStream *bstream;
878  gsize checked;
879  gssize found_pos;
880  gssize res;
881  int stop_char_len;
882  char *data_until;
883
884  g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), NULL);
885
886  bstream = G_BUFFERED_INPUT_STREAM (stream);
887
888  stop_char_len = 1;
889  checked = 0;
890
891  while ((found_pos = scan_for_chars (stream, &checked, stop_chars)) == -1)
892    {
893      if (g_buffered_input_stream_get_available (bstream) ==
894	  g_buffered_input_stream_get_buffer_size (bstream))
895	g_buffered_input_stream_set_buffer_size (bstream,
896						 2 * g_buffered_input_stream_get_buffer_size (bstream));
897
898      res = g_buffered_input_stream_fill (bstream, -1, cancellable, error);
899      if (res < 0)
900	return NULL;
901      if (res == 0)
902	{
903	  /* End of stream */
904	  if (g_buffered_input_stream_get_available (bstream) == 0)
905	    {
906	      if (length)
907		*length = 0;
908	      return NULL;
909	    }
910	  else
911	    {
912	      found_pos = checked;
913	      stop_char_len = 0;
914	      break;
915	    }
916	}
917    }
918
919  data_until = g_malloc (found_pos + stop_char_len + 1);
920
921  res = g_input_stream_read (G_INPUT_STREAM (stream),
922			     data_until,
923			     found_pos + stop_char_len,
924			     NULL, NULL);
925  if (length)
926    *length = (gsize)found_pos;
927  g_warn_if_fail (res == found_pos + stop_char_len);
928  data_until[found_pos] = 0;
929
930  return data_until;
931}
932
933typedef struct
934{
935  GDataInputStream *stream;
936  GSimpleAsyncResult *simple;
937  gboolean last_saw_cr;
938  gsize checked;
939  gint io_priority;
940  GCancellable *cancellable;
941
942  gchar *stop_chars;
943  gchar *line;
944  gsize length;
945} GDataInputStreamReadData;
946
947static void
948g_data_input_stream_read_complete (GDataInputStreamReadData *data,
949                                   gsize                     read_length,
950                                   gsize                     skip_length,
951                                   gboolean                  need_idle_dispatch)
952{
953  if (read_length || skip_length)
954    {
955      gssize bytes;
956
957      data->length = read_length;
958      data->line = g_malloc (read_length + 1);
959      data->line[read_length] = '\0';
960
961      /* we already checked the buffer.  this shouldn't fail. */
962      bytes = g_input_stream_read (G_INPUT_STREAM (data->stream),
963                                   data->line, read_length, NULL, NULL);
964      g_assert_cmpint (bytes, ==, read_length);
965
966      bytes = g_input_stream_skip (G_INPUT_STREAM (data->stream),
967                                   skip_length, NULL, NULL);
968      g_assert_cmpint (bytes, ==, skip_length);
969    }
970
971  if (need_idle_dispatch)
972    g_simple_async_result_complete_in_idle (data->simple);
973  else
974    g_simple_async_result_complete (data->simple);
975
976  g_object_unref (data->simple);
977}
978
979static void
980g_data_input_stream_read_line_ready (GObject      *object,
981                                     GAsyncResult *result,
982                                     gpointer      user_data)
983{
984  GDataInputStreamReadData *data = user_data;
985  gssize found_pos;
986  gint newline_len;
987
988  if (result)
989    /* this is a callback.  finish the async call. */
990    {
991      GBufferedInputStream *buffer = G_BUFFERED_INPUT_STREAM (data->stream);
992      GError *error = NULL;
993      gssize bytes;
994
995      bytes = g_buffered_input_stream_fill_finish (buffer, result, &error);
996
997      if (bytes <= 0)
998        {
999          if (bytes < 0)
1000            /* stream error. */
1001            {
1002              g_simple_async_result_set_from_error (data->simple, error);
1003              g_error_free (error);
1004              data->checked = 0;
1005            }
1006
1007          g_data_input_stream_read_complete (data, data->checked, 0, FALSE);
1008          return;
1009        }
1010
1011      /* only proceed if we got more bytes... */
1012    }
1013
1014  if (data->stop_chars)
1015    {
1016      found_pos = scan_for_chars (data->stream,
1017                                  &data->checked,
1018                                  data->stop_chars);
1019      newline_len = 0;
1020    }
1021  else
1022    found_pos = scan_for_newline (data->stream, &data->checked,
1023                                  &data->last_saw_cr, &newline_len);
1024
1025  if (found_pos == -1)
1026    /* didn't find a full line; need to buffer some more bytes */
1027    {
1028      GBufferedInputStream *buffer = G_BUFFERED_INPUT_STREAM (data->stream);
1029      gsize size;
1030
1031      size = g_buffered_input_stream_get_buffer_size (buffer);
1032
1033      if (g_buffered_input_stream_get_available (buffer) == size)
1034        /* need to grow the buffer */
1035        g_buffered_input_stream_set_buffer_size (buffer, size * 2);
1036
1037      /* try again */
1038      g_buffered_input_stream_fill_async (buffer, -1, data->io_priority,
1039                                          data->cancellable,
1040                                          g_data_input_stream_read_line_ready,
1041                                          user_data);
1042    }
1043  else
1044    {
1045      /* read the line and the EOL.  no error is possible. */
1046      g_data_input_stream_read_complete (data, found_pos,
1047                                         newline_len, result == NULL);
1048    }
1049}
1050
1051static void
1052g_data_input_stream_read_data_free (gpointer user_data)
1053{
1054  GDataInputStreamReadData *data = user_data;
1055
1056  /* we don't hold a ref to ->simple because it keeps a ref to us.
1057   * we are called because it is being finalized.
1058   */
1059
1060  g_free (data->stop_chars);
1061  if (data->cancellable)
1062    g_object_unref (data->cancellable);
1063  g_free (data->line);
1064  g_slice_free (GDataInputStreamReadData, data);
1065}
1066
1067static void
1068g_data_input_stream_read_async (GDataInputStream    *stream,
1069                                const gchar         *stop_chars,
1070                                gint                 io_priority,
1071                                GCancellable        *cancellable,
1072                                GAsyncReadyCallback  callback,
1073                                gpointer             user_data,
1074                                gpointer             source_tag)
1075{
1076  GDataInputStreamReadData *data;
1077
1078  data = g_slice_new (GDataInputStreamReadData);
1079  data->stream = stream;
1080  if (cancellable)
1081    g_object_ref (cancellable);
1082  data->cancellable = cancellable;
1083  data->stop_chars = g_strdup (stop_chars);
1084  data->io_priority = io_priority;
1085  data->last_saw_cr = FALSE;
1086  data->checked = 0;
1087  data->line = NULL;
1088
1089  data->simple = g_simple_async_result_new (G_OBJECT (stream), callback,
1090                                            user_data, source_tag);
1091  g_simple_async_result_set_op_res_gpointer (data->simple, data,
1092                                             g_data_input_stream_read_data_free);
1093  g_data_input_stream_read_line_ready (NULL, NULL, data);
1094}
1095
1096static gchar *
1097g_data_input_stream_read_finish (GDataInputStream  *stream,
1098                                 GAsyncResult      *result,
1099                                 gsize             *length,
1100                                 GError           **error)
1101{
1102  GDataInputStreamReadData *data;
1103  GSimpleAsyncResult *simple;
1104  gchar *line;
1105
1106  simple = G_SIMPLE_ASYNC_RESULT (result);
1107
1108  if (g_simple_async_result_propagate_error (simple, error))
1109    return NULL;
1110
1111  data = g_simple_async_result_get_op_res_gpointer (simple);
1112
1113  line = data->line;
1114  data->line = NULL;
1115
1116  if (length && line)
1117    *length = data->length;
1118
1119  return line;
1120}
1121
1122/**
1123 * g_data_input_stream_read_line_async:
1124 * @stream: a given #GDataInputStream.
1125 * @io_priority: the <link linkend="io-priority">I/O priority</link>
1126 *     of the request.
1127 * @cancellable: optional #GCancellable object, %NULL to ignore.
1128 * @callback: callback to call when the request is satisfied.
1129 * @user_data: the data to pass to callback function.
1130 *
1131 * The asynchronous version of g_data_input_stream_read_line().  It is
1132 * an error to have two outstanding calls to this function.
1133 *
1134 * When the operation is finished, @callback will be called. You
1135 * can then call g_data_input_stream_read_line_finish() to get
1136 * the result of the operation.
1137 *
1138 * Since: 2.20
1139 */
1140void
1141g_data_input_stream_read_line_async (GDataInputStream    *stream,
1142                                     gint                 io_priority,
1143                                     GCancellable        *cancellable,
1144                                     GAsyncReadyCallback  callback,
1145                                     gpointer             user_data)
1146{
1147  g_return_if_fail (G_IS_DATA_INPUT_STREAM (stream));
1148  g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1149
1150  g_data_input_stream_read_async (stream, NULL, io_priority,
1151                                  cancellable, callback, user_data,
1152                                  g_data_input_stream_read_line_async);
1153}
1154
1155/**
1156 * g_data_input_stream_read_until_async:
1157 * @stream: a given #GDataInputStream.
1158 * @stop_chars: characters to terminate the read.
1159 * @io_priority: the <link linkend="io-priority">I/O priority</link>
1160 *     of the request.
1161 * @cancellable: optional #GCancellable object, %NULL to ignore.
1162 * @callback: callback to call when the request is satisfied.
1163 * @user_data: the data to pass to callback function.
1164 *
1165 * The asynchronous version of g_data_input_stream_read_until().
1166 * It is an error to have two outstanding calls to this function.
1167 *
1168 * When the operation is finished, @callback will be called. You
1169 * can then call g_data_input_stream_read_until_finish() to get
1170 * the result of the operation.
1171 *
1172 * Since: 2.20
1173 */
1174void
1175g_data_input_stream_read_until_async (GDataInputStream    *stream,
1176                                      const gchar         *stop_chars,
1177                                      gint                 io_priority,
1178                                      GCancellable        *cancellable,
1179                                      GAsyncReadyCallback  callback,
1180                                      gpointer             user_data)
1181{
1182  g_return_if_fail (G_IS_DATA_INPUT_STREAM (stream));
1183  g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1184  g_return_if_fail (stop_chars != NULL);
1185
1186  g_data_input_stream_read_async (stream, stop_chars, io_priority,
1187                                  cancellable, callback, user_data,
1188                                  g_data_input_stream_read_until_async);
1189}
1190
1191/**
1192 * g_data_input_stream_read_line_finish:
1193 * @stream: a given #GDataInputStream.
1194 * @result: the #GAsyncResult that was provided to the callback.
1195 * @length: a #gsize to get the length of the data read in.
1196 * @error: #GError for error reporting.
1197 *
1198 * Finish an asynchronous call started by
1199 * g_data_input_stream_read_line_async().
1200 *
1201 * Returns: a string with the line that was read in (without the newlines).
1202 *     Set @length to a #gsize to get the length of the read line.
1203 *     On an error, it will return %NULL and @error will be set. If there's no
1204 *     content to read, it will still return %NULL, but @error won't be set.
1205 *
1206 * Since: 2,20
1207 */
1208gchar *
1209g_data_input_stream_read_line_finish (GDataInputStream  *stream,
1210                                      GAsyncResult      *result,
1211                                      gsize             *length,
1212                                      GError           **error)
1213{
1214  g_return_val_if_fail (
1215    g_simple_async_result_is_valid (result, G_OBJECT (stream),
1216      g_data_input_stream_read_line_async), NULL);
1217
1218  return g_data_input_stream_read_finish (stream, result, length, error);
1219}
1220
1221/**
1222 * g_data_input_stream_read_until_finish:
1223 * @stream: a given #GDataInputStream.
1224 * @result: the #GAsyncResult that was provided to the callback.
1225 * @length: a #gsize to get the length of the data read in.
1226 * @error: #GError for error reporting.
1227 *
1228 * Finish an asynchronous call started by
1229 * g_data_input_stream_read_until_async().
1230 *
1231 * Since: 2.20
1232 *
1233 * Returns: a string with the data that was read before encountering
1234 *     any of the stop characters. Set @length to a #gsize to get the length
1235 *     of the string. This function will return %NULL on an error.
1236 */
1237gchar *
1238g_data_input_stream_read_until_finish (GDataInputStream  *stream,
1239                                       GAsyncResult      *result,
1240                                       gsize             *length,
1241                                       GError           **error)
1242{
1243  g_return_val_if_fail (
1244    g_simple_async_result_is_valid (result, G_OBJECT (stream),
1245      g_data_input_stream_read_until_async), NULL);
1246
1247  return g_data_input_stream_read_finish (stream, result, length, error);
1248}
1249
1250
1251#define __G_DATA_INPUT_STREAM_C__
1252#include "gioaliasdef.c"
1253