Audacious $Id:Doxyfile42802007-03-2104:39:00Znenolod$

vfs_buffered_file.c

Go to the documentation of this file.
00001 /*
00002  *  Copyright (c) 2006-2007 William Pitcock
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; under version 3 of the License.
00007  *
00008  *  This program is distributed in the hope that it will be useful,
00009  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00010  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011  *  GNU General Public License for more details.
00012  *
00013  *  You should have received a copy of the GNU General Public License
00014  *  along with this program.  If not, see <http://www.gnu.org/licenses>.
00015  *
00016  *  The Audacious team does not consider modular code linking to
00017  *  Audacious or using our public API to be a derived work.
00018  */
00019 
00020 #include <glib.h>
00021 #include <string.h>
00022 #include "vfs.h"
00023 #include "vfs_buffer.h"
00024 #include "vfs_buffered_file.h"
00025 
00026 VFSFile *
00027 buffered_file_vfs_fopen_impl(const gchar * path,
00028           const gchar * mode)
00029 {
00030     return NULL;
00031 }
00032 
00033 gint
00034 buffered_file_vfs_fclose_impl(VFSFile * file)
00035 {
00036     g_return_val_if_fail(file != NULL, -1);
00037 
00038     if (file->handle)
00039     {
00040         VFSBufferedFile *handle = (VFSBufferedFile *) file->handle;
00041 
00042         if (handle->fd != NULL)
00043             vfs_fclose(handle->fd);
00044 
00045         vfs_fclose(handle->buffer);
00046         g_free(handle->mem);
00047         g_free(handle);
00048     }
00049 
00050     return 0;
00051 }
00052 
00053 gint64 buffered_file_vfs_fread_impl (void * i_ptr, gint64 size, gint64 nmemb,
00054  VFSFile * file)
00055 {
00056     VFSBufferedFile *handle = (VFSBufferedFile *) file->handle;
00057 
00058     /* is this request within the buffered area, or should we switch to
00059      * an FD? --nenolod
00060      */
00061     if (handle->which == FALSE &&
00062         (vfs_ftell(handle->buffer)) + (size * nmemb) >
00063         ((VFSBuffer *) handle->buffer->handle)->size)
00064     {
00065         if (vfs_fseek (handle->fd, vfs_ftell (handle->buffer), SEEK_SET))
00066             return 0;
00067         handle->which = TRUE;
00068     }
00069 
00070     return vfs_fread(i_ptr, size, nmemb, handle->which == TRUE ? handle->fd : handle->buffer);
00071 }
00072 
00073 gint64 buffered_file_vfs_fwrite_impl (const void * i_ptr, gint64 size, gint64
00074  nmemb, VFSFile * file)
00075 {
00076     VFSBufferedFile *handle = (VFSBufferedFile *) file->handle;
00077 
00078     return vfs_fwrite(i_ptr, size, nmemb, handle->fd);
00079 }
00080 
00081 gint
00082 buffered_file_vfs_getc_impl(VFSFile *stream)
00083 {
00084     VFSBufferedFile *handle = (VFSBufferedFile *) stream->handle;
00085 
00086     /* is this request within the buffered area, or should we switch to
00087      * an FD? --nenolod
00088      */
00089     if ((vfs_ftell(handle->buffer)) + 1 >
00090         ((VFSBuffer *) handle->buffer->handle)->size)
00091     {
00092         if (vfs_fseek (handle->fd, vfs_ftell (handle->buffer), SEEK_SET))
00093             return EOF;
00094         handle->which = TRUE;
00095     }
00096 
00097     return vfs_getc(handle->which == TRUE ? handle->fd : handle->buffer);
00098 }
00099 
00100 gint
00101 buffered_file_vfs_ungetc_impl(gint c, VFSFile *stream)
00102 {
00103     return -1;
00104 }
00105 
00106 gint
00107 buffered_file_vfs_fseek_impl(VFSFile * file,
00108           gint64 offset,
00109           gint whence)
00110 {
00111     VFSBufferedFile *handle = (VFSBufferedFile *) file->handle;
00112 
00113     if (vfs_fseek (handle->buffer, offset, whence))
00114         return -1;
00115 
00116     switch(whence)
00117     {
00118         case SEEK_END:
00119             handle->which = TRUE;
00120             return vfs_fseek (handle->fd, offset, whence);
00121         case SEEK_CUR:
00122             if (vfs_ftell(handle->buffer) + offset >= ((VFSBuffer *) handle->buffer->handle)->size)
00123             {
00124                 handle->which = TRUE;
00125                 return vfs_fseek (handle->fd, offset, whence);
00126             }
00127             else
00128             {
00129                 gint64 noff;
00130 
00131                 handle->which = FALSE;
00132                 noff = ((VFSBuffer *) handle->buffer->handle)->size - (vfs_ftell(handle->buffer) + offset);
00133                 return vfs_fseek (handle->buffer, noff, whence);
00134             }
00135             break;
00136         case SEEK_SET:
00137         default:
00138             if (offset > ((VFSBuffer *) handle->buffer->handle)->size)
00139             {
00140                 handle->which = TRUE;
00141                 return vfs_fseek (handle->fd, offset, whence);
00142             }
00143             else
00144             {
00145                 handle->which = FALSE;
00146                 return vfs_fseek (handle->buffer, offset, whence);
00147             }
00148             break;
00149     }
00150     return 0;
00151 }
00152 
00153 void
00154 buffered_file_vfs_rewind_impl(VFSFile * file)
00155 {
00156     VFSBufferedFile *handle = (VFSBufferedFile *) file->handle;
00157 
00158     vfs_rewind(handle->buffer);
00159     vfs_rewind(handle->fd);
00160     handle->which = FALSE;
00161 }
00162 
00163 gint64
00164 buffered_file_vfs_ftell_impl(VFSFile * file)
00165 {
00166     VFSBufferedFile *handle = (VFSBufferedFile *) file->handle;
00167 
00168     return vfs_ftell(handle->which == TRUE ? handle->fd : handle->buffer);
00169 }
00170 
00171 gboolean
00172 buffered_file_vfs_feof_impl(VFSFile * file)
00173 {
00174     VFSBufferedFile *handle = (VFSBufferedFile *) file->handle;
00175 
00176     return vfs_feof(handle->which == TRUE ? handle->fd : handle->buffer);
00177 }
00178 
00179 gint
00180 buffered_file_vfs_truncate_impl (VFSFile * file, gint64 size)
00181 {
00182     return 0;
00183 }
00184 
00185 gint64
00186 buffered_file_vfs_fsize_impl(VFSFile * file)
00187 {
00188     VFSBufferedFile *handle = (VFSBufferedFile *) file->handle;
00189 
00190     return vfs_fsize(handle->fd);
00191 }
00192 
00193 gchar *
00194 buffered_file_vfs_metadata_impl(VFSFile * file, const gchar * field)
00195 {
00196     VFSBufferedFile *handle = (VFSBufferedFile *) file->handle;
00197 
00198     return vfs_get_metadata(handle->fd, field);
00199 }
00200 
00201 VFSConstructor buffered_file_const = {
00202         NULL,                   // not a normal VFS class
00203         buffered_file_vfs_fopen_impl,
00204         buffered_file_vfs_fclose_impl,
00205         buffered_file_vfs_fread_impl,
00206         buffered_file_vfs_fwrite_impl,
00207         buffered_file_vfs_getc_impl,
00208         buffered_file_vfs_ungetc_impl,
00209         buffered_file_vfs_fseek_impl,
00210         buffered_file_vfs_rewind_impl,
00211         buffered_file_vfs_ftell_impl,
00212         buffered_file_vfs_feof_impl,
00213         buffered_file_vfs_truncate_impl,
00214         buffered_file_vfs_fsize_impl,
00215         buffered_file_vfs_metadata_impl
00216 };
00217 
00224 VFSFile *
00225 vfs_buffered_file_new_from_uri(const gchar *uri)
00226 {
00227     VFSFile *handle;
00228     VFSBufferedFile *fd;
00229     gsize sz;
00230 
00231     g_return_val_if_fail(uri != NULL, NULL);
00232 
00233     handle = g_new0(VFSFile, 1);
00234     fd = g_new0(VFSBufferedFile, 1);
00235     fd->mem = g_malloc0(128000);
00236     fd->fd = vfs_fopen(uri, "rb");
00237 
00238     if (fd->fd == NULL)
00239     {
00240         g_free(fd->mem);
00241         g_free(fd);
00242         g_free(handle);
00243 
00244         return NULL;
00245     }
00246 
00247     sz = vfs_fread(fd->mem, 1, 128000, fd->fd);
00248     vfs_rewind(fd->fd);
00249 
00250     if (!sz)
00251     {
00252         vfs_fclose(fd->fd);
00253         g_free(fd->mem);
00254         g_free(fd);
00255         g_free(handle);
00256 
00257         return NULL;
00258     }
00259 
00260     fd->buffer = vfs_buffer_new(fd->mem, sz);
00261 
00262     handle->handle = fd;
00263     handle->base = &buffered_file_const;
00264     handle->uri = g_strdup(uri);
00265     handle->ref = 1;
00266 
00267     return handle;
00268 }
00269 
00274 VFSFile *
00275 vfs_buffered_file_release_live_fd(VFSFile *fd)
00276 {
00277     VFSBufferedFile *file = (VFSBufferedFile *) fd;
00278     VFSFile *out;
00279 
00280     g_return_val_if_fail(file != NULL, NULL);
00281 
00282     out = file->fd;
00283     file->fd = NULL;
00284 
00285     vfs_fclose(fd);
00286 
00287     return out;
00288 }