Add properties
[platform/upstream/glib.git] / gio / gdatainputstream.c
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  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General
17  * Public License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
19  * Boston, MA 02111-1307, USA.
20  *
21  * Author: Alexander Larsson <alexl@redhat.com>
22  */
23
24 #include <config.h>
25 #include "gdatainputstream.h"
26 #include "gioenumtypes.h"
27 #include "glibintl.h"
28
29 #include "gioalias.h"
30
31 /**
32  * SECTION:gdatainputstream
33  * @short_description: Data Input Stream
34  * @see_also: #GInputStream
35  * 
36  * Data input stream implements #GInputStream and includes functions for 
37  * reading data directly from an input stream.
38  *
39  **/
40
41 struct _GDataInputStreamPrivate {
42   GDataStreamByteOrder byte_order;
43   GDataStreamNewlineType newline_type;
44 };
45
46 enum {
47   PROP_0,
48   PROP_BYTE_ORDER,
49   PROP_NEWLINE_TYPE
50 };
51
52 static void g_data_input_stream_set_property (GObject      *object,
53                                               guint         prop_id,
54                                               const GValue *value,
55                                               GParamSpec   *pspec);
56 static void g_data_input_stream_get_property (GObject      *object,
57                                               guint         prop_id,
58                                               GValue       *value,
59                                               GParamSpec   *pspec);
60
61 G_DEFINE_TYPE (GDataInputStream,
62                g_data_input_stream,
63                G_TYPE_BUFFERED_INPUT_STREAM)
64
65
66 static void
67 g_data_input_stream_class_init (GDataInputStreamClass *klass)
68 {
69   GObjectClass *object_class;
70
71   g_type_class_add_private (klass, sizeof (GDataInputStreamPrivate));
72
73   object_class = G_OBJECT_CLASS (klass);
74   object_class->get_property = g_data_input_stream_get_property;
75   object_class->set_property = g_data_input_stream_set_property;
76
77   /**
78    * GDataStream:byte-order:
79    *
80    * The ::byte-order property determines the byte ordering that
81    * is used when reading multi-byte entities (such as integers)
82    * from the stream.
83    */ 
84   g_object_class_install_property (object_class,
85                                    PROP_BYTE_ORDER,
86                                    g_param_spec_enum ("byte-order",
87                                                       P_("Byte order"),
88                                                       P_("The byte order"),
89                                                       G_TYPE_DATA_STREAM_BYTE_ORDER,
90                                                       G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN,
91                                                       G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_BLURB));
92
93   /**
94    * GDataStream:newline-type:
95    *
96    * The :newline-type property determines what is considered
97    * as a line ending when reading complete lines from the stream.
98    */ 
99   g_object_class_install_property (object_class,
100                                    PROP_NEWLINE_TYPE,
101                                    g_param_spec_enum ("newline-type",
102                                                       P_("Newline type"),
103                                                       P_("The accepted types of line ending"),
104                                                       G_TYPE_DATA_STREAM_NEWLINE_TYPE,
105                                                       G_DATA_STREAM_NEWLINE_TYPE_LF,
106                                                       G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_BLURB));
107 }
108
109 static void
110 g_data_input_stream_set_property (GObject      *object,
111                                   guint         prop_id,
112                                   const GValue *value,
113                                   GParamSpec   *pspec)
114 {
115   GDataInputStreamPrivate *priv;
116   GDataInputStream        *dstream;
117
118   dstream = G_DATA_INPUT_STREAM (object);
119   priv = dstream->priv;
120
121    switch (prop_id) 
122     {
123     case PROP_BYTE_ORDER:
124       g_data_input_stream_set_byte_order (dstream, g_value_get_enum (value));
125       break;
126
127     case PROP_NEWLINE_TYPE:
128       g_data_input_stream_set_newline_type (dstream, g_value_get_enum (value));
129       break;
130
131     default:
132       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
133       break;
134     }
135
136 }
137
138 static void
139 g_data_input_stream_get_property (GObject    *object,
140                                   guint       prop_id,
141                                   GValue     *value,
142                                   GParamSpec *pspec)
143 {
144   GDataInputStreamPrivate *priv;
145   GDataInputStream        *dstream;
146
147   dstream = G_DATA_INPUT_STREAM (object);
148   priv = dstream->priv;
149
150   switch (prop_id)
151     { 
152     case PROP_BYTE_ORDER:
153       g_value_set_enum (value, priv->byte_order);
154       break;
155
156     case PROP_NEWLINE_TYPE:
157       g_value_set_enum (value, priv->newline_type);
158       break;
159
160     default:
161       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
162       break;
163     }
164
165 }
166 static void
167 g_data_input_stream_init (GDataInputStream *stream)
168 {
169   stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
170                                               G_TYPE_DATA_INPUT_STREAM,
171                                               GDataInputStreamPrivate);
172
173   stream->priv->byte_order = G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN;
174   stream->priv->newline_type = G_DATA_STREAM_NEWLINE_TYPE_LF;
175 }
176
177 /**
178  * g_data_input_stream_new:
179  * @base_stream: a #GInputStream.
180  * 
181  * Creates a new data input stream for the @base_stream.
182  * 
183  * Returns: a new #GDataInputStream.
184  **/
185 GDataInputStream *
186 g_data_input_stream_new (GInputStream *base_stream)
187 {
188   GDataInputStream *stream;
189
190   g_return_val_if_fail (G_IS_INPUT_STREAM (base_stream), NULL);
191
192   stream = g_object_new (G_TYPE_DATA_INPUT_STREAM,
193                          "base-stream", base_stream,
194                          NULL);
195
196   return stream;
197 }
198
199 /**
200  * g_data_input_stream_set_byte_order:
201  * @stream: a given #GDataInputStream.
202  * @order: a #GDataStreamByteOrder to set.
203  * 
204  * This function sets the byte order for the given @stream. All subsequent
205  * reads from the @stream will be read in the given @order.
206  *  
207  **/
208 void
209 g_data_input_stream_set_byte_order (GDataInputStream     *stream,
210                                     GDataStreamByteOrder  order)
211 {
212   GDataInputStreamPrivate *priv;
213
214   g_return_if_fail (G_IS_DATA_INPUT_STREAM (stream));
215
216   priv = stream->priv;
217
218   if (priv->byte_order != order)
219     {
220       priv->byte_order = order;
221       
222       g_object_notify (G_OBJECT (stream), "byte-order");
223     }
224 }
225
226 /**
227  * g_data_input_stream_get_byte_order:
228  * @stream: a given #GDataInputStream.
229  * 
230  * Gets the byte order for the data input stream.
231  * 
232  * Returns: the @stream's current #GDataStreamByteOrder. 
233  **/
234 GDataStreamByteOrder
235 g_data_input_stream_get_byte_order (GDataInputStream *stream)
236 {
237   g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN);
238
239   return stream->priv->byte_order;
240 }
241
242 /**
243  * g_data_input_stream_set_newline_type:
244  * @stream: a #GDataInputStream.
245  * @type: the type of new line return as #GDataStreamNewlineType.
246  * 
247  * Sets the newline type for the @stream.
248  * 
249  * TODO: is it valid to set this to G_DATA_STREAM_NEWLINE_TYPE_ANY, or
250  * should it always be set to {_LF, _CR, _CR_LF}
251  *  
252  **/
253 void
254 g_data_input_stream_set_newline_type (GDataInputStream       *stream,
255                                       GDataStreamNewlineType  type)
256 {
257   GDataInputStreamPrivate *priv;
258
259   g_return_if_fail (G_IS_DATA_INPUT_STREAM (stream));
260
261   priv = stream->priv;
262   
263   if (priv->newline_type != type)
264     {
265       priv->newline_type = type;
266
267       g_object_notify (G_OBJECT (stream), "newline-type");
268     }
269 }
270
271 /**
272  * g_data_input_stream_get_newline_type:
273  * @stream: a given #GDataInputStream.
274  * 
275  * Gets the current newline type for the @stream.
276  * 
277  * Returns: #GDataStreamNewlineType for the given @stream.
278  **/
279 GDataStreamNewlineType
280 g_data_input_stream_get_newline_type (GDataInputStream *stream)
281 {
282   g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), G_DATA_STREAM_NEWLINE_TYPE_ANY);
283
284   return stream->priv->newline_type;
285 }
286
287 static gboolean
288 read_data (GDataInputStream  *stream,
289            void              *buffer,
290            gsize              size,
291            GCancellable      *cancellable,
292            GError           **error)
293 {
294   gsize available;
295   gssize res;
296
297   while ((available = g_buffered_input_stream_get_available (G_BUFFERED_INPUT_STREAM (stream))) < size)
298     {
299       res = g_buffered_input_stream_fill (G_BUFFERED_INPUT_STREAM (stream),
300                                           size - available,
301                                           cancellable, error);
302       if (res < 0)
303         return FALSE;
304       if (res == 0)
305         {
306           g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
307                        _("Unexpected early end-of-stream"));
308           return FALSE;
309         }
310     }
311   
312   /* This should always succeed, since its in the buffer */
313   res = g_input_stream_read (G_INPUT_STREAM (stream),
314                              buffer, size,
315                              NULL, NULL);
316   g_assert (res == size);
317   return TRUE;
318 }
319
320
321 /**
322  * g_data_input_stream_read_byte:
323  * @stream: a given #GDataInputStream.
324  * @cancellable: optional #GCancellable object, %NULL to ignore.
325  * @error: #GError for error reporting.
326  * 
327  * Reads an unsigned 8-bit/1-byte value from @stream.
328  *
329  * Returns: an unsigned 8-bit/1-byte value read from the @stream or %0 
330  * if an error occured.
331  **/
332 guchar
333 g_data_input_stream_read_byte (GDataInputStream  *stream,
334                               GCancellable       *cancellable,
335                               GError            **error)
336 {
337   guchar c;
338   
339   g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), '\0');
340   
341   if (read_data (stream, &c, 1, cancellable, error))
342       return c;
343   
344   return 0;
345 }
346
347
348 /**
349  * g_data_input_stream_read_int16:
350  * @stream: a given #GDataInputStream.
351  * @cancellable: optional #GCancellable object, %NULL to ignore.
352  * @error: #GError for error reporting.
353  * 
354  * Reads a 16-bit/2-byte value from @stream.
355  *
356  * In order to get the correct byte order for this read operation, 
357  * see g_data_stream_get_byte_order() and g_data_stream_set_byte_order().
358  * 
359  * Returns: a signed 16-bit/2-byte value read from @stream or %0 if 
360  * an error occured.
361  **/
362 gint16
363 g_data_input_stream_read_int16 (GDataInputStream  *stream,
364                                GCancellable       *cancellable,
365                                GError            **error)
366 {
367   gint16 v;
368   
369   g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), 0);
370   
371   if (read_data (stream, &v, 2, cancellable, error))
372     {
373       switch (stream->priv->byte_order)
374         {
375         case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
376           v = GINT16_FROM_BE (v);
377           break;
378         case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
379           v = GINT16_FROM_LE (v);
380           break;
381         case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
382         default:
383           break;
384         }
385       return v;
386     }
387   
388   return 0;
389 }
390
391
392 /**
393  * g_data_input_stream_read_uint16:
394  * @stream: a given #GDataInputStream.
395  * @cancellable: optional #GCancellable object, %NULL to ignore.
396  * @error: #GError for error reporting.
397  *
398  * Reads an unsigned 16-bit/2-byte value from @stream.
399  *
400  * In order to get the correct byte order for this read operation, 
401  * see g_data_stream_get_byte_order() and g_data_stream_set_byte_order(). 
402  * 
403  * Returns: an unsigned 16-bit/2-byte value read from the @stream or %0 if 
404  * an error occured. 
405  **/
406 guint16
407 g_data_input_stream_read_uint16 (GDataInputStream  *stream,
408                                 GCancellable       *cancellable,
409                                 GError            **error)
410 {
411   guint16 v;
412   
413   g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), 0);
414   
415   if (read_data (stream, &v, 2, cancellable, error))
416     {
417       switch (stream->priv->byte_order)
418         {
419         case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
420           v = GUINT16_FROM_BE (v);
421           break;
422         case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
423           v = GUINT16_FROM_LE (v);
424           break;
425         case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
426         default:
427           break;
428         }
429       return v;
430     }
431   
432   return 0;
433 }
434
435
436 /**
437  * g_data_input_stream_read_int32:
438  * @stream: a given #GDataInputStream.
439  * @cancellable: optional #GCancellable object, %NULL to ignore.
440  * @error: #GError for error reporting.
441  * 
442  * Reads a signed 32-bit/4-byte value from @stream.
443  *
444  * In order to get the correct byte order for this read operation, 
445  * see g_data_stream_get_byte_order() and g_data_stream_set_byte_order().
446  *
447  * If @cancellable is not %NULL, then the operation can be cancelled by
448  * triggering the cancellable object from another thread. If the operation
449  * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned. 
450  *   
451  * Returns: a signed 32-bit/4-byte value read from the @stream or %0 if 
452  * an error occured. 
453  **/
454 gint32
455 g_data_input_stream_read_int32 (GDataInputStream  *stream,
456                                GCancellable       *cancellable,
457                                GError            **error)
458 {
459   gint32 v;
460   
461   g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), 0);
462   
463   if (read_data (stream, &v, 4, cancellable, error))
464     {
465       switch (stream->priv->byte_order)
466         {
467         case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
468           v = GINT32_FROM_BE (v);
469           break;
470         case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
471           v = GINT32_FROM_LE (v);
472           break;
473         case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
474         default:
475           break;
476         }
477       return v;
478     }
479   
480   return 0;
481 }
482
483
484 /**
485  * g_data_input_stream_read_uint32:
486  * @stream: a given #GDataInputStream.
487  * @cancellable: optional #GCancellable object, %NULL to ignore.
488  * @error: #GError for error reporting.
489  * 
490  * Reads an unsigned 32-bit/4-byte value from @stream.
491  *
492  * In order to get the correct byte order for this read operation, 
493  * see g_data_stream_get_byte_order() and g_data_stream_set_byte_order().
494  *
495  * If @cancellable is not %NULL, then the operation can be cancelled by
496  * triggering the cancellable object from another thread. If the operation
497  * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned. 
498  * 
499  * Returns: an unsigned 32-bit/4-byte value read from the @stream or %0 if 
500  * an error occured. 
501  **/
502 guint32
503 g_data_input_stream_read_uint32 (GDataInputStream  *stream,
504                                 GCancellable       *cancellable,
505                                 GError            **error)
506 {
507   guint32 v;
508   
509   g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), 0);
510   
511   if (read_data (stream, &v, 4, cancellable, error))
512     {
513       switch (stream->priv->byte_order)
514         {
515         case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
516           v = GUINT32_FROM_BE (v);
517           break;
518         case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
519           v = GUINT32_FROM_LE (v);
520           break;
521         case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
522         default:
523           break;
524         }
525       return v;
526     }
527   
528   return 0;
529 }
530
531
532 /**
533  * g_data_input_stream_read_int64:
534  * @stream: a given #GDataInputStream.
535  * @cancellable: optional #GCancellable object, %NULL to ignore.
536  * @error: #GError for error reporting.
537  * 
538  * Reads a 64-bit/8-byte value from @stream.
539  *
540  * In order to get the correct byte order for this read operation, 
541  * see g_data_stream_get_byte_order() and g_data_stream_set_byte_order().
542  *
543  * If @cancellable is not %NULL, then the operation can be cancelled by
544  * triggering the cancellable object from another thread. If the operation
545  * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned. 
546  * 
547  * Returns: a signed 64-bit/8-byte value read from @stream or %0 if 
548  * an error occured.  
549  **/
550 gint64
551 g_data_input_stream_read_int64 (GDataInputStream  *stream,
552                                GCancellable       *cancellable,
553                                GError            **error)
554 {
555   gint64 v;
556   
557   g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), 0);
558   
559   if (read_data (stream, &v, 8, cancellable, error))
560     {
561       switch (stream->priv->byte_order)
562         {
563         case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
564           v = GINT64_FROM_BE (v);
565           break;
566         case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
567           v = GINT64_FROM_LE (v);
568           break;
569         case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
570         default:
571           break;
572         }
573       return v;
574     }
575   
576   return 0;
577 }
578
579
580 /**
581  * g_data_input_stream_read_uint64:
582  * @stream: a given #GDataInputStream.
583  * @cancellable: optional #GCancellable object, %NULL to ignore.
584  * @error: #GError for error reporting.
585  * 
586  * Reads an unsigned 64-bit/8-byte value from @stream.
587  *
588  * In order to get the correct byte order for this read operation, 
589  * see g_data_stream_get_byte_order().
590  *
591  * If @cancellable is not %NULL, then the operation can be cancelled by
592  * triggering the cancellable object from another thread. If the operation
593  * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned. 
594  * 
595  * Returns: an unsigned 64-bit/8-byte read from @stream or %0 if 
596  * an error occured. 
597  **/
598 guint64
599 g_data_input_stream_read_uint64 (GDataInputStream  *stream,
600                                 GCancellable       *cancellable,
601                                 GError            **error)
602 {
603   guint64 v;
604   
605   g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), 0);
606   
607   if (read_data (stream, &v, 8, cancellable, error))
608     {
609       switch (stream->priv->byte_order)
610         {
611         case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN:
612           v = GUINT64_FROM_BE (v);
613           break;
614         case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN:
615           v = GUINT64_FROM_LE (v);
616           break;
617         case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN:
618         default:
619           break;
620         }
621       return v;
622     }
623   
624   return 0;
625 }
626
627 static gssize
628 scan_for_newline (GDataInputStream *stream,
629                   gsize            *checked_out,
630                   gboolean         *last_saw_cr_out,
631                   int              *newline_len_out)
632 {
633   GBufferedInputStream *bstream;
634   GDataInputStreamPrivate *priv;
635   const char *buffer;
636   gsize start, end, peeked;
637   int i;
638   gssize found_pos;
639   int newline_len;
640   gsize available, checked;
641   gboolean last_saw_cr;
642
643   priv = stream->priv;
644   
645   bstream = G_BUFFERED_INPUT_STREAM (stream);
646
647   checked = *checked_out;
648   last_saw_cr = *last_saw_cr_out;
649   found_pos = -1;
650   newline_len = 0;
651   
652   start = checked;
653   buffer = g_buffered_input_stream_peek_buffer (bstream, &available) + start;
654   end = available;
655   peeked = end - start;
656
657   for (i = 0; checked < available && i < peeked; i++)
658     {
659       switch (priv->newline_type)
660         {
661         case G_DATA_STREAM_NEWLINE_TYPE_LF:
662           if (buffer[i] == 10)
663             {
664               found_pos = start + i;
665               newline_len = 1;
666             }
667           break;
668         case G_DATA_STREAM_NEWLINE_TYPE_CR:
669           if (buffer[i] == 13)
670             {
671               found_pos = start + i;
672               newline_len = 1;
673             }
674           break;
675         case G_DATA_STREAM_NEWLINE_TYPE_CR_LF:
676           if (last_saw_cr && buffer[i] == 10)
677             {
678               found_pos = start + i - 1;
679               newline_len = 2;
680             }
681           break;
682         default:
683         case G_DATA_STREAM_NEWLINE_TYPE_ANY:
684           if (buffer[i] == 10) /* LF */
685             {
686               if (last_saw_cr)
687                 {
688                   /* CR LF */
689                   found_pos = start + i - 1;
690                   newline_len = 2;
691                 }
692               else
693                 {
694                   /* LF */
695                   found_pos = start + i;
696                   newline_len = 1;
697                 }
698             }
699           else if (last_saw_cr)
700             {
701               /* Last was cr, this is not LF, end is CR */
702               found_pos = start + i - 1;
703               newline_len = 1;
704             }
705           /* Don't check for CR here, instead look at last_saw_cr on next byte */
706           break;
707         }
708         
709       last_saw_cr = (buffer[i] == 13);
710
711       if (found_pos != -1)
712         {
713           *newline_len_out = newline_len;
714           return found_pos;
715         }
716     }
717
718   checked = end;
719
720   *checked_out = checked;
721   *last_saw_cr_out = last_saw_cr;
722   return -1;
723 }
724                   
725
726 /**
727  * g_data_input_stream_read_line:
728  * @stream: a given #GDataInputStream.
729  * @length: a #gsize to get the length of the data read in.
730  * @cancellable: optional #GCancellable object, %NULL to ignore.
731  * @error: #GError for error reporting.
732  *
733  * Reads a line from the data input stream.
734  * 
735  * If @cancellable is not %NULL, then the operation can be cancelled by
736  * triggering the cancellable object from another thread. If the operation
737  * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned. 
738  * 
739  * Returns: a string with the line that was read in. Set @length to 
740  * a #gsize to get the length of the read line. Returns %NULL on an error.
741  **/
742 char *
743 g_data_input_stream_read_line (GDataInputStream  *stream,
744                                gsize             *length,
745                                GCancellable      *cancellable,
746                                GError           **error)
747 {
748   GBufferedInputStream *bstream;
749   gsize checked;
750   gboolean last_saw_cr;
751   gssize found_pos;
752   gssize res;
753   int newline_len;
754   char *line;
755   
756   g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), NULL);  
757
758   bstream = G_BUFFERED_INPUT_STREAM (stream);
759
760   newline_len = 0;
761   checked = 0;
762   last_saw_cr = FALSE;
763
764   while ((found_pos = scan_for_newline (stream, &checked, &last_saw_cr, &newline_len)) == -1)
765     {
766       if (g_buffered_input_stream_get_available (bstream) ==
767           g_buffered_input_stream_get_buffer_size (bstream))
768         g_buffered_input_stream_set_buffer_size (bstream,
769                                                  2 * g_buffered_input_stream_get_buffer_size (bstream));
770
771       res = g_buffered_input_stream_fill (bstream, -1, cancellable, error);
772       if (res < 0)
773         return NULL;
774       if (res == 0)
775         {
776           /* End of stream */
777           if (g_buffered_input_stream_get_available (bstream) == 0)
778             {
779               if (length)
780                 *length = 0;
781               return NULL;
782             }
783           else
784             {
785               found_pos = checked;
786               newline_len = 0;
787               break;
788             }
789         }
790     }
791
792   line = g_malloc (found_pos + newline_len + 1);
793
794   res = g_input_stream_read (G_INPUT_STREAM (stream),
795                              line,
796                              found_pos + newline_len,
797                              NULL, NULL);
798   if (length)
799     *length = (gsize)found_pos;
800   g_assert (res == found_pos + newline_len);
801   line[found_pos] = 0;
802   
803   return line;
804 }
805
806
807 static gssize
808 scan_for_chars (GDataInputStream *stream,
809                 gsize            *checked_out,
810                 const char       *stop_chars)
811 {
812   GBufferedInputStream *bstream;
813   GDataInputStreamPrivate *priv;
814   const char *buffer;
815   gsize start, end, peeked;
816   int i;
817   gssize found_pos;
818   gsize available, checked;
819   const char *stop_char;
820
821   priv = stream->priv;
822   
823   bstream = G_BUFFERED_INPUT_STREAM (stream);
824
825   checked = *checked_out;
826   found_pos = -1;
827   
828   start = checked;
829   buffer = g_buffered_input_stream_peek_buffer (bstream, &available) + start;
830   end = available;
831   peeked = end - start;
832
833   for (i = 0; checked < available && i < peeked; i++)
834     {
835       for (stop_char = stop_chars; *stop_char != '\0'; stop_char++)
836         {
837           if (buffer[i] == *stop_char)
838             return (start + i);
839         }
840     }
841
842   checked = end;
843
844   *checked_out = checked;
845   return -1;
846 }
847
848 /**
849  * g_data_input_stream_read_until:
850  * @stream: a given #GDataInputStream.
851  * @stop_chars: characters to terminate the read.
852  * @length: a #gsize to get the length of the data read in.
853  * @cancellable: optional #GCancellable object, %NULL to ignore.
854  * @error: #GError for error reporting.
855  * 
856  * Reads a string from the data input stream, up to the first 
857  * occurrance of any of the stop characters.
858  *
859  * Returns: a string with the data that was read before encountering 
860  * any of the stop characters. Set @length to a #gsize to get the length 
861  * of the string. This function will return %NULL on an error.
862  **/
863 char *
864 g_data_input_stream_read_until (GDataInputStream  *stream,
865                                const gchar        *stop_chars,
866                                gsize              *length,
867                                GCancellable       *cancellable,
868                                GError            **error)
869 {
870   GBufferedInputStream *bstream;
871   gsize checked;
872   gssize found_pos;
873   gssize res;
874   int stop_char_len;
875   char *data_until;
876   
877   g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), NULL);  
878
879   bstream = G_BUFFERED_INPUT_STREAM (stream);
880
881   stop_char_len = 1;
882   checked = 0;
883
884   while ((found_pos = scan_for_chars (stream, &checked, stop_chars)) == -1)
885     {
886       if (g_buffered_input_stream_get_available (bstream) ==
887           g_buffered_input_stream_get_buffer_size (bstream))
888         g_buffered_input_stream_set_buffer_size (bstream,
889                                                  2 * g_buffered_input_stream_get_buffer_size (bstream));
890
891       res = g_buffered_input_stream_fill (bstream, -1, cancellable, error);
892       if (res < 0)
893         return NULL;
894       if (res == 0)
895         {
896           /* End of stream */
897           if (g_buffered_input_stream_get_available (bstream) == 0)
898             {
899               if (length)
900                 *length = 0;
901               return NULL;
902             }
903           else
904             {
905               found_pos = checked;
906               stop_char_len = 0;
907               break;
908             }
909         }
910     }
911
912   data_until = g_malloc (found_pos + stop_char_len + 1);
913
914   res = g_input_stream_read (G_INPUT_STREAM (stream),
915                              data_until,
916                              found_pos + stop_char_len,
917                              NULL, NULL);
918   if (length)
919     *length = (gsize)found_pos;
920   g_assert (res == found_pos + stop_char_len);
921   data_until[found_pos] = 0;
922   
923   return data_until;
924 }
925
926 #define __G_DATA_INPUT_STREAM_C__
927 #include "gioaliasdef.c"