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