/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Copyright (C) 2008, 2010 Red Hat, Inc. * Copyright (C) 2010 Igalia, S.L. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H #include #endif #include #include "soup-directory-input-stream.h" #include "soup.h" #define INIT_STRING "\n\n\n" #define ROW_FORMAT "\n" #define EXIT_STRING "
NameSizeDate Modified%s%s%s
\n\n" G_DEFINE_TYPE (SoupDirectoryInputStream, soup_directory_input_stream, G_TYPE_INPUT_STREAM) static SoupBuffer * soup_directory_input_stream_parse_info (SoupDirectoryInputStream *stream, GFileInfo *info) { SoupBuffer *buffer; GString *string; const char *file_name; char *escaped, *path, *xml_string, *size, *time; GTimeVal modified; GDateTime *modification_time; if (!g_file_info_get_name (info)) return NULL; file_name = g_file_info_get_display_name (info); if (!file_name) { file_name = g_file_info_get_name (info); /* FIXME: convert somehow? */ if (!g_utf8_validate (file_name, -1, NULL)) return NULL; } string = g_string_new (""); xml_string = g_markup_escape_text (file_name, -1); escaped = g_uri_escape_string (file_name, NULL, FALSE); path = g_strconcat (stream->uri, G_DIR_SEPARATOR_S, escaped, NULL); size = g_format_size (g_file_info_get_size (info)); g_file_info_get_modification_time (info, &modified); modification_time = g_date_time_new_from_timeval_local (&modified); time = g_date_time_format (modification_time, "%X %x"); g_date_time_unref (modification_time); g_string_append_printf (string, ROW_FORMAT, path, xml_string, size, time); g_string_append (string, "\n"); buffer = soup_buffer_new (SOUP_MEMORY_TAKE, string->str, string->len); g_free (time); g_free (escaped); g_free (size); g_free (path); g_free (xml_string); g_string_free (string, FALSE); return buffer; } static SoupBuffer * soup_directory_input_stream_read_next_file (SoupDirectoryInputStream *stream, GCancellable *cancellable, GError **error) { GFileInfo *info; SoupBuffer *buffer; GError *err = NULL; do { info = g_file_enumerator_next_file (stream->enumerator, cancellable, &err); if (info == NULL) { if (err) { g_propagate_error (error, err); return NULL; } else if (!stream->done) { stream->done = TRUE; return soup_buffer_new (SOUP_MEMORY_STATIC, EXIT_STRING, sizeof (EXIT_STRING)); } else { return NULL; } } buffer = soup_directory_input_stream_parse_info (stream, info); g_object_unref (info); } while (buffer == NULL); return buffer; } static gssize soup_directory_input_stream_read (GInputStream *input, void *buffer, gsize count, GCancellable *cancellable, GError **error) { SoupDirectoryInputStream *stream = SOUP_DIRECTORY_INPUT_STREAM (input); gsize total, size; for (total = 0; total < count; total += size) { if (stream->buffer == NULL) { stream->buffer = soup_directory_input_stream_read_next_file (stream, cancellable, error); if (stream->buffer == NULL) { /* FIXME: Is this correct or should we forward the error? */ if (total) g_clear_error (error); return total; } } size = MIN (stream->buffer->length, count - total); memcpy ((char *)buffer + total, stream->buffer->data, size); if (size == stream->buffer->length) { soup_buffer_free (stream->buffer); stream->buffer = NULL; } else { SoupBuffer *sub = soup_buffer_new_subbuffer (stream->buffer, size, stream->buffer->length - size); soup_buffer_free (stream->buffer); stream->buffer = sub; } } return total; } static gboolean soup_directory_input_stream_close (GInputStream *input, GCancellable *cancellable, GError **error) { SoupDirectoryInputStream *stream = SOUP_DIRECTORY_INPUT_STREAM (input); gboolean result; if (stream->buffer) { soup_buffer_free (stream->buffer); stream->buffer = NULL; } result = g_file_enumerator_close (stream->enumerator, cancellable, error); g_object_unref (stream->enumerator); stream->enumerator = NULL; g_free (stream->uri); stream->uri = NULL; return result; } static void soup_directory_input_stream_class_init (SoupDirectoryInputStreamClass *stream_class) { GInputStreamClass *inputstream_class = G_INPUT_STREAM_CLASS (stream_class); inputstream_class->read_fn = soup_directory_input_stream_read; inputstream_class->close_fn = soup_directory_input_stream_close; } static void soup_directory_input_stream_init (SoupDirectoryInputStream *stream) { stream->buffer = soup_buffer_new (SOUP_MEMORY_STATIC, INIT_STRING, sizeof (INIT_STRING)); } GInputStream * soup_directory_input_stream_new (GFileEnumerator *enumerator, SoupURI *uri) { GInputStream *stream; g_return_val_if_fail (G_IS_FILE_ENUMERATOR (enumerator), NULL); g_return_val_if_fail (uri != NULL, NULL); stream = g_object_new (SOUP_TYPE_DIRECTORY_INPUT_STREAM, NULL); SOUP_DIRECTORY_INPUT_STREAM (stream)->enumerator = g_object_ref (enumerator); SOUP_DIRECTORY_INPUT_STREAM (stream)->uri = soup_uri_to_string (uri, FALSE); return stream; }