Rev 1905 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1905 | serge | 1 | /* TODO: Check all read calls (in loops, especially!) for return value 0 (EOF)! */ |
2 | |||
3 | /* |
||
4 | readers.c: reading input data |
||
5 | |||
6 | copyright ?-2008 by the mpg123 project - free software under the terms of the LGPL 2.1 |
||
7 | see COPYING and AUTHORS files in distribution or http://mpg123.org |
||
8 | initially written by Michael Hipp |
||
9 | */ |
||
10 | |||
11 | #include "mpg123lib_intern.h" |
||
12 | #include |
||
13 | #include |
||
14 | #include |
||
3960 | Serge | 15 | /* For select(), I need select.h according to POSIX 2001, else: sys/time.h sys/types.h unistd.h (the latter two included in compat.h already). */ |
1905 | serge | 16 | #ifdef HAVE_SYS_SELECT_H |
17 | #include |
||
18 | #endif |
||
19 | #ifdef HAVE_SYS_TIME_H |
||
20 | #include |
||
21 | #endif |
||
22 | #ifdef _MSC_VER |
||
23 | #include |
||
24 | #endif |
||
25 | |||
3960 | Serge | 26 | #include "compat.h" |
1905 | serge | 27 | #include "debug.h" |
28 | |||
29 | static int default_init(mpg123_handle *fr); |
||
30 | static off_t get_fileinfo(mpg123_handle *); |
||
31 | static ssize_t posix_read(int fd, void *buf, size_t count){ return read(fd, buf, count); } |
||
32 | static off_t posix_lseek(int fd, off_t offset, int whence){ return lseek(fd, offset, whence); } |
||
3960 | Serge | 33 | static off_t nix_lseek(int fd, off_t offset, int whence){ return -1; } |
1905 | serge | 34 | |
35 | static ssize_t plain_fullread(mpg123_handle *fr,unsigned char *buf, ssize_t count); |
||
36 | |||
3960 | Serge | 37 | /* Wrapper to decide between descriptor-based and external handle-based I/O. */ |
38 | static off_t io_seek(struct reader_data *rdat, off_t offset, int whence); |
||
39 | static ssize_t io_read(struct reader_data *rdat, void *buf, size_t count); |
||
40 | |||
1905 | serge | 41 | #ifndef NO_FEEDER |
42 | /* Bufferchain methods. */ |
||
43 | static void bc_init(struct bufferchain *bc); |
||
44 | static void bc_reset(struct bufferchain *bc); |
||
45 | static int bc_append(struct bufferchain *bc, ssize_t size); |
||
46 | #if 0 |
||
47 | static void bc_drop(struct bufferchain *bc); |
||
48 | #endif |
||
49 | static int bc_add(struct bufferchain *bc, const unsigned char *data, ssize_t size); |
||
50 | static ssize_t bc_give(struct bufferchain *bc, unsigned char *out, ssize_t size); |
||
51 | static ssize_t bc_skip(struct bufferchain *bc, ssize_t count); |
||
52 | static ssize_t bc_seekback(struct bufferchain *bc, ssize_t count); |
||
53 | static void bc_forget(struct bufferchain *bc); |
||
54 | #endif |
||
55 | |||
56 | /* A normal read and a read with timeout. */ |
||
57 | static ssize_t plain_read(mpg123_handle *fr, void *buf, size_t count) |
||
58 | { |
||
3960 | Serge | 59 | ssize_t ret = io_read(&fr->rdat, buf, count); |
1905 | serge | 60 | if(VERBOSE3) debug2("read %li bytes of %li", (long)ret, (long)count); |
61 | return ret; |
||
62 | } |
||
63 | |||
3960 | Serge | 64 | #ifdef TIMEOUT_READ |
65 | |||
66 | /* Wait for data becoming available, allowing soft-broken network connection to die |
||
67 | This is needed for Shoutcast servers that have forgotten about us while connection was temporarily down. */ |
||
68 | static ssize_t timeout_read(mpg123_handle *fr, void *buf, size_t count) |
||
69 | { |
||
70 | struct timeval tv; |
||
71 | ssize_t ret = 0; |
||
72 | fd_set fds; |
||
73 | tv.tv_sec = fr->rdat.timeout_sec; |
||
74 | tv.tv_usec = 0; |
||
75 | FD_ZERO(&fds); |
||
76 | FD_SET(fr->rdat.filept, &fds); |
||
77 | ret = select(fr->rdat.filept+1, &fds, NULL, NULL, &tv); |
||
78 | /* This works only with "my" read function. Not user-replaced. */ |
||
79 | if(ret > 0) ret = read(fr->rdat.filept, buf, count); |
||
80 | else |
||
81 | { |
||
82 | ret=-1; /* no activity is the error */ |
||
83 | if(NOQUIET) error("stream timed out"); |
||
84 | } |
||
85 | return ret; |
||
86 | } |
||
87 | #endif |
||
88 | |||
1905 | serge | 89 | #ifndef NO_ICY |
90 | /* stream based operation with icy meta data*/ |
||
91 | static ssize_t icy_fullread(mpg123_handle *fr, unsigned char *buf, ssize_t count) |
||
92 | { |
||
93 | ssize_t ret,cnt; |
||
94 | cnt = 0; |
||
95 | if(fr->rdat.flags & READER_SEEKABLE) |
||
96 | { |
||
97 | if(NOQUIET) error("mpg123 programmer error: I don't do ICY on seekable streams."); |
||
98 | return -1; |
||
99 | } |
||
100 | /* |
||
101 | There used to be a check for expected file end here (length value or ID3 flag). |
||
102 | This is not needed: |
||
103 | 1. EOF is indicated by fdread returning zero bytes anyway. |
||
104 | 2. We get false positives of EOF for either files that grew or |
||
105 | 3. ... files that have ID3v1 tags in between (stream with intro). |
||
106 | */ |
||
107 | |||
108 | while(cnt < count) |
||
109 | { |
||
110 | /* all icy code is inside this if block, everything else is the plain fullread we know */ |
||
111 | /* debug1("read: %li left", (long) count-cnt); */ |
||
112 | if(fr->icy.next < count-cnt) |
||
113 | { |
||
114 | unsigned char temp_buff; |
||
115 | size_t meta_size; |
||
116 | ssize_t cut_pos; |
||
117 | |||
118 | /* we are near icy-metaint boundary, read up to the boundary */ |
||
119 | if(fr->icy.next > 0) |
||
120 | { |
||
121 | cut_pos = fr->icy.next; |
||
3960 | Serge | 122 | ret = fr->rdat.fdread(fr,buf+cnt,cut_pos); |
1905 | serge | 123 | if(ret < 1) |
124 | { |
||
125 | if(ret == 0) break; /* Just EOF. */ |
||
126 | if(NOQUIET) error("icy boundary read"); |
||
127 | |||
128 | return READER_ERROR; |
||
129 | } |
||
3960 | Serge | 130 | |
131 | if(!(fr->rdat.flags & READER_BUFFERED)) fr->rdat.filepos += ret; |
||
1905 | serge | 132 | cnt += ret; |
133 | fr->icy.next -= ret; |
||
134 | if(fr->icy.next > 0) |
||
135 | { |
||
136 | debug1("another try... still %li left", (long)fr->icy.next); |
||
137 | continue; |
||
138 | } |
||
139 | } |
||
140 | /* now off to read icy data */ |
||
141 | |||
142 | /* one byte icy-meta size (must be multiplied by 16 to get icy-meta length) */ |
||
3960 | Serge | 143 | |
1905 | serge | 144 | ret = fr->rdat.fdread(fr,&temp_buff,1); /* Getting one single byte hast to suceed. */ |
145 | if(ret < 0){ if(NOQUIET) error("reading icy size"); return READER_ERROR; } |
||
146 | if(ret == 0) break; |
||
147 | |||
148 | debug2("got meta-size byte: %u, at filepos %li", temp_buff, (long)fr->rdat.filepos ); |
||
149 | if(!(fr->rdat.flags & READER_BUFFERED)) fr->rdat.filepos += ret; /* 1... */ |
||
150 | |||
151 | if((meta_size = ((size_t) temp_buff) * 16)) |
||
152 | { |
||
153 | /* we have got some metadata */ |
||
154 | char *meta_buff; |
||
3960 | Serge | 155 | /* TODO: Get rid of this malloc ... perhaps hooking into the reader buffer pool? */ |
1905 | serge | 156 | meta_buff = malloc(meta_size+1); |
157 | if(meta_buff != NULL) |
||
158 | { |
||
159 | ssize_t left = meta_size; |
||
160 | while(left > 0) |
||
161 | { |
||
162 | ret = fr->rdat.fdread(fr,meta_buff+meta_size-left,left); |
||
163 | /* 0 is error here, too... there _must_ be the ICY data, the server promised! */ |
||
164 | if(ret < 1){ if(NOQUIET) error("reading icy-meta"); return READER_ERROR; } |
||
165 | left -= ret; |
||
166 | } |
||
167 | meta_buff[meta_size] = 0; /* string paranoia */ |
||
168 | if(!(fr->rdat.flags & READER_BUFFERED)) fr->rdat.filepos += ret; |
||
169 | |||
170 | if(fr->icy.data) free(fr->icy.data); |
||
171 | fr->icy.data = meta_buff; |
||
172 | fr->metaflags |= MPG123_NEW_ICY; |
||
173 | debug2("icy-meta: %s size: %d bytes", fr->icy.data, (int)meta_size); |
||
174 | } |
||
175 | else |
||
176 | { |
||
177 | if(NOQUIET) error1("cannot allocate memory for meta_buff (%lu bytes) ... trying to skip the metadata!", (unsigned long)meta_size); |
||
178 | fr->rd->skip_bytes(fr, meta_size); |
||
179 | } |
||
180 | } |
||
181 | fr->icy.next = fr->icy.interval; |
||
182 | } |
||
3960 | Serge | 183 | else |
184 | { |
||
185 | ret = plain_fullread(fr, buf+cnt, count-cnt); |
||
186 | if(ret < 0){ if(NOQUIET) error1("reading the rest of %li", (long)(count-cnt)); return READER_ERROR; } |
||
187 | if(ret == 0) break; |
||
1905 | serge | 188 | |
3960 | Serge | 189 | cnt += ret; |
190 | fr->icy.next -= ret; |
||
191 | } |
||
1905 | serge | 192 | } |
193 | /* debug1("done reading, got %li", (long)cnt); */ |
||
194 | return cnt; |
||
195 | } |
||
196 | #else |
||
197 | #define icy_fullread NULL |
||
198 | #endif /* NO_ICY */ |
||
199 | |||
200 | /* stream based operation */ |
||
201 | static ssize_t plain_fullread(mpg123_handle *fr,unsigned char *buf, ssize_t count) |
||
202 | { |
||
203 | ssize_t ret,cnt=0; |
||
204 | |||
3960 | Serge | 205 | #ifdef EXTRA_DEBUG |
206 | debug1("plain fullread of %"SSIZE_P, (size_p)count); |
||
207 | #endif |
||
1905 | serge | 208 | /* |
209 | There used to be a check for expected file end here (length value or ID3 flag). |
||
210 | This is not needed: |
||
211 | 1. EOF is indicated by fdread returning zero bytes anyway. |
||
212 | 2. We get false positives of EOF for either files that grew or |
||
213 | 3. ... files that have ID3v1 tags in between (stream with intro). |
||
214 | */ |
||
215 | while(cnt < count) |
||
216 | { |
||
217 | ret = fr->rdat.fdread(fr,buf+cnt,count-cnt); |
||
218 | if(ret < 0) return READER_ERROR; |
||
219 | if(ret == 0) break; |
||
220 | if(!(fr->rdat.flags & READER_BUFFERED)) fr->rdat.filepos += ret; |
||
221 | cnt += ret; |
||
222 | } |
||
223 | return cnt; |
||
224 | } |
||
225 | |||
226 | static off_t stream_lseek(mpg123_handle *fr, off_t pos, int whence) |
||
227 | { |
||
228 | off_t ret; |
||
3960 | Serge | 229 | ret = io_seek(&fr->rdat, pos, whence); |
1905 | serge | 230 | if (ret >= 0) fr->rdat.filepos = ret; |
231 | else |
||
232 | { |
||
233 | fr->err = MPG123_LSEEK_FAILED; |
||
234 | ret = READER_ERROR; /* not the original value */ |
||
235 | } |
||
236 | return ret; |
||
237 | } |
||
238 | |||
239 | static void stream_close(mpg123_handle *fr) |
||
240 | { |
||
3960 | Serge | 241 | if(fr->rdat.flags & READER_FD_OPENED) compat_close(fr->rdat.filept); |
242 | |||
243 | fr->rdat.filept = 0; |
||
244 | |||
245 | #ifndef NO_FEEDER |
||
1905 | serge | 246 | if(fr->rdat.flags & READER_BUFFERED) bc_reset(&fr->rdat.buffer); |
3960 | Serge | 247 | #endif |
248 | if(fr->rdat.flags & READER_HANDLEIO) |
||
249 | { |
||
250 | if(fr->rdat.cleanup_handle != NULL) fr->rdat.cleanup_handle(fr->rdat.iohandle); |
||
251 | |||
252 | fr->rdat.iohandle = NULL; |
||
253 | } |
||
1905 | serge | 254 | } |
255 | |||
256 | static int stream_seek_frame(mpg123_handle *fr, off_t newframe) |
||
257 | { |
||
258 | debug2("seek_frame to %"OFF_P" (from %"OFF_P")", (off_p)newframe, (off_p)fr->num); |
||
259 | /* Seekable streams can go backwards and jump forwards. |
||
260 | Non-seekable streams still can go forward, just not jump. */ |
||
261 | if((fr->rdat.flags & READER_SEEKABLE) || (newframe >= fr->num)) |
||
262 | { |
||
263 | off_t preframe; /* a leading frame we jump to */ |
||
264 | off_t seek_to; /* the byte offset we want to reach */ |
||
265 | off_t to_skip; /* bytes to skip to get there (can be negative) */ |
||
266 | /* |
||
267 | now seek to nearest leading index position and read from there until newframe is reached. |
||
268 | We use skip_bytes, which handles seekable and non-seekable streams |
||
269 | (the latter only for positive offset, which we ensured before entering here). |
||
270 | */ |
||
271 | seek_to = frame_index_find(fr, newframe, &preframe); |
||
272 | /* No need to seek to index position if we are closer already. |
||
273 | But I am picky about fr->num == newframe, play safe by reading the frame again. |
||
274 | If you think that's stupid, don't call a seek to the current frame. */ |
||
275 | if(fr->num >= newframe || fr->num < preframe) |
||
276 | { |
||
277 | to_skip = seek_to - fr->rd->tell(fr); |
||
278 | if(fr->rd->skip_bytes(fr, to_skip) != seek_to) |
||
279 | return READER_ERROR; |
||
280 | |||
281 | debug2("going to %lu; just got %lu", (long unsigned)newframe, (long unsigned)preframe); |
||
282 | fr->num = preframe-1; /* Watch out! I am going to read preframe... fr->num should indicate the frame before! */ |
||
283 | } |
||
284 | while(fr->num < newframe) |
||
285 | { |
||
286 | /* try to be non-fatal now... frameNum only gets advanced on success anyway */ |
||
287 | if(!read_frame(fr)) break; |
||
288 | } |
||
289 | /* Now the wanted frame should be ready for decoding. */ |
||
290 | debug1("arrived at %lu", (long unsigned)fr->num); |
||
291 | |||
292 | return MPG123_OK; |
||
293 | } |
||
294 | else |
||
295 | { |
||
296 | fr->err = MPG123_NO_SEEK; |
||
297 | return READER_ERROR; /* invalid, no seek happened */ |
||
298 | } |
||
299 | } |
||
300 | |||
301 | /* return FALSE on error, TRUE on success, READER_MORE on occasion */ |
||
302 | static int generic_head_read(mpg123_handle *fr,unsigned long *newhead) |
||
303 | { |
||
304 | unsigned char hbuf[4]; |
||
305 | int ret = fr->rd->fullread(fr,hbuf,4); |
||
306 | if(ret == READER_MORE) return ret; |
||
307 | if(ret != 4) return FALSE; |
||
308 | |||
309 | *newhead = ((unsigned long) hbuf[0] << 24) | |
||
310 | ((unsigned long) hbuf[1] << 16) | |
||
311 | ((unsigned long) hbuf[2] << 8) | |
||
312 | (unsigned long) hbuf[3]; |
||
313 | |||
314 | return TRUE; |
||
315 | } |
||
316 | |||
317 | /* return FALSE on error, TRUE on success, READER_MORE on occasion */ |
||
318 | static int generic_head_shift(mpg123_handle *fr,unsigned long *head) |
||
319 | { |
||
320 | unsigned char hbuf; |
||
321 | int ret = fr->rd->fullread(fr,&hbuf,1); |
||
322 | if(ret == READER_MORE) return ret; |
||
323 | if(ret != 1) return FALSE; |
||
324 | |||
325 | *head <<= 8; |
||
326 | *head |= hbuf; |
||
327 | *head &= 0xffffffff; |
||
328 | return TRUE; |
||
329 | } |
||
330 | |||
331 | /* returns reached position... negative ones are bad... */ |
||
332 | static off_t stream_skip_bytes(mpg123_handle *fr,off_t len) |
||
333 | { |
||
334 | if(fr->rdat.flags & READER_SEEKABLE) |
||
335 | { |
||
336 | off_t ret = stream_lseek(fr, len, SEEK_CUR); |
||
337 | return (ret < 0) ? READER_ERROR : ret; |
||
338 | } |
||
339 | else if(len >= 0) |
||
340 | { |
||
341 | unsigned char buf[1024]; /* ThOr: Compaq cxx complained and it makes sense to me... or should one do a cast? What for? */ |
||
342 | ssize_t ret; |
||
343 | while (len > 0) |
||
344 | { |
||
345 | ssize_t num = len < (off_t)sizeof(buf) ? (ssize_t)len : (ssize_t)sizeof(buf); |
||
346 | ret = fr->rd->fullread(fr, buf, num); |
||
347 | if (ret < 0) return ret; |
||
348 | else if(ret == 0) break; /* EOF... an error? interface defined to tell the actual position... */ |
||
349 | len -= ret; |
||
350 | } |
||
351 | return fr->rd->tell(fr); |
||
352 | } |
||
3960 | Serge | 353 | #ifndef NO_FEEDER |
1905 | serge | 354 | else if(fr->rdat.flags & READER_BUFFERED) |
355 | { /* Perhaps we _can_ go a bit back. */ |
||
356 | if(fr->rdat.buffer.pos >= -len) |
||
357 | { |
||
358 | fr->rdat.buffer.pos += len; |
||
359 | return fr->rd->tell(fr); |
||
360 | } |
||
361 | else |
||
362 | { |
||
363 | fr->err = MPG123_NO_SEEK; |
||
364 | return READER_ERROR; |
||
365 | } |
||
366 | } |
||
3960 | Serge | 367 | #endif |
1905 | serge | 368 | else |
369 | { |
||
370 | fr->err = MPG123_NO_SEEK; |
||
371 | return READER_ERROR; |
||
372 | } |
||
373 | } |
||
374 | |||
375 | /* Return 0 on success... */ |
||
376 | static int stream_back_bytes(mpg123_handle *fr, off_t bytes) |
||
377 | { |
||
378 | off_t want = fr->rd->tell(fr)-bytes; |
||
379 | if(want < 0) return READER_ERROR; |
||
380 | if(stream_skip_bytes(fr,-bytes) != want) return READER_ERROR; |
||
381 | |||
382 | return 0; |
||
383 | } |
||
384 | |||
385 | |||
386 | /* returns size on success... */ |
||
387 | static int generic_read_frame_body(mpg123_handle *fr,unsigned char *buf, int size) |
||
388 | { |
||
389 | long l; |
||
390 | |||
391 | if((l=fr->rd->fullread(fr,buf,size)) != size) |
||
392 | { |
||
393 | long ll = l; |
||
394 | if(ll <= 0) ll = 0; |
||
3960 | Serge | 395 | return READER_MORE; |
1905 | serge | 396 | } |
397 | return l; |
||
398 | } |
||
399 | |||
400 | static off_t generic_tell(mpg123_handle *fr) |
||
401 | { |
||
3960 | Serge | 402 | #ifndef NO_FEEDER |
1905 | serge | 403 | if(fr->rdat.flags & READER_BUFFERED) |
404 | fr->rdat.filepos = fr->rdat.buffer.fileoff+fr->rdat.buffer.pos; |
||
3960 | Serge | 405 | #endif |
1905 | serge | 406 | |
407 | return fr->rdat.filepos; |
||
408 | } |
||
409 | |||
410 | /* This does not (fully) work for non-seekable streams... You have to check for that flag, pal! */ |
||
411 | static void stream_rewind(mpg123_handle *fr) |
||
412 | { |
||
413 | if(fr->rdat.flags & READER_SEEKABLE) |
||
3960 | Serge | 414 | { |
415 | fr->rdat.filepos = stream_lseek(fr,0,SEEK_SET); |
||
416 | #ifndef NO_FEEDER |
||
417 | fr->rdat.buffer.fileoff = fr->rdat.filepos; |
||
418 | #endif |
||
419 | } |
||
420 | #ifndef NO_FEEDER |
||
1905 | serge | 421 | if(fr->rdat.flags & READER_BUFFERED) |
422 | { |
||
423 | fr->rdat.buffer.pos = 0; |
||
424 | fr->rdat.buffer.firstpos = 0; |
||
425 | fr->rdat.filepos = fr->rdat.buffer.fileoff; |
||
426 | } |
||
3960 | Serge | 427 | #endif |
1905 | serge | 428 | } |
429 | |||
430 | /* |
||
431 | * returns length of a file (if filept points to a file) |
||
432 | * reads the last 128 bytes information into buffer |
||
433 | * ... that is not totally safe... |
||
434 | */ |
||
435 | static off_t get_fileinfo(mpg123_handle *fr) |
||
436 | { |
||
437 | off_t len; |
||
438 | |||
3960 | Serge | 439 | if((len=io_seek(&fr->rdat,0,SEEK_END)) < 0) return -1; |
1905 | serge | 440 | |
3960 | Serge | 441 | if(io_seek(&fr->rdat,-128,SEEK_END) < 0) return -1; |
1905 | serge | 442 | |
443 | if(fr->rd->fullread(fr,(unsigned char *)fr->id3buf,128) != 128) return -1; |
||
444 | |||
445 | if(!strncmp((char*)fr->id3buf,"TAG",3)) len -= 128; |
||
446 | |||
3960 | Serge | 447 | if(io_seek(&fr->rdat,0,SEEK_SET) < 0) return -1; |
1905 | serge | 448 | |
449 | if(len <= 0) return -1; |
||
450 | |||
451 | return len; |
||
452 | } |
||
453 | |||
454 | #ifndef NO_FEEDER |
||
455 | /* Methods for the buffer chain, mainly used for feed reader, but not just that. */ |
||
456 | |||
3960 | Serge | 457 | |
458 | static struct buffy* buffy_new(size_t size, size_t minsize) |
||
459 | { |
||
460 | struct buffy *newbuf; |
||
461 | newbuf = malloc(sizeof(struct buffy)); |
||
462 | if(newbuf == NULL) return NULL; |
||
463 | |||
464 | newbuf->realsize = size > minsize ? size : minsize; |
||
465 | newbuf->data = malloc(newbuf->realsize); |
||
466 | if(newbuf->data == NULL) |
||
467 | { |
||
468 | free(newbuf); |
||
469 | return NULL; |
||
470 | } |
||
471 | newbuf->size = 0; |
||
472 | newbuf->next = NULL; |
||
473 | return newbuf; |
||
474 | } |
||
475 | |||
476 | static void buffy_del(struct buffy* buf) |
||
477 | { |
||
478 | if(buf) |
||
479 | { |
||
480 | free(buf->data); |
||
481 | free(buf); |
||
482 | } |
||
483 | } |
||
484 | |||
485 | /* Delete this buffy and all following buffies. */ |
||
486 | static void buffy_del_chain(struct buffy* buf) |
||
487 | { |
||
488 | while(buf) |
||
489 | { |
||
490 | struct buffy* next = buf->next; |
||
491 | buffy_del(buf); |
||
492 | buf = next; |
||
493 | } |
||
494 | } |
||
495 | |||
496 | void bc_prepare(struct bufferchain *bc, size_t pool_size, size_t bufblock) |
||
497 | { |
||
498 | bc_poolsize(bc, pool_size, bufblock); |
||
499 | bc->pool = NULL; |
||
500 | bc->pool_fill = 0; |
||
501 | bc_init(bc); /* Ensure that members are zeroed for read-only use. */ |
||
502 | } |
||
503 | |||
504 | size_t bc_fill(struct bufferchain *bc) |
||
505 | { |
||
506 | return (size_t)(bc->size - bc->pos); |
||
507 | } |
||
508 | |||
509 | void bc_poolsize(struct bufferchain *bc, size_t pool_size, size_t bufblock) |
||
510 | { |
||
511 | bc->pool_size = pool_size; |
||
512 | bc->bufblock = bufblock; |
||
513 | } |
||
514 | |||
515 | void bc_cleanup(struct bufferchain *bc) |
||
516 | { |
||
517 | buffy_del_chain(bc->pool); |
||
518 | bc->pool = NULL; |
||
519 | bc->pool_fill = 0; |
||
520 | } |
||
521 | |||
522 | /* Fetch a buffer from the pool (if possible) or create one. */ |
||
523 | static struct buffy* bc_alloc(struct bufferchain *bc, size_t size) |
||
524 | { |
||
525 | /* Easy route: Just try the first available buffer. |
||
526 | Size does not matter, it's only a hint for creation of new buffers. */ |
||
527 | if(bc->pool) |
||
528 | { |
||
529 | struct buffy *buf = bc->pool; |
||
530 | bc->pool = buf->next; |
||
531 | buf->next = NULL; /* That shall be set to a sensible value later. */ |
||
532 | buf->size = 0; |
||
533 | --bc->pool_fill; |
||
534 | debug2("bc_alloc: picked %p from pool (fill now %"SIZE_P")", (void*)buf, (size_p)bc->pool_fill); |
||
535 | return buf; |
||
536 | } |
||
537 | else return buffy_new(size, bc->bufblock); |
||
538 | } |
||
539 | |||
540 | /* Either stuff the buffer back into the pool or free it for good. */ |
||
541 | static void bc_free(struct bufferchain *bc, struct buffy* buf) |
||
542 | { |
||
543 | if(!buf) return; |
||
544 | |||
545 | if(bc->pool_fill < bc->pool_size) |
||
546 | { |
||
547 | buf->next = bc->pool; |
||
548 | bc->pool = buf; |
||
549 | ++bc->pool_fill; |
||
550 | } |
||
551 | else buffy_del(buf); |
||
552 | } |
||
553 | |||
554 | /* Make the buffer count in the pool match the pool size. */ |
||
555 | static int bc_fill_pool(struct bufferchain *bc) |
||
556 | { |
||
557 | /* Remove superfluous ones. */ |
||
558 | while(bc->pool_fill > bc->pool_size) |
||
559 | { |
||
560 | /* Lazyness: Just work on the front. */ |
||
561 | struct buffy* buf = bc->pool; |
||
562 | bc->pool = buf->next; |
||
563 | buffy_del(buf); |
||
564 | --bc->pool_fill; |
||
565 | } |
||
566 | |||
567 | /* Add missing ones. */ |
||
568 | while(bc->pool_fill < bc->pool_size) |
||
569 | { |
||
570 | /* Again, just work on the front. */ |
||
571 | struct buffy* buf; |
||
572 | buf = buffy_new(0, bc->bufblock); /* Use default block size. */ |
||
573 | if(!buf) return -1; |
||
574 | |||
575 | buf->next = bc->pool; |
||
576 | bc->pool = buf; |
||
577 | ++bc->pool_fill; |
||
578 | } |
||
579 | |||
580 | return 0; |
||
581 | } |
||
582 | |||
583 | |||
1905 | serge | 584 | static void bc_init(struct bufferchain *bc) |
585 | { |
||
586 | bc->first = NULL; |
||
587 | bc->last = bc->first; |
||
588 | bc->size = 0; |
||
589 | bc->pos = 0; |
||
590 | bc->firstpos = 0; |
||
591 | bc->fileoff = 0; |
||
592 | } |
||
593 | |||
594 | static void bc_reset(struct bufferchain *bc) |
||
595 | { |
||
3960 | Serge | 596 | /* Free current chain, possibly stuffing back into the pool. */ |
597 | while(bc->first) |
||
1905 | serge | 598 | { |
3960 | Serge | 599 | struct buffy* buf = bc->first; |
600 | bc->first = buf->next; |
||
601 | bc_free(bc, buf); |
||
1905 | serge | 602 | } |
3960 | Serge | 603 | bc_fill_pool(bc); /* Ignoring an error here... */ |
1905 | serge | 604 | bc_init(bc); |
605 | } |
||
606 | |||
607 | /* Create a new buffy at the end to be filled. */ |
||
608 | static int bc_append(struct bufferchain *bc, ssize_t size) |
||
609 | { |
||
610 | struct buffy *newbuf; |
||
611 | if(size < 1) return -1; |
||
612 | |||
3960 | Serge | 613 | newbuf = bc_alloc(bc, size); |
1905 | serge | 614 | if(newbuf == NULL) return -2; |
615 | |||
616 | if(bc->last != NULL) bc->last->next = newbuf; |
||
617 | else if(bc->first == NULL) bc->first = newbuf; |
||
618 | |||
619 | bc->last = newbuf; |
||
3960 | Serge | 620 | debug3("bc_append: new last buffer %p with %"SSIZE_P" B (really %"SSIZE_P")", (void*)bc->last, (ssize_p)bc->last->size, (ssize_p)bc->last->realsize); |
1905 | serge | 621 | return 0; |
622 | } |
||
623 | |||
624 | /* Append a new buffer and copy content to it. */ |
||
625 | static int bc_add(struct bufferchain *bc, const unsigned char *data, ssize_t size) |
||
626 | { |
||
627 | int ret = 0; |
||
3960 | Serge | 628 | ssize_t part = 0; |
629 | debug2("bc_add: adding %"SSIZE_P" bytes at %"OFF_P, (ssize_p)size, (off_p)(bc->fileoff+bc->size)); |
||
630 | if(size >=4) debug4("first bytes: %02x %02x %02x %02x", data[0], data[1], data[2], data[3]); |
||
1905 | serge | 631 | |
3960 | Serge | 632 | while(size > 0) |
633 | { |
||
634 | /* Try to fill up the last buffer block. */ |
||
635 | if(bc->last != NULL && bc->last->size < bc->last->realsize) |
||
636 | { |
||
637 | part = bc->last->realsize - bc->last->size; |
||
638 | if(part > size) part = size; |
||
639 | |||
640 | debug2("bc_add: adding %"SSIZE_P" B to existing block %p", (ssize_p)part, (void*)bc->last); |
||
641 | memcpy(bc->last->data+bc->last->size, data, part); |
||
642 | bc->last->size += part; |
||
643 | size -= part; |
||
644 | bc->size += part; |
||
645 | data += part; |
||
646 | } |
||
647 | |||
648 | /* If there is still data left, put it into a new buffer block. */ |
||
649 | if(size > 0 && (ret = bc_append(bc, size)) != 0) |
||
650 | break; |
||
651 | } |
||
652 | |||
1905 | serge | 653 | return ret; |
654 | } |
||
655 | |||
3960 | Serge | 656 | /* Common handler for "You want more than I can give." situation. */ |
657 | static ssize_t bc_need_more(struct bufferchain *bc) |
||
658 | { |
||
659 | debug3("hit end, back to beginning (%li - %li < %li)", (long)bc->size, (long)bc->pos, (long)bc->size); |
||
660 | /* go back to firstpos, undo the previous reads */ |
||
661 | bc->pos = bc->firstpos; |
||
662 | return READER_MORE; |
||
663 | } |
||
664 | |||
1905 | serge | 665 | /* Give some data, advancing position but not forgetting yet. */ |
666 | static ssize_t bc_give(struct bufferchain *bc, unsigned char *out, ssize_t size) |
||
667 | { |
||
668 | struct buffy *b = bc->first; |
||
669 | ssize_t gotcount = 0; |
||
670 | ssize_t offset = 0; |
||
3960 | Serge | 671 | if(bc->size - bc->pos < size) return bc_need_more(bc); |
672 | |||
1905 | serge | 673 | /* find the current buffer */ |
674 | while(b != NULL && (offset + b->size) <= bc->pos) |
||
675 | { |
||
676 | offset += b->size; |
||
677 | b = b->next; |
||
678 | } |
||
679 | /* now start copying from there */ |
||
680 | while(gotcount < size && (b != NULL)) |
||
681 | { |
||
682 | ssize_t loff = bc->pos - offset; |
||
683 | ssize_t chunk = size - gotcount; /* amount of bytes to get from here... */ |
||
684 | if(chunk > b->size - loff) chunk = b->size - loff; |
||
685 | |||
686 | #ifdef EXTRA_DEBUG |
||
3960 | Serge | 687 | debug3("copying %liB from %p+%li",(long)chunk, b->data, (long)loff); |
1905 | serge | 688 | #endif |
689 | |||
690 | memcpy(out+gotcount, b->data+loff, chunk); |
||
691 | gotcount += chunk; |
||
692 | bc->pos += chunk; |
||
693 | offset += b->size; |
||
694 | b = b->next; |
||
695 | } |
||
696 | #ifdef EXTRA_DEBUG |
||
697 | debug2("got %li bytes, pos advanced to %li", (long)gotcount, (long)bc->pos); |
||
698 | #endif |
||
699 | |||
700 | return gotcount; |
||
701 | } |
||
702 | |||
703 | /* Skip some bytes and return the new position. |
||
704 | The buffers are still there, just the read pointer is moved! */ |
||
705 | static ssize_t bc_skip(struct bufferchain *bc, ssize_t count) |
||
706 | { |
||
707 | if(count >= 0) |
||
708 | { |
||
3960 | Serge | 709 | if(bc->size - bc->pos < count) return bc_need_more(bc); |
1905 | serge | 710 | else return bc->pos += count; |
711 | } |
||
712 | else return READER_ERROR; |
||
713 | } |
||
714 | |||
715 | static ssize_t bc_seekback(struct bufferchain *bc, ssize_t count) |
||
716 | { |
||
717 | if(count >= 0 && count <= bc->pos) return bc->pos -= count; |
||
718 | else return READER_ERROR; |
||
719 | } |
||
720 | |||
721 | /* Throw away buffies that we passed. */ |
||
722 | static void bc_forget(struct bufferchain *bc) |
||
723 | { |
||
724 | struct buffy *b = bc->first; |
||
725 | /* free all buffers that are def'n'tly outdated */ |
||
726 | /* we have buffers until filepos... delete all buffers fully below it */ |
||
727 | if(b) debug2("bc_forget: block %lu pos %lu", (unsigned long)b->size, (unsigned long)bc->pos); |
||
728 | else debug("forget with nothing there!"); |
||
3960 | Serge | 729 | |
1905 | serge | 730 | while(b != NULL && bc->pos >= b->size) |
731 | { |
||
732 | struct buffy *n = b->next; /* != NULL or this is indeed the end and the last cycle anyway */ |
||
733 | if(n == NULL) bc->last = NULL; /* Going to delete the last buffy... */ |
||
734 | bc->fileoff += b->size; |
||
735 | bc->pos -= b->size; |
||
736 | bc->size -= b->size; |
||
3960 | Serge | 737 | |
1905 | serge | 738 | debug5("bc_forget: forgot %p with %lu, pos=%li, size=%li, fileoff=%li", (void*)b->data, (long)b->size, (long)bc->pos, (long)bc->size, (long)bc->fileoff); |
3960 | Serge | 739 | |
740 | bc_free(bc, b); |
||
1905 | serge | 741 | b = n; |
742 | } |
||
743 | bc->first = b; |
||
744 | bc->firstpos = bc->pos; |
||
745 | } |
||
746 | |||
747 | /* reader for input via manually provided buffers */ |
||
748 | |||
749 | static int feed_init(mpg123_handle *fr) |
||
750 | { |
||
751 | bc_init(&fr->rdat.buffer); |
||
3960 | Serge | 752 | bc_fill_pool(&fr->rdat.buffer); |
1905 | serge | 753 | fr->rdat.filelen = 0; |
754 | fr->rdat.filepos = 0; |
||
755 | fr->rdat.flags |= READER_BUFFERED; |
||
756 | return 0; |
||
757 | } |
||
758 | |||
759 | /* externally called function, returns 0 on success, -1 on error */ |
||
760 | int feed_more(mpg123_handle *fr, const unsigned char *in, long count) |
||
761 | { |
||
762 | int ret = 0; |
||
763 | if(VERBOSE3) debug("feed_more"); |
||
764 | if((ret = bc_add(&fr->rdat.buffer, in, count)) != 0) |
||
765 | { |
||
766 | ret = READER_ERROR; |
||
767 | if(NOQUIET) error1("Failed to add buffer, return: %i", ret); |
||
768 | } |
||
769 | else /* Not talking about filelen... that stays at 0. */ |
||
770 | |||
771 | if(VERBOSE3) debug3("feed_more: %p %luB bufsize=%lu", fr->rdat.buffer.last->data, |
||
772 | (unsigned long)fr->rdat.buffer.last->size, (unsigned long)fr->rdat.buffer.size); |
||
773 | return ret; |
||
774 | } |
||
775 | |||
776 | static ssize_t feed_read(mpg123_handle *fr, unsigned char *out, ssize_t count) |
||
777 | { |
||
778 | ssize_t gotcount = bc_give(&fr->rdat.buffer, out, count); |
||
779 | if(gotcount >= 0 && gotcount != count) return READER_ERROR; |
||
780 | else return gotcount; |
||
781 | } |
||
782 | |||
783 | /* returns reached position... negative ones are bad... */ |
||
784 | static off_t feed_skip_bytes(mpg123_handle *fr,off_t len) |
||
785 | { |
||
3960 | Serge | 786 | /* This is either the new buffer offset or some negative error value. */ |
787 | off_t res = bc_skip(&fr->rdat.buffer, (ssize_t)len); |
||
788 | if(res < 0) return res; |
||
789 | |||
790 | return fr->rdat.buffer.fileoff+res; |
||
1905 | serge | 791 | } |
792 | |||
793 | static int feed_back_bytes(mpg123_handle *fr, off_t bytes) |
||
794 | { |
||
795 | if(bytes >=0) |
||
796 | return bc_seekback(&fr->rdat.buffer, (ssize_t)bytes) >= 0 ? 0 : READER_ERROR; |
||
797 | else |
||
798 | return feed_skip_bytes(fr, -bytes) >= 0 ? 0 : READER_ERROR; |
||
799 | } |
||
800 | |||
801 | static int feed_seek_frame(mpg123_handle *fr, off_t num){ return READER_ERROR; } |
||
802 | |||
803 | /* Not just for feed reader, also for self-feeding buffered reader. */ |
||
804 | static void buffered_forget(mpg123_handle *fr) |
||
805 | { |
||
806 | bc_forget(&fr->rdat.buffer); |
||
807 | fr->rdat.filepos = fr->rdat.buffer.fileoff + fr->rdat.buffer.pos; |
||
808 | } |
||
809 | |||
810 | off_t feed_set_pos(mpg123_handle *fr, off_t pos) |
||
811 | { |
||
812 | struct bufferchain *bc = &fr->rdat.buffer; |
||
813 | if(pos >= bc->fileoff && pos-bc->fileoff < bc->size) |
||
814 | { /* We have the position! */ |
||
815 | bc->pos = (ssize_t)(pos - bc->fileoff); |
||
3960 | Serge | 816 | debug1("feed_set_pos inside, next feed from %"OFF_P, (off_p)(bc->fileoff+bc->size)); |
817 | return bc->fileoff+bc->size; /* Next input after end of buffer... */ |
||
1905 | serge | 818 | } |
819 | else |
||
820 | { /* I expect to get the specific position on next feed. Forget what I have now. */ |
||
821 | bc_reset(bc); |
||
822 | bc->fileoff = pos; |
||
3960 | Serge | 823 | debug1("feed_set_pos outside, buffer reset, next feed from %"OFF_P, (off_p)pos); |
1905 | serge | 824 | return pos; /* Next input from exactly that position. */ |
825 | } |
||
826 | } |
||
827 | |||
828 | /* The specific stuff for buffered stream reader. */ |
||
829 | |||
830 | static ssize_t buffered_fullread(mpg123_handle *fr, unsigned char *out, ssize_t count) |
||
831 | { |
||
832 | struct bufferchain *bc = &fr->rdat.buffer; |
||
833 | ssize_t gotcount; |
||
834 | if(bc->size - bc->pos < count) |
||
835 | { /* Add more stuff to buffer. If hitting end of file, adjust count. */ |
||
3960 | Serge | 836 | unsigned char readbuf[4096]; |
1905 | serge | 837 | ssize_t need = count - (bc->size-bc->pos); |
838 | while(need>0) |
||
839 | { |
||
840 | int ret; |
||
3960 | Serge | 841 | ssize_t got = fr->rdat.fullread(fr, readbuf, sizeof(readbuf)); |
1905 | serge | 842 | if(got < 0) |
843 | { |
||
844 | if(NOQUIET) error("buffer reading"); |
||
845 | return READER_ERROR; |
||
846 | } |
||
847 | |||
848 | if(VERBOSE3) debug1("buffered_fullread: buffering %li bytes from stream (if > 0)", (long)got); |
||
849 | if(got > 0 && (ret=bc_add(bc, readbuf, got)) != 0) |
||
850 | { |
||
851 | if(NOQUIET) error1("unable to add to chain, return: %i", ret); |
||
852 | return READER_ERROR; |
||
853 | } |
||
854 | |||
855 | need -= got; /* May underflow here... */ |
||
3960 | Serge | 856 | if(got < sizeof(readbuf)) /* That naturally catches got == 0, too. */ |
1905 | serge | 857 | { |
858 | if(VERBOSE3) fprintf(stderr, "Note: Input data end.\n"); |
||
859 | break; /* End. */ |
||
860 | } |
||
861 | } |
||
862 | if(bc->size - bc->pos < count) |
||
863 | count = bc->size - bc->pos; /* We want only what we got. */ |
||
864 | } |
||
865 | gotcount = bc_give(bc, out, count); |
||
866 | |||
867 | if(VERBOSE3) debug2("wanted %li, got %li", (long)count, (long)gotcount); |
||
868 | |||
869 | if(gotcount != count){ if(NOQUIET) error("gotcount != count"); return READER_ERROR; } |
||
870 | else return gotcount; |
||
871 | } |
||
872 | #else |
||
873 | int feed_more(mpg123_handle *fr, const unsigned char *in, long count) |
||
874 | { |
||
875 | fr->err = MPG123_MISSING_FEATURE; |
||
876 | return -1; |
||
877 | } |
||
878 | off_t feed_set_pos(mpg123_handle *fr, off_t pos) |
||
879 | { |
||
880 | fr->err = MPG123_MISSING_FEATURE; |
||
881 | return -1; |
||
882 | } |
||
883 | #endif /* NO_FEEDER */ |
||
884 | |||
885 | /***************************************************************** |
||
886 | * read frame helper |
||
887 | */ |
||
888 | |||
889 | #define bugger_off { mh->err = MPG123_NO_READER; return MPG123_ERR; } |
||
3960 | Serge | 890 | static int bad_init(mpg123_handle *mh) bugger_off |
891 | static void bad_close(mpg123_handle *mh){} |
||
892 | static ssize_t bad_fullread(mpg123_handle *mh, unsigned char *data, ssize_t count) bugger_off |
||
893 | static int bad_head_read(mpg123_handle *mh, unsigned long *newhead) bugger_off |
||
894 | static int bad_head_shift(mpg123_handle *mh, unsigned long *head) bugger_off |
||
895 | static off_t bad_skip_bytes(mpg123_handle *mh, off_t len) bugger_off |
||
896 | static int bad_read_frame_body(mpg123_handle *mh, unsigned char *data, int size) bugger_off |
||
897 | static int bad_back_bytes(mpg123_handle *mh, off_t bytes) bugger_off |
||
898 | static int bad_seek_frame(mpg123_handle *mh, off_t num) bugger_off |
||
899 | static off_t bad_tell(mpg123_handle *mh) bugger_off |
||
900 | static void bad_rewind(mpg123_handle *mh){} |
||
1905 | serge | 901 | #undef bugger_off |
902 | |||
903 | #define READER_STREAM 0 |
||
904 | #define READER_ICY_STREAM 1 |
||
905 | #define READER_FEED 2 |
||
906 | #define READER_BUF_STREAM 3 |
||
907 | #define READER_BUF_ICY_STREAM 4 |
||
3960 | Serge | 908 | static struct reader readers[] = |
1905 | serge | 909 | { |
910 | { /* READER_STREAM */ |
||
911 | default_init, |
||
912 | stream_close, |
||
913 | plain_fullread, |
||
914 | generic_head_read, |
||
915 | generic_head_shift, |
||
916 | stream_skip_bytes, |
||
917 | generic_read_frame_body, |
||
918 | stream_back_bytes, |
||
919 | stream_seek_frame, |
||
920 | generic_tell, |
||
921 | stream_rewind, |
||
922 | NULL |
||
923 | } , |
||
924 | { /* READER_ICY_STREAM */ |
||
925 | default_init, |
||
926 | stream_close, |
||
927 | icy_fullread, |
||
928 | generic_head_read, |
||
929 | generic_head_shift, |
||
930 | stream_skip_bytes, |
||
931 | generic_read_frame_body, |
||
932 | stream_back_bytes, |
||
933 | stream_seek_frame, |
||
934 | generic_tell, |
||
935 | stream_rewind, |
||
936 | NULL |
||
937 | }, |
||
938 | #ifdef NO_FEEDER |
||
939 | #define feed_init NULL |
||
940 | #define feed_read NULL |
||
941 | #define buffered_fullread NULL |
||
942 | #define feed_seek_frame NULL |
||
943 | #define feed_back_bytes NULL |
||
944 | #define feed_skip_bytes NULL |
||
945 | #define buffered_forget NULL |
||
946 | #endif |
||
947 | { /* READER_FEED */ |
||
948 | feed_init, |
||
949 | stream_close, |
||
950 | feed_read, |
||
951 | generic_head_read, |
||
952 | generic_head_shift, |
||
953 | feed_skip_bytes, |
||
954 | generic_read_frame_body, |
||
955 | feed_back_bytes, |
||
956 | feed_seek_frame, |
||
957 | generic_tell, |
||
958 | stream_rewind, |
||
959 | buffered_forget |
||
960 | }, |
||
961 | { /* READER_BUF_STREAM */ |
||
962 | default_init, |
||
963 | stream_close, |
||
964 | buffered_fullread, |
||
965 | generic_head_read, |
||
966 | generic_head_shift, |
||
967 | stream_skip_bytes, |
||
968 | generic_read_frame_body, |
||
969 | stream_back_bytes, |
||
970 | stream_seek_frame, |
||
971 | generic_tell, |
||
972 | stream_rewind, |
||
973 | buffered_forget |
||
974 | } , |
||
975 | { /* READER_BUF_ICY_STREAM */ |
||
976 | default_init, |
||
977 | stream_close, |
||
978 | buffered_fullread, |
||
979 | generic_head_read, |
||
980 | generic_head_shift, |
||
981 | stream_skip_bytes, |
||
982 | generic_read_frame_body, |
||
983 | stream_back_bytes, |
||
984 | stream_seek_frame, |
||
985 | generic_tell, |
||
986 | stream_rewind, |
||
987 | buffered_forget |
||
988 | }, |
||
989 | #ifdef READ_SYSTEM |
||
990 | ,{ |
||
991 | system_init, |
||
992 | NULL, /* filled in by system_init() */ |
||
993 | fullread, |
||
994 | NULL, |
||
995 | NULL, |
||
996 | NULL, |
||
997 | NULL, |
||
998 | NULL, |
||
999 | NULL, |
||
1000 | NULL, |
||
1001 | NULL, |
||
1002 | NULL, |
||
1003 | } |
||
1004 | #endif |
||
1005 | }; |
||
1006 | |||
3960 | Serge | 1007 | static struct reader bad_reader = |
1905 | serge | 1008 | { |
1009 | bad_init, |
||
1010 | bad_close, |
||
1011 | bad_fullread, |
||
1012 | bad_head_read, |
||
1013 | bad_head_shift, |
||
1014 | bad_skip_bytes, |
||
1015 | bad_read_frame_body, |
||
1016 | bad_back_bytes, |
||
1017 | bad_seek_frame, |
||
1018 | bad_tell, |
||
1019 | bad_rewind, |
||
1020 | NULL |
||
1021 | }; |
||
1022 | |||
1023 | static int default_init(mpg123_handle *fr) |
||
1024 | { |
||
3960 | Serge | 1025 | #ifdef TIMEOUT_READ |
1026 | if(fr->p.timeout > 0) |
||
1027 | { |
||
1028 | int flags; |
||
1029 | if(fr->rdat.r_read != NULL) |
||
1030 | { |
||
1031 | error("Timeout reading does not work with user-provided read function. Implement it yourself!"); |
||
1032 | return -1; |
||
1033 | } |
||
1034 | flags = fcntl(fr->rdat.filept, F_GETFL); |
||
1035 | flags |= O_NONBLOCK; |
||
1036 | fcntl(fr->rdat.filept, F_SETFL, flags); |
||
1037 | fr->rdat.fdread = timeout_read; |
||
1038 | fr->rdat.timeout_sec = fr->p.timeout; |
||
1039 | fr->rdat.flags |= READER_NONBLOCK; |
||
1040 | } |
||
1041 | else |
||
1042 | #endif |
||
1043 | fr->rdat.fdread = plain_read; |
||
1905 | serge | 1044 | |
1045 | fr->rdat.read = fr->rdat.r_read != NULL ? fr->rdat.r_read : posix_read; |
||
1046 | fr->rdat.lseek = fr->rdat.r_lseek != NULL ? fr->rdat.r_lseek : posix_lseek; |
||
3960 | Serge | 1047 | #ifndef NO_ICY |
1048 | /* ICY streams of any sort shall not be seekable. */ |
||
1049 | if(fr->p.icy_interval > 0) fr->rdat.lseek = nix_lseek; |
||
1050 | #endif |
||
1051 | |||
1905 | serge | 1052 | fr->rdat.filelen = get_fileinfo(fr); |
1053 | fr->rdat.filepos = 0; |
||
3960 | Serge | 1054 | /* |
1055 | Don't enable seeking on ICY streams, just plain normal files. |
||
1056 | This check is necessary since the client can enforce ICY parsing on files that would otherwise be seekable. |
||
1057 | It is a task for the future to make the ICY parsing safe with seeks ... or not. |
||
1058 | */ |
||
1905 | serge | 1059 | if(fr->rdat.filelen >= 0) |
1060 | { |
||
1061 | fr->rdat.flags |= READER_SEEKABLE; |
||
1062 | if(!strncmp((char*)fr->id3buf,"TAG",3)) |
||
1063 | { |
||
1064 | fr->rdat.flags |= READER_ID3TAG; |
||
1065 | fr->metaflags |= MPG123_NEW_ID3; |
||
1066 | } |
||
1067 | } |
||
1068 | /* Switch reader to a buffered one, if allowed. */ |
||
1069 | else if(fr->p.flags & MPG123_SEEKBUFFER) |
||
1070 | { |
||
1071 | #ifdef NO_FEEDER |
||
1072 | error("Buffered readers not supported in this build."); |
||
1073 | fr->err = MPG123_MISSING_FEATURE; |
||
1074 | return -1; |
||
1075 | #else |
||
1076 | if (fr->rd == &readers[READER_STREAM]) |
||
1077 | { |
||
1078 | fr->rd = &readers[READER_BUF_STREAM]; |
||
1079 | fr->rdat.fullread = plain_fullread; |
||
1080 | } |
||
1081 | #ifndef NO_ICY |
||
1082 | else if(fr->rd == &readers[READER_ICY_STREAM]) |
||
1083 | { |
||
1084 | fr->rd = &readers[READER_BUF_ICY_STREAM]; |
||
1085 | fr->rdat.fullread = icy_fullread; |
||
1086 | } |
||
1087 | #endif |
||
1088 | else |
||
1089 | { |
||
1090 | if(NOQUIET) error("mpg123 Programmer's fault: invalid reader"); |
||
1091 | return -1; |
||
1092 | } |
||
1093 | bc_init(&fr->rdat.buffer); |
||
1094 | fr->rdat.filelen = 0; /* We carry the offset, but never know how big the stream is. */ |
||
1095 | fr->rdat.flags |= READER_BUFFERED; |
||
1096 | #endif /* NO_FEEDER */ |
||
1097 | } |
||
1098 | return 0; |
||
1099 | } |
||
1100 | |||
1101 | |||
1102 | void open_bad(mpg123_handle *mh) |
||
1103 | { |
||
3960 | Serge | 1104 | debug("open_bad"); |
1905 | serge | 1105 | #ifndef NO_ICY |
1106 | clear_icy(&mh->icy); |
||
1107 | #endif |
||
1108 | mh->rd = &bad_reader; |
||
1109 | mh->rdat.flags = 0; |
||
3960 | Serge | 1110 | #ifndef NO_FEEDER |
1905 | serge | 1111 | bc_init(&mh->rdat.buffer); |
3960 | Serge | 1112 | #endif |
1113 | mh->rdat.filelen = -1; |
||
1905 | serge | 1114 | } |
1115 | |||
1116 | int open_feed(mpg123_handle *fr) |
||
1117 | { |
||
1118 | debug("feed reader"); |
||
1119 | #ifdef NO_FEEDER |
||
1120 | error("Buffered readers not supported in this build."); |
||
1121 | fr->err = MPG123_MISSING_FEATURE; |
||
1122 | return -1; |
||
1123 | #else |
||
1124 | #ifndef NO_ICY |
||
1125 | if(fr->p.icy_interval > 0) |
||
1126 | { |
||
1127 | if(NOQUIET) error("Feed reader cannot do ICY parsing!"); |
||
1128 | |||
1129 | return -1; |
||
1130 | } |
||
1131 | clear_icy(&fr->icy); |
||
1132 | #endif |
||
1133 | fr->rd = &readers[READER_FEED]; |
||
1134 | fr->rdat.flags = 0; |
||
1135 | if(fr->rd->init(fr) < 0) return -1; |
||
3960 | Serge | 1136 | |
1137 | debug("feed reader init successful"); |
||
1905 | serge | 1138 | return 0; |
1139 | #endif /* NO_FEEDER */ |
||
1140 | } |
||
1141 | |||
3960 | Serge | 1142 | /* Final code common to open_stream and open_stream_handle. */ |
1143 | static int open_finish(mpg123_handle *fr) |
||
1144 | { |
||
1145 | #ifndef NO_ICY |
||
1146 | if(fr->p.icy_interval > 0) |
||
1147 | { |
||
1148 | debug("ICY reader"); |
||
1149 | fr->icy.interval = fr->p.icy_interval; |
||
1150 | fr->icy.next = fr->icy.interval; |
||
1151 | fr->rd = &readers[READER_ICY_STREAM]; |
||
1152 | } |
||
1153 | else |
||
1154 | #endif |
||
1155 | { |
||
1156 | fr->rd = &readers[READER_STREAM]; |
||
1157 | debug("stream reader"); |
||
1158 | } |
||
1159 | |||
1160 | if(fr->rd->init(fr) < 0) return -1; |
||
1161 | |||
1162 | return MPG123_OK; |
||
1163 | } |
||
1164 | |||
1905 | serge | 1165 | int open_stream(mpg123_handle *fr, const char *bs_filenam, int fd) |
1166 | { |
||
1167 | int filept_opened = 1; |
||
1168 | int filept; /* descriptor of opened file/stream */ |
||
1169 | |||
1170 | clear_icy(&fr->icy); /* can be done inside frame_clear ...? */ |
||
3960 | Serge | 1171 | |
1905 | serge | 1172 | if(!bs_filenam) /* no file to open, got a descriptor (stdin) */ |
1173 | { |
||
1174 | filept = fd; |
||
1175 | filept_opened = 0; /* and don't try to close it... */ |
||
1176 | } |
||
1177 | #ifndef O_BINARY |
||
1178 | #define O_BINARY (0) |
||
1179 | #endif |
||
3960 | Serge | 1180 | else if((filept = compat_open(bs_filenam, O_RDONLY|O_BINARY)) < 0) /* a plain old file to open... */ |
1905 | serge | 1181 | { |
1182 | if(NOQUIET) error2("Cannot open file %s: %s", bs_filenam, strerror(errno)); |
||
1183 | fr->err = MPG123_BAD_FILE; |
||
1184 | return MPG123_ERR; /* error... */ |
||
1185 | } |
||
1186 | |||
1187 | /* now we have something behind filept and can init the reader */ |
||
1188 | fr->rdat.filelen = -1; |
||
1189 | fr->rdat.filept = filept; |
||
1190 | fr->rdat.flags = 0; |
||
1191 | if(filept_opened) fr->rdat.flags |= READER_FD_OPENED; |
||
1192 | |||
3960 | Serge | 1193 | return open_finish(fr); |
1194 | } |
||
1195 | |||
1196 | int open_stream_handle(mpg123_handle *fr, void *iohandle) |
||
1197 | { |
||
1198 | clear_icy(&fr->icy); /* can be done inside frame_clear ...? */ |
||
1199 | fr->rdat.filelen = -1; |
||
1200 | fr->rdat.filept = -1; |
||
1201 | fr->rdat.iohandle = iohandle; |
||
1202 | fr->rdat.flags = 0; |
||
1203 | fr->rdat.flags |= READER_HANDLEIO; |
||
1204 | |||
1205 | return open_finish(fr); |
||
1206 | } |
||
1207 | |||
1208 | /* Wrappers for actual reading/seeking... I'm full of wrappers here. */ |
||
1209 | static off_t io_seek(struct reader_data *rdat, off_t offset, int whence) |
||
1210 | { |
||
1211 | if(rdat->flags & READER_HANDLEIO) |
||
1905 | serge | 1212 | { |
3960 | Serge | 1213 | if(rdat->r_lseek_handle != NULL) |
1214 | { |
||
1215 | return rdat->r_lseek_handle(rdat->iohandle, offset, whence); |
||
1216 | } |
||
1217 | else return -1; |
||
1905 | serge | 1218 | } |
1219 | else |
||
3960 | Serge | 1220 | return rdat->lseek(rdat->filept, offset, whence); |
1221 | } |
||
1222 | |||
1223 | static ssize_t io_read(struct reader_data *rdat, void *buf, size_t count) |
||
1224 | { |
||
1225 | if(rdat->flags & READER_HANDLEIO) |
||
1905 | serge | 1226 | { |
3960 | Serge | 1227 | if(rdat->r_read_handle != NULL) |
1228 | { |
||
1229 | return rdat->r_read_handle(rdat->iohandle, buf, count); |
||
1230 | } |
||
1231 | else return -1; |
||
1905 | serge | 1232 | } |
3960 | Serge | 1233 | else |
1234 | return rdat->read(rdat->filept, buf, count); |
||
1905 | serge | 1235 | }>>>>>>>>>=>>>=>>>>>>>=>>>>=>>>>>=><=>><>><>><>>>>>>>>>>> |