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