1 /* 2 lfs_wrap: Crappy wrapper code for supporting crappy ambiguous large file support. 3 4 copyright 2010 by the mpg123 project - free software under the terms of the LGPL 2.1 5 see COPYING and AUTHORS files in distribution or http://mpg123.org 6 7 initially written by Thomas Orgis, thanks to Guido Draheim for consulting 8 9 This file contains wrappers for the case that _FILE_OFFSET_BITS (or equivalent, theoretically, depends on mpg123.h) is defined and thus certain mpg123 API calls get renamed with a suffix (p.ex. _64). 10 The renamed calls expect large off_t arguments, and possibly return large off_t values... these wrappers here provide the same functionality with long integer arguments/values. 11 12 Prototypical idea: There is 13 off_t mpg123_seek_64(mpg123_handle*, off_t, int) 14 This code provides 15 long mpg123_seek(mpg123_handle*, long, int) 16 17 This is rather simple business... wouldn't mpg123 offer replacing the I/O core with callbacks. Translating the callbacks between long and off_t world is the main reason why this file contains non-trivial code. 18 19 Note about file descriptors: We just assume that they are generally interchangeable between large and small file code... and that a large file descriptor will trigger errors when accessed with small file code where it may cause trouble (a really large file). 20 */ 21 22 /* It mainly needs the official API ... */ 23 /* ... but also some inside access (frame struct, readers). */ 24 #include "mpg123lib_intern.h" 25 /* Include the system headers _after_ the implied config.h! 26 Otherwise _FILE_OFFSET_BITS is not in effect! */ 27 #include <errno.h> 28 #include <sys/stat.h> 29 #include <fcntl.h> 30 #include "compat.h" 31 #include "debug.h" 32 33 /* 34 Now, start off easy... translate simple API calls. 35 I need to deal with these here: 36 perl -ne ' 37 if(/^\s*MPG123_EXPORT\s+(\S+)\s+(mpg123_\S+)\((.*)\);\s*$/) 38 { 39 $type = $1; 40 $name = $2; 41 $args = $3; 42 next unless ($type =~ /off_t/ or $args =~ /off_t/); 43 print "$name\n" unless grep {$_ eq $name} 44 ("mpg123_open", "mpg123_open_fd", "mpg123_open_handle", "mpg123_replace_reader", "mpg123_replace_reader_handle"); 45 }' < mpg123.h.in 46 47 mpg123_decode_frame 48 mpg123_framebyframe_decode 49 mpg123_framepos 50 mpg123_tell 51 mpg123_tellframe 52 mpg123_tell_stream 53 mpg123_seek 54 mpg123_feedseek 55 mpg123_seek_frame 56 mpg123_timeframe 57 mpg123_index 58 mpg123_set_index 59 mpg123_position 60 mpg123_length 61 mpg123_set_filesize 62 mpg123_decode_raw ... that's experimental. 63 64 Let's work on them in that order. 65 */ 66 67 /* I see that I will need custom data storage. Main use is for the replaced I/O later, but the seek table for small file offsets needs extra storage, too. */ 68 69 /* The wrapper handle for descriptor and handle I/O. */ 70 71 /* The handle is used for nothing (0), or one of these two modes of operation: */ 72 #define IO_FD 1 /* Wrapping over callbacks operation on integer file descriptor. */ 73 #define IO_HANDLE 2 /* Wrapping over custom handle callbacks. */ 74 75 struct wrap_data 76 { 77 /* Storage for small offset index table. */ 78 long *indextable; 79 /* I/O handle stuff */ 80 int iotype; /* IO_FD or IO_HANDLE */ 81 /* Data for IO_FD. */ 82 int fd; 83 int my_fd; /* A descriptor that the wrapper code opened itself. */ 84 /* The actual callbacks from the outside. */ 85 ssize_t (*r_read) (int, void *, size_t); 86 long (*r_lseek)(int, long, int); 87 /* Data for IO_HANDLE. */ 88 void* handle; 89 ssize_t (*r_h_read)(void *, void *, size_t); 90 long (*r_h_lseek)(void*, long, int); 91 void (*h_cleanup)(void*); 92 }; 93 94 95 /* Cleanup I/O part of the handle handle... but not deleting the wrapper handle itself. 96 That is stored in the frame and only deleted on mpg123_delete(). */ 97 static void wrap_io_cleanup(void *handle) 98 { 99 struct wrap_data *ioh = handle; 100 if(ioh->iotype == IO_HANDLE) 101 { 102 if(ioh->h_cleanup != NULL && ioh->handle != NULL) 103 ioh->h_cleanup(ioh->handle); 104 105 ioh->handle = NULL; 106 } 107 if(ioh->my_fd >= 0) 108 { 109 close(ioh->my_fd); 110 ioh->my_fd = -1; 111 } 112 } 113 114 /* Really finish off the handle... freeing all memory. */ 115 static void wrap_destroy(void *handle) 116 { 117 struct wrap_data *wh = handle; 118 wrap_io_cleanup(handle); 119 if(wh->indextable != NULL) 120 free(wh->indextable); 121 122 free(wh); 123 } 124 125 /* More helper code... extract the special wrapper handle, possible allocate and initialize it. */ 126 static struct wrap_data* wrap_get(mpg123_handle *mh) 127 { 128 struct wrap_data* whd; 129 if(mh == NULL) return NULL; 130 131 /* Access the private storage inside the mpg123 handle. 132 The real callback functions and handles are stored there. */ 133 if(mh->wrapperdata == NULL) 134 { 135 /* Create a new one. */ 136 mh->wrapperdata = malloc(sizeof(struct wrap_data)); 137 if(mh->wrapperdata == NULL) 138 { 139 mh->err = MPG123_OUT_OF_MEM; 140 return NULL; 141 } 142 /* When we have wrapper data present, the callback for its proper cleanup is needed. */ 143 mh->wrapperclean = wrap_destroy; 144 145 whd = mh->wrapperdata; 146 whd->indextable = NULL; 147 whd->iotype = 0; 148 whd->fd = -1; 149 whd->my_fd = -1; 150 whd->r_read = NULL; 151 whd->r_lseek = NULL; 152 whd->handle = NULL; 153 whd->r_h_read = NULL; 154 whd->r_h_lseek = NULL; 155 whd->h_cleanup = NULL; 156 } 157 else whd = mh->wrapperdata; 158 159 return whd; 160 } 161 162 /* After settling the data... start with some simple wrappers. */ 163 164 #undef mpg123_decode_frame 165 /* int mpg123_decode_frame(mpg123_handle *mh, off_t *num, unsigned char **audio, size_t *bytes) */ 166 int attribute_align_arg mpg123_decode_frame(mpg123_handle *mh, long *num, unsigned char **audio, size_t *bytes) 167 { 168 off_t largenum; 169 int err; 170 171 err = MPG123_LARGENAME(mpg123_decode_frame)(mh, &largenum, audio, bytes); 172 if(err == MPG123_OK && num != NULL) 173 { 174 *num = largenum; 175 if(*num != largenum) 176 { 177 mh->err = MPG123_LFS_OVERFLOW; 178 err = MPG123_ERR; 179 } 180 } 181 return err; 182 } 183 184 #undef mpg123_framebyframe_decode 185 /* int mpg123_framebyframe_decode(mpg123_handle *mh, off_t *num, unsigned char **audio, size_t *bytes); */ 186 int attribute_align_arg mpg123_framebyframe_decode(mpg123_handle *mh, long *num, unsigned char **audio, size_t *bytes) 187 { 188 off_t largenum; 189 int err; 190 191 err = MPG123_LARGENAME(mpg123_framebyframe_decode)(mh, &largenum, audio, bytes); 192 if(err == MPG123_OK && num != NULL) 193 { 194 *num = largenum; 195 if(*num != largenum) 196 { 197 mh->err = MPG123_LFS_OVERFLOW; 198 err = MPG123_ERR; 199 } 200 } 201 return err; 202 } 203 204 #undef mpg123_framepos 205 /* off_t mpg123_framepos(mpg123_handle *mh); */ 206 long attribute_align_arg mpg123_framepos(mpg123_handle *mh) 207 { 208 long val; 209 off_t largeval; 210 211 largeval = MPG123_LARGENAME(mpg123_framepos)(mh); 212 val = largeval; 213 if(val != largeval) 214 { 215 mh->err = MPG123_LFS_OVERFLOW; 216 return MPG123_ERR; 217 } 218 return val; 219 } 220 221 #undef mpg123_tell 222 /* off_t mpg123_tell(mpg123_handle *mh); */ 223 long attribute_align_arg mpg123_tell(mpg123_handle *mh) 224 { 225 long val; 226 off_t largeval; 227 228 largeval = MPG123_LARGENAME(mpg123_tell)(mh); 229 val = largeval; 230 if(val != largeval) 231 { 232 mh->err = MPG123_LFS_OVERFLOW; 233 return MPG123_ERR; 234 } 235 return val; 236 } 237 238 #undef mpg123_tellframe 239 /* off_t mpg123_tellframe(mpg123_handle *mh); */ 240 long attribute_align_arg mpg123_tellframe(mpg123_handle *mh) 241 { 242 long val; 243 off_t largeval; 244 245 largeval = MPG123_LARGENAME(mpg123_tellframe)(mh); 246 val = largeval; 247 if(val != largeval) 248 { 249 mh->err = MPG123_LFS_OVERFLOW; 250 return MPG123_ERR; 251 } 252 return val; 253 } 254 255 #undef mpg123_tell_stream 256 /* off_t mpg123_tell_stream(mpg123_handle *mh); */ 257 long attribute_align_arg mpg123_tell_stream(mpg123_handle *mh) 258 { 259 long val; 260 off_t largeval; 261 262 largeval = MPG123_LARGENAME(mpg123_tell_stream)(mh); 263 val = largeval; 264 if(val != largeval) 265 { 266 mh->err = MPG123_LFS_OVERFLOW; 267 return MPG123_ERR; 268 } 269 return val; 270 } 271 272 #undef mpg123_seek 273 /* off_t mpg123_seek(mpg123_handle *mh, off_t sampleoff, int whence); */ 274 long attribute_align_arg mpg123_seek(mpg123_handle *mh, long sampleoff, int whence) 275 { 276 long val; 277 off_t largeval; 278 279 largeval = MPG123_LARGENAME(mpg123_seek)(mh, sampleoff, whence); 280 val = largeval; 281 if(val != largeval) 282 { 283 mh->err = MPG123_LFS_OVERFLOW; 284 return MPG123_ERR; 285 } 286 return val; 287 } 288 289 #undef mpg123_feedseek 290 /* off_t mpg123_feedseek(mpg123_handle *mh, off_t sampleoff, int whence, off_t *input_offset); */ 291 long attribute_align_arg mpg123_feedseek(mpg123_handle *mh, long sampleoff, int whence, long *input_offset) 292 { 293 long val; 294 off_t largeioff; 295 off_t largeval; 296 297 largeval = MPG123_LARGENAME(mpg123_feedseek)(mh, sampleoff, whence, &largeioff); 298 /* Error/message codes are small... */ 299 if(largeval < 0) return (long)largeval; 300 301 val = largeval; 302 *input_offset = largeioff; 303 if(val != largeval || *input_offset != largeioff) 304 { 305 mh->err = MPG123_LFS_OVERFLOW; 306 return MPG123_ERR; 307 } 308 return val; 309 } 310 311 #undef mpg123_seek_frame 312 /* off_t mpg123_seek_frame(mpg123_handle *mh, off_t frameoff, int whence); */ 313 long attribute_align_arg mpg123_seek_frame(mpg123_handle *mh, long frameoff, int whence) 314 { 315 long val; 316 off_t largeval; 317 318 largeval = MPG123_LARGENAME(mpg123_seek_frame)(mh, frameoff, whence); 319 val = largeval; 320 if(val != largeval) 321 { 322 mh->err = MPG123_LFS_OVERFLOW; 323 return MPG123_ERR; 324 } 325 return val; 326 } 327 328 #undef mpg123_timeframe 329 /* off_t mpg123_timeframe(mpg123_handle *mh, double sec); */ 330 long attribute_align_arg mpg123_timeframe(mpg123_handle *mh, double sec) 331 { 332 long val; 333 off_t largeval; 334 335 largeval = MPG123_LARGENAME(mpg123_timeframe)(mh, sec); 336 val = largeval; 337 if(val != largeval) 338 { 339 mh->err = MPG123_LFS_OVERFLOW; 340 return MPG123_ERR; 341 } 342 return val; 343 } 344 345 /* Now something less simple: Index retrieval and manipulation. 346 The index is an _array_ of off_t, which means that I need to construct a copy with translated long values. */ 347 #undef mpg123_index 348 /* int mpg123_index(mpg123_handle *mh, off_t **offsets, off_t *step, size_t *fill) */ 349 int attribute_align_arg mpg123_index(mpg123_handle *mh, long **offsets, long *step, size_t *fill) 350 { 351 int err; 352 size_t i; 353 long smallstep; 354 size_t thefill; 355 off_t largestep; 356 off_t *largeoffsets; 357 struct wrap_data *whd; 358 359 whd = wrap_get(mh); 360 if(whd == NULL) return MPG123_ERR; 361 362 err = MPG123_LARGENAME(mpg123_index)(mh, &largeoffsets, &largestep, &thefill); 363 if(err != MPG123_OK) return err; 364 365 /* For a _very_ large file, even the step could overflow. */ 366 smallstep = largestep; 367 if(smallstep != largestep) 368 { 369 mh->err = MPG123_LFS_OVERFLOW; 370 return MPG123_ERR; 371 } 372 if(step != NULL) *step = smallstep; 373 374 /* When there are no values stored, there is no table content to take care of. 375 Table pointer does not matter. Mission completed. */ 376 if(thefill == 0) return MPG123_OK; 377 378 if(fill != NULL) *fill = thefill; 379 380 /* Construct a copy of the index to hand over to the small-minded client. */ 381 *offsets = safe_realloc(whd->indextable, (*fill)*sizeof(long)); 382 if(*offsets == NULL) 383 { 384 mh->err = MPG123_OUT_OF_MEM; 385 return MPG123_ERR; 386 } 387 whd->indextable = *offsets; 388 /* Elaborate conversion of each index value, with overflow check. */ 389 for(i=0; i<*fill; ++i) 390 { 391 whd->indextable[i] = largeoffsets[i]; 392 if(whd->indextable[i] != largeoffsets[i]) 393 { 394 mh->err = MPG123_LFS_OVERFLOW; 395 return MPG123_ERR; 396 } 397 } 398 /* If we came that far... there should be a valid copy of the table now. */ 399 return MPG123_OK; 400 } 401 402 /* The writing does basically the same than the above, just the opposite. 403 Oh, and the overflow checks are not needed -- off_t is bigger than long. */ 404 #undef mpg123_set_index 405 /* int mpg123_set_index(mpg123_handle *mh, off_t *offsets, off_t step, size_t fill); */ 406 int attribute_align_arg mpg123_set_index(mpg123_handle *mh, long *offsets, long step, size_t fill) 407 { 408 int err; 409 size_t i; 410 struct wrap_data *whd; 411 off_t *indextmp; 412 413 whd = wrap_get(mh); 414 if(whd == NULL) return MPG123_ERR; 415 416 /* Expensive temporary storage... for staying outside at the API layer. */ 417 indextmp = malloc(fill*sizeof(off_t)); 418 if(indextmp == NULL) 419 { 420 mh->err = MPG123_OUT_OF_MEM; 421 return MPG123_ERR; 422 } 423 424 if(fill > 0 && offsets == NULL) 425 { 426 mh->err = MPG123_BAD_INDEX_PAR; 427 err = MPG123_ERR; 428 } 429 else 430 { 431 /* Fill the large-file copy of the provided index, then feed it to mpg123. */ 432 for(i=0; i<fill; ++i) 433 indextmp[i] = offsets[i]; 434 435 err = MPG123_LARGENAME(mpg123_set_index)(mh, indextmp, step, fill); 436 } 437 free(indextmp); 438 439 return err; 440 } 441 442 /* So... breathe... a couple of simple wrappers before the big mess. */ 443 #undef mpg123_position 444 /* int mpg123_position( mpg123_handle *mh, off_t frame_offset, off_t buffered_bytes, off_t *current_frame, off_t *frames_left, double *current_seconds, double *seconds_left); */ 445 int attribute_align_arg mpg123_position(mpg123_handle *mh, long frame_offset, long buffered_bytes, long *current_frame, long *frames_left, double *current_seconds, double *seconds_left) 446 { 447 off_t curframe, frameleft; 448 long small_curframe, small_frameleft; 449 int err; 450 451 err = MPG123_LARGENAME(mpg123_position)(mh, frame_offset, buffered_bytes, &curframe, &frameleft, current_seconds, seconds_left); 452 if(err != MPG123_OK) return err; 453 454 small_curframe = curframe; 455 small_frameleft = frameleft; 456 if(small_curframe != curframe || small_frameleft != frameleft) 457 { 458 mh->err = MPG123_LFS_OVERFLOW; 459 return MPG123_ERR; 460 } 461 462 if(current_frame != NULL) *current_frame = small_curframe; 463 464 if(frames_left != NULL) *frames_left = small_frameleft; 465 466 467 return MPG123_OK; 468 } 469 470 #undef mpg123_framelength 471 /* off_t mpg123_framelength(mpg123_handle *mh); */ 472 long attribute_align_arg mpg123_framelength(mpg123_handle *mh) 473 { 474 long val; 475 off_t largeval; 476 477 largeval = MPG123_LARGENAME(mpg123_framelength)(mh); 478 val = largeval; 479 if(val != largeval) 480 { 481 mh->err = MPG123_LFS_OVERFLOW; 482 return MPG123_ERR; 483 } 484 return val; 485 } 486 487 #undef mpg123_length 488 /* off_t mpg123_length(mpg123_handle *mh); */ 489 long attribute_align_arg mpg123_length(mpg123_handle *mh) 490 { 491 long val; 492 off_t largeval; 493 494 largeval = MPG123_LARGENAME(mpg123_length)(mh); 495 val = largeval; 496 if(val != largeval) 497 { 498 mh->err = MPG123_LFS_OVERFLOW; 499 return MPG123_ERR; 500 } 501 return val; 502 } 503 504 /* The simplest wrapper of all... */ 505 #undef mpg123_set_filesize 506 /* int mpg123_set_filesize(mpg123_handle *mh, off_t size); */ 507 int attribute_align_arg mpg123_set_filesize(mpg123_handle *mh, long size) 508 { 509 return MPG123_LARGENAME(mpg123_set_filesize)(mh, size); 510 } 511 512 513 /* ========================================= 514 THE BOUNDARY OF SANITY 515 Behold, stranger! 516 ========================================= */ 517 518 519 /* 520 The messy part: Replacement of I/O core (actally, this is only due to lseek()). 521 Both descriptor and handle replaced I/O are mapped to replaced handle I/O, the handle wrapping over the actual callbacks and the actual handle/descriptor. 522 You got multiple levels of handles and callbacks to think about. Have fun reading and comprehending. 523 */ 524 525 /* Could go into compat.h ... Windows needs that flag. */ 526 #ifndef O_BINARY 527 #define O_BINARY 0 528 #endif 529 530 /* Read callback needs nothing special. */ 531 ssize_t wrap_read(void* handle, void *buf, size_t count) 532 { 533 struct wrap_data *ioh = handle; 534 switch(ioh->iotype) 535 { 536 case IO_FD: return ioh->r_read(ioh->fd, buf, count); 537 case IO_HANDLE: return ioh->r_h_read(ioh->handle, buf, count); 538 } 539 error("Serious breakage - bad IO type in LFS wrapper!"); 540 return -1; 541 } 542 543 /* Seek callback needs protection from too big offsets. */ 544 off_t wrap_lseek(void *handle, off_t offset, int whence) 545 { 546 struct wrap_data *ioh = handle; 547 long smalloff = offset; 548 if(smalloff == offset) 549 { 550 switch(ioh->iotype) 551 { 552 case IO_FD: return ioh->r_lseek(ioh->fd, smalloff, whence); 553 case IO_HANDLE: return ioh->r_h_lseek(ioh->handle, smalloff, whence); 554 } 555 error("Serious breakage - bad IO type in LFS wrapper!"); 556 return -1; 557 } 558 else 559 { 560 errno = EOVERFLOW; 561 return -1; 562 } 563 } 564 565 566 /* 567 Now, let's replace the API dealing with replacement I/O. 568 Start with undefining the renames... 569 */ 570 571 #undef mpg123_replace_reader 572 #undef mpg123_replace_reader_handle 573 #undef mpg123_open 574 #undef mpg123_open_fd 575 #undef mpg123_open_handle 576 577 578 /* Normal reader replacement needs fallback implementations. */ 579 static ssize_t fallback_read(int fd, void *buf, size_t count) 580 { 581 return read(fd, buf, count); 582 } 583 584 static long fallback_lseek(int fd, long offset, int whence) 585 { 586 /* Since the offset is long int already, the returned value really should fit into a long... but whatever. */ 587 long newpos_long; 588 off_t newpos; 589 newpos = lseek(fd, offset, whence); 590 newpos_long = newpos; 591 if(newpos_long == newpos) 592 return newpos_long; 593 else 594 { 595 errno = EOVERFLOW; 596 return -1; 597 } 598 } 599 600 /* Reader replacement prepares the hidden handle storage for next mpg123_open_fd() or plain mpg123_open(). */ 601 int attribute_align_arg mpg123_replace_reader(mpg123_handle *mh, ssize_t (*r_read) (int, void *, size_t), long (*r_lseek)(int, long, int) ) 602 { 603 struct wrap_data* ioh; 604 605 if(mh == NULL) return MPG123_ERR; 606 607 mpg123_close(mh); 608 ioh = wrap_get(mh); 609 if(ioh == NULL) return MPG123_ERR; 610 611 /* If both callbacks are NULL, switch totally to internal I/O, else just use fallback for at most half of them. */ 612 if(r_read == NULL && r_lseek == NULL) 613 { 614 /* Only the type is actually important to disable the code. */ 615 ioh->iotype = 0; 616 ioh->fd = -1; 617 ioh->r_read = NULL; 618 ioh->r_lseek = NULL; 619 } 620 else 621 { 622 ioh->iotype = IO_FD; 623 ioh->fd = -1; /* On next mpg123_open_fd(), this gets a value. */ 624 ioh->r_read = r_read != NULL ? r_read : fallback_read; 625 ioh->r_lseek = r_lseek != NULL ? r_lseek : fallback_lseek; 626 } 627 628 /* The real reader replacement will happen while opening. */ 629 return MPG123_OK; 630 } 631 632 int attribute_align_arg mpg123_replace_reader_handle(mpg123_handle *mh, ssize_t (*r_read) (void*, void *, size_t), long (*r_lseek)(void*, long, int), void (*cleanup)(void*)) 633 { 634 struct wrap_data* ioh; 635 636 if(mh == NULL) return MPG123_ERR; 637 638 mpg123_close(mh); 639 ioh = wrap_get(mh); 640 if(ioh == NULL) return MPG123_ERR; 641 642 ioh->iotype = IO_HANDLE; 643 ioh->handle = NULL; 644 ioh->r_h_read = r_read; 645 ioh->r_h_lseek = r_lseek; 646 ioh->h_cleanup = cleanup; 647 648 /* The real reader replacement will happen while opening. */ 649 return MPG123_OK; 650 } 651 652 /* 653 The open routines always need to watch out for a prepared wrapper handle to use replaced normal I/O. 654 Two cases to consider: 655 1. Plain normal open using internal I/O. 656 2. Client called mpg123_replace_reader() before. 657 The second case needs hackery to activate the client I/O callbacks. For that, we create a custom I/O handle and use the guts of mpg123_open_fd() on it. 658 */ 659 int attribute_align_arg mpg123_open(mpg123_handle *mh, const char *path) 660 { 661 struct wrap_data* ioh; 662 663 if(mh == NULL) return MPG123_ERR; 664 665 ioh = mh->wrapperdata; 666 /* Mimic the use of mpg123_replace_reader() functions by lower levels... 667 IO_HANDLE is not valid here, though. Only IO_FD. */ 668 if(ioh != NULL && ioh->iotype == IO_FD) 669 { 670 int err; 671 err = MPG123_LARGENAME(mpg123_replace_reader_handle)(mh, wrap_read, wrap_lseek, wrap_io_cleanup); 672 if(err != MPG123_OK) return MPG123_ERR; 673 674 /* The above call implied mpg123_close() already */ 675 /* 676 I really need to open the file here... to be able to use the replacer handle I/O ... 677 my_fd is used to indicate closing of the descriptor on cleanup. 678 */ 679 ioh->my_fd = compat_open(path, O_RDONLY|O_BINARY); 680 if(ioh->my_fd < 0) 681 { 682 if(!(mh->p.flags & MPG123_QUIET)) error2("Cannot open file %s: %s", path, strerror(errno)); 683 684 mh->err = MPG123_BAD_FILE; 685 return MPG123_ERR; 686 } 687 /* Store a copy of the descriptor where it is actually used. */ 688 ioh->fd = ioh->my_fd; 689 /* Initiate I/O operating on my handle now. */ 690 err = open_stream_handle(mh, ioh); 691 if(err != MPG123_OK) 692 { 693 wrap_io_cleanup(ioh); 694 return MPG123_ERR; 695 } 696 /* All fine... */ 697 return MPG123_OK; 698 } 699 else return MPG123_LARGENAME(mpg123_open)(mh, path); 700 } 701 702 /* 703 This is in fact very similar to the above: 704 The open routines always need to watch out for a prepared wrapper handle to use replaced normal I/O. 705 Two cases to consider: 706 1. Plain normal open_fd using internal I/O. 707 2. Client called mpg123_replace_reader() before. 708 The second case needs hackery to activate the client I/O callbacks. For that, we create a custom I/O handle and use the guts of mpg123_open_fd() on it. 709 */ 710 711 int attribute_align_arg mpg123_open_fd(mpg123_handle *mh, int fd) 712 { 713 struct wrap_data* ioh; 714 715 if(mh == NULL) return MPG123_ERR; 716 717 mpg123_close(mh); 718 ioh = mh->wrapperdata; 719 if(ioh != NULL && ioh->iotype == IO_FD) 720 { 721 int err; 722 err = MPG123_LARGENAME(mpg123_replace_reader_handle)(mh, wrap_read, wrap_lseek, wrap_io_cleanup); 723 if(err != MPG123_OK) return MPG123_ERR; 724 725 /* The above call implied mpg123_close() already */ 726 727 /* Store the real file descriptor inside the handle. */ 728 ioh->fd = fd; 729 /* Initiate I/O operating on my handle now. */ 730 err = open_stream_handle(mh, ioh); 731 if(err != MPG123_OK) 732 { 733 wrap_io_cleanup(ioh); 734 return MPG123_ERR; 735 } 736 /* All fine... */ 737 return MPG123_OK; 738 } 739 else return MPG123_LARGENAME(mpg123_open_fd)(mh, fd); 740 } 741 742 int attribute_align_arg mpg123_open_handle(mpg123_handle *mh, void *handle) 743 { 744 struct wrap_data* ioh; 745 746 if(mh == NULL) return MPG123_ERR; 747 748 mpg123_close(mh); 749 ioh = mh->wrapperdata; 750 if(ioh != NULL && ioh->iotype == IO_HANDLE && ioh->r_h_read != NULL) 751 { 752 /* Wrap the custom handle into my handle. */ 753 int err; 754 err = MPG123_LARGENAME(mpg123_replace_reader_handle)(mh, wrap_read, wrap_lseek, wrap_io_cleanup); 755 if(err != MPG123_OK) return MPG123_ERR; 756 757 ioh->handle = handle; 758 /* No extra error handling, keep behaviour of the original open_handle. */ 759 return open_stream_handle(mh, ioh); 760 } 761 else 762 { 763 /* This is an error ... you need to prepare the I/O before using it. */ 764 mh->err = MPG123_BAD_CUSTOM_IO; 765 return MPG123_ERR; 766 } 767 } 768 769