X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gio%2Fgdatainputstream.c;h=3753bd81b721656b2a52d386eb14614546141efd;hb=cea9de93c8838099661f5b54462f9c4b6410bfc9;hp=2407637c373a6c2b10e6586bb348cc040699aee1;hpb=6c061da2a232d8c817d9744a234ceee7b87b3dd8;p=platform%2Fupstream%2Fglib.git diff --git a/gio/gdatainputstream.c b/gio/gdatainputstream.c index 2407637..3753bd8 100644 --- a/gio/gdatainputstream.c +++ b/gio/gdatainputstream.c @@ -15,22 +15,20 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General - * Public License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. + * Public License along with this library; if not, see . * * Author: Alexander Larsson */ #include "config.h" #include "gdatainputstream.h" -#include "gsimpleasyncresult.h" +#include "gtask.h" #include "gcancellable.h" #include "gioenumtypes.h" #include "gioerror.h" #include "glibintl.h" -#include "gioalias.h" +#include /** * SECTION:gdatainputstream @@ -63,9 +61,9 @@ static void g_data_input_stream_get_property (GObject *object, GValue *value, GParamSpec *pspec); -G_DEFINE_TYPE (GDataInputStream, - g_data_input_stream, - G_TYPE_BUFFERED_INPUT_STREAM) +G_DEFINE_TYPE_WITH_PRIVATE (GDataInputStream, + g_data_input_stream, + G_TYPE_BUFFERED_INPUT_STREAM) static void @@ -73,8 +71,6 @@ g_data_input_stream_class_init (GDataInputStreamClass *klass) { GObjectClass *object_class; - g_type_class_add_private (klass, sizeof (GDataInputStreamPrivate)); - object_class = G_OBJECT_CLASS (klass); object_class->get_property = g_data_input_stream_get_property; object_class->set_property = g_data_input_stream_set_property; @@ -169,10 +165,7 @@ g_data_input_stream_get_property (GObject *object, static void g_data_input_stream_init (GDataInputStream *stream) { - stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream, - G_TYPE_DATA_INPUT_STREAM, - GDataInputStreamPrivate); - + stream->priv = g_data_input_stream_get_instance_private (stream); stream->priv->byte_order = G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN; stream->priv->newline_type = G_DATA_STREAM_NEWLINE_TYPE_LF; } @@ -251,7 +244,7 @@ g_data_input_stream_get_byte_order (GDataInputStream *stream) * * Note that using G_DATA_STREAM_NEWLINE_TYPE_ANY is slightly unsafe. If a read * chunk ends in "CR" we must read an additional byte to know if this is "CR" or - * "CR LF", and this might block if there is no more data availible. + * "CR LF", and this might block if there is no more data available. * **/ void @@ -325,7 +318,7 @@ read_data (GDataInputStream *stream, /** * g_data_input_stream_read_byte: * @stream: a given #GDataInputStream. - * @cancellable: optional #GCancellable object, %NULL to ignore. + * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore. * @error: #GError for error reporting. * * Reads an unsigned 8-bit/1-byte value from @stream. @@ -352,13 +345,13 @@ g_data_input_stream_read_byte (GDataInputStream *stream, /** * g_data_input_stream_read_int16: * @stream: a given #GDataInputStream. - * @cancellable: optional #GCancellable object, %NULL to ignore. + * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore. * @error: #GError for error reporting. * * Reads a 16-bit/2-byte value from @stream. * * In order to get the correct byte order for this read operation, - * see g_data_stream_get_byte_order() and g_data_stream_set_byte_order(). + * see g_data_input_stream_get_byte_order() and g_data_input_stream_set_byte_order(). * * Returns: a signed 16-bit/2-byte value read from @stream or %0 if * an error occurred. @@ -396,13 +389,13 @@ g_data_input_stream_read_int16 (GDataInputStream *stream, /** * g_data_input_stream_read_uint16: * @stream: a given #GDataInputStream. - * @cancellable: optional #GCancellable object, %NULL to ignore. + * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore. * @error: #GError for error reporting. * * Reads an unsigned 16-bit/2-byte value from @stream. * * In order to get the correct byte order for this read operation, - * see g_data_stream_get_byte_order() and g_data_stream_set_byte_order(). + * see g_data_input_stream_get_byte_order() and g_data_input_stream_set_byte_order(). * * Returns: an unsigned 16-bit/2-byte value read from the @stream or %0 if * an error occurred. @@ -440,13 +433,13 @@ g_data_input_stream_read_uint16 (GDataInputStream *stream, /** * g_data_input_stream_read_int32: * @stream: a given #GDataInputStream. - * @cancellable: optional #GCancellable object, %NULL to ignore. + * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore. * @error: #GError for error reporting. * * Reads a signed 32-bit/4-byte value from @stream. * * In order to get the correct byte order for this read operation, - * see g_data_stream_get_byte_order() and g_data_stream_set_byte_order(). + * see g_data_input_stream_get_byte_order() and g_data_input_stream_set_byte_order(). * * If @cancellable is not %NULL, then the operation can be cancelled by * triggering the cancellable object from another thread. If the operation @@ -488,13 +481,13 @@ g_data_input_stream_read_int32 (GDataInputStream *stream, /** * g_data_input_stream_read_uint32: * @stream: a given #GDataInputStream. - * @cancellable: optional #GCancellable object, %NULL to ignore. + * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore. * @error: #GError for error reporting. * * Reads an unsigned 32-bit/4-byte value from @stream. * * In order to get the correct byte order for this read operation, - * see g_data_stream_get_byte_order() and g_data_stream_set_byte_order(). + * see g_data_input_stream_get_byte_order() and g_data_input_stream_set_byte_order(). * * If @cancellable is not %NULL, then the operation can be cancelled by * triggering the cancellable object from another thread. If the operation @@ -536,13 +529,13 @@ g_data_input_stream_read_uint32 (GDataInputStream *stream, /** * g_data_input_stream_read_int64: * @stream: a given #GDataInputStream. - * @cancellable: optional #GCancellable object, %NULL to ignore. + * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore. * @error: #GError for error reporting. * * Reads a 64-bit/8-byte value from @stream. * * In order to get the correct byte order for this read operation, - * see g_data_stream_get_byte_order() and g_data_stream_set_byte_order(). + * see g_data_input_stream_get_byte_order() and g_data_input_stream_set_byte_order(). * * If @cancellable is not %NULL, then the operation can be cancelled by * triggering the cancellable object from another thread. If the operation @@ -584,13 +577,13 @@ g_data_input_stream_read_int64 (GDataInputStream *stream, /** * g_data_input_stream_read_uint64: * @stream: a given #GDataInputStream. - * @cancellable: optional #GCancellable object, %NULL to ignore. + * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore. * @error: #GError for error reporting. * * Reads an unsigned 64-bit/8-byte value from @stream. * * In order to get the correct byte order for this read operation, - * see g_data_stream_get_byte_order(). + * see g_data_input_stream_get_byte_order(). * * If @cancellable is not %NULL, then the operation can be cancelled by * triggering the cancellable object from another thread. If the operation @@ -730,20 +723,24 @@ scan_for_newline (GDataInputStream *stream, /** * g_data_input_stream_read_line: * @stream: a given #GDataInputStream. - * @length: a #gsize to get the length of the data read in. - * @cancellable: optional #GCancellable object, %NULL to ignore. + * @length: (out): a #gsize to get the length of the data read in. + * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore. * @error: #GError for error reporting. * - * Reads a line from the data input stream. + * Reads a line from the data input stream. Note that no encoding + * checks or conversion is performed; the input is not guaranteed to + * be UTF-8, and may in fact have embedded NUL characters. * * If @cancellable is not %NULL, then the operation can be cancelled by * triggering the cancellable object from another thread. If the operation * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned. * - * Returns: a string with the line that was read in (without the newlines). - * Set @length to a #gsize to get the length of the read line. - * On an error, it will return %NULL and @error will be set. If there's no - * content to read, it will still return %NULL, but @error won't be set. + * Returns: (nullable) (transfer full) (array zero-terminated=1) (element-type guint8): + * a NUL terminated byte array with the line that was read in + * (without the newlines). Set @length to a #gsize to get the length + * of the read line. On an error, it will return %NULL and @error + * will be set. If there's no content to read, it will still return + * %NULL, but @error won't be set. **/ char * g_data_input_stream_read_line (GDataInputStream *stream, @@ -809,10 +806,57 @@ g_data_input_stream_read_line (GDataInputStream *stream, return line; } +/** + * g_data_input_stream_read_line_utf8: + * @stream: a given #GDataInputStream. + * @length: (out): a #gsize to get the length of the data read in. + * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore. + * @error: #GError for error reporting. + * + * Reads a UTF-8 encoded line from the data input stream. + * + * If @cancellable is not %NULL, then the operation can be cancelled by + * triggering the cancellable object from another thread. If the operation + * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned. + * + * Returns: (nullable) (transfer full): a NUL terminated UTF-8 string + * with the line that was read in (without the newlines). Set + * @length to a #gsize to get the length of the read line. On an + * error, it will return %NULL and @error will be set. For UTF-8 + * conversion errors, the set error domain is %G_CONVERT_ERROR. If + * there's no content to read, it will still return %NULL, but @error + * won't be set. + * + * Since: 2.30 + **/ +char * +g_data_input_stream_read_line_utf8 (GDataInputStream *stream, + gsize *length, + GCancellable *cancellable, + GError **error) +{ + char *res; + + res = g_data_input_stream_read_line (stream, length, cancellable, error); + if (!res) + return NULL; + + if (!g_utf8_validate (res, -1, NULL)) + { + g_set_error_literal (error, G_CONVERT_ERROR, + G_CONVERT_ERROR_ILLEGAL_SEQUENCE, + _("Invalid byte sequence in conversion input")); + g_free (res); + return NULL; + } + return res; +} + static gssize scan_for_chars (GDataInputStream *stream, gsize *checked_out, - const char *stop_chars) + const char *stop_chars, + gssize stop_chars_len) { GBufferedInputStream *bstream; const char *buffer; @@ -820,8 +864,10 @@ scan_for_chars (GDataInputStream *stream, int i; gsize available, checked; const char *stop_char; + const char *stop_end; bstream = G_BUFFERED_INPUT_STREAM (stream); + stop_end = stop_chars + stop_chars_len; checked = *checked_out; @@ -832,7 +878,7 @@ scan_for_chars (GDataInputStream *stream, for (i = 0; checked < available && i < peeked; i++) { - for (stop_char = stop_chars; *stop_char != '\0'; stop_char++) + for (stop_char = stop_chars; stop_char != stop_end; stop_char++) { if (buffer[i] == *stop_char) return (start + i); @@ -849,16 +895,26 @@ scan_for_chars (GDataInputStream *stream, * g_data_input_stream_read_until: * @stream: a given #GDataInputStream. * @stop_chars: characters to terminate the read. - * @length: a #gsize to get the length of the data read in. - * @cancellable: optional #GCancellable object, %NULL to ignore. + * @length: (out): a #gsize to get the length of the data read in. + * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore. * @error: #GError for error reporting. * * Reads a string from the data input stream, up to the first * occurrence of any of the stop characters. * - * Returns: a string with the data that was read before encountering - * any of the stop characters. Set @length to a #gsize to get the length - * of the string. This function will return %NULL on an error. + * Note that, in contrast to g_data_input_stream_read_until_async(), + * this function consumes the stop character that it finds. + * + * Don't use this function in new code. Its functionality is + * inconsistent with g_data_input_stream_read_until_async(). Both + * functions will be marked as deprecated in a future release. Use + * g_data_input_stream_read_upto() instead, but note that that function + * does not consume the stop character. + * + * Returns: (transfer full): a string with the data that was read + * before encountering any of the stop characters. Set @length to + * a #gsize to get the length of the string. This function will + * return %NULL on an error. */ char * g_data_input_stream_read_until (GDataInputStream *stream, @@ -868,105 +924,63 @@ g_data_input_stream_read_until (GDataInputStream *stream, GError **error) { GBufferedInputStream *bstream; - gsize checked; - gssize found_pos; - gssize res; - int stop_char_len; - char *data_until; - - g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), NULL); + gchar *result; bstream = G_BUFFERED_INPUT_STREAM (stream); - stop_char_len = 1; - checked = 0; + result = g_data_input_stream_read_upto (stream, stop_chars, -1, + length, cancellable, error); - while ((found_pos = scan_for_chars (stream, &checked, stop_chars)) == -1) + /* If we're not at end of stream then we have a stop_char to consume. */ + if (result != NULL && g_buffered_input_stream_get_available (bstream) > 0) { - if (g_buffered_input_stream_get_available (bstream) == - g_buffered_input_stream_get_buffer_size (bstream)) - g_buffered_input_stream_set_buffer_size (bstream, - 2 * g_buffered_input_stream_get_buffer_size (bstream)); + gsize res; + gchar b; - res = g_buffered_input_stream_fill (bstream, -1, cancellable, error); - if (res < 0) - return NULL; - if (res == 0) - { - /* End of stream */ - if (g_buffered_input_stream_get_available (bstream) == 0) - { - if (length) - *length = 0; - return NULL; - } - else - { - found_pos = checked; - stop_char_len = 0; - break; - } - } + res = g_input_stream_read (G_INPUT_STREAM (stream), &b, 1, NULL, NULL); + g_assert (res == 1); } - data_until = g_malloc (found_pos + stop_char_len + 1); - - res = g_input_stream_read (G_INPUT_STREAM (stream), - data_until, - found_pos + stop_char_len, - NULL, NULL); - if (length) - *length = (gsize)found_pos; - g_warn_if_fail (res == found_pos + stop_char_len); - data_until[found_pos] = 0; - - return data_until; + return result; } typedef struct { - GDataInputStream *stream; - GSimpleAsyncResult *simple; gboolean last_saw_cr; gsize checked; - gint io_priority; - GCancellable *cancellable; gchar *stop_chars; - gchar *line; + gssize stop_chars_len; gsize length; } GDataInputStreamReadData; static void -g_data_input_stream_read_complete (GDataInputStreamReadData *data, - gsize read_length, - gsize skip_length, - gboolean need_idle_dispatch) +g_data_input_stream_read_complete (GTask *task, + gsize read_length, + gsize skip_length) { + GDataInputStreamReadData *data = g_task_get_task_data (task); + GInputStream *stream = g_task_get_source_object (task); + char *line = NULL; + if (read_length || skip_length) { gssize bytes; data->length = read_length; - data->line = g_malloc (read_length + 1); - data->line[read_length] = '\0'; + line = g_malloc (read_length + 1); + line[read_length] = '\0'; /* we already checked the buffer. this shouldn't fail. */ - bytes = g_input_stream_read (G_INPUT_STREAM (data->stream), - data->line, read_length, NULL, NULL); + bytes = g_input_stream_read (stream, line, read_length, NULL, NULL); g_assert_cmpint (bytes, ==, read_length); - bytes = g_input_stream_skip (G_INPUT_STREAM (data->stream), - skip_length, NULL, NULL); + bytes = g_input_stream_skip (stream, skip_length, NULL, NULL); g_assert_cmpint (bytes, ==, skip_length); } - if (need_idle_dispatch) - g_simple_async_result_complete_in_idle (data->simple); - else - g_simple_async_result_complete (data->simple); - - g_object_unref (data->simple); + g_task_return_pointer (task, line, g_free); + g_object_unref (task); } static void @@ -974,14 +988,15 @@ g_data_input_stream_read_line_ready (GObject *object, GAsyncResult *result, gpointer user_data) { - GDataInputStreamReadData *data = user_data; + GTask *task = user_data; + GDataInputStreamReadData *data = g_task_get_task_data (task); + GBufferedInputStream *buffer = g_task_get_source_object (task); gssize found_pos; gint newline_len; if (result) /* this is a callback. finish the async call. */ { - GBufferedInputStream *buffer = G_BUFFERED_INPUT_STREAM (data->stream); GError *error = NULL; gssize bytes; @@ -992,12 +1007,12 @@ g_data_input_stream_read_line_ready (GObject *object, if (bytes < 0) /* stream error. */ { - g_simple_async_result_set_from_error (data->simple, error); - g_error_free (error); - data->checked = 0; + g_task_return_error (task, error); + g_object_unref (task); + return; } - g_data_input_stream_read_complete (data, data->checked, 0, FALSE); + g_data_input_stream_read_complete (task, data->checked, 0); return; } @@ -1006,19 +1021,19 @@ g_data_input_stream_read_line_ready (GObject *object, if (data->stop_chars) { - found_pos = scan_for_chars (data->stream, + found_pos = scan_for_chars (G_DATA_INPUT_STREAM (buffer), &data->checked, - data->stop_chars); + data->stop_chars, + data->stop_chars_len); newline_len = 0; } else - found_pos = scan_for_newline (data->stream, &data->checked, + found_pos = scan_for_newline (G_DATA_INPUT_STREAM (buffer), &data->checked, &data->last_saw_cr, &newline_len); if (found_pos == -1) /* didn't find a full line; need to buffer some more bytes */ { - GBufferedInputStream *buffer = G_BUFFERED_INPUT_STREAM (data->stream); gsize size; size = g_buffered_input_stream_get_buffer_size (buffer); @@ -1028,16 +1043,16 @@ g_data_input_stream_read_line_ready (GObject *object, g_buffered_input_stream_set_buffer_size (buffer, size * 2); /* try again */ - g_buffered_input_stream_fill_async (buffer, -1, data->io_priority, - data->cancellable, + g_buffered_input_stream_fill_async (buffer, -1, + g_task_get_priority (task), + g_task_get_cancellable (task), g_data_input_stream_read_line_ready, user_data); } else { /* read the line and the EOL. no error is possible. */ - g_data_input_stream_read_complete (data, found_pos, - newline_len, result == NULL); + g_data_input_stream_read_complete (task, found_pos, newline_len); } } @@ -1046,44 +1061,34 @@ g_data_input_stream_read_data_free (gpointer user_data) { GDataInputStreamReadData *data = user_data; - /* we don't hold a ref to ->simple because it keeps a ref to us. - * we are called because it is being finalized. - */ - g_free (data->stop_chars); - if (data->cancellable) - g_object_unref (data->cancellable); - g_free (data->line); g_slice_free (GDataInputStreamReadData, data); } static void g_data_input_stream_read_async (GDataInputStream *stream, const gchar *stop_chars, + gssize stop_chars_len, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, - gpointer user_data, - gpointer source_tag) + gpointer user_data) { GDataInputStreamReadData *data; + GTask *task; - data = g_slice_new (GDataInputStreamReadData); - data->stream = stream; - if (cancellable) - g_object_ref (cancellable); - data->cancellable = cancellable; - data->stop_chars = g_strdup (stop_chars); - data->io_priority = io_priority; + data = g_slice_new0 (GDataInputStreamReadData); + if (stop_chars_len == -1) + stop_chars_len = strlen (stop_chars); + data->stop_chars = g_memdup (stop_chars, stop_chars_len); + data->stop_chars_len = stop_chars_len; data->last_saw_cr = FALSE; - data->checked = 0; - data->line = NULL; - - data->simple = g_simple_async_result_new (G_OBJECT (stream), callback, - user_data, source_tag); - g_simple_async_result_set_op_res_gpointer (data->simple, data, - g_data_input_stream_read_data_free); - g_data_input_stream_read_line_ready (NULL, NULL, data); + + task = g_task_new (stream, cancellable, callback, user_data); + g_task_set_task_data (task, data, g_data_input_stream_read_data_free); + g_task_set_priority (task, io_priority); + + g_data_input_stream_read_line_ready (NULL, NULL, task); } static gchar * @@ -1092,22 +1097,17 @@ g_data_input_stream_read_finish (GDataInputStream *stream, gsize *length, GError **error) { - GDataInputStreamReadData *data; - GSimpleAsyncResult *simple; + GTask *task = G_TASK (result); gchar *line; - simple = G_SIMPLE_ASYNC_RESULT (result); - - if (g_simple_async_result_propagate_error (simple, error)) - return NULL; - - data = g_simple_async_result_get_op_res_gpointer (simple); - - line = data->line; - data->line = NULL; + line = g_task_propagate_pointer (task, error); if (length && line) - *length = data->length; + { + GDataInputStreamReadData *data = g_task_get_task_data (task); + + *length = data->length; + } return line; } @@ -1115,11 +1115,10 @@ g_data_input_stream_read_finish (GDataInputStream *stream, /** * g_data_input_stream_read_line_async: * @stream: a given #GDataInputStream. - * @io_priority: the I/O priority - * of the request. - * @cancellable: optional #GCancellable object, %NULL to ignore. - * @callback: callback to call when the request is satisfied. - * @user_data: the data to pass to callback function. + * @io_priority: the [I/O priority][io-priority] of the request + * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore. + * @callback: (scope async): callback to call when the request is satisfied. + * @user_data: (closure): the data to pass to callback function. * * The asynchronous version of g_data_input_stream_read_line(). It is * an error to have two outstanding calls to this function. @@ -1140,28 +1139,35 @@ g_data_input_stream_read_line_async (GDataInputStream *stream, g_return_if_fail (G_IS_DATA_INPUT_STREAM (stream)); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); - g_data_input_stream_read_async (stream, NULL, io_priority, - cancellable, callback, user_data, - g_data_input_stream_read_line_async); + g_data_input_stream_read_async (stream, NULL, 0, io_priority, + cancellable, callback, user_data); } /** * g_data_input_stream_read_until_async: * @stream: a given #GDataInputStream. * @stop_chars: characters to terminate the read. - * @io_priority: the I/O priority - * of the request. - * @cancellable: optional #GCancellable object, %NULL to ignore. - * @callback: callback to call when the request is satisfied. - * @user_data: the data to pass to callback function. + * @io_priority: the [I/O priority][io-priority] of the request + * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore. + * @callback: (scope async): callback to call when the request is satisfied. + * @user_data: (closure): the data to pass to callback function. * * The asynchronous version of g_data_input_stream_read_until(). * It is an error to have two outstanding calls to this function. * + * Note that, in contrast to g_data_input_stream_read_until(), + * this function does not consume the stop character that it finds. You + * must read it for yourself. + * * When the operation is finished, @callback will be called. You * can then call g_data_input_stream_read_until_finish() to get * the result of the operation. * + * Don't use this function in new code. Its functionality is + * inconsistent with g_data_input_stream_read_until(). Both functions + * will be marked as deprecated in a future release. Use + * g_data_input_stream_read_upto_async() instead. + * * Since: 2.20 */ void @@ -1176,25 +1182,28 @@ g_data_input_stream_read_until_async (GDataInputStream *stream, g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); g_return_if_fail (stop_chars != NULL); - g_data_input_stream_read_async (stream, stop_chars, io_priority, - cancellable, callback, user_data, - g_data_input_stream_read_until_async); + g_data_input_stream_read_async (stream, stop_chars, -1, io_priority, + cancellable, callback, user_data); } /** * g_data_input_stream_read_line_finish: * @stream: a given #GDataInputStream. * @result: the #GAsyncResult that was provided to the callback. - * @length: a #gsize to get the length of the data read in. + * @length: (out): a #gsize to get the length of the data read in. * @error: #GError for error reporting. * * Finish an asynchronous call started by - * g_data_input_stream_read_line_async(). + * g_data_input_stream_read_line_async(). Note the warning about + * string encoding in g_data_input_stream_read_line() applies here as + * well. * - * Returns: a string with the line that was read in (without the newlines). - * Set @length to a #gsize to get the length of the read line. - * On an error, it will return %NULL and @error will be set. If there's no - * content to read, it will still return %NULL, but @error won't be set. + * Returns: (nullable) (transfer full) (array zero-terminated=1) (element-type guint8): + * a NUL-terminated byte array with the line that was read in + * (without the newlines). Set @length to a #gsize to get the length + * of the read line. On an error, it will return %NULL and @error + * will be set. If there's no content to read, it will still return + * %NULL, but @error won't be set. * * Since: 2.20 */ @@ -1204,18 +1213,58 @@ g_data_input_stream_read_line_finish (GDataInputStream *stream, gsize *length, GError **error) { - g_return_val_if_fail ( - g_simple_async_result_is_valid (result, G_OBJECT (stream), - g_data_input_stream_read_line_async), NULL); + g_return_val_if_fail (g_task_is_valid (result, stream), NULL); return g_data_input_stream_read_finish (stream, result, length, error); } /** + * g_data_input_stream_read_line_finish_utf8: + * @stream: a given #GDataInputStream. + * @result: the #GAsyncResult that was provided to the callback. + * @length: (out): a #gsize to get the length of the data read in. + * @error: #GError for error reporting. + * + * Finish an asynchronous call started by + * g_data_input_stream_read_line_async(). + * + * Returns: (nullable) (transfer full): a string with the line that + * was read in (without the newlines). Set @length to a #gsize to + * get the length of the read line. On an error, it will return + * %NULL and @error will be set. For UTF-8 conversion errors, the set + * error domain is %G_CONVERT_ERROR. If there's no content to read, + * it will still return %NULL, but @error won't be set. + * + * Since: 2.30 + */ +gchar * +g_data_input_stream_read_line_finish_utf8 (GDataInputStream *stream, + GAsyncResult *result, + gsize *length, + GError **error) +{ + gchar *res; + + res = g_data_input_stream_read_line_finish (stream, result, length, error); + if (!res) + return NULL; + + if (!g_utf8_validate (res, -1, NULL)) + { + g_set_error_literal (error, G_CONVERT_ERROR, + G_CONVERT_ERROR_ILLEGAL_SEQUENCE, + _("Invalid byte sequence in conversion input")); + g_free (res); + return NULL; + } + return res; +} + +/** * g_data_input_stream_read_until_finish: * @stream: a given #GDataInputStream. * @result: the #GAsyncResult that was provided to the callback. - * @length: a #gsize to get the length of the data read in. + * @length: (out): a #gsize to get the length of the data read in. * @error: #GError for error reporting. * * Finish an asynchronous call started by @@ -1223,9 +1272,10 @@ g_data_input_stream_read_line_finish (GDataInputStream *stream, * * Since: 2.20 * - * Returns: a string with the data that was read before encountering - * any of the stop characters. Set @length to a #gsize to get the length - * of the string. This function will return %NULL on an error. + * Returns: (transfer full): a string with the data that was read + * before encountering any of the stop characters. Set @length to + * a #gsize to get the length of the string. This function will + * return %NULL on an error. */ gchar * g_data_input_stream_read_until_finish (GDataInputStream *stream, @@ -1233,13 +1283,176 @@ g_data_input_stream_read_until_finish (GDataInputStream *stream, gsize *length, GError **error) { - g_return_val_if_fail ( - g_simple_async_result_is_valid (result, G_OBJECT (stream), - g_data_input_stream_read_until_async), NULL); + g_return_val_if_fail (g_task_is_valid (result, stream), NULL); return g_data_input_stream_read_finish (stream, result, length, error); } +/** + * g_data_input_stream_read_upto: + * @stream: a #GDataInputStream + * @stop_chars: characters to terminate the read + * @stop_chars_len: length of @stop_chars. May be -1 if @stop_chars is + * nul-terminated + * @length: (out): a #gsize to get the length of the data read in + * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore + * @error: #GError for error reporting + * + * Reads a string from the data input stream, up to the first + * occurrence of any of the stop characters. + * + * In contrast to g_data_input_stream_read_until(), this function + * does not consume the stop character. You have to use + * g_data_input_stream_read_byte() to get it before calling + * g_data_input_stream_read_upto() again. + * + * Note that @stop_chars may contain '\0' if @stop_chars_len is + * specified. + * + * Returns: (transfer full): a string with the data that was read + * before encountering any of the stop characters. Set @length to + * a #gsize to get the length of the string. This function will + * return %NULL on an error + * + * Since: 2.26 + */ +char * +g_data_input_stream_read_upto (GDataInputStream *stream, + const gchar *stop_chars, + gssize stop_chars_len, + gsize *length, + GCancellable *cancellable, + GError **error) +{ + GBufferedInputStream *bstream; + gsize checked; + gssize found_pos; + gssize res; + char *data_until; + + g_return_val_if_fail (G_IS_DATA_INPUT_STREAM (stream), NULL); + + if (stop_chars_len < 0) + stop_chars_len = strlen (stop_chars); + + bstream = G_BUFFERED_INPUT_STREAM (stream); + + checked = 0; + + while ((found_pos = scan_for_chars (stream, &checked, stop_chars, stop_chars_len)) == -1) + { + if (g_buffered_input_stream_get_available (bstream) == + g_buffered_input_stream_get_buffer_size (bstream)) + g_buffered_input_stream_set_buffer_size (bstream, + 2 * g_buffered_input_stream_get_buffer_size (bstream)); + + res = g_buffered_input_stream_fill (bstream, -1, cancellable, error); + if (res < 0) + return NULL; + if (res == 0) + { + /* End of stream */ + if (g_buffered_input_stream_get_available (bstream) == 0) + { + if (length) + *length = 0; + return NULL; + } + else + { + found_pos = checked; + break; + } + } + } + + data_until = g_malloc (found_pos + 1); -#define __G_DATA_INPUT_STREAM_C__ -#include "gioaliasdef.c" + res = g_input_stream_read (G_INPUT_STREAM (stream), + data_until, + found_pos, + NULL, NULL); + if (length) + *length = (gsize)found_pos; + g_warn_if_fail (res == found_pos); + data_until[found_pos] = 0; + + return data_until; +} + +/** + * g_data_input_stream_read_upto_async: + * @stream: a #GDataInputStream + * @stop_chars: characters to terminate the read + * @stop_chars_len: length of @stop_chars. May be -1 if @stop_chars is + * nul-terminated + * @io_priority: the [I/O priority][io-priority] of the request + * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore + * @callback: (scope async): callback to call when the request is satisfied + * @user_data: (closure): the data to pass to callback function + * + * The asynchronous version of g_data_input_stream_read_upto(). + * It is an error to have two outstanding calls to this function. + * + * In contrast to g_data_input_stream_read_until(), this function + * does not consume the stop character. You have to use + * g_data_input_stream_read_byte() to get it before calling + * g_data_input_stream_read_upto() again. + * + * Note that @stop_chars may contain '\0' if @stop_chars_len is + * specified. + * + * When the operation is finished, @callback will be called. You + * can then call g_data_input_stream_read_upto_finish() to get + * the result of the operation. + * + * Since: 2.26 + */ +void +g_data_input_stream_read_upto_async (GDataInputStream *stream, + const gchar *stop_chars, + gssize stop_chars_len, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_return_if_fail (G_IS_DATA_INPUT_STREAM (stream)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (stop_chars != NULL); + + g_data_input_stream_read_async (stream, stop_chars, stop_chars_len, io_priority, + cancellable, callback, user_data); +} + +/** + * g_data_input_stream_read_upto_finish: + * @stream: a #GDataInputStream + * @result: the #GAsyncResult that was provided to the callback + * @length: (out): a #gsize to get the length of the data read in + * @error: #GError for error reporting + * + * Finish an asynchronous call started by + * g_data_input_stream_read_upto_async(). + * + * Note that this function does not consume the stop character. You + * have to use g_data_input_stream_read_byte() to get it before calling + * g_data_input_stream_read_upto_async() again. + * + * Returns: (transfer full): a string with the data that was read + * before encountering any of the stop characters. Set @length to + * a #gsize to get the length of the string. This function will + * return %NULL on an error. + * + * Since: 2.24 + */ +gchar * +g_data_input_stream_read_upto_finish (GDataInputStream *stream, + GAsyncResult *result, + gsize *length, + GError **error) +{ + g_return_val_if_fail (g_task_is_valid (result, stream), NULL); + + return g_data_input_stream_read_finish (stream, result, length, error); +}