1 /*
2 This file is part of Deadbeef Player source code
3 http://deadbeef.sourceforge.net
4
5 standard file vfs implementation
6
7 Copyright (C) 2009-2015 Alexey Yakovenko
8
9 This software is provided 'as-is', without any express or implied
10 warranty. In no event will the authors be held liable for any damages
11 arising from the use of this software.
12
13 Permission is granted to anyone to use this software for any purpose,
14 including commercial applications, and to alter it and redistribute it
15 freely, subject to the following restrictions:
16
17 1. The origin of this software must not be misrepresented; you must not
18 claim that you wrote the original software. If you use this software
19 in a product, an acknowledgment in the product documentation would be
20 appreciated but is not required.
21 2. Altered source versions must be plainly marked as such, and must not be
22 misrepresented as being the original software.
23 3. This notice may not be removed or altered from any source distribution.
24
25 Alexey Yakovenko waker@users.sourceforge.net
26 */
27 #include "deadbeef.h"
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <assert.h>
31 #include <string.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36
37 #ifndef __linux__
38 #define off64_t off_t
39 #define lseek64 lseek
40 #define O_LARGEFILE 0
41 #endif
42
43 //#define USE_STDIO
44
45 #ifndef USE_STDIO
46 #define BUFSIZE 1024
47 #endif
48
49 static DB_functions_t *deadbeef;
50 typedef struct {
51 DB_vfs_t *vfs;
52 #ifdef USE_STDIO
53 FILE *stream;
54 #else
55 int stream;
56 int64_t offs;
57 uint8_t buffer[BUFSIZE];
58 uint8_t *bufptr;
59 int bufremaining;
60 int have_size;
61 size_t size;
62 #endif
63 } STDIO_FILE;
64
65 static DB_vfs_t plugin;
66
67 static DB_FILE *
stdio_open(const char * fname)68 stdio_open (const char *fname) {
69 if (!memcmp (fname, "file://", 7)) {
70 fname += 7;
71 }
72 #ifdef USE_STDIO
73 FILE *file = fopen (fname, "rb");
74 if (!file) {
75 return NULL;
76 }
77 #else
78 int file = open (fname, O_LARGEFILE);
79 if (file == -1) {
80 return NULL;
81 }
82 #endif
83 STDIO_FILE *fp = malloc (sizeof (STDIO_FILE));
84 memset (fp, 0, sizeof (STDIO_FILE));
85 fp->vfs = &plugin;
86 fp->stream = file;
87 return (DB_FILE*)fp;
88 }
89
90 static void
stdio_close(DB_FILE * stream)91 stdio_close (DB_FILE *stream) {
92 assert (stream);
93 #ifdef USE_STDIO
94 fclose (((STDIO_FILE *)stream)->stream);
95 #else
96 close (((STDIO_FILE *)stream)->stream);
97 #endif
98 free (stream);
99 }
100
101 static int
fillbuffer(STDIO_FILE * f)102 fillbuffer (STDIO_FILE *f) {
103 assert (f->bufremaining >= 0);
104 if (f->bufremaining == 0) {
105 f->bufremaining = (int)read (f->stream, f->buffer, BUFSIZE);
106 if (f->bufremaining < 0) {
107 f->bufremaining = 0;
108 return -1;
109 }
110 f->bufptr = f->buffer;
111 }
112 return f->bufremaining;
113 }
114
115 static size_t
stdio_read(void * ptr,size_t size,size_t nmemb,DB_FILE * stream)116 stdio_read (void *ptr, size_t size, size_t nmemb, DB_FILE *stream) {
117 assert (stream);
118 assert (ptr);
119 #ifdef USE_STDIO
120 return fread (ptr, size, nmemb, ((STDIO_FILE*)stream)->stream);
121 #else
122 STDIO_FILE *f = (STDIO_FILE*)stream;
123 size_t nb = size * nmemb;
124 while (nb > 0) {
125 if (fillbuffer (f) <= 0) {
126 break;
127 }
128 int r = f->bufremaining;
129 if (r > nb) {
130 r = (int)nb;
131 }
132 memcpy (ptr, f->bufptr, r);
133 f->bufremaining -= r;
134 f->bufptr += r;
135 ptr += r;
136 f->offs += r;
137 nb -= r;
138 }
139 size_t ret = ((size * nmemb) - nb) / size;
140 return ret;
141 #endif
142 }
143
144 static int
stdio_seek(DB_FILE * stream,int64_t offset,int whence)145 stdio_seek (DB_FILE *stream, int64_t offset, int whence) {
146 assert (stream);
147 #ifdef USE_STDIO
148 return fseek (((STDIO_FILE *)stream)->stream, offset, whence);
149 #else
150 // convert offset to absolute
151 if (whence == SEEK_CUR) {
152 whence = SEEK_SET;
153 offset = ((STDIO_FILE*)stream)->offs + offset;
154 }
155 off64_t res = lseek64 (((STDIO_FILE *)stream)->stream, offset, whence);
156 if (res == -1) {
157 return -1;
158 }
159 // printf ("lseek res: %lld (%lld, %d, prev=%lld)\n", res, offset, whence, ((STDIO_FILE*)stream)->offs);
160 ((STDIO_FILE*)stream)->offs = res;
161 ((STDIO_FILE*)stream)->bufremaining = 0;
162 #endif
163 return 0;
164 }
165
166 static int64_t
stdio_tell(DB_FILE * stream)167 stdio_tell (DB_FILE *stream) {
168 assert (stream);
169 #ifdef USE_STDIO
170 return ftell (((STDIO_FILE*)stream)->stream);
171 #else
172 return ((STDIO_FILE*)stream)->offs;
173 #endif
174 }
175
176 static void
stdio_rewind(DB_FILE * stream)177 stdio_rewind (DB_FILE *stream) {
178 assert (stream);
179 #ifdef USE_STDIO
180 rewind (((STDIO_FILE*)stream)->stream);
181 #else
182 stdio_seek (stream, 0, SEEK_SET);
183 #endif
184 }
185
186 static int64_t
stdio_getlength(DB_FILE * stream)187 stdio_getlength (DB_FILE *stream) {
188 assert (stream);
189 STDIO_FILE *f = (STDIO_FILE *)stream;
190 #ifdef USE_STDIO
191 size_t offs = ftell (f->stream);
192 fseek (f->stream, 0, SEEK_END);
193 size_t l = ftell (f->stream);
194 fseek (f->stream, offs, SEEK_SET);
195 return l;
196 #else
197 if (!f->have_size) {
198 int64_t size = lseek64 (f->stream, 0, SEEK_END);
199 lseek64 (f->stream, f->offs, SEEK_SET);
200 f->bufremaining = 0;
201 f->have_size = 1;
202 f->size = size;
203 }
204 return f->size;
205 #endif
206 }
207
208 const char *
stdio_get_content_type(DB_FILE * stream)209 stdio_get_content_type (DB_FILE *stream) {
210 return NULL;
211 }
212
213 int
stdio_is_streaming(void)214 stdio_is_streaming (void) {
215 return 0;
216 }
217
218 // standard stdio vfs
219 static DB_vfs_t plugin = {
220 DB_PLUGIN_SET_API_VERSION
221 .plugin.version_major = 1,
222 .plugin.version_minor = 0,
223 .plugin.type = DB_PLUGIN_VFS,
224 .plugin.name = "stdio vfs",
225 .plugin.id = "vfs_stdio",
226 .plugin.descr = "Standard IO plugin\nUsed for reading normal local files\nIt is statically linked, so you can't delete it.",
227 .plugin.copyright =
228 "standard file vfs implementation\n"
229 "\n"
230 "Copyright (C) 2009-2015 Alexey Yakovenko\n"
231 "\n"
232 "This software is provided 'as-is', without any express or implied\n"
233 "warranty. In no event will the authors be held liable for any damages\n"
234 "arising from the use of this software.\n"
235 "\n"
236 "Permission is granted to anyone to use this software for any purpose,\n"
237 "including commercial applications, and to alter it and redistribute it\n"
238 "freely, subject to the following restrictions:\n"
239 "\n"
240 "1. The origin of this software must not be misrepresented; you must not\n"
241 " claim that you wrote the original software. If you use this software\n"
242 " in a product, an acknowledgment in the product documentation would be\n"
243 " appreciated but is not required.\n"
244 "2. Altered source versions must be plainly marked as such, and must not be\n"
245 " misrepresented as being the original software.\n"
246 "3. This notice may not be removed or altered from any source distribution.\n"
247 "\n"
248 "Alexey Yakovenko waker@users.sourceforge.net\n"
249 ,
250 .plugin.website = "http://deadbeef.sf.net",
251 .open = stdio_open,
252 .close = stdio_close,
253 .read = stdio_read,
254 .seek = stdio_seek,
255 .tell = stdio_tell,
256 .rewind = stdio_rewind,
257 .getlength = stdio_getlength,
258 .get_content_type = stdio_get_content_type,
259 .is_streaming = stdio_is_streaming
260 };
261
262 DB_plugin_t *
stdio_load(DB_functions_t * api)263 stdio_load (DB_functions_t *api) {
264 deadbeef = api;
265 return DB_PLUGIN (&plugin);
266 }
267
268