ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

readers.c
Go to the documentation of this file.
00001 /* TODO: Check all read calls (in loops, especially!) for return value 0 (EOF)! */
00002 
00003 /*
00004     readers.c: reading input data
00005 
00006     copyright ?-2008 by the mpg123 project - free software under the terms of the LGPL 2.1
00007     see COPYING and AUTHORS files in distribution or http://mpg123.org
00008     initially written by Michael Hipp
00009 */
00010 
00011 #include "mpg123lib_intern.h"
00012 #include <sys/stat.h>
00013 #include <fcntl.h>
00014 #include <errno.h>
00015 /* 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). */
00016 #ifdef HAVE_SYS_SELECT_H
00017 #include <sys/select.h>
00018 #endif
00019 #ifdef HAVE_SYS_TIME_H
00020 #include <sys/time.h>
00021 #endif
00022 #ifdef _MSC_VER
00023 #include <io.h>
00024 #endif
00025 
00026 #include "compat.h"
00027 #include "debug.h"
00028 
00029 static int default_init(mpg123_handle *fr);
00030 static off_t get_fileinfo(mpg123_handle *);
00031 static long posix_read(int fd, void *buf, size_t count){ return read(fd, buf, count); }
00032 static off_t   posix_lseek(int fd, off_t offset, int whence){ return lseek(fd, offset, whence); }
00033 
00034 static long plain_fullread(mpg123_handle *fr,unsigned char *buf, long count);
00035 
00036 /* Wrapper to decide between descriptor-based and external handle-based I/O. */
00037 static off_t io_seek(struct reader_data *rdat, off_t offset, int whence);
00038 static long io_read(struct reader_data *rdat, void *buf, size_t count);
00039 
00040 #ifndef NO_FEEDER
00041 /* Bufferchain methods. */
00042 static void bc_init(struct bufferchain *bc);
00043 static void bc_reset(struct bufferchain *bc);
00044 static int bc_append(struct bufferchain *bc, long size);
00045 #if 0
00046 static void bc_drop(struct bufferchain *bc);
00047 #endif
00048 static int bc_add(struct bufferchain *bc, const unsigned char *data, long size);
00049 static long bc_give(struct bufferchain *bc, unsigned char *out, long size);
00050 static long bc_skip(struct bufferchain *bc, long count);
00051 static long bc_seekback(struct bufferchain *bc, long count);
00052 static void bc_forget(struct bufferchain *bc);
00053 #else
00054 #define bc_init(a)
00055 #define bc_reset(a)
00056 #endif
00057 
00058 /* A normal read and a read with timeout. */
00059 static long plain_read(mpg123_handle *fr, void *buf, size_t count)
00060 {
00061     long ret = io_read(&fr->rdat, buf, count);
00062     if(VERBOSE3) debug2("read %li bytes of %li", (long)ret, (long)count);
00063     return ret;
00064 }
00065 
00066 #ifdef TIMEOUT_READ
00067 
00068 /* Wait for data becoming available, allowing soft-broken network connection to die
00069    This is needed for Shoutcast servers that have forgotten about us while connection was temporarily down. */
00070 static long timeout_read(mpg123_handle *fr, void *buf, size_t count)
00071 {
00072     struct timeval tv;
00073     long ret = 0;
00074     fd_set fds;
00075     tv.tv_sec = fr->rdat.timeout_sec;
00076     tv.tv_usec = 0;
00077     FD_ZERO(&fds);
00078     FD_SET(fr->rdat.filept, &fds);
00079     ret = select(fr->rdat.filept+1, &fds, NULL, NULL, &tv);
00080     /* This works only with "my" read function. Not user-replaced. */
00081     if(ret > 0) ret = read(fr->rdat.filept, buf, count);
00082     else
00083     {
00084         ret=-1; /* no activity is the error */
00085         if(NOQUIET) error("stream timed out");
00086     }
00087     return ret;
00088 }
00089 #endif
00090 
00091 #ifndef NO_ICY
00092 /* stream based operation  with icy meta data*/
00093 static long icy_fullread(mpg123_handle *fr, unsigned char *buf, long count)
00094 {
00095     long ret,cnt;
00096     cnt = 0;
00097     if(fr->rdat.flags & READER_SEEKABLE)
00098     {
00099         if(NOQUIET) error("mpg123 programmer error: I don't do ICY on seekable streams.");
00100         return -1;
00101     }
00102     /*
00103         There used to be a check for expected file end here (length value or ID3 flag).
00104         This is not needed:
00105         1. EOF is indicated by fdread returning zero bytes anyway.
00106         2. We get false positives of EOF for either files that grew or
00107         3. ... files that have ID3v1 tags in between (stream with intro).
00108     */
00109 
00110     while(cnt < count)
00111     {
00112         /* all icy code is inside this if block, everything else is the plain fullread we know */
00113         /* debug1("read: %li left", (long) count-cnt); */
00114         if(fr->icy.next < count-cnt)
00115         {
00116             unsigned char temp_buff;
00117             size_t meta_size;
00118             long cut_pos;
00119 
00120             /* we are near icy-metaint boundary, read up to the boundary */
00121             if(fr->icy.next > 0)
00122             {
00123                 cut_pos = fr->icy.next;
00124                 ret = fr->rdat.fdread(fr,buf+cnt,cut_pos);
00125                 if(ret < 1)
00126                 {
00127                     if(ret == 0) break; /* Just EOF. */
00128                     if(NOQUIET) error("icy boundary read");
00129 
00130                     return READER_ERROR;
00131                 }
00132 
00133                 if(!(fr->rdat.flags & READER_BUFFERED)) fr->rdat.filepos += ret;
00134                 cnt += ret;
00135                 fr->icy.next -= ret;
00136                 if(fr->icy.next > 0)
00137                 {
00138                     debug1("another try... still %li left", (long)fr->icy.next);
00139                     continue;
00140                 }
00141             }
00142             /* now off to read icy data */
00143 
00144             /* one byte icy-meta size (must be multiplied by 16 to get icy-meta length) */
00145             
00146             ret = fr->rdat.fdread(fr,&temp_buff,1); /* Getting one single byte hast to suceed. */
00147             if(ret < 0){ if(NOQUIET) error("reading icy size"); return READER_ERROR; }
00148             if(ret == 0) break;
00149 
00150             debug2("got meta-size byte: %u, at filepos %li", temp_buff, (long)fr->rdat.filepos );
00151             if(!(fr->rdat.flags & READER_BUFFERED)) fr->rdat.filepos += ret; /* 1... */
00152 
00153             if((meta_size = ((size_t) temp_buff) * 16))
00154             {
00155                 /* we have got some metadata */
00156                 char *meta_buff;
00157                 meta_buff = malloc(meta_size+1);
00158                 if(meta_buff != NULL)
00159                 {
00160                     long left = meta_size;
00161                     while(left > 0)
00162                     {
00163                         ret = fr->rdat.fdread(fr,meta_buff+meta_size-left,left);
00164                         /* 0 is error here, too... there _must_ be the ICY data, the server promised! */
00165                         if(ret < 1){ if(NOQUIET) error("reading icy-meta"); return READER_ERROR; }
00166                         left -= ret;
00167                     }
00168                     meta_buff[meta_size] = 0; /* string paranoia */
00169                     if(!(fr->rdat.flags & READER_BUFFERED)) fr->rdat.filepos += ret;
00170 
00171                     if(fr->icy.data) free(fr->icy.data);
00172                     fr->icy.data = meta_buff;
00173                     fr->metaflags |= MPG123_NEW_ICY;
00174                     debug2("icy-meta: %s size: %d bytes", fr->icy.data, (int)meta_size);
00175                 }
00176                 else
00177                 {
00178                     if(NOQUIET) error1("cannot allocate memory for meta_buff (%lu bytes) ... trying to skip the metadata!", (unsigned long)meta_size);
00179                     fr->rd->skip_bytes(fr, meta_size);
00180                 }
00181             }
00182             fr->icy.next = fr->icy.interval;
00183         }
00184         else
00185         {
00186             ret = plain_fullread(fr, buf+cnt, count-cnt);
00187             if(ret < 0){ if(NOQUIET) error1("reading the rest of %li", (long)(count-cnt)); return READER_ERROR; }
00188             if(ret == 0) break;
00189 
00190             cnt += ret;
00191             fr->icy.next -= ret;
00192         }
00193     }
00194     /* debug1("done reading, got %li", (long)cnt); */
00195     return cnt;
00196 }
00197 #else
00198 #define icy_fullread NULL
00199 #endif /* NO_ICY */
00200 
00201 /* stream based operation */
00202 static long plain_fullread(mpg123_handle *fr,unsigned char *buf, long count)
00203 {
00204     long ret,cnt=0;
00205 
00206     /*
00207         There used to be a check for expected file end here (length value or ID3 flag).
00208         This is not needed:
00209         1. EOF is indicated by fdread returning zero bytes anyway.
00210         2. We get false positives of EOF for either files that grew or
00211         3. ... files that have ID3v1 tags in between (stream with intro).
00212     */
00213     while(cnt < count)
00214     {
00215         ret = fr->rdat.fdread(fr,buf+cnt,count-cnt);
00216         if(ret < 0) return READER_ERROR;
00217         if(ret == 0) break;
00218         if(!(fr->rdat.flags & READER_BUFFERED)) fr->rdat.filepos += ret;
00219         cnt += ret;
00220     }
00221     return cnt;
00222 }
00223 
00224 static off_t stream_lseek(mpg123_handle *fr, off_t pos, int whence)
00225 {
00226     off_t ret;
00227     ret = io_seek(&fr->rdat, pos, whence);
00228     if (ret >= 0)   fr->rdat.filepos = ret;
00229     else
00230     {
00231         fr->err = MPG123_LSEEK_FAILED;
00232         ret = READER_ERROR; /* not the original value */
00233     }
00234     return ret;
00235 }
00236 
00237 static void stream_close(mpg123_handle *fr)
00238 {
00239     if(fr->rdat.flags & READER_FD_OPENED) compat_close(fr->rdat.filept);
00240 
00241     fr->rdat.filept = 0;
00242 
00243     if(fr->rdat.flags & READER_BUFFERED)  bc_reset(&fr->rdat.buffer);
00244     if(fr->rdat.flags & READER_HANDLEIO)
00245     {
00246         if(fr->rdat.cleanup_handle != NULL) fr->rdat.cleanup_handle(fr->rdat.iohandle);
00247 
00248         fr->rdat.iohandle = NULL;
00249     }
00250 }
00251 
00252 static int stream_seek_frame(mpg123_handle *fr, off_t newframe)
00253 {
00254     debug2("seek_frame to %"OFF_P" (from %"OFF_P")", (off_p)newframe, (off_p)fr->num);
00255     /* Seekable streams can go backwards and jump forwards.
00256        Non-seekable streams still can go forward, just not jump. */
00257     if((fr->rdat.flags & READER_SEEKABLE) || (newframe >= fr->num))
00258     {
00259         off_t preframe; /* a leading frame we jump to */
00260         off_t seek_to;  /* the byte offset we want to reach */
00261         off_t to_skip;  /* bytes to skip to get there (can be negative) */
00262         /*
00263             now seek to nearest leading index position and read from there until newframe is reached.
00264             We use skip_bytes, which handles seekable and non-seekable streams
00265             (the latter only for positive offset, which we ensured before entering here).
00266         */
00267         seek_to = frame_index_find(fr, newframe, &preframe);
00268         /* No need to seek to index position if we are closer already.
00269            But I am picky about fr->num == newframe, play safe by reading the frame again.
00270            If you think that's stupid, don't call a seek to the current frame. */
00271         if(fr->num >= newframe || fr->num < preframe)
00272         {
00273             to_skip = seek_to - fr->rd->tell(fr);
00274             if(fr->rd->skip_bytes(fr, to_skip) != seek_to)
00275             return READER_ERROR;
00276 
00277             debug2("going to %lu; just got %lu", (long unsigned)newframe, (long unsigned)preframe);
00278             fr->num = preframe-1; /* Watch out! I am going to read preframe... fr->num should indicate the frame before! */
00279         }
00280         while(fr->num < newframe)
00281         {
00282             /* try to be non-fatal now... frameNum only gets advanced on success anyway */
00283             if(!read_frame(fr)) break;
00284         }
00285         /* Now the wanted frame should be ready for decoding. */
00286         debug1("arrived at %lu", (long unsigned)fr->num);
00287 
00288         return MPG123_OK;
00289     }
00290     else
00291     {
00292         fr->err = MPG123_NO_SEEK;
00293         return READER_ERROR; /* invalid, no seek happened */
00294     }
00295 }
00296 
00297 /* return FALSE on error, TRUE on success, READER_MORE on occasion */
00298 static int generic_head_read(mpg123_handle *fr,unsigned long *newhead)
00299 {
00300     unsigned char hbuf[4];
00301     int ret = fr->rd->fullread(fr,hbuf,4);
00302     if(ret == READER_MORE) return ret;
00303     if(ret != 4) return FALSE;
00304 
00305     *newhead = ((unsigned long) hbuf[0] << 24) |
00306                ((unsigned long) hbuf[1] << 16) |
00307                ((unsigned long) hbuf[2] << 8)  |
00308                 (unsigned long) hbuf[3];
00309 
00310     return TRUE;
00311 }
00312 
00313 /* return FALSE on error, TRUE on success, READER_MORE on occasion */
00314 static int generic_head_shift(mpg123_handle *fr,unsigned long *head)
00315 {
00316     unsigned char hbuf;
00317     int ret = fr->rd->fullread(fr,&hbuf,1);
00318     if(ret == READER_MORE) return ret;
00319     if(ret != 1) return FALSE;
00320 
00321     *head <<= 8;
00322     *head |= hbuf;
00323     *head &= 0xffffffff;
00324     return TRUE;
00325 }
00326 
00327 /* returns reached position... negative ones are bad... */
00328 static off_t stream_skip_bytes(mpg123_handle *fr,off_t len)
00329 {
00330     if(fr->rdat.flags & READER_SEEKABLE)
00331     {
00332         off_t ret = stream_lseek(fr, len, SEEK_CUR);
00333         return (ret < 0) ? READER_ERROR : ret;
00334     }
00335     else if(len >= 0)
00336     {
00337         unsigned char buf[1024]; /* ThOr: Compaq cxx complained and it makes sense to me... or should one do a cast? What for? */
00338         long ret;
00339         while (len > 0)
00340         {
00341             long num = len < (off_t)sizeof(buf) ? (long)len : (long)sizeof(buf);
00342             ret = fr->rd->fullread(fr, buf, num);
00343             if (ret < 0) return ret;
00344             else if(ret == 0) break; /* EOF... an error? interface defined to tell the actual position... */
00345             len -= ret;
00346         }
00347         return fr->rd->tell(fr);
00348     }
00349     else if(fr->rdat.flags & READER_BUFFERED)
00350     { /* Perhaps we _can_ go a bit back. */
00351         if(fr->rdat.buffer.pos >= -len)
00352         {
00353             fr->rdat.buffer.pos += len;
00354             return fr->rd->tell(fr);
00355         }
00356         else
00357         {
00358             fr->err = MPG123_NO_SEEK;
00359             return READER_ERROR;
00360         }
00361     }
00362     else
00363     {
00364         fr->err = MPG123_NO_SEEK;
00365         return READER_ERROR;
00366     }
00367 }
00368 
00369 /* Return 0 on success... */
00370 static int stream_back_bytes(mpg123_handle *fr, off_t bytes)
00371 {
00372     off_t want = fr->rd->tell(fr)-bytes;
00373     if(want < 0) return READER_ERROR;
00374     if(stream_skip_bytes(fr,-bytes) != want) return READER_ERROR;
00375 
00376     return 0;
00377 }
00378 
00379 
00380 /* returns size on success... */
00381 static int generic_read_frame_body(mpg123_handle *fr,unsigned char *buf, int size)
00382 {
00383     long l;
00384 
00385     if((l=fr->rd->fullread(fr,buf,size)) != size)
00386     {
00387         long ll = l;
00388         if(ll <= 0) ll = 0;
00389         return READER_MORE;
00390     }
00391     return l;
00392 }
00393 
00394 static off_t generic_tell(mpg123_handle *fr)
00395 {
00396     if(fr->rdat.flags & READER_BUFFERED)
00397     fr->rdat.filepos = fr->rdat.buffer.fileoff+fr->rdat.buffer.pos;
00398 
00399     return fr->rdat.filepos;
00400 }
00401 
00402 /* This does not (fully) work for non-seekable streams... You have to check for that flag, pal! */
00403 static void stream_rewind(mpg123_handle *fr)
00404 {
00405     if(fr->rdat.flags & READER_SEEKABLE)
00406     fr->rdat.buffer.fileoff = fr->rdat.filepos = stream_lseek(fr,0,SEEK_SET);
00407     if(fr->rdat.flags & READER_BUFFERED)
00408     {
00409         fr->rdat.buffer.pos      = 0;
00410         fr->rdat.buffer.firstpos = 0;
00411         fr->rdat.filepos = fr->rdat.buffer.fileoff;
00412     }
00413 }
00414 
00415 /*
00416  * returns length of a file (if filept points to a file)
00417  * reads the last 128 bytes information into buffer
00418  * ... that is not totally safe...
00419  */
00420 static off_t get_fileinfo(mpg123_handle *fr)
00421 {
00422     off_t len;
00423 
00424     if((len=io_seek(&fr->rdat,0,SEEK_END)) < 0) return -1;
00425 
00426     if(io_seek(&fr->rdat,-128,SEEK_END) < 0) return -1;
00427 
00428     if(fr->rd->fullread(fr,(unsigned char *)fr->id3buf,128) != 128) return -1;
00429 
00430     if(!strncmp((char*)fr->id3buf,"TAG",3)) len -= 128;
00431 
00432     if(io_seek(&fr->rdat,0,SEEK_SET) < 0)   return -1;
00433 
00434     if(len <= 0)    return -1;
00435 
00436     return len;
00437 }
00438 
00439 /* Let's work in nice 4K blocks, that may be nicely reusable (by malloc(), even). */
00440 #define BUFFBLOCK 4096
00441 
00442 #ifndef NO_FEEDER
00443 /* Methods for the buffer chain, mainly used for feed reader, but not just that. */
00444 
00445 static void bc_init(struct bufferchain *bc)
00446 {
00447     bc->first = NULL;
00448     bc->last  = bc->first;
00449     bc->size  = 0;
00450     bc->pos   = 0;
00451     bc->firstpos = 0;
00452     bc->fileoff  = 0;
00453 }
00454 
00455 static void bc_reset(struct bufferchain *bc)
00456 {
00457     /* free the buffer chain */
00458     struct buffy *b = bc->first;
00459     while(b != NULL)
00460     {
00461         struct buffy *n = b->next;
00462         free(b->data);
00463         free(b);
00464         b = n;
00465     }
00466     bc_init(bc);
00467 }
00468 
00469 /* Create a new buffy at the end to be filled. */
00470 static int bc_append(struct bufferchain *bc, long size)
00471 {
00472     struct buffy *newbuf;
00473     if(size < 1) return -1;
00474 
00475     newbuf = malloc(sizeof(struct buffy));
00476     if(newbuf == NULL) return -2;
00477 
00478     newbuf->realsize = size > BUFFBLOCK ? size : BUFFBLOCK;
00479     newbuf->data = malloc(newbuf->realsize);
00480     if(newbuf->data == NULL)
00481     {
00482         free(newbuf);
00483         return -3;
00484     }
00485     newbuf->size = size;
00486     newbuf->next = NULL;
00487     if(bc->last != NULL)  bc->last->next = newbuf;
00488     else if(bc->first == NULL) bc->first = newbuf;
00489 
00490     bc->last  = newbuf;
00491     bc->size += size;
00492     return 0;
00493 }
00494 
00495 #if 0
00496 /* Drop the last one (again).
00497    This is not optimal but should happen on error situations only, anyway. */
00498 static void bc_drop(struct bufferchain *bc)
00499 {
00500     struct buffy *cur = bc->first;
00501     if(bc->first == NULL || bc->last == NULL) return;
00502     /* Special case: only one buffer there. */
00503     if(cur->next == NULL)
00504     {
00505         free(cur->data);
00506         free(cur);
00507         bc->first = bc->last = NULL;
00508         bc->size  = 0;
00509         return;
00510     }
00511     /* Find the pre-last buffy. If chain is consistent, this _will_ succeed. */
00512     while(cur->next != bc->last){ cur = cur->next; }
00513 
00514     bc->size -= bc->last->size;
00515     free(bc->last->data);
00516     free(bc->last);
00517     cur->next = NULL;
00518     bc->last  = cur;
00519 }
00520 #endif
00521 
00522 /* Append a new buffer and copy content to it. */
00523 static int bc_add(struct bufferchain *bc, const unsigned char *data, long size)
00524 {
00525     int ret = 0;
00526     long part = 0;
00527     debug2("bc_add: adding %"SSIZE_P" bytes at %"OFF_P, (ssize_p)size, (off_p)(bc->fileoff+bc->size));
00528     if(size >=4) debug4("first bytes: %02x %02x %02x %02x", data[0], data[1], data[2], data[3]);
00529 
00530     /* Try to fill up the last buffer block. */
00531     if(bc->last != NULL && bc->last->size < bc->last->realsize)
00532     {
00533         part = bc->last->realsize - bc->last->size;
00534         if(part > size) part = size;
00535 
00536         memcpy(bc->last->data+bc->last->size, data, part);
00537         bc->last->size += part;
00538         size -= part;
00539         bc->size += part;
00540     }
00541 
00542 
00543     /* If there is still data left, put it into a new buffer block. */
00544     if(size > 0 && (ret = bc_append(bc, size)) == 0)
00545     memcpy(bc->last->data, data+part, size);
00546 
00547     return ret;
00548 }
00549 
00550 /* Common handler for "You want more than I can give." situation. */
00551 static long bc_need_more(struct bufferchain *bc)
00552 {
00553     debug3("hit end, back to beginning (%li - %li < %li)", (long)bc->size, (long)bc->pos, (long)bc->size);
00554     /* go back to firstpos, undo the previous reads */
00555     bc->pos = bc->firstpos;
00556     return READER_MORE;
00557 }
00558 
00559 /* Give some data, advancing position but not forgetting yet. */
00560 static long bc_give(struct bufferchain *bc, unsigned char *out, long size)
00561 {
00562     struct buffy *b = bc->first;
00563     long gotcount = 0;
00564     long offset = 0;
00565     if(bc->size - bc->pos < size) return bc_need_more(bc);
00566 
00567     /* find the current buffer */
00568     while(b != NULL && (offset + b->size) <= bc->pos)
00569     {
00570         offset += b->size;
00571         b = b->next;
00572     }
00573     /* now start copying from there */
00574     while(gotcount < size && (b != NULL))
00575     {
00576         long loff = bc->pos - offset;
00577         long chunk = size - gotcount; /* amount of bytes to get from here... */
00578         if(chunk > b->size - loff) chunk = b->size - loff;
00579 
00580 #ifdef EXTRA_DEBUG
00581         debug3("copying %liB from %p+%li",(long)chunk, b->data, (long)loff);
00582 #endif
00583 
00584         memcpy(out+gotcount, b->data+loff, chunk);
00585         gotcount += chunk;
00586         bc->pos  += chunk;
00587         offset += b->size;
00588         b = b->next;
00589     }
00590 #ifdef EXTRA_DEBUG
00591     debug2("got %li bytes, pos advanced to %li", (long)gotcount, (long)bc->pos);
00592 #endif
00593 
00594     return gotcount;
00595 }
00596 
00597 /* Skip some bytes and return the new position.
00598    The buffers are still there, just the read pointer is moved! */
00599 static long bc_skip(struct bufferchain *bc, long count)
00600 {
00601     if(count >= 0)
00602     {
00603         if(bc->size - bc->pos < count) return bc_need_more(bc);
00604         else return bc->pos += count;
00605     }
00606     else return READER_ERROR;
00607 }
00608 
00609 static long bc_seekback(struct bufferchain *bc, long count)
00610 {
00611     if(count >= 0 && count <= bc->pos) return bc->pos -= count;
00612     else return READER_ERROR;
00613 }
00614 
00615 /* Throw away buffies that we passed. */
00616 static void bc_forget(struct bufferchain *bc)
00617 {
00618     struct buffy *b = bc->first;
00619     /* free all buffers that are def'n'tly outdated */
00620     /* we have buffers until filepos... delete all buffers fully below it */
00621     if(b) debug2("bc_forget: block %lu pos %lu", (unsigned long)b->size, (unsigned long)bc->pos);
00622     else debug("forget with nothing there!");
00623 
00624     while(b != NULL && bc->pos >= b->size)
00625     {
00626         struct buffy *n = b->next; /* != NULL or this is indeed the end and the last cycle anyway */
00627         if(n == NULL) bc->last = NULL; /* Going to delete the last buffy... */
00628         bc->fileoff += b->size;
00629         bc->pos  -= b->size;
00630         bc->size -= b->size;
00631 
00632         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);
00633 
00634         free(b->data);
00635         free(b);
00636         b = n;
00637     }
00638     bc->first = b;
00639     bc->firstpos = bc->pos;
00640 }
00641 
00642 /* reader for input via manually provided buffers */
00643 
00644 static int feed_init(mpg123_handle *fr)
00645 {
00646     bc_init(&fr->rdat.buffer);
00647     fr->rdat.filelen = 0;
00648     fr->rdat.filepos = 0;
00649     fr->rdat.flags |= READER_BUFFERED;
00650     return 0;
00651 }
00652 
00653 /* externally called function, returns 0 on success, -1 on error */
00654 int feed_more(mpg123_handle *fr, const unsigned char *in, long count)
00655 {
00656     int ret = 0;
00657     if(VERBOSE3) debug("feed_more");
00658     if((ret = bc_add(&fr->rdat.buffer, in, count)) != 0)
00659     {
00660         ret = READER_ERROR;
00661         if(NOQUIET) error1("Failed to add buffer, return: %i", ret);
00662     }
00663     else /* Not talking about filelen... that stays at 0. */
00664 
00665     if(VERBOSE3) debug3("feed_more: %p %luB bufsize=%lu", fr->rdat.buffer.last->data,
00666         (unsigned long)fr->rdat.buffer.last->size, (unsigned long)fr->rdat.buffer.size);
00667     return ret;
00668 }
00669 
00670 static long feed_read(mpg123_handle *fr, unsigned char *out, long count)
00671 {
00672     long gotcount = bc_give(&fr->rdat.buffer, out, count);
00673     if(gotcount >= 0 && gotcount != count) return READER_ERROR;
00674     else return gotcount;
00675 }
00676 
00677 /* returns reached position... negative ones are bad... */
00678 static off_t feed_skip_bytes(mpg123_handle *fr,off_t len)
00679 {
00680     /* This is either the new buffer offset or some negative error value. */
00681     off_t res = bc_skip(&fr->rdat.buffer, (long)len);
00682     if(res < 0) return res;
00683 
00684     return fr->rdat.buffer.fileoff+res;
00685 }
00686 
00687 static int feed_back_bytes(mpg123_handle *fr, off_t bytes)
00688 {
00689     if(bytes >=0)
00690     return bc_seekback(&fr->rdat.buffer, (long)bytes) >= 0 ? 0 : READER_ERROR;
00691     else
00692     return feed_skip_bytes(fr, -bytes) >= 0 ? 0 : READER_ERROR;
00693 }
00694 
00695 static int feed_seek_frame(mpg123_handle *fr, off_t num){ return READER_ERROR; }
00696 
00697 /* Not just for feed reader, also for self-feeding buffered reader. */
00698 static void buffered_forget(mpg123_handle *fr)
00699 {
00700     bc_forget(&fr->rdat.buffer);
00701     fr->rdat.filepos = fr->rdat.buffer.fileoff + fr->rdat.buffer.pos;
00702 }
00703 
00704 off_t feed_set_pos(mpg123_handle *fr, off_t pos)
00705 {
00706     struct bufferchain *bc = &fr->rdat.buffer;
00707     if(pos >= bc->fileoff && pos-bc->fileoff < bc->size)
00708     { /* We have the position! */
00709         bc->pos = (long)(pos - bc->fileoff);
00710         debug1("feed_set_pos inside, next feed from %"OFF_P, (off_p)(bc->fileoff+bc->size));
00711         return bc->fileoff+bc->size; /* Next input after end of buffer... */
00712     }
00713     else
00714     { /* I expect to get the specific position on next feed. Forget what I have now. */
00715         bc_reset(bc);
00716         bc->fileoff = pos;
00717         debug1("feed_set_pos outside, buffer reset, next feed from %"OFF_P, (off_p)pos);
00718         return pos; /* Next input from exactly that position. */
00719     }
00720 }
00721 
00722 /* The specific stuff for buffered stream reader. */
00723 
00724 static long buffered_fullread(mpg123_handle *fr, unsigned char *out, long count)
00725 {
00726     struct bufferchain *bc = &fr->rdat.buffer;
00727     long gotcount;
00728     if(bc->size - bc->pos < count)
00729     { /* Add more stuff to buffer. If hitting end of file, adjust count. */
00730         unsigned char readbuf[BUFFBLOCK];
00731         long need = count - (bc->size-bc->pos);
00732         while(need>0)
00733         {
00734             int ret;
00735             long got = fr->rdat.fullread(fr, readbuf, BUFFBLOCK);
00736             if(got < 0)
00737             {
00738                 if(NOQUIET) error("buffer reading");
00739                 return READER_ERROR;
00740             }
00741 
00742             if(VERBOSE3) debug1("buffered_fullread: buffering %li bytes from stream (if > 0)", (long)got);
00743             if(got > 0 && (ret=bc_add(bc, readbuf, got)) != 0)
00744             {
00745                 if(NOQUIET) error1("unable to add to chain, return: %i", ret);
00746                 return READER_ERROR;
00747             }
00748 
00749             need -= got; /* May underflow here... */
00750             if(got < BUFFBLOCK) /* That naturally catches got == 0, too. */
00751             {
00752                 if(VERBOSE3) fprintf(stderr, "Note: Input data end.\n");
00753                 break; /* End. */
00754             }
00755         }
00756         if(bc->size - bc->pos < count)
00757         count = bc->size - bc->pos; /* We want only what we got. */
00758     }
00759     gotcount = bc_give(bc, out, count);
00760 
00761     if(VERBOSE3) debug2("wanted %li, got %li", (long)count, (long)gotcount);
00762 
00763     if(gotcount != count){ if(NOQUIET) error("gotcount != count"); return READER_ERROR; }
00764     else return gotcount;
00765 }
00766 #else
00767 int feed_more(mpg123_handle *fr, const unsigned char *in, long count)
00768 {
00769     fr->err = MPG123_MISSING_FEATURE;
00770     return -1;
00771 }
00772 off_t feed_set_pos(mpg123_handle *fr, off_t pos)
00773 {
00774     fr->err = MPG123_MISSING_FEATURE;
00775     return -1;
00776 }
00777 #endif /* NO_FEEDER */
00778 
00779 /*****************************************************************
00780  * read frame helper
00781  */
00782 
00783 #define bugger_off { mh->err = MPG123_NO_READER; return MPG123_ERR; }
00784 int bad_init(mpg123_handle *mh) bugger_off
00785 void bad_close(mpg123_handle *mh){}
00786 long bad_fullread(mpg123_handle *mh, unsigned char *data, long count) bugger_off
00787 int bad_head_read(mpg123_handle *mh, unsigned long *newhead) bugger_off
00788 int bad_head_shift(mpg123_handle *mh, unsigned long *head) bugger_off
00789 off_t bad_skip_bytes(mpg123_handle *mh, off_t len) bugger_off
00790 int bad_read_frame_body(mpg123_handle *mh, unsigned char *data, int size) bugger_off
00791 int bad_back_bytes(mpg123_handle *mh, off_t bytes) bugger_off
00792 int bad_seek_frame(mpg123_handle *mh, off_t num) bugger_off
00793 off_t bad_tell(mpg123_handle *mh) bugger_off
00794 void bad_rewind(mpg123_handle *mh){}
00795 #undef bugger_off
00796 
00797 #define READER_STREAM 0
00798 #define READER_ICY_STREAM 1
00799 #define READER_FEED       2
00800 #define READER_BUF_STREAM 3
00801 #define READER_BUF_ICY_STREAM 4
00802 struct reader readers[] =
00803 {
00804     { /* READER_STREAM */
00805         default_init,
00806         stream_close,
00807         plain_fullread,
00808         generic_head_read,
00809         generic_head_shift,
00810         stream_skip_bytes,
00811         generic_read_frame_body,
00812         stream_back_bytes,
00813         stream_seek_frame,
00814         generic_tell,
00815         stream_rewind,
00816         NULL
00817     } ,
00818     { /* READER_ICY_STREAM */
00819         default_init,
00820         stream_close,
00821         icy_fullread,
00822         generic_head_read,
00823         generic_head_shift,
00824         stream_skip_bytes,
00825         generic_read_frame_body,
00826         stream_back_bytes,
00827         stream_seek_frame,
00828         generic_tell,
00829         stream_rewind,
00830         NULL
00831     },
00832 #ifdef NO_FEEDER
00833 #define feed_init NULL
00834 #define feed_read NULL
00835 #define buffered_fullread NULL
00836 #define feed_seek_frame NULL
00837 #define feed_back_bytes NULL
00838 #define feed_skip_bytes NULL
00839 #define buffered_forget NULL
00840 #endif
00841     { /* READER_FEED */
00842         feed_init,
00843         stream_close,
00844         feed_read,
00845         generic_head_read,
00846         generic_head_shift,
00847         feed_skip_bytes,
00848         generic_read_frame_body,
00849         feed_back_bytes,
00850         feed_seek_frame,
00851         generic_tell,
00852         stream_rewind,
00853         buffered_forget
00854     },
00855     { /* READER_BUF_STREAM */
00856         default_init,
00857         stream_close,
00858         buffered_fullread,
00859         generic_head_read,
00860         generic_head_shift,
00861         stream_skip_bytes,
00862         generic_read_frame_body,
00863         stream_back_bytes,
00864         stream_seek_frame,
00865         generic_tell,
00866         stream_rewind,
00867         buffered_forget
00868     } ,
00869     { /* READER_BUF_ICY_STREAM */
00870         default_init,
00871         stream_close,
00872         buffered_fullread,
00873         generic_head_read,
00874         generic_head_shift,
00875         stream_skip_bytes,
00876         generic_read_frame_body,
00877         stream_back_bytes,
00878         stream_seek_frame,
00879         generic_tell,
00880         stream_rewind,
00881         buffered_forget
00882     },
00883 #ifdef READ_SYSTEM
00884     ,{
00885         system_init,
00886         NULL,   /* filled in by system_init() */
00887         fullread,
00888         NULL,
00889         NULL,
00890         NULL,
00891         NULL,
00892         NULL,
00893         NULL,
00894         NULL,
00895         NULL,
00896         NULL,
00897     }
00898 #endif
00899 };
00900 
00901 struct reader bad_reader =
00902 {
00903     bad_init,
00904     bad_close,
00905     bad_fullread,
00906     bad_head_read,
00907     bad_head_shift,
00908     bad_skip_bytes,
00909     bad_read_frame_body,
00910     bad_back_bytes,
00911     bad_seek_frame,
00912     bad_tell,
00913     bad_rewind,
00914     NULL
00915 };
00916 
00917 static int default_init(mpg123_handle *fr)
00918 {
00919 #ifdef TIMEOUT_READ
00920     if(fr->p.timeout > 0)
00921     {
00922         int flags;
00923         if(fr->rdat.r_read != NULL)
00924         {
00925             error("Timeout reading does not work with user-provided read function. Implement it yourself!");
00926             return -1;
00927         }
00928         flags = fcntl(fr->rdat.filept, F_GETFL);
00929         flags |= O_NONBLOCK;
00930         fcntl(fr->rdat.filept, F_SETFL, flags);
00931         fr->rdat.fdread = timeout_read;
00932         fr->rdat.timeout_sec = fr->p.timeout;
00933         fr->rdat.flags |= READER_NONBLOCK;
00934     }
00935     else
00936 #endif
00937     fr->rdat.fdread = plain_read;
00938 
00939     fr->rdat.read  = fr->rdat.r_read  != NULL ? fr->rdat.r_read  : posix_read;
00940     fr->rdat.lseek = fr->rdat.r_lseek != NULL ? fr->rdat.r_lseek : posix_lseek;
00941     fr->rdat.filelen = get_fileinfo(fr);
00942     fr->rdat.filepos = 0;
00943     if(fr->rdat.filelen >= 0)
00944     {
00945         fr->rdat.flags |= READER_SEEKABLE;
00946         if(!strncmp((char*)fr->id3buf,"TAG",3))
00947         {
00948             fr->rdat.flags |= READER_ID3TAG;
00949             fr->metaflags  |= MPG123_NEW_ID3;
00950         }
00951     }
00952     /* Switch reader to a buffered one, if allowed. */
00953     else if(fr->p.flags & MPG123_SEEKBUFFER)
00954     {
00955 #ifdef NO_FEEDER
00956         error("Buffered readers not supported in this build.");
00957         fr->err = MPG123_MISSING_FEATURE;
00958         return -1;
00959 #else
00960         if     (fr->rd == &readers[READER_STREAM])
00961         {
00962             fr->rd = &readers[READER_BUF_STREAM];
00963             fr->rdat.fullread = plain_fullread;
00964         }
00965 #ifndef NO_ICY
00966         else if(fr->rd == &readers[READER_ICY_STREAM])
00967         {
00968             fr->rd = &readers[READER_BUF_ICY_STREAM];
00969             fr->rdat.fullread = icy_fullread;
00970         }
00971 #endif
00972         else
00973         {
00974             if(NOQUIET) error("mpg123 Programmer's fault: invalid reader");
00975             return -1;
00976         }
00977         bc_init(&fr->rdat.buffer);
00978         fr->rdat.filelen = 0; /* We carry the offset, but never know how big the stream is. */
00979         fr->rdat.flags |= READER_BUFFERED;
00980 #endif /* NO_FEEDER */
00981     }
00982     return 0;
00983 }
00984 
00985 
00986 void open_bad(mpg123_handle *mh)
00987 {
00988 #ifndef NO_ICY
00989     clear_icy(&mh->icy);
00990 #endif
00991     mh->rd = &bad_reader;
00992     mh->rdat.flags = 0;
00993     bc_init(&mh->rdat.buffer);
00994 }
00995 
00996 int open_feed(mpg123_handle *fr)
00997 {
00998     debug("feed reader");
00999 #ifdef NO_FEEDER
01000     error("Buffered readers not supported in this build.");
01001     fr->err = MPG123_MISSING_FEATURE;
01002     return -1;
01003 #else
01004 #ifndef NO_ICY
01005     if(fr->p.icy_interval > 0)
01006     {
01007         if(NOQUIET) error("Feed reader cannot do ICY parsing!");
01008 
01009         return -1;
01010     }
01011     clear_icy(&fr->icy);
01012 #endif
01013     fr->rd = &readers[READER_FEED];
01014     fr->rdat.flags = 0;
01015     if(fr->rd->init(fr) < 0) return -1;
01016     return 0;
01017 #endif /* NO_FEEDER */
01018 }
01019 
01020 /* Final code common to open_stream and open_stream_handle. */
01021 static int open_finish(mpg123_handle *fr)
01022 {
01023 #ifndef NO_ICY
01024     if(fr->p.icy_interval > 0)
01025     {
01026         debug("ICY reader");
01027         fr->icy.interval = fr->p.icy_interval;
01028         fr->icy.next = fr->icy.interval;
01029         fr->rd = &readers[READER_ICY_STREAM];
01030     }
01031     else
01032 #endif
01033     {
01034         fr->rd = &readers[READER_STREAM];
01035         debug("stream reader");
01036     }
01037 
01038     if(fr->rd->init(fr) < 0) return -1;
01039 
01040     return MPG123_OK;
01041 }
01042 
01043 int open_stream(mpg123_handle *fr, const char *bs_filenam, int fd)
01044 {
01045     int filept_opened = 1;
01046     int filept; /* descriptor of opened file/stream */
01047 
01048     clear_icy(&fr->icy); /* can be done inside frame_clear ...? */
01049 
01050     if(!bs_filenam) /* no file to open, got a descriptor (stdin) */
01051     {
01052         filept = fd;
01053         filept_opened = 0; /* and don't try to close it... */
01054     }
01055     #ifndef O_BINARY
01056     #define O_BINARY (0)
01057     #endif
01058     else if((filept = compat_open(bs_filenam, O_RDONLY|O_BINARY)) < 0) /* a plain old file to open... */
01059     {
01060         if(NOQUIET) error2("Cannot open file %s: %s", bs_filenam, strerror(errno));
01061         fr->err = MPG123_BAD_FILE;
01062         return MPG123_ERR; /* error... */
01063     }
01064 
01065     /* now we have something behind filept and can init the reader */
01066     fr->rdat.filelen = -1;
01067     fr->rdat.filept  = filept;
01068     fr->rdat.flags = 0;
01069     if(filept_opened)   fr->rdat.flags |= READER_FD_OPENED;
01070 
01071     return open_finish(fr);
01072 }
01073 
01074 int open_stream_handle(mpg123_handle *fr, void *iohandle)
01075 {
01076     clear_icy(&fr->icy); /* can be done inside frame_clear ...? */
01077     fr->rdat.filelen = -1;
01078     fr->rdat.filept  = -1;
01079     fr->rdat.iohandle = iohandle;
01080     fr->rdat.flags = 0;
01081     fr->rdat.flags |= READER_HANDLEIO;
01082 
01083     return open_finish(fr);
01084 }
01085 
01086 /* Wrappers for actual reading/seeking... I'm full of wrappers here. */
01087 static off_t io_seek(struct reader_data *rdat, off_t offset, int whence)
01088 {
01089     if(rdat->flags & READER_HANDLEIO)
01090     {
01091         if(rdat->r_lseek_handle != NULL)
01092         {
01093             return rdat->r_lseek_handle(rdat->iohandle, offset, whence);
01094         }
01095         else return -1;
01096     }
01097     else
01098     return rdat->lseek(rdat->filept, offset, whence);
01099 }
01100 
01101 static long io_read(struct reader_data *rdat, void *buf, size_t count)
01102 {
01103     if(rdat->flags & READER_HANDLEIO)
01104     {
01105         if(rdat->r_read_handle != NULL)
01106         {
01107             return rdat->r_read_handle(rdat->iohandle, buf, count);
01108         }
01109         else return -1;
01110     }
01111     else
01112     return rdat->read(rdat->filept, buf, count);
01113 }

Generated on Fri May 25 2012 04:32:37 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.