1 | /* GIO - GLib Input, Output and Streaming Library |
2 | * |
3 | * Copyright (C) 2006-2007 Red Hat, Inc. |
4 | * Copyright (C) 2007 Jürg Billeter |
5 | * Copyright © 2009 Codethink Limited |
6 | * |
7 | * This library is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU Lesser General Public |
9 | * License as published by the Free Software Foundation; either |
10 | * version 2.1 of the License, or (at your option) any later version. |
11 | * |
12 | * This library is distributed in the hope that it will be useful, |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | * Lesser General Public License for more details. |
16 | * |
17 | * You should have received a copy of the GNU Lesser General |
18 | * Public License along with this library; if not, see <http://www.gnu.org/licenses/>. |
19 | * |
20 | * Author: Alexander Larsson <alexl@redhat.com> |
21 | */ |
22 | |
23 | #include "config.h" |
24 | #include "gdatainputstream.h" |
25 | #include "gtask.h" |
26 | #include "gcancellable.h" |
27 | #include "gioenumtypes.h" |
28 | #include "gioerror.h" |
29 | #include "glibintl.h" |
30 | |
31 | #include <string.h> |
32 | |
33 | /** |
34 | * SECTION:gdatainputstream |
35 | * @short_description: Data Input Stream |
36 | * @include: gio/gio.h |
37 | * @see_also: #GInputStream |
38 | * |
39 | * Data input stream implements #GInputStream and includes functions for |
40 | * reading structured data directly from a binary input stream. |
41 | * |
42 | **/ |
43 | |
44 | struct _GDataInputStreamPrivate { |
45 | GDataStreamByteOrder byte_order; |
46 | GDataStreamNewlineType newline_type; |
47 | }; |
48 | |
49 | enum { |
50 | PROP_0, |
51 | PROP_BYTE_ORDER, |
52 | PROP_NEWLINE_TYPE |
53 | }; |
54 | |
55 | static void g_data_input_stream_set_property (GObject *object, |
56 | guint prop_id, |
57 | const GValue *value, |
58 | GParamSpec *pspec); |
59 | static void g_data_input_stream_get_property (GObject *object, |
60 | guint prop_id, |
61 | GValue *value, |
62 | GParamSpec *pspec); |
63 | |
64 | G_DEFINE_TYPE_WITH_PRIVATE (GDataInputStream, |
65 | g_data_input_stream, |
66 | G_TYPE_BUFFERED_INPUT_STREAM) |
67 | |
68 | |
69 | static void |
70 | g_data_input_stream_class_init (GDataInputStreamClass *klass) |
71 | { |
72 | GObjectClass *object_class; |
73 | |
74 | object_class = G_OBJECT_CLASS (klass); |
75 | object_class->get_property = g_data_input_stream_get_property; |
76 | object_class->set_property = g_data_input_stream_set_property; |
77 | |
78 | /** |
79 | * GDataStream:byte-order: |
80 | * |
81 | * The ::byte-order property determines the byte ordering that |
82 | * is used when reading multi-byte entities (such as integers) |
83 | * from the stream. |
84 | */ |
85 | g_object_class_install_property (oclass: object_class, |
86 | property_id: PROP_BYTE_ORDER, |
87 | pspec: g_param_spec_enum (name: "byte-order" , |
88 | P_("Byte order" ), |
89 | P_("The byte order" ), |
90 | enum_type: G_TYPE_DATA_STREAM_BYTE_ORDER, |
91 | default_value: G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN, |
92 | flags: G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_BLURB)); |
93 | |
94 | /** |
95 | * GDataStream:newline-type: |
96 | * |
97 | * The :newline-type property determines what is considered |
98 | * as a line ending when reading complete lines from the stream. |
99 | */ |
100 | g_object_class_install_property (oclass: object_class, |
101 | property_id: PROP_NEWLINE_TYPE, |
102 | pspec: g_param_spec_enum (name: "newline-type" , |
103 | P_("Newline type" ), |
104 | P_("The accepted types of line ending" ), |
105 | enum_type: G_TYPE_DATA_STREAM_NEWLINE_TYPE, |
106 | default_value: G_DATA_STREAM_NEWLINE_TYPE_LF, |
107 | flags: G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_BLURB)); |
108 | } |
109 | |
110 | static void |
111 | g_data_input_stream_set_property (GObject *object, |
112 | guint prop_id, |
113 | const GValue *value, |
114 | GParamSpec *pspec) |
115 | { |
116 | GDataInputStream *dstream; |
117 | |
118 | dstream = G_DATA_INPUT_STREAM (object); |
119 | |
120 | switch (prop_id) |
121 | { |
122 | case PROP_BYTE_ORDER: |
123 | g_data_input_stream_set_byte_order (stream: dstream, order: g_value_get_enum (value)); |
124 | break; |
125 | |
126 | case PROP_NEWLINE_TYPE: |
127 | g_data_input_stream_set_newline_type (stream: dstream, type: g_value_get_enum (value)); |
128 | break; |
129 | |
130 | default: |
131 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
132 | break; |
133 | } |
134 | |
135 | } |
136 | |
137 | static void |
138 | g_data_input_stream_get_property (GObject *object, |
139 | guint prop_id, |
140 | GValue *value, |
141 | GParamSpec *pspec) |
142 | { |
143 | GDataInputStreamPrivate *priv; |
144 | GDataInputStream *dstream; |
145 | |
146 | dstream = G_DATA_INPUT_STREAM (object); |
147 | priv = dstream->priv; |
148 | |
149 | switch (prop_id) |
150 | { |
151 | case PROP_BYTE_ORDER: |
152 | g_value_set_enum (value, v_enum: priv->byte_order); |
153 | break; |
154 | |
155 | case PROP_NEWLINE_TYPE: |
156 | g_value_set_enum (value, v_enum: priv->newline_type); |
157 | break; |
158 | |
159 | default: |
160 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
161 | break; |
162 | } |
163 | |
164 | } |
165 | static void |
166 | g_data_input_stream_init (GDataInputStream *stream) |
167 | { |
168 | stream->priv = g_data_input_stream_get_instance_private (self: stream); |
169 | stream->priv->byte_order = G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN; |
170 | stream->priv->newline_type = G_DATA_STREAM_NEWLINE_TYPE_LF; |
171 | } |
172 | |
173 | /** |
174 | * g_data_input_stream_new: |
175 | * @base_stream: a #GInputStream. |
176 | * |
177 | * Creates a new data input stream for the @base_stream. |
178 | * |
179 | * Returns: a new #GDataInputStream. |
180 | **/ |
181 | GDataInputStream * |
182 | g_data_input_stream_new (GInputStream *base_stream) |
183 | { |
184 | GDataInputStream *stream; |
185 | |
186 | g_return_val_if_fail (G_IS_INPUT_STREAM (base_stream), NULL); |
187 | |
188 | stream = g_object_new (G_TYPE_DATA_INPUT_STREAM, |
189 | first_property_name: "base-stream" , base_stream, |
190 | NULL); |
191 | |
192 | return stream; |
193 | } |
194 | |
195 | /** |
196 | * g_data_input_stream_set_byte_order: |
197 | * @stream: a given #GDataInputStream. |
198 | * @order: a #GDataStreamByteOrder to set. |
199 | * |
200 | * This function sets the byte order for the given @stream. All subsequent |
201 | * reads from the @stream will be read in the given @order. |
202 | * |
203 | **/ |
204 | void |
205 | g_data_input_stream_set_byte_order (GDataInputStream *stream, |
206 | GDataStreamByteOrder order) |
207 | { |
208 | GDataInputStreamPrivate *priv; |
209 | |
210 | g_return_if_fail (G_IS_DATA_INPUT_STREAM (stream)); |
211 | |
212 | priv = stream->priv; |
213 | |
214 | if (priv->byte_order != order) |
215 | { |
216 | priv->byte_order = order; |
217 | |
218 | g_object_notify (G_OBJECT (stream), property_name: "byte-order" ); |
219 | } |
220 | } |
221 | |
222 | /** |
223 | * g_data_input_stream_get_byte_order: |
224 | * @stream: a given #GDataInputStream. |
225 | * |
226 | * Gets the byte order for the data input stream. |
227 | * |
228 | * Returns: the @stream's current #GDataStreamByteOrder. |
229 | **/ |
230 | GDataStreamByteOrder |
231 | g_data_input_stream_get_byte_order (GDataInputStream *stream) |
232 | { |
233 | g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN); |
234 | |
235 | return stream->priv->byte_order; |
236 | } |
237 | |
238 | /** |
239 | * g_data_input_stream_set_newline_type: |
240 | * @stream: a #GDataInputStream. |
241 | * @type: the type of new line return as #GDataStreamNewlineType. |
242 | * |
243 | * Sets the newline type for the @stream. |
244 | * |
245 | * Note that using G_DATA_STREAM_NEWLINE_TYPE_ANY is slightly unsafe. If a read |
246 | * chunk ends in "CR" we must read an additional byte to know if this is "CR" or |
247 | * "CR LF", and this might block if there is no more data available. |
248 | * |
249 | **/ |
250 | void |
251 | g_data_input_stream_set_newline_type (GDataInputStream *stream, |
252 | GDataStreamNewlineType type) |
253 | { |
254 | GDataInputStreamPrivate *priv; |
255 | |
256 | g_return_if_fail (G_IS_DATA_INPUT_STREAM (stream)); |
257 | |
258 | priv = stream->priv; |
259 | |
260 | if (priv->newline_type != type) |
261 | { |
262 | priv->newline_type = type; |
263 | |
264 | g_object_notify (G_OBJECT (stream), property_name: "newline-type" ); |
265 | } |
266 | } |
267 | |
268 | /** |
269 | * g_data_input_stream_get_newline_type: |
270 | * @stream: a given #GDataInputStream. |
271 | * |
272 | * Gets the current newline type for the @stream. |
273 | * |
274 | * Returns: #GDataStreamNewlineType for the given @stream. |
275 | **/ |
276 | GDataStreamNewlineType |
277 | g_data_input_stream_get_newline_type (GDataInputStream *stream) |
278 | { |
279 | g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), G_DATA_STREAM_NEWLINE_TYPE_ANY); |
280 | |
281 | return stream->priv->newline_type; |
282 | } |
283 | |
284 | static gboolean |
285 | read_data (GDataInputStream *stream, |
286 | void *buffer, |
287 | gsize size, |
288 | GCancellable *cancellable, |
289 | GError **error) |
290 | { |
291 | gsize available; |
292 | gssize res; |
293 | |
294 | while ((available = g_buffered_input_stream_get_available (G_BUFFERED_INPUT_STREAM (stream))) < size) |
295 | { |
296 | res = g_buffered_input_stream_fill (G_BUFFERED_INPUT_STREAM (stream), |
297 | count: size - available, |
298 | cancellable, error); |
299 | if (res < 0) |
300 | return FALSE; |
301 | if (res == 0) |
302 | { |
303 | g_set_error_literal (err: error, G_IO_ERROR, code: G_IO_ERROR_FAILED, |
304 | _("Unexpected early end-of-stream" )); |
305 | return FALSE; |
306 | } |
307 | } |
308 | |
309 | /* This should always succeed, since it's in the buffer */ |
310 | res = g_input_stream_read (G_INPUT_STREAM (stream), |
311 | buffer, count: size, |
312 | NULL, NULL); |
313 | g_warn_if_fail (res >= 0 && (gsize) res == size); |
314 | return TRUE; |
315 | } |
316 | |
317 | |
318 | /** |
319 | * g_data_input_stream_read_byte: |
320 | * @stream: a given #GDataInputStream. |
321 | * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore. |
322 | * @error: #GError for error reporting. |
323 | * |
324 | * Reads an unsigned 8-bit/1-byte value from @stream. |
325 | * |
326 | * Returns: an unsigned 8-bit/1-byte value read from the @stream or `0` |
327 | * if an error occurred. |
328 | **/ |
329 | guchar |
330 | g_data_input_stream_read_byte (GDataInputStream *stream, |
331 | GCancellable *cancellable, |
332 | GError **error) |
333 | { |
334 | guchar c; |
335 | |
336 | g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), '\0'); |
337 | |
338 | if (read_data (stream, buffer: &c, size: 1, cancellable, error)) |
339 | return c; |
340 | |
341 | return 0; |
342 | } |
343 | |
344 | |
345 | /** |
346 | * g_data_input_stream_read_int16: |
347 | * @stream: a given #GDataInputStream. |
348 | * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore. |
349 | * @error: #GError for error reporting. |
350 | * |
351 | * Reads a 16-bit/2-byte value from @stream. |
352 | * |
353 | * In order to get the correct byte order for this read operation, |
354 | * see g_data_input_stream_get_byte_order() and g_data_input_stream_set_byte_order(). |
355 | * |
356 | * Returns: a signed 16-bit/2-byte value read from @stream or `0` if |
357 | * an error occurred. |
358 | **/ |
359 | gint16 |
360 | g_data_input_stream_read_int16 (GDataInputStream *stream, |
361 | GCancellable *cancellable, |
362 | GError **error) |
363 | { |
364 | gint16 v; |
365 | |
366 | g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), 0); |
367 | |
368 | if (read_data (stream, buffer: &v, size: 2, cancellable, error)) |
369 | { |
370 | switch (stream->priv->byte_order) |
371 | { |
372 | case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN: |
373 | v = GINT16_FROM_BE (v); |
374 | break; |
375 | case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN: |
376 | v = GINT16_FROM_LE (v); |
377 | break; |
378 | case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN: |
379 | default: |
380 | break; |
381 | } |
382 | return v; |
383 | } |
384 | |
385 | return 0; |
386 | } |
387 | |
388 | |
389 | /** |
390 | * g_data_input_stream_read_uint16: |
391 | * @stream: a given #GDataInputStream. |
392 | * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore. |
393 | * @error: #GError for error reporting. |
394 | * |
395 | * Reads an unsigned 16-bit/2-byte value from @stream. |
396 | * |
397 | * In order to get the correct byte order for this read operation, |
398 | * see g_data_input_stream_get_byte_order() and g_data_input_stream_set_byte_order(). |
399 | * |
400 | * Returns: an unsigned 16-bit/2-byte value read from the @stream or `0` if |
401 | * an error occurred. |
402 | **/ |
403 | guint16 |
404 | g_data_input_stream_read_uint16 (GDataInputStream *stream, |
405 | GCancellable *cancellable, |
406 | GError **error) |
407 | { |
408 | guint16 v; |
409 | |
410 | g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), 0); |
411 | |
412 | if (read_data (stream, buffer: &v, size: 2, cancellable, error)) |
413 | { |
414 | switch (stream->priv->byte_order) |
415 | { |
416 | case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN: |
417 | v = GUINT16_FROM_BE (v); |
418 | break; |
419 | case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN: |
420 | v = GUINT16_FROM_LE (v); |
421 | break; |
422 | case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN: |
423 | default: |
424 | break; |
425 | } |
426 | return v; |
427 | } |
428 | |
429 | return 0; |
430 | } |
431 | |
432 | |
433 | /** |
434 | * g_data_input_stream_read_int32: |
435 | * @stream: a given #GDataInputStream. |
436 | * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore. |
437 | * @error: #GError for error reporting. |
438 | * |
439 | * Reads a signed 32-bit/4-byte value from @stream. |
440 | * |
441 | * In order to get the correct byte order for this read operation, |
442 | * see g_data_input_stream_get_byte_order() and g_data_input_stream_set_byte_order(). |
443 | * |
444 | * If @cancellable is not %NULL, then the operation can be cancelled by |
445 | * triggering the cancellable object from another thread. If the operation |
446 | * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned. |
447 | * |
448 | * Returns: a signed 32-bit/4-byte value read from the @stream or `0` if |
449 | * an error occurred. |
450 | **/ |
451 | gint32 |
452 | g_data_input_stream_read_int32 (GDataInputStream *stream, |
453 | GCancellable *cancellable, |
454 | GError **error) |
455 | { |
456 | gint32 v; |
457 | |
458 | g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), 0); |
459 | |
460 | if (read_data (stream, buffer: &v, size: 4, cancellable, error)) |
461 | { |
462 | switch (stream->priv->byte_order) |
463 | { |
464 | case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN: |
465 | v = GINT32_FROM_BE (v); |
466 | break; |
467 | case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN: |
468 | v = GINT32_FROM_LE (v); |
469 | break; |
470 | case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN: |
471 | default: |
472 | break; |
473 | } |
474 | return v; |
475 | } |
476 | |
477 | return 0; |
478 | } |
479 | |
480 | |
481 | /** |
482 | * g_data_input_stream_read_uint32: |
483 | * @stream: a given #GDataInputStream. |
484 | * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore. |
485 | * @error: #GError for error reporting. |
486 | * |
487 | * Reads an unsigned 32-bit/4-byte value from @stream. |
488 | * |
489 | * In order to get the correct byte order for this read operation, |
490 | * see g_data_input_stream_get_byte_order() and g_data_input_stream_set_byte_order(). |
491 | * |
492 | * If @cancellable is not %NULL, then the operation can be cancelled by |
493 | * triggering the cancellable object from another thread. If the operation |
494 | * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned. |
495 | * |
496 | * Returns: an unsigned 32-bit/4-byte value read from the @stream or `0` if |
497 | * an error occurred. |
498 | **/ |
499 | guint32 |
500 | g_data_input_stream_read_uint32 (GDataInputStream *stream, |
501 | GCancellable *cancellable, |
502 | GError **error) |
503 | { |
504 | guint32 v; |
505 | |
506 | g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), 0); |
507 | |
508 | if (read_data (stream, buffer: &v, size: 4, cancellable, error)) |
509 | { |
510 | switch (stream->priv->byte_order) |
511 | { |
512 | case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN: |
513 | v = GUINT32_FROM_BE (v); |
514 | break; |
515 | case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN: |
516 | v = GUINT32_FROM_LE (v); |
517 | break; |
518 | case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN: |
519 | default: |
520 | break; |
521 | } |
522 | return v; |
523 | } |
524 | |
525 | return 0; |
526 | } |
527 | |
528 | |
529 | /** |
530 | * g_data_input_stream_read_int64: |
531 | * @stream: a given #GDataInputStream. |
532 | * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore. |
533 | * @error: #GError for error reporting. |
534 | * |
535 | * Reads a 64-bit/8-byte value from @stream. |
536 | * |
537 | * In order to get the correct byte order for this read operation, |
538 | * see g_data_input_stream_get_byte_order() and g_data_input_stream_set_byte_order(). |
539 | * |
540 | * If @cancellable is not %NULL, then the operation can be cancelled by |
541 | * triggering the cancellable object from another thread. If the operation |
542 | * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned. |
543 | * |
544 | * Returns: a signed 64-bit/8-byte value read from @stream or `0` if |
545 | * an error occurred. |
546 | **/ |
547 | gint64 |
548 | g_data_input_stream_read_int64 (GDataInputStream *stream, |
549 | GCancellable *cancellable, |
550 | GError **error) |
551 | { |
552 | gint64 v; |
553 | |
554 | g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), 0); |
555 | |
556 | if (read_data (stream, buffer: &v, size: 8, cancellable, error)) |
557 | { |
558 | switch (stream->priv->byte_order) |
559 | { |
560 | case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN: |
561 | v = GINT64_FROM_BE (v); |
562 | break; |
563 | case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN: |
564 | v = GINT64_FROM_LE (v); |
565 | break; |
566 | case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN: |
567 | default: |
568 | break; |
569 | } |
570 | return v; |
571 | } |
572 | |
573 | return 0; |
574 | } |
575 | |
576 | |
577 | /** |
578 | * g_data_input_stream_read_uint64: |
579 | * @stream: a given #GDataInputStream. |
580 | * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore. |
581 | * @error: #GError for error reporting. |
582 | * |
583 | * Reads an unsigned 64-bit/8-byte value from @stream. |
584 | * |
585 | * In order to get the correct byte order for this read operation, |
586 | * see g_data_input_stream_get_byte_order(). |
587 | * |
588 | * If @cancellable is not %NULL, then the operation can be cancelled by |
589 | * triggering the cancellable object from another thread. If the operation |
590 | * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned. |
591 | * |
592 | * Returns: an unsigned 64-bit/8-byte read from @stream or `0` if |
593 | * an error occurred. |
594 | **/ |
595 | guint64 |
596 | g_data_input_stream_read_uint64 (GDataInputStream *stream, |
597 | GCancellable *cancellable, |
598 | GError **error) |
599 | { |
600 | guint64 v; |
601 | |
602 | g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), 0); |
603 | |
604 | if (read_data (stream, buffer: &v, size: 8, cancellable, error)) |
605 | { |
606 | switch (stream->priv->byte_order) |
607 | { |
608 | case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN: |
609 | v = GUINT64_FROM_BE (v); |
610 | break; |
611 | case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN: |
612 | v = GUINT64_FROM_LE (v); |
613 | break; |
614 | case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN: |
615 | default: |
616 | break; |
617 | } |
618 | return v; |
619 | } |
620 | |
621 | return 0; |
622 | } |
623 | |
624 | static gssize |
625 | scan_for_newline (GDataInputStream *stream, |
626 | gsize *checked_out, |
627 | gboolean *last_saw_cr_out, |
628 | int *newline_len_out) |
629 | { |
630 | GBufferedInputStream *bstream; |
631 | GDataInputStreamPrivate *priv; |
632 | const char *buffer; |
633 | gsize start, end, peeked; |
634 | gsize i; |
635 | gssize found_pos; |
636 | int newline_len; |
637 | gsize available, checked; |
638 | gboolean last_saw_cr; |
639 | |
640 | priv = stream->priv; |
641 | |
642 | bstream = G_BUFFERED_INPUT_STREAM (stream); |
643 | |
644 | checked = *checked_out; |
645 | last_saw_cr = *last_saw_cr_out; |
646 | found_pos = -1; |
647 | newline_len = 0; |
648 | |
649 | start = checked; |
650 | buffer = (const char*)g_buffered_input_stream_peek_buffer (stream: bstream, count: &available) + start; |
651 | end = available; |
652 | peeked = end - start; |
653 | |
654 | for (i = 0; checked < available && i < peeked; i++) |
655 | { |
656 | switch (priv->newline_type) |
657 | { |
658 | case G_DATA_STREAM_NEWLINE_TYPE_LF: |
659 | if (buffer[i] == 10) |
660 | { |
661 | found_pos = start + i; |
662 | newline_len = 1; |
663 | } |
664 | break; |
665 | case G_DATA_STREAM_NEWLINE_TYPE_CR: |
666 | if (buffer[i] == 13) |
667 | { |
668 | found_pos = start + i; |
669 | newline_len = 1; |
670 | } |
671 | break; |
672 | case G_DATA_STREAM_NEWLINE_TYPE_CR_LF: |
673 | if (last_saw_cr && buffer[i] == 10) |
674 | { |
675 | found_pos = start + i - 1; |
676 | newline_len = 2; |
677 | } |
678 | break; |
679 | default: |
680 | case G_DATA_STREAM_NEWLINE_TYPE_ANY: |
681 | if (buffer[i] == 10) /* LF */ |
682 | { |
683 | if (last_saw_cr) |
684 | { |
685 | /* CR LF */ |
686 | found_pos = start + i - 1; |
687 | newline_len = 2; |
688 | } |
689 | else |
690 | { |
691 | /* LF */ |
692 | found_pos = start + i; |
693 | newline_len = 1; |
694 | } |
695 | } |
696 | else if (last_saw_cr) |
697 | { |
698 | /* Last was cr, this is not LF, end is CR */ |
699 | found_pos = start + i - 1; |
700 | newline_len = 1; |
701 | } |
702 | /* Don't check for CR here, instead look at last_saw_cr on next byte */ |
703 | break; |
704 | } |
705 | |
706 | last_saw_cr = (buffer[i] == 13); |
707 | |
708 | if (found_pos != -1) |
709 | { |
710 | *newline_len_out = newline_len; |
711 | return found_pos; |
712 | } |
713 | } |
714 | |
715 | checked = end; |
716 | |
717 | *checked_out = checked; |
718 | *last_saw_cr_out = last_saw_cr; |
719 | return -1; |
720 | } |
721 | |
722 | |
723 | /** |
724 | * g_data_input_stream_read_line: |
725 | * @stream: a given #GDataInputStream. |
726 | * @length: (out) (optional): a #gsize to get the length of the data read in. |
727 | * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore. |
728 | * @error: #GError for error reporting. |
729 | * |
730 | * Reads a line from the data input stream. Note that no encoding |
731 | * checks or conversion is performed; the input is not guaranteed to |
732 | * be UTF-8, and may in fact have embedded NUL characters. |
733 | * |
734 | * If @cancellable is not %NULL, then the operation can be cancelled by |
735 | * triggering the cancellable object from another thread. If the operation |
736 | * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned. |
737 | * |
738 | * Returns: (nullable) (transfer full) (array zero-terminated=1) (element-type guint8): |
739 | * a NUL terminated byte array with the line that was read in |
740 | * (without the newlines). Set @length to a #gsize to get the length |
741 | * of the read line. On an error, it will return %NULL and @error |
742 | * will be set. If there's no content to read, it will still return |
743 | * %NULL, but @error won't be set. |
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_out: &checked, last_saw_cr_out: &last_saw_cr, newline_len_out: &newline_len)) == -1) |
768 | { |
769 | if (g_buffered_input_stream_get_available (stream: bstream) == |
770 | g_buffered_input_stream_get_buffer_size (stream: bstream)) |
771 | g_buffered_input_stream_set_buffer_size (stream: bstream, |
772 | size: 2 * g_buffered_input_stream_get_buffer_size (stream: bstream)); |
773 | |
774 | res = g_buffered_input_stream_fill (stream: bstream, count: -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 (stream: 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 (n_bytes: found_pos + newline_len + 1); |
796 | |
797 | res = g_input_stream_read (G_INPUT_STREAM (stream), |
798 | buffer: line, |
799 | count: 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 | * g_data_input_stream_read_line_utf8: |
811 | * @stream: a given #GDataInputStream. |
812 | * @length: (out) (optional): a #gsize to get the length of the data read in. |
813 | * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore. |
814 | * @error: #GError for error reporting. |
815 | * |
816 | * Reads a UTF-8 encoded line from the data input stream. |
817 | * |
818 | * If @cancellable is not %NULL, then the operation can be cancelled by |
819 | * triggering the cancellable object from another thread. If the operation |
820 | * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned. |
821 | * |
822 | * Returns: (nullable) (transfer full): a NUL terminated UTF-8 string |
823 | * with the line that was read in (without the newlines). Set |
824 | * @length to a #gsize to get the length of the read line. On an |
825 | * error, it will return %NULL and @error will be set. For UTF-8 |
826 | * conversion errors, the set error domain is %G_CONVERT_ERROR. If |
827 | * there's no content to read, it will still return %NULL, but @error |
828 | * won't be set. |
829 | * |
830 | * Since: 2.30 |
831 | **/ |
832 | char * |
833 | g_data_input_stream_read_line_utf8 (GDataInputStream *stream, |
834 | gsize *length, |
835 | GCancellable *cancellable, |
836 | GError **error) |
837 | { |
838 | char *res; |
839 | |
840 | res = g_data_input_stream_read_line (stream, length, cancellable, error); |
841 | if (!res) |
842 | return NULL; |
843 | |
844 | if (!g_utf8_validate (str: res, max_len: -1, NULL)) |
845 | { |
846 | g_set_error_literal (err: error, G_CONVERT_ERROR, |
847 | code: G_CONVERT_ERROR_ILLEGAL_SEQUENCE, |
848 | _("Invalid byte sequence in conversion input" )); |
849 | g_free (mem: res); |
850 | return NULL; |
851 | } |
852 | return res; |
853 | } |
854 | |
855 | static gssize |
856 | scan_for_chars (GDataInputStream *stream, |
857 | gsize *checked_out, |
858 | const char *stop_chars, |
859 | gsize stop_chars_len) |
860 | { |
861 | GBufferedInputStream *bstream; |
862 | const char *buffer; |
863 | gsize start, end, peeked; |
864 | gsize i; |
865 | gsize available, checked; |
866 | const char *stop_char; |
867 | const char *stop_end; |
868 | |
869 | bstream = G_BUFFERED_INPUT_STREAM (stream); |
870 | stop_end = stop_chars + stop_chars_len; |
871 | |
872 | checked = *checked_out; |
873 | |
874 | start = checked; |
875 | buffer = (const char *)g_buffered_input_stream_peek_buffer (stream: bstream, count: &available) + start; |
876 | end = available; |
877 | peeked = end - start; |
878 | |
879 | for (i = 0; checked < available && i < peeked; i++) |
880 | { |
881 | for (stop_char = stop_chars; stop_char != stop_end; stop_char++) |
882 | { |
883 | if (buffer[i] == *stop_char) |
884 | return (start + i); |
885 | } |
886 | } |
887 | |
888 | checked = end; |
889 | |
890 | *checked_out = checked; |
891 | return -1; |
892 | } |
893 | |
894 | /** |
895 | * g_data_input_stream_read_until: |
896 | * @stream: a given #GDataInputStream. |
897 | * @stop_chars: characters to terminate the read. |
898 | * @length: (out) (optional): a #gsize to get the length of the data read in. |
899 | * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore. |
900 | * @error: #GError for error reporting. |
901 | * |
902 | * Reads a string from the data input stream, up to the first |
903 | * occurrence of any of the stop characters. |
904 | * |
905 | * Note that, in contrast to g_data_input_stream_read_until_async(), |
906 | * this function consumes the stop character that it finds. |
907 | * |
908 | * Don't use this function in new code. Its functionality is |
909 | * inconsistent with g_data_input_stream_read_until_async(). Both |
910 | * functions will be marked as deprecated in a future release. Use |
911 | * g_data_input_stream_read_upto() instead, but note that that function |
912 | * does not consume the stop character. |
913 | * |
914 | * Returns: (transfer full): a string with the data that was read |
915 | * before encountering any of the stop characters. Set @length to |
916 | * a #gsize to get the length of the string. This function will |
917 | * return %NULL on an error. |
918 | * Deprecated: 2.56: Use g_data_input_stream_read_upto() instead, which has more |
919 | * consistent behaviour regarding the stop character. |
920 | */ |
921 | char * |
922 | g_data_input_stream_read_until (GDataInputStream *stream, |
923 | const gchar *stop_chars, |
924 | gsize *length, |
925 | GCancellable *cancellable, |
926 | GError **error) |
927 | { |
928 | GBufferedInputStream *bstream; |
929 | gchar *result; |
930 | |
931 | bstream = G_BUFFERED_INPUT_STREAM (stream); |
932 | |
933 | result = g_data_input_stream_read_upto (stream, stop_chars, stop_chars_len: -1, |
934 | length, cancellable, error); |
935 | |
936 | /* If we're not at end of stream then we have a stop_char to consume. */ |
937 | if (result != NULL && g_buffered_input_stream_get_available (stream: bstream) > 0) |
938 | { |
939 | gsize res G_GNUC_UNUSED /* when compiling with G_DISABLE_ASSERT */; |
940 | gchar b; |
941 | |
942 | res = g_input_stream_read (G_INPUT_STREAM (stream), buffer: &b, count: 1, NULL, NULL); |
943 | g_assert (res == 1); |
944 | } |
945 | |
946 | return result; |
947 | } |
948 | |
949 | typedef struct |
950 | { |
951 | gboolean last_saw_cr; |
952 | gsize checked; |
953 | |
954 | gchar *stop_chars; |
955 | gsize stop_chars_len; |
956 | gsize length; |
957 | } GDataInputStreamReadData; |
958 | |
959 | static void |
960 | g_data_input_stream_read_complete (GTask *task, |
961 | gsize read_length, |
962 | gsize skip_length) |
963 | { |
964 | GDataInputStreamReadData *data = g_task_get_task_data (task); |
965 | GInputStream *stream = g_task_get_source_object (task); |
966 | char *line = NULL; |
967 | |
968 | if (read_length || skip_length) |
969 | { |
970 | gssize bytes; |
971 | |
972 | data->length = read_length; |
973 | line = g_malloc (n_bytes: read_length + 1); |
974 | line[read_length] = '\0'; |
975 | |
976 | /* we already checked the buffer. this shouldn't fail. */ |
977 | bytes = g_input_stream_read (stream, buffer: line, count: read_length, NULL, NULL); |
978 | g_assert_cmpint (bytes, ==, read_length); |
979 | |
980 | bytes = g_input_stream_skip (stream, count: skip_length, NULL, NULL); |
981 | g_assert_cmpint (bytes, ==, skip_length); |
982 | } |
983 | |
984 | g_task_return_pointer (task, result: line, result_destroy: g_free); |
985 | g_object_unref (object: task); |
986 | } |
987 | |
988 | static void |
989 | g_data_input_stream_read_line_ready (GObject *object, |
990 | GAsyncResult *result, |
991 | gpointer user_data) |
992 | { |
993 | GTask *task = user_data; |
994 | GDataInputStreamReadData *data = g_task_get_task_data (task); |
995 | GBufferedInputStream *buffer = g_task_get_source_object (task); |
996 | gssize found_pos; |
997 | gint newline_len; |
998 | |
999 | if (result) |
1000 | /* this is a callback. finish the async call. */ |
1001 | { |
1002 | GError *error = NULL; |
1003 | gssize bytes; |
1004 | |
1005 | bytes = g_buffered_input_stream_fill_finish (stream: buffer, result, error: &error); |
1006 | |
1007 | if (bytes <= 0) |
1008 | { |
1009 | if (bytes < 0) |
1010 | /* stream error. */ |
1011 | { |
1012 | g_task_return_error (task, error); |
1013 | g_object_unref (object: task); |
1014 | return; |
1015 | } |
1016 | |
1017 | g_data_input_stream_read_complete (task, read_length: data->checked, skip_length: 0); |
1018 | return; |
1019 | } |
1020 | |
1021 | /* only proceed if we got more bytes... */ |
1022 | } |
1023 | |
1024 | if (data->stop_chars) |
1025 | { |
1026 | found_pos = scan_for_chars (G_DATA_INPUT_STREAM (buffer), |
1027 | checked_out: &data->checked, |
1028 | stop_chars: data->stop_chars, |
1029 | stop_chars_len: data->stop_chars_len); |
1030 | newline_len = 0; |
1031 | } |
1032 | else |
1033 | found_pos = scan_for_newline (G_DATA_INPUT_STREAM (buffer), checked_out: &data->checked, |
1034 | last_saw_cr_out: &data->last_saw_cr, newline_len_out: &newline_len); |
1035 | |
1036 | if (found_pos == -1) |
1037 | /* didn't find a full line; need to buffer some more bytes */ |
1038 | { |
1039 | gsize size; |
1040 | |
1041 | size = g_buffered_input_stream_get_buffer_size (stream: buffer); |
1042 | |
1043 | if (g_buffered_input_stream_get_available (stream: buffer) == size) |
1044 | /* need to grow the buffer */ |
1045 | g_buffered_input_stream_set_buffer_size (stream: buffer, size: size * 2); |
1046 | |
1047 | /* try again */ |
1048 | g_buffered_input_stream_fill_async (stream: buffer, count: -1, |
1049 | io_priority: g_task_get_priority (task), |
1050 | cancellable: g_task_get_cancellable (task), |
1051 | callback: g_data_input_stream_read_line_ready, |
1052 | user_data); |
1053 | } |
1054 | else |
1055 | { |
1056 | /* read the line and the EOL. no error is possible. */ |
1057 | g_data_input_stream_read_complete (task, read_length: found_pos, skip_length: newline_len); |
1058 | } |
1059 | } |
1060 | |
1061 | static void |
1062 | g_data_input_stream_read_data_free (gpointer user_data) |
1063 | { |
1064 | GDataInputStreamReadData *data = user_data; |
1065 | |
1066 | g_free (mem: data->stop_chars); |
1067 | g_slice_free (GDataInputStreamReadData, data); |
1068 | } |
1069 | |
1070 | static void |
1071 | g_data_input_stream_read_async (GDataInputStream *stream, |
1072 | const gchar *stop_chars, |
1073 | gssize stop_chars_len, |
1074 | gint io_priority, |
1075 | GCancellable *cancellable, |
1076 | GAsyncReadyCallback callback, |
1077 | gpointer user_data) |
1078 | { |
1079 | GDataInputStreamReadData *data; |
1080 | GTask *task; |
1081 | gsize stop_chars_len_unsigned; |
1082 | |
1083 | data = g_slice_new0 (GDataInputStreamReadData); |
1084 | |
1085 | if (stop_chars_len < 0) |
1086 | stop_chars_len_unsigned = strlen (s: stop_chars); |
1087 | else |
1088 | stop_chars_len_unsigned = (gsize) stop_chars_len; |
1089 | |
1090 | data->stop_chars = g_memdup2 (mem: stop_chars, byte_size: stop_chars_len_unsigned); |
1091 | data->stop_chars_len = stop_chars_len_unsigned; |
1092 | data->last_saw_cr = FALSE; |
1093 | |
1094 | task = g_task_new (source_object: stream, cancellable, callback, callback_data: user_data); |
1095 | g_task_set_source_tag (task, g_data_input_stream_read_async); |
1096 | g_task_set_task_data (task, task_data: data, task_data_destroy: g_data_input_stream_read_data_free); |
1097 | g_task_set_priority (task, priority: io_priority); |
1098 | |
1099 | g_data_input_stream_read_line_ready (NULL, NULL, user_data: task); |
1100 | } |
1101 | |
1102 | static gchar * |
1103 | g_data_input_stream_read_finish (GDataInputStream *stream, |
1104 | GAsyncResult *result, |
1105 | gsize *length, |
1106 | GError **error) |
1107 | { |
1108 | GTask *task = G_TASK (result); |
1109 | gchar *line; |
1110 | |
1111 | line = g_task_propagate_pointer (task, error); |
1112 | |
1113 | if (length && line) |
1114 | { |
1115 | GDataInputStreamReadData *data = g_task_get_task_data (task); |
1116 | |
1117 | *length = data->length; |
1118 | } |
1119 | |
1120 | return line; |
1121 | } |
1122 | |
1123 | /** |
1124 | * g_data_input_stream_read_line_async: |
1125 | * @stream: a given #GDataInputStream. |
1126 | * @io_priority: the [I/O priority][io-priority] of the request |
1127 | * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore. |
1128 | * @callback: (scope async): callback to call when the request is satisfied. |
1129 | * @user_data: (closure): the data to pass to callback function. |
1130 | * |
1131 | * The asynchronous version of g_data_input_stream_read_line(). It is |
1132 | * an error to have two outstanding calls to this function. |
1133 | * |
1134 | * When the operation is finished, @callback will be called. You |
1135 | * can then call g_data_input_stream_read_line_finish() to get |
1136 | * the result of the operation. |
1137 | * |
1138 | * Since: 2.20 |
1139 | */ |
1140 | void |
1141 | g_data_input_stream_read_line_async (GDataInputStream *stream, |
1142 | gint io_priority, |
1143 | GCancellable *cancellable, |
1144 | GAsyncReadyCallback callback, |
1145 | gpointer user_data) |
1146 | { |
1147 | g_return_if_fail (G_IS_DATA_INPUT_STREAM (stream)); |
1148 | g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); |
1149 | |
1150 | g_data_input_stream_read_async (stream, NULL, stop_chars_len: 0, io_priority, |
1151 | cancellable, callback, user_data); |
1152 | } |
1153 | |
1154 | /** |
1155 | * g_data_input_stream_read_until_async: |
1156 | * @stream: a given #GDataInputStream. |
1157 | * @stop_chars: characters to terminate the read. |
1158 | * @io_priority: the [I/O priority][io-priority] of the request |
1159 | * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore. |
1160 | * @callback: (scope async): callback to call when the request is satisfied. |
1161 | * @user_data: (closure): the data to pass to callback function. |
1162 | * |
1163 | * The asynchronous version of g_data_input_stream_read_until(). |
1164 | * It is an error to have two outstanding calls to this function. |
1165 | * |
1166 | * Note that, in contrast to g_data_input_stream_read_until(), |
1167 | * this function does not consume the stop character that it finds. You |
1168 | * must read it for yourself. |
1169 | * |
1170 | * When the operation is finished, @callback will be called. You |
1171 | * can then call g_data_input_stream_read_until_finish() to get |
1172 | * the result of the operation. |
1173 | * |
1174 | * Don't use this function in new code. Its functionality is |
1175 | * inconsistent with g_data_input_stream_read_until(). Both functions |
1176 | * will be marked as deprecated in a future release. Use |
1177 | * g_data_input_stream_read_upto_async() instead. |
1178 | * |
1179 | * Since: 2.20 |
1180 | * Deprecated: 2.56: Use g_data_input_stream_read_upto_async() instead, which |
1181 | * has more consistent behaviour regarding the stop character. |
1182 | */ |
1183 | void |
1184 | g_data_input_stream_read_until_async (GDataInputStream *stream, |
1185 | const gchar *stop_chars, |
1186 | gint io_priority, |
1187 | GCancellable *cancellable, |
1188 | GAsyncReadyCallback callback, |
1189 | gpointer user_data) |
1190 | { |
1191 | g_return_if_fail (G_IS_DATA_INPUT_STREAM (stream)); |
1192 | g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); |
1193 | g_return_if_fail (stop_chars != NULL); |
1194 | |
1195 | g_data_input_stream_read_async (stream, stop_chars, stop_chars_len: -1, io_priority, |
1196 | cancellable, callback, user_data); |
1197 | } |
1198 | |
1199 | /** |
1200 | * g_data_input_stream_read_line_finish: |
1201 | * @stream: a given #GDataInputStream. |
1202 | * @result: the #GAsyncResult that was provided to the callback. |
1203 | * @length: (out) (optional): a #gsize to get the length of the data read in. |
1204 | * @error: #GError for error reporting. |
1205 | * |
1206 | * Finish an asynchronous call started by |
1207 | * g_data_input_stream_read_line_async(). Note the warning about |
1208 | * string encoding in g_data_input_stream_read_line() applies here as |
1209 | * well. |
1210 | * |
1211 | * Returns: (nullable) (transfer full) (array zero-terminated=1) (element-type guint8): |
1212 | * a NUL-terminated byte array with the line that was read in |
1213 | * (without the newlines). Set @length to a #gsize to get the length |
1214 | * of the read line. On an error, it will return %NULL and @error |
1215 | * will be set. If there's no content to read, it will still return |
1216 | * %NULL, but @error won't be set. |
1217 | * |
1218 | * Since: 2.20 |
1219 | */ |
1220 | gchar * |
1221 | g_data_input_stream_read_line_finish (GDataInputStream *stream, |
1222 | GAsyncResult *result, |
1223 | gsize *length, |
1224 | GError **error) |
1225 | { |
1226 | g_return_val_if_fail (g_task_is_valid (result, stream), NULL); |
1227 | |
1228 | return g_data_input_stream_read_finish (stream, result, length, error); |
1229 | } |
1230 | |
1231 | /** |
1232 | * g_data_input_stream_read_line_finish_utf8: |
1233 | * @stream: a given #GDataInputStream. |
1234 | * @result: the #GAsyncResult that was provided to the callback. |
1235 | * @length: (out) (optional): a #gsize to get the length of the data read in. |
1236 | * @error: #GError for error reporting. |
1237 | * |
1238 | * Finish an asynchronous call started by |
1239 | * g_data_input_stream_read_line_async(). |
1240 | * |
1241 | * Returns: (nullable) (transfer full): a string with the line that |
1242 | * was read in (without the newlines). Set @length to a #gsize to |
1243 | * get the length of the read line. On an error, it will return |
1244 | * %NULL and @error will be set. For UTF-8 conversion errors, the set |
1245 | * error domain is %G_CONVERT_ERROR. If there's no content to read, |
1246 | * it will still return %NULL, but @error won't be set. |
1247 | * |
1248 | * Since: 2.30 |
1249 | */ |
1250 | gchar * |
1251 | g_data_input_stream_read_line_finish_utf8 (GDataInputStream *stream, |
1252 | GAsyncResult *result, |
1253 | gsize *length, |
1254 | GError **error) |
1255 | { |
1256 | gchar *res; |
1257 | |
1258 | res = g_data_input_stream_read_line_finish (stream, result, length, error); |
1259 | if (!res) |
1260 | return NULL; |
1261 | |
1262 | if (!g_utf8_validate (str: res, max_len: -1, NULL)) |
1263 | { |
1264 | g_set_error_literal (err: error, G_CONVERT_ERROR, |
1265 | code: G_CONVERT_ERROR_ILLEGAL_SEQUENCE, |
1266 | _("Invalid byte sequence in conversion input" )); |
1267 | g_free (mem: res); |
1268 | return NULL; |
1269 | } |
1270 | return res; |
1271 | } |
1272 | |
1273 | /** |
1274 | * g_data_input_stream_read_until_finish: |
1275 | * @stream: a given #GDataInputStream. |
1276 | * @result: the #GAsyncResult that was provided to the callback. |
1277 | * @length: (out) (optional): a #gsize to get the length of the data read in. |
1278 | * @error: #GError for error reporting. |
1279 | * |
1280 | * Finish an asynchronous call started by |
1281 | * g_data_input_stream_read_until_async(). |
1282 | * |
1283 | * Since: 2.20 |
1284 | * |
1285 | * Returns: (transfer full): a string with the data that was read |
1286 | * before encountering any of the stop characters. Set @length to |
1287 | * a #gsize to get the length of the string. This function will |
1288 | * return %NULL on an error. |
1289 | * Deprecated: 2.56: Use g_data_input_stream_read_upto_finish() instead, which |
1290 | * has more consistent behaviour regarding the stop character. |
1291 | */ |
1292 | gchar * |
1293 | g_data_input_stream_read_until_finish (GDataInputStream *stream, |
1294 | GAsyncResult *result, |
1295 | gsize *length, |
1296 | GError **error) |
1297 | { |
1298 | g_return_val_if_fail (g_task_is_valid (result, stream), NULL); |
1299 | |
1300 | return g_data_input_stream_read_finish (stream, result, length, error); |
1301 | } |
1302 | |
1303 | /** |
1304 | * g_data_input_stream_read_upto: |
1305 | * @stream: a #GDataInputStream |
1306 | * @stop_chars: characters to terminate the read |
1307 | * @stop_chars_len: length of @stop_chars. May be -1 if @stop_chars is |
1308 | * nul-terminated |
1309 | * @length: (out) (optional): a #gsize to get the length of the data read in |
1310 | * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore |
1311 | * @error: #GError for error reporting |
1312 | * |
1313 | * Reads a string from the data input stream, up to the first |
1314 | * occurrence of any of the stop characters. |
1315 | * |
1316 | * In contrast to g_data_input_stream_read_until(), this function |
1317 | * does not consume the stop character. You have to use |
1318 | * g_data_input_stream_read_byte() to get it before calling |
1319 | * g_data_input_stream_read_upto() again. |
1320 | * |
1321 | * Note that @stop_chars may contain '\0' if @stop_chars_len is |
1322 | * specified. |
1323 | * |
1324 | * The returned string will always be nul-terminated on success. |
1325 | * |
1326 | * Returns: (transfer full): a string with the data that was read |
1327 | * before encountering any of the stop characters. Set @length to |
1328 | * a #gsize to get the length of the string. This function will |
1329 | * return %NULL on an error |
1330 | * |
1331 | * Since: 2.26 |
1332 | */ |
1333 | char * |
1334 | g_data_input_stream_read_upto (GDataInputStream *stream, |
1335 | const gchar *stop_chars, |
1336 | gssize stop_chars_len, |
1337 | gsize *length, |
1338 | GCancellable *cancellable, |
1339 | GError **error) |
1340 | { |
1341 | GBufferedInputStream *bstream; |
1342 | gsize checked; |
1343 | gssize found_pos; |
1344 | gssize res; |
1345 | char *data_until; |
1346 | gsize stop_chars_len_unsigned; |
1347 | |
1348 | g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), NULL); |
1349 | |
1350 | if (stop_chars_len < 0) |
1351 | stop_chars_len_unsigned = strlen (s: stop_chars); |
1352 | else |
1353 | stop_chars_len_unsigned = (gsize) stop_chars_len; |
1354 | |
1355 | bstream = G_BUFFERED_INPUT_STREAM (stream); |
1356 | |
1357 | checked = 0; |
1358 | |
1359 | while ((found_pos = scan_for_chars (stream, checked_out: &checked, stop_chars, stop_chars_len: stop_chars_len_unsigned)) == -1) |
1360 | { |
1361 | if (g_buffered_input_stream_get_available (stream: bstream) == |
1362 | g_buffered_input_stream_get_buffer_size (stream: bstream)) |
1363 | g_buffered_input_stream_set_buffer_size (stream: bstream, |
1364 | size: 2 * g_buffered_input_stream_get_buffer_size (stream: bstream)); |
1365 | |
1366 | res = g_buffered_input_stream_fill (stream: bstream, count: -1, cancellable, error); |
1367 | if (res < 0) |
1368 | return NULL; |
1369 | if (res == 0) |
1370 | { |
1371 | /* End of stream */ |
1372 | if (g_buffered_input_stream_get_available (stream: bstream) == 0) |
1373 | { |
1374 | if (length) |
1375 | *length = 0; |
1376 | return NULL; |
1377 | } |
1378 | else |
1379 | { |
1380 | found_pos = checked; |
1381 | break; |
1382 | } |
1383 | } |
1384 | } |
1385 | |
1386 | data_until = g_malloc (n_bytes: found_pos + 1); |
1387 | |
1388 | res = g_input_stream_read (G_INPUT_STREAM (stream), |
1389 | buffer: data_until, |
1390 | count: found_pos, |
1391 | NULL, NULL); |
1392 | if (length) |
1393 | *length = (gsize)found_pos; |
1394 | g_warn_if_fail (res == found_pos); |
1395 | data_until[found_pos] = 0; |
1396 | |
1397 | return data_until; |
1398 | } |
1399 | |
1400 | /** |
1401 | * g_data_input_stream_read_upto_async: |
1402 | * @stream: a #GDataInputStream |
1403 | * @stop_chars: characters to terminate the read |
1404 | * @stop_chars_len: length of @stop_chars. May be -1 if @stop_chars is |
1405 | * nul-terminated |
1406 | * @io_priority: the [I/O priority][io-priority] of the request |
1407 | * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore |
1408 | * @callback: (scope async): callback to call when the request is satisfied |
1409 | * @user_data: (closure): the data to pass to callback function |
1410 | * |
1411 | * The asynchronous version of g_data_input_stream_read_upto(). |
1412 | * It is an error to have two outstanding calls to this function. |
1413 | * |
1414 | * In contrast to g_data_input_stream_read_until(), this function |
1415 | * does not consume the stop character. You have to use |
1416 | * g_data_input_stream_read_byte() to get it before calling |
1417 | * g_data_input_stream_read_upto() again. |
1418 | * |
1419 | * Note that @stop_chars may contain '\0' if @stop_chars_len is |
1420 | * specified. |
1421 | * |
1422 | * When the operation is finished, @callback will be called. You |
1423 | * can then call g_data_input_stream_read_upto_finish() to get |
1424 | * the result of the operation. |
1425 | * |
1426 | * Since: 2.26 |
1427 | */ |
1428 | void |
1429 | g_data_input_stream_read_upto_async (GDataInputStream *stream, |
1430 | const gchar *stop_chars, |
1431 | gssize stop_chars_len, |
1432 | gint io_priority, |
1433 | GCancellable *cancellable, |
1434 | GAsyncReadyCallback callback, |
1435 | gpointer user_data) |
1436 | { |
1437 | g_return_if_fail (G_IS_DATA_INPUT_STREAM (stream)); |
1438 | g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); |
1439 | g_return_if_fail (stop_chars != NULL); |
1440 | |
1441 | g_data_input_stream_read_async (stream, stop_chars, stop_chars_len, io_priority, |
1442 | cancellable, callback, user_data); |
1443 | } |
1444 | |
1445 | /** |
1446 | * g_data_input_stream_read_upto_finish: |
1447 | * @stream: a #GDataInputStream |
1448 | * @result: the #GAsyncResult that was provided to the callback |
1449 | * @length: (out) (optional): a #gsize to get the length of the data read in |
1450 | * @error: #GError for error reporting |
1451 | * |
1452 | * Finish an asynchronous call started by |
1453 | * g_data_input_stream_read_upto_async(). |
1454 | * |
1455 | * Note that this function does not consume the stop character. You |
1456 | * have to use g_data_input_stream_read_byte() to get it before calling |
1457 | * g_data_input_stream_read_upto_async() again. |
1458 | * |
1459 | * The returned string will always be nul-terminated on success. |
1460 | * |
1461 | * Returns: (transfer full): a string with the data that was read |
1462 | * before encountering any of the stop characters. Set @length to |
1463 | * a #gsize to get the length of the string. This function will |
1464 | * return %NULL on an error. |
1465 | * |
1466 | * Since: 2.24 |
1467 | */ |
1468 | gchar * |
1469 | g_data_input_stream_read_upto_finish (GDataInputStream *stream, |
1470 | GAsyncResult *result, |
1471 | gsize *length, |
1472 | GError **error) |
1473 | { |
1474 | g_return_val_if_fail (g_task_is_valid (result, stream), NULL); |
1475 | |
1476 | return g_data_input_stream_read_finish (stream, result, length, error); |
1477 | } |
1478 | |