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