00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <stdio.h>
00023 #include <stdlib.h>
00024 #include <string.h>
00025
00026 #include "probe-buffer.h"
00027
00028 typedef struct
00029 {
00030 const gchar * filename, * decoder;
00031 VFSFile * file;
00032 guchar buffer[16384];
00033 gint filled, at;
00034 const gchar * read_warned, * seek_warned;
00035 }
00036 ProbeBuffer;
00037
00038 static gint probe_buffer_fclose (VFSFile * file)
00039 {
00040 gint ret = vfs_fclose (((ProbeBuffer *) file->handle)->file);
00041 g_free (file->handle);
00042 return ret;
00043 }
00044
00045 static void increase_buffer (ProbeBuffer * p, gint64 size)
00046 {
00047 size = (size + 0xFF) & ~0xFF;
00048
00049 if (size > sizeof p->buffer)
00050 {
00051 if (p->read_warned != p->decoder)
00052 {
00053 fprintf (stderr, "%s tried to read past end of buffer while "
00054 "probing %s.\n", p->decoder, p->filename);
00055 p->read_warned = p->decoder;
00056 }
00057
00058 size = sizeof p->buffer;
00059 }
00060
00061 if (p->filled < size)
00062 p->filled += vfs_fread (p->buffer + p->filled, 1, size - p->filled,
00063 p->file);
00064 }
00065
00066 static gint64 probe_buffer_fread (void * buffer, gint64 size, gint64 count,
00067 VFSFile * file)
00068 {
00069 ProbeBuffer * p = file->handle;
00070
00071 increase_buffer (p, p->at + size * count);
00072 gint readed = (size > 0) ? MIN (count, (p->filled - p->at) / size) : 0;
00073 memcpy (buffer, p->buffer + p->at, size * readed);
00074
00075 p->at += size * readed;
00076 return readed;
00077 }
00078
00079 static gint64 probe_buffer_fwrite (const void * data, gint64 size, gint64 count,
00080 VFSFile * file)
00081 {
00082
00083 return 0;
00084 }
00085
00086 static gint probe_buffer_getc (VFSFile * file)
00087 {
00088 guchar c;
00089 return (probe_buffer_fread (& c, 1, 1, file) == 1) ? c : EOF;
00090 }
00091
00092 static gint probe_buffer_fseek (VFSFile * file, gint64 offset, gint whence)
00093 {
00094 ProbeBuffer * p = file->handle;
00095
00096 if (whence == SEEK_END)
00097 {
00098 if (p->seek_warned != p->decoder)
00099 {
00100 fprintf (stderr, "%s tried to seek to end of file while probing "
00101 "%s.\n", p->decoder, p->filename);
00102 p->seek_warned = p->decoder;
00103 }
00104
00105 return -1;
00106 }
00107
00108 if (whence == SEEK_CUR)
00109 offset += p->at;
00110
00111 g_return_val_if_fail (offset >= 0, -1);
00112 increase_buffer (p, offset);
00113
00114 if (offset > p->filled)
00115 return -1;
00116
00117 p->at = offset;
00118 return 0;
00119 }
00120
00121 static gint probe_buffer_ungetc (gint c, VFSFile * file)
00122 {
00123 return (! probe_buffer_fseek (file, -1, SEEK_CUR)) ? c : EOF;
00124 }
00125
00126 static void probe_buffer_rewind (VFSFile * file)
00127 {
00128 probe_buffer_fseek (file, 0, SEEK_SET);
00129 }
00130
00131 static gint64 probe_buffer_ftell (VFSFile * file)
00132 {
00133 return ((ProbeBuffer *) file->handle)->at;
00134 }
00135
00136 static gboolean probe_buffer_feof (VFSFile * file)
00137 {
00138 ProbeBuffer * p = file->handle;
00139 return (p->at < p->filled) ? FALSE : vfs_feof (p->file);
00140 }
00141
00142 static gint probe_buffer_ftruncate (VFSFile * file, gint64 size)
00143 {
00144
00145 return -1;
00146 }
00147
00148 static gint64 probe_buffer_fsize (VFSFile * file)
00149 {
00150 return vfs_fsize (((ProbeBuffer *) file->handle)->file);
00151 }
00152
00153 static gchar * probe_buffer_get_metadata (VFSFile * file, const gchar * field)
00154 {
00155 return vfs_get_metadata (((ProbeBuffer *) file->handle)->file, field);
00156 }
00157
00158 static VFSConstructor probe_buffer_table =
00159 {
00160 .vfs_fopen_impl = NULL,
00161 .vfs_fclose_impl = probe_buffer_fclose,
00162 .vfs_fread_impl = probe_buffer_fread,
00163 .vfs_fwrite_impl = probe_buffer_fwrite,
00164 .vfs_getc_impl = probe_buffer_getc,
00165 .vfs_ungetc_impl = probe_buffer_ungetc,
00166 .vfs_fseek_impl = probe_buffer_fseek,
00167 .vfs_rewind_impl = probe_buffer_rewind,
00168 .vfs_ftell_impl = probe_buffer_ftell,
00169 .vfs_feof_impl = probe_buffer_feof,
00170 .vfs_ftruncate_impl = probe_buffer_ftruncate,
00171 .vfs_fsize_impl = probe_buffer_fsize,
00172 .vfs_get_metadata_impl = probe_buffer_get_metadata,
00173 };
00174
00175 VFSFile * probe_buffer_new (const gchar * filename)
00176 {
00177 VFSFile * file = vfs_fopen (filename, "r");
00178
00179 if (! file)
00180 return NULL;
00181
00182 ProbeBuffer * p = g_malloc (sizeof (ProbeBuffer));
00183 p->decoder = NULL;
00184 p->filename = filename;
00185 p->file = file;
00186 p->filled = 0;
00187 p->at = 0;
00188 p->read_warned = NULL;
00189 p->seek_warned = NULL;
00190
00191 VFSFile * file2 = g_malloc (sizeof (VFSFile));
00192 file2->base = & probe_buffer_table;
00193 file2->handle = p;
00194 file2->uri = g_strdup (filename);
00195 file2->ref = 1;
00196 file2->sig = VFS_SIG;
00197
00198 return file2;
00199 }
00200
00201 void probe_buffer_set_decoder (VFSFile * file, const gchar * decoder)
00202 {
00203 ProbeBuffer * p = file->handle;
00204 p->decoder = decoder;
00205 }