1
0
mirror of http://mpg123.de/trunk/.git synced 2025-08-06 10:02:38 +03:00

libmpg123: purge off_t out of the core, offer 64 bit portable API (bug 344)

This now is the result of way to much time of thinking hard about disentangling
the various I/O paths in libmpg123. It needed days of hacking, way too many
hours continuously, to figure out how this would work. So this is my draft
that I tested in various settings and am hopeful that it fulfills the ideas
drafted in bug 344, the relentless discussion with manx about how portable
API should look.

Instead of just adding some 64 bit functions, this is a refactoring of the
reader code, moving the parts actually dealing with OS calls and largefile
support into lfs_wrap.c, which now offers wrappers and aliases. All file I/O
is now routed through the interface of mpg123_reader64() and could neatly be
split into a separate library, weren't it for only a handful of internal hooks.

I fixed up the autoconf and the CMake build. Ideally, both break only on
a limited set of platforms. I am pushing this directly to trunk as a)
I did testing on x86-64 and i686 with some largefile switchery and think
it should work and b) I want people to quickly tell me what does not work.

Let's see how many iterations we'll need until 1.32.0 can finally be released.



git-svn-id: svn://scm.orgis.org/mpg123/trunk@5304 35dc7657-300d-0410-a2e5-dc2837fedb53
This commit is contained in:
thor
2023-08-21 09:07:08 +00:00
parent 23500f3a89
commit bb3d506871
44 changed files with 1830 additions and 1993 deletions

View File

@@ -74,10 +74,6 @@ EXTRA_DIST += \
ports/cmake/src/tests/CMakeLists.txt \ ports/cmake/src/tests/CMakeLists.txt \
ports/cmake/src/compat/CMakeLists.txt \ ports/cmake/src/compat/CMakeLists.txt \
ports/README \ ports/README \
ports/Sony_PSP/config.h \
ports/Sony_PSP/README \
ports/Sony_PSP/Makefile.psp \
ports/Sony_PSP/readers.c.patch \
scripts/benchmark-cpu.pl \ scripts/benchmark-cpu.pl \
scripts/tag_lyrics.py \ scripts/tag_lyrics.py \
scripts/conplay \ scripts/conplay \

18
NEWS
View File

@@ -5,9 +5,15 @@
-- Include "fmt123.h" instead of <fmt123.h> in main API headers to make it more likely the -- Include "fmt123.h" instead of <fmt123.h> in main API headers to make it more likely the
correct one is included (at least gcc picks the one in the same directory as the correct one is included (at least gcc picks the one in the same directory as the
including header first). including header first).
-- TODO: make headers build-independent (some lfs aliasing for non-sensitive) -- All headers are build-independent now.
-- fix build for picky linkers by avoiding definition of wrap_getcpuflags() where it is not -- Fix build for picky linkers by avoiding definition of wrap_getcpuflags() where it is not
used (spurious linker error to non-exitent getcpuflags(), bug 353). used (spurious linker error to non-exitent getcpuflags(), bug 353).
-- Handle deprecation of C99 detection macro in autoconf 2.70.
-- No use of AC_SYS_LARGEFILE anymore for explicit handling and differing choice for
the libraries and frontend programs.
-- Added --enable-portable and --disable-largefile to configure, removing the other
largefile-related options.
- ports/Sony_PSP: removed
- mpg123: - mpg123:
-- Added --libversion. -- Added --libversion.
-- Added proper A-B looping with terminal control key 'o', renamed -- Added proper A-B looping with terminal control key 'o', renamed
@@ -25,6 +31,14 @@
- libsyn123: - libsyn123:
-- Introduced SYN123_PORTABLE_API for an API without off_t and ssize_t -- Introduced SYN123_PORTABLE_API for an API without off_t and ssize_t
(see NEWS.libsyn123). (see NEWS.libsyn123).
- libmpg123:
-- Internal I/O using explicit largefile support via off64_t, lseek64, fallback
to plain 32 bit off_t.
-- Added explicit 64 bit API with 64 suffix (mpg123_tell64(), not mpg123_tell_64()).
This allows full avoidance of ambiguus off_t. The API is always using 64 bit
integers, regardless of internal implementation. (bug 344)
-- Introduced MPG123_PORTABLE_API for an API subset without off_t and
ssize_t.
1.31.3 1.31.3
------ ------

View File

@@ -2,8 +2,16 @@ Changes in libmpg123 libtool interface versions. Next to the version
the mpg123 release where its changes first appeared to the public the mpg123 release where its changes first appeared to the public
is given. is given.
48.0.48 48.0.48 (mpg123 1.32)
- Added mpg123_distversion() and mpg123_libversion(). - Added mpg123_distversion() and mpg123_libversion().
- Added mpg123_reader64() and the other int64_t-based functions:
mpg123_framebyframe_decode64(), mpg123_framepos64(), mpg123_tell64(),
mpg123_tellframe64(), mpg123_tell_stream64(), mpg123_seek64(),
mpg123_feedseek64(), mpg123_seek_frame64(), mpg123_timeframe64(),
mpg123_index64(), mpg123_set_index64(), mpg123_framelength64(),
mpg123_length64(), and mpg123_set_filesize64().
- Added MPG123_PORTABLE_API to hide non-portable API (off_t, ssize_t)
from mpg123.h.
47.0.47 (mpg123 1.30) 47.0.47 (mpg123 1.30)
- Added mpg123_eq_bands(), mpg123_eq_change() and mpg123_volume_change_db(). - Added mpg123_eq_bands(), mpg123_eq_change() and mpg123_volume_change_db().

View File

@@ -2,7 +2,7 @@ Changes in libsyn23 libtool interface versions. Next to the version
the mpg123 release where its changes first appeared to the public the mpg123 release where its changes first appeared to the public
is given. is given.
2.0.2 2.0.2 (mpg123 1.32)
- Added syn123_distversion() and syn123_libversion(). - Added syn123_distversion() and syn123_libversion().
- Added switch SYN123_PORTABLE_API to hide off_t and ssize_t - Added switch SYN123_PORTABLE_API to hide off_t and ssize_t
(consistent with libmpg123). (consistent with libmpg123).

View File

@@ -32,7 +32,7 @@ m4_undefine([V_HEADER])
AC_INIT([mpg123], V_MAJOR.V_MINOR.V_PATCH[]V_SUFFIX, [maintainer@mpg123.org]) AC_INIT([mpg123], V_MAJOR.V_MINOR.V_PATCH[]V_SUFFIX, [maintainer@mpg123.org])
m4_define([V_HEADER], m4_esyscmd(grep -e _API_VERSION -e _PATCHLEVEL src/libmpg123/mpg123.h.in src/libout123/out123.h src/libsyn123/syn123.h)) m4_define([V_HEADER], m4_esyscmd(grep -e _API_VERSION -e _PATCHLEVEL src/libmpg123/mpg123.h src/libout123/out123.h src/libsyn123/syn123.h))
dnl libmpg123 dnl libmpg123
m4_define([API_VERSION], m4_bregexp(V_HEADER, m4_define([API_VERSION], m4_bregexp(V_HEADER,
@@ -135,9 +135,7 @@ if test "x$all_static" = xyes; then
fi fi
AM_PROG_AS AM_PROG_AS
dnl For autocinf 2.69, the C99 macro still does something. m4_version_prereq(2.70, [AC_PROG_CC], [AC_PROG_CC_C99])
AC_PROG_CC_C99
AM_PROG_CC_C_O
AC_PROG_CPP AC_PROG_CPP
AC_PROG_INSTALL AC_PROG_INSTALL
# Just look, no touch. # Just look, no touch.
@@ -1149,98 +1147,118 @@ AC_CHECK_HEADERS([stdio.h stdlib.h string.h unistd.h sched.h sys/ioctl.h sys/typ
dnl ############## Types dnl ############## Types
dnl Large file support stuff needs cleanup. There are superfluous variables.
dnl Detect large file support, enable switches if needed.
AC_SYS_LARGEFILE
dnl If we do have a switch for large files, rename off_t-aware API calls.
dnl Using the file_offset_bits variable here is fine for linux (possibly Solaris),
dnl Others... we'll have to see.
dnl Note: I started writing this with with multiline replacements.
dnl Does not work. Automake insists on putting these into Makefiles where they break things.
dnl It is also assumed that a system that does not set file offset bits is not
dnl sensitive to largefile changes, i.e. FreeBSD always using 64 bit off_t.
if test "x$ac_cv_sys_file_offset_bits" = x || echo "$ac_cv_sys_file_offset_bits" | $GREP '@<:@^0-9@:>@' > /dev/null; then
dnl if it has non-numeric chars or is empty... ignore...
largefile_sensitive=no
BUILD_NO_LARGENAME=1
AC_DEFINE(BUILD_NO_LARGENAME, 1, [ No suffixed symbols for large file support (only alias for backwards compat.) ])
else
largefile_sensitive=yes
BUILD_NO_LARGENAME=0
fi
# Add dual-mode wrapper code.
AM_CONDITIONAL([HAVE_LFS_WRAP], [ test x"$largefile_sensitive" = xyes ] )
# Any non-sensitive platform does not bother with off_t-based function renaming.
AC_SUBST(BUILD_NO_LARGENAME)
# Using the lower level macros instead of AC_TYPE_* for compatibility with not freshest autoconf. # Using the lower level macros instead of AC_TYPE_* for compatibility with not freshest autoconf.
# Re-think this list. Some things just should be a given. We assume C99 now.
# Rather think about assumptions like int64_t >= ptrdiff_t.
AC_CHECK_TYPE(size_t, unsigned long) AC_CHECK_TYPE(size_t, unsigned long)
AC_CHECK_TYPE(uintptr_t, unsigned long) AC_CHECK_TYPE(uintptr_t, unsigned long)
AC_CHECK_TYPE(ssize_t, long) AC_CHECK_TYPE(ssize_t, long)
AC_CHECK_TYPE(off_t, long int) AC_CHECK_TYPE(ptrdiff_t, long)
AC_CHECK_TYPE(int32_t, int) AC_CHECK_TYPE(int32_t, int)
AC_CHECK_TYPE(int64_t, long long) AC_CHECK_TYPE(int64_t, long long)
AC_CHECK_TYPE(uint32_t, unsigned int) AC_CHECK_TYPE(uint32_t, unsigned int)
AC_CHECK_TYPE(int16_t, short) AC_CHECK_TYPE(int16_t, short)
AC_CHECK_TYPE(uint16_t, unsigned short) AC_CHECK_TYPE(uint16_t, unsigned short)
AC_CHECK_SIZEOF(size_t,4) AC_CHECK_SIZEOF(size_t)
AC_CHECK_SIZEOF(ssize_t,4) AC_CHECK_SIZEOF(ssize_t)
AC_CHECK_SIZEOF(off_t,4)
AC_CHECK_SIZEOF(int32_t) AC_CHECK_SIZEOF(int32_t)
AC_CHECK_SIZEOF(long,4) AC_CHECK_SIZEOF(long)
dnl The native type used for aliases is what off_t maps to without any largefile- # We do not need to know if off_t actually changes size using
dnl enabling switches. So, it's long int if the system is largefile-senstive, # _FILE_OFFSET_BITS, only need to know what size it has.
dnl but it is actual plain off_t if the system does not have such switches.
if test "x$largefile_sensitive" = xyes; then
lfs_alias_type=long
lfs_alias_size=$ac_cv_sizeof_long
elif test "x$android_build" = xyes; then
lfs_alias_type=off64_t
lfs_alias_size=$ac_cv_sizeof_off64_t
else
lfs_alias_type=off_t
lfs_alias_size=$ac_cv_sizeof_off_t
fi
if test "x$lfs_alias_size" = "x"; then dnl ############## LFS stuff
AC_MSG_ERROR([Cannot determine sizeof(lfs_alias_t)?])
else
LFS_ALIAS_BITS=`expr "$lfs_alias_size" "*" "8"`
AC_DEFINE_UNQUOTED([lfs_alias_t], $lfs_alias_type,
[Define to the native offset type (long or actually off_t).])
AC_DEFINE_UNQUOTED([LFS_ALIAS_BITS], $LFS_ALIAS_BITS,
[Define this to the size of native offset type in bits, used for LFS alias functions.])
fi
AC_SUBST(LFS_ALIAS_BITS) portable_api=no
AC_ARG_ENABLE(portable,
lfs_alias=enabled [ --enable-portable=[no/yes] only build portable API (no off_t, no internal I/O) ],
AC_ARG_ENABLE(lfs-alias,
[ --disable-lfs-alias disable alias wrappers for largefile bitness (mpg123_seek_32 or mpg123_seek_64 in addition to mpg123_seek, or the other way around; It is a mess, do not play with this!) ],
[ [
if test "x$enableval" = xno; then if test "x$enableval" = xyes; then
lfs_alias="disabled" portable_api="yes"
fi fi
], ], [])
[ if test "x$portable_api" = xyes; then
case $host in AC_DEFINE(PORTABLE_API, 1, [ Define to only include portable library API (no off_t, no internal I/O). ])
*-cygwin*) fi
lfs_alias="disabled"
AC_MSG_NOTICE([lfs-alias disabled for Cygwin, use --enable-lfs-alias explicitly to enable, only if you know what you are doing])
;;
esac
]) AM_CONDITIONAL([HAVE_LFS_WRAP], [ test x"$portable_api" = xno ] )
AC_MSG_CHECKING([if we want to enable alias wrappers for largefile]) # Check for shape-shifting off_t just for the mpg123 client application.
if test "x$lfs_alias" = "xenabled"; then # At least at first, mpg123 itself will excercise the wrappers, otherwise
# we don't know they work.
AC_CHECK_SIZEOF(off_t, [], [
#undef _FILE_OFFSET_BITS
#define _FILE_OFFSET_BITS 64
#include <sys/types.h>
])
switched_off_size=$ac_cv_sizeof_off_t
AS_UNSET([ac_cv_sizeof_off_t])
# If you have predefined _FILE_OFFSET_BITS, I will treat that as a system
# property.
AC_CHECK_SIZEOF(off_t, [], [
#include <sys/types.h>
])
# Some paranoia about the limited choices we accept.
# 32 or 64 bit offsets, an the switched one better not be smaller.
if test "x$ac_cv_sizeof_off_t" = x0; then
AC_MSG_ERROR([Not even off_t found. I need some POSIX.])
fi
if test "x$ac_cv_sizeof_off_t" != x8 &&
test "x$ac_cv_sizeof_off_t" != x4; then
AC_MSG_ERROR([unexpected size of off_t])
fi
if test "x$ac_cv_sizeof_off_t" != "x$switched_off_size"; then
if test "x$switched_off_size" != x8; then
AC_MSG_ERROR([bad switched off_t size])
fi
lfs_sensitive=yes
AC_DEFINE(LFS_SENSITIVE, 1, [ System redefines off_t when defining _FILE_OFFSET_BITS to 64. ])
else
lfs_sensitive=no
fi
use_largefile=auto
AC_MSG_CHECKING([if native off_t is already 64 bits])
if test "x$ac_cv_sizeof_off_t" = x8; then
AC_MSG_RESULT([yes]) AC_MSG_RESULT([yes])
use_largefile=no
else else
AC_MSG_RESULT([no]) AC_MSG_RESULT([no])
fi fi
AM_CONDITIONAL([HAVE_LFS_ALIAS], [ test x"$lfs_alias" = xenabled ])
AC_ARG_ENABLE(largefile,
[ --disable-largefile to not attempt to use 64 bit file offsets internally ],
[ if test "x$enableval" = xno; then
use_largefile=no
fi
],
[])
# Large file support without the magic. Check for the API explicitly.
# The shape-shifting off_t has to be avoided for the library builds.
# The mpg123 application might still use it to check if the API works.
# Or we limit it to portable, off_t-less API at some point.
if test x"$use_largefile" != xno; then
# Expect usual_LARGEFILE64_SOURCE mechanics with off64_t and lseek64 present.
AC_CHECK_FUNCS([lseek64])
AC_CHECK_TYPE(off64_t, [have_off64_t=yes], [have_off64_t=no], [[
#define _LARGEFILE64_SOURCE
#include <sys/types.h>
#include <unistd.h>
]])
if test "x$have_off64_t" = xyes && test "x$ac_cv_func_lseek64" = xyes; then
use_largefile=yes
AC_DEFINE(LFS_LARGEFILE_64, 1, [ Define if we use _LARGEFILE64_SOURCE with off64_t and lseek64. ])
else
use_largefile=no
fi
fi # use_largefile auto or yes
dnl ############## Function Checks dnl ############## Function Checks
@@ -1346,29 +1364,6 @@ AC_SEARCH_LIBS(socket, socket)
AC_CHECK_FUNCS( getaddrinfo, [ have_ipv6=yes ], [ have_ipv6=no ] ) AC_CHECK_FUNCS( getaddrinfo, [ have_ipv6=yes ], [ have_ipv6=no ] )
# Substitutions for the installable mpg123.h header
if test "x$ac_cv_header_stdio_h" = "xyes"; then
INCLUDE_STDIO_H="#include <stdio.h>"
else
INCLUDE_STDIO_H="/* #include <stdio.h> is not available on this system */"
fi
AC_SUBST(INCLUDE_STDIO_H)
if test "x$ac_cv_header_stdlib_h" = "xyes"; then
INCLUDE_STDLIB_H="#include <stdlib.h>"
else
INCLUDE_STDLIB_H="/* #include <stdlib.h> is not available on this system */"
fi
AC_SUBST(INCLUDE_STDLIB_H)
if test "x$ac_cv_header_sys_types_h" = "xyes"; then
INCLUDE_SYS_TYPE_H="#include <sys/types.h>"
else
INCLUDE_SYS_TYPE_H="/* #include <sys/types.h> is not available on this system */"
fi
AC_SUBST(INCLUDE_SYS_TYPE_H)
# Checks for maths libraries. # Checks for maths libraries.
AC_CHECK_LIB([m], [sqrt]) AC_CHECK_LIB([m], [sqrt])
AC_CHECK_LIB([mx], [powf]) AC_CHECK_LIB([mx], [powf])
@@ -2784,20 +2779,27 @@ AC_CONFIG_FILES([
libout123.pc libout123.pc
libsyn123.pc libsyn123.pc
mpg123.spec mpg123.spec
src/libmpg123/mpg123.h
]) ])
AC_OUTPUT AC_OUTPUT
dnl ############## Display Message dnl ############## Display Message
default_offset_bits=`expr "$ac_cv_sizeof_off_t" "*" "8"`
echo " echo "
$PACKAGE_NAME $PACKAGE_VERSION $PACKAGE_NAME $PACKAGE_VERSION
Install path ............ $prefix Install path ............ $prefix
CPU Optimization ........ $cpu_type CPU Optimization ........ $cpu_type
Compiler Optimization ... $with_optimization Compiler Optimization ... $with_optimization"
Gapless Support ......... $gapless if test x"$use_yasm_for_avx" = xyes; then
echo " Use yasm (for AVX only) . enabled"
else
echo " Use yasm (for AVX only) . disabled"
fi
echo " Gapless Support ......... $gapless
Debugging ............... $debugging Debugging ............... $debugging
Terminal control ........ $term_type Terminal control ........ $term_type
Extreme debugging ....... $xdebugging Extreme debugging ....... $xdebugging
@@ -2811,19 +2813,10 @@ if test x$network_type != xdisabled; then
echo " Internal network type ... $network_internal echo " Internal network type ... $network_internal
IPv6 (getaddrinfo) ...... $ipv6" IPv6 (getaddrinfo) ...... $ipv6"
fi fi
if test x"$LARGEFILE_BITS" = x; then echo " largefile sensitive ..... $lfs_sensitive"
echo " File offsets ............ default" echo " default offsets ......... $default_offset_bits"
else echo " explicit 64 bit offsets . $use_largefile"
echo " File offsets ............ $LARGEFILE_BITS" echo " only portable API ....... $portable_api"
echo " The lib will (try to) support default offset size, too."
fi
echo " LFS alias symbols ....... $lfs_alias ($LFS_ALIAS_BITS)"
echo " LFS alias type .......... $lfs_alias_type"
if test x"$use_yasm_for_avx" = xyes; then
echo " Use yasm (for AVX only) . enabled"
else
echo " Use yasm (for AVX only) . disabled"
fi
echo " echo "
Core libmpg123 features: Core libmpg123 features:

View File

@@ -14,6 +14,7 @@ EXTRA_DIST += \
doc/THANKS \ doc/THANKS \
doc/ACCURACY \ doc/ACCURACY \
doc/LARGEFILE \ doc/LARGEFILE \
doc/READERS \
doc/libmpg123_speed.txt \ doc/libmpg123_speed.txt \
doc/doxyhead.xhtml \ doc/doxyhead.xhtml \
doc/doxyfoot.xhtml \ doc/doxyfoot.xhtml \
@@ -21,6 +22,7 @@ EXTRA_DIST += \
doc/doxygen.conf \ doc/doxygen.conf \
doc/windows-notes.html \ doc/windows-notes.html \
doc/examples/mpg123_to_out123.c \ doc/examples/mpg123_to_out123.c \
doc/examples/mpg123_to_wav_replaced_io.c \
doc/examples/scan.c \ doc/examples/scan.c \
doc/examples/mpglib.c \ doc/examples/mpglib.c \
doc/examples/id3dump.c \ doc/examples/id3dump.c \

209
doc/READERS Normal file
View File

@@ -0,0 +1,209 @@
The libmpg123 web of reader abstractions
========================================
Somehow the differing ways of getting compressed data into libmpg123 reached
unholy numbers with the years. As keeper of the legacy, I got quite some of that
to keep. There are intersectional layers ... however you might call it.
An attempt to get an overview and be able to refactor that for the glorious
portable API of mpg123 1.32.0.
The frame struct has two parts concerned with input streams.
struct reader *rd; /* pointer to the reading functions */
struct reader_data rdat; /* reader data and state info */
The distinction is blurred a bit: Over time, I added function pointers to
the latter.
1. Basic methods of data input for (seekable) streams
-----------------------------------------------------
These reside in the struct reader_data member of the frame struct (mpg123_handle), so
normally fr->rdat. This is an assortment of (user-supplied) function pointers
and stores the stream position and length. The latter was the initial purpose.
1.1 Reader based around POSIX I/O
---------------------------------
This one relies on some read() and lseek() to give the input bytes. With an
innocent mpg123_open(), you trigger compat_open() and further work on the
resulting fd.
But you can also do mpg123_open_fd() to provide the descriptor yourself. Same
further code path, just no closing.
1.1.1 Timeout read
------------------
The timeout reader is a variant that squeezes into the internal POSIX I/O with
some fcntl() and select() on the file descriptor, and a separate reader callback
stored as fdread().
1.2 Replaced I/O on file descriptor
-----------------------------------
After calling mpg123_replace_reader(), you have your callbacks (or the respective
fallback callback) operating on the file descriptor that could have resulted
from internal opening or been handed over to libmpg123.
1.3 Replaced I/O on custom handle
---------------------------------
This replaces both read() and lseek() with your callbacks and opening is
full external, just the handle being handed over via mpg123_open_handle().
1.4 Replaced I/O on custom handle using 64 bit offsets
------------------------------------------------------
This is to come, the above just with a differing style of callbacks that avoid
off_t. I intend to pack all the above into wrapper code and have this whole
first aspect of differing callbacks removed.
2. Abstractions
---------------
The actual interface to the parser is given by instances of struct reader. This
is usually accessed as fr->rd and contains function pointers to specific routines
like fullread() and head_read(). These access the basic methods behind the scenes.
There is overlap in the functions. The main differentiator is the fullread() call,
which is the next layer of read(). I guess code sharing could be one excuse not
to have each of these as a wholly separate I/O layer implementation.
2.1 READER_STREAM
-----------------
This reader handles a plain possibly seekable input stream. It introduces the
plain_fullread() function which loops over fr->rdat.fdread() until the desired
bytes are aquired or EOF occurs. There is no signal handling. A return value
less than zero is an error and the end, the function returning a short byte
count. This function also advances fr->rdat.filepos if the reader is not
buffered.
2.2 READER_ICY_STREAM
---------------------
This replaces plain_fullread() with icy_fullread(), which looks out for ICY
metadata at the configured interval. It resorts to fr->rdat.fdread() and
plain_fullread() to do its chores.
2.3 READER_FEED
---------------
The reader handling libmpg123 feeder mode. It stuffs data into an internal buffer
and extracts from that, handing out READER_MORE as error to be recovered from
when the client provides more data. It provides a bit of seeking within the
buffer for parsing (look-ahead) purposes, before read data is purged from the
buffer chain.
The actual mid-level reader here is feed_read(), wrapping over the bufferchain data
structre with its methods.
2.4 READER_BUF_STREAM
---------------------
For some reason, I had to add a mode for a stream with some buffering
(MPG123_SEEKBUFFER). Well ... yes, MPEG parsing is just more fun if you can peek
ahead and have a little window of input data to work with. This used to employ
buffered_fullread(), which in turn called fr->rdat.fullread(), which was
plain_fullread() for this variant, and wraped a bufferchain around it.
Now this got its separate buffered_plain_fullread() without the extra function
pointer in fr->rdat.
2.5 READER_BUF_ICY_STREAM
-------------------------
This is the same buffered reader but with buffered_icy_fullread() instead.
3. Control flow for setting up a stream
=======================================
3.1 mpg123_open()
-----------------
Client code just opens a track or possibly called mpg123_replace_reader()
beforehand, which does not change the opening behaviour.
This accesses the given file path via compat_open(), stores a file descriptor,
calls reader stream init which checks seekability (also fetching ID3v1) and
stores file size. This results in one of the READER_*STREAM family.
The lfs_wrap machinery gets triggrered and inserts its callbacks, working
on the prepared wrapper data.
3.2 mpg123_open_fd()
--------------------
This just skips the compat_open() and stores the given file descriptor, assuming
that it works with the configured callbacks. The same dance with stream setup.
The lfs_wrap machinery gets triggrered and inserts its callbacks, working
on the prepared wrapper data.
3.3 mpg123_open_handle()
------------------------
Also skips the opening, stores the handle and does the stream setup.
This shall not trigger callback insertion. The idea is that the user did
call mpg123_reader64() or a wrapper variant of it before. The wrapper code
itself finalizes its work with a call to mpg123_reader64().
Oh, wait. What about the other wrapper calls? Client code calls
mpg123_replace_reader_handle() with its callbacks, be it off_t or off64_t.
This needs to trigger preparation of wrapperdata and installment of wrapper
callbacks via mpg123_reader64(). A subsequent mpg123_open_handle() needs
to store the actual client handle inside the wrapperdata structure and use
the latter as iohandle for stream operation. I need tell apart internal and
external use of mpg123_reader64().
So store a flag for that? Is there another way without introducing yet another
function? Well, the wrapperdata can have two states that fit this scenario:
- not present at all
- present with a respective state set
I want to avoid unnecessary allocation of the wrapperdata (just because I am that
kind of person). So I need to ensure that INT123_wrap_open() when called with
an external handle and not encountering an existing wrapperdata instance, does not
allocate one, but just silently does nothing, as there is nothing to do. Well,
it can check if callbacks are in place. At least that.
3.4 mpg123_open_feed()
----------------------
Prepares for the non-seekable feeder mode, limited stream setup because peeking
at the end won't work.
This does not trigger the wrapper ... except ... should it unregister its
callbacks? No. The code path of the feeder is separate enough that it does
not interfere.
4. Plan
=======
Keep the abstractions in readers.c, move all variants of POSIX-like callback stuff
into the wrapper section (lfs_wrap.c for now). In theory, the buffer chain for
the feeder could also be moved into a variant hidden behind mpg123_reader64(). Maybe
in the future. At some point.
I don't want any mpg123 internals regarding the frame struct in the wrapper
implementation. So maybe lfs_wrap.c only offers wrapper setup as such and
libmpg123.c does the actual stream opening? No. The explicit largefile stuff
needs to be handled (O_LARGEFILE). But the further stream setup ... that
should happen in mpg123_open() and friends, after reader handle setup.
I still need fr->rdat.flags for selecting buffered etc., but not for
READER_FD_OPENEND or READER_NONBLOCK.
Both fr->rdat.fullread and fr->rdat.fdread are gone now. The picture is getting
clearer.
I made the static functions fdread() and fdseek() robust against missing
callbacks. It's a question if we'd rather want to catch those earlier, though.

View File

@@ -13,5 +13,7 @@ it to work with minimal fuzz.
- cmake: CMake build to get started on non-Unix-like platforms, especially - cmake: CMake build to get started on non-Unix-like platforms, especially
for just libmpg123 on Windows for just libmpg123 on Windows
- Sony PSP: Sony_PSP/; building libmpg123 for the PSP (used for the MODO player).
...by Bastian Pflieger <wb@illogical.de> There used to be other ports, last of those for the Sony PSP. There was not
much porting involved on that one, though, just a custom Makefile for building
a generic libmpg123.

View File

@@ -1,38 +0,0 @@
PSPSDK = $(shell psp-config --pspsdk-path)
PSPDIR = $(shell psp-config --psp-prefix)
#DEFINES := PSP OPT_GENERIC REAL_IS_FIXED HAVE_CONFIG_H
DEFINES := PSP OPT_GENERIC REAL_IS_FLOAT HAVE_CONFIG_H
#DEFINES := PSP OPT_GENERIC FLOATOUT REAL_IS_FLOAT HAVE_CONFIG_H
DEFINEFLAGS := $(addprefix -D,$(DEFINES))
INCDIR := ../.
CFLAGS = -g -O2 -Wall -fomit-frame-pointer -funroll-all-loops -finline-functions -ffast-math $(DEFINEFLAGS)
MPG123_OBJS = compat.o parse.o frame.o format.o index.o synth.o synth_8bit.o \
ntom.o icy2utf8.o synth_real.o synth_s32.o\
equalizer.o icy.o id3.o layer1.o layer2.o layer3.o optimize.o readers.o tabinit.o stringbuf.o libmpg123.o dct64.o
MPG123_LIB_FILE = ./libmpg123.a
OBJS = $(MPG123_OBJS)
TARGET_LIB = $(MPG123_LIB_FILE)
include $(PSPSDK)/lib/build.mak
####################
## Makefile rules ##
####################
install: $(MPG123_LIB_FILE)
@echo ""
@echo "**********************************************************************"
@echo "Installing libstsound into $(PSPDIR)"
@mkdir -p $(PSPDIR)/include $(PSPDIR)/lib
@cp -v mpg123.h $(PSPDIR)/include
@cp -v libmpg123.a $(PSPDIR)/lib
@echo "Done"
@echo "**********************************************************************"
@echo ""

View File

@@ -1,11 +0,0 @@
Hi
* Place Makefile.psp in the directory src/libmpg123.
* Patch readers.c (present in src/libmpg123) using readers.c.patch
* Place Config.h in directory src/
* cd to src/libmpg123 and do "make -f Makefile.psp install"
Tested on mpg123 1.4.x and psptoolchain rev. 2398
Regards
Bastian

View File

@@ -1,368 +0,0 @@
/* src/config.h. Generated from config.h.in by configure. */
/* src/config.h.in. Generated from configure.ac by autoheader. */
/* Define if your architecture wants/needs/can use attribute_align_arg and
alignment checks. It's for 32bit x86... */
#define ABI_ALIGN_FUN 1
/* Define to use proper rounding. */
/* #undef ACCURATE_ROUNDING */
/* Define if .align takes 3 for alignment of 2^3=8 bytes instead of 8. */
/* #undef ASMALIGN_EXP */
/* Define if __attribute__((aligned(16))) shall be used */
/* #undef CCALIGN */
/* Define if checking of stack alignment is wanted. */
#define CHECK_ALIGN 1
/* Define if debugging is enabled. */
/* #undef DEBUG */
/* The default audio output module(s) to use */
#define DEFAULT_OUTPUT_MODULE "alsa,oss,esd,sdl,nas,arts"
/* Define if building with dynamcally linked libmpg123 */
#define DYNAMIC_BUILD 1
/* Define if FIFO support is enabled. */
#define FIFO 1
/* Define if frame index should be used. */
#define FRAME_INDEX 1
/* Define if gapless is enabled. */
#define GAPLESS 1
/* Define to 1 if you have the <Alib.h> header file. */
/* #undef HAVE_ALIB_H */
/* Define to 1 if you have the <arpa/inet.h> header file. */
#define HAVE_ARPA_INET_H 1
/* Define to 1 if you have the <asm/audioio.h> header file. */
/* #undef HAVE_ASM_AUDIOIO_H */
/* Define to 1 if you have the `atoll' function. */
#define HAVE_ATOLL 1
/* Define to 1 if you have the <audios.h> header file. */
/* #undef HAVE_AUDIOS_H */
/* Define to 1 if you have the <AudioToolbox/AudioToolbox.h> header file. */
/* #undef HAVE_AUDIOTOOLBOX_AUDIOTOOLBOX_H */
/* Define to 1 if you have the <AudioUnit/AudioUnit.h> header file. */
/* #undef HAVE_AUDIOUNIT_AUDIOUNIT_H */
/* Define to 1 if you have the <CoreServices/CoreServices.h> header file. */
/* #undef HAVE_CORESERVICES_CORESERVICES_H */
/* Define to 1 if you have the <CUlib.h> header file. */
/* #undef HAVE_CULIB_H */
/* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1
/* Define to 1 if you have the `getaddrinfo' function. */
#define HAVE_GETADDRINFO 1
/* Define to 1 if you have the `getpagesize' function. */
#define HAVE_GETPAGESIZE 1
/* Define to 1 if you have the `getuid' function. */
#define HAVE_GETUID 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the <langinfo.h> header file. */
#define HAVE_LANGINFO_H 1
/* Define to 1 if you have the `m' library (-lm). */
#define HAVE_LIBM 1
/* Define to 1 if you have the `mx' library (-lmx). */
/* #undef HAVE_LIBMX */
/* Define to 1 if you have the <limits.h> header file. */
#define HAVE_LIMITS_H 1
/* Define to 1 if you have the <linux/soundcard.h> header file. */
#define HAVE_LINUX_SOUNDCARD_H 1
/* Define to 1 if you have the <locale.h> header file. */
#define HAVE_LOCALE_H 1
/* Define if libltdl is available */
#define HAVE_LTDL 1
/* Define to 1 if you have the <machine/soundcard.h> header file. */
/* #undef HAVE_MACHINE_SOUNDCARD_H */
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the `mkfifo' function. */
#define HAVE_MKFIFO 1
/* Define to 1 if you have a working `mmap' system call. */
#define HAVE_MMAP 1
/* Define to 1 if you have the <netdb.h> header file. */
#define HAVE_NETDB_H 1
/* Define to 1 if you have the <netinet/in.h> header file. */
#define HAVE_NETINET_IN_H 1
/* Define to 1 if you have the <netinet/tcp.h> header file. */
/* #undef HAVE_NETINET_TCP_H */
/* Define to 1 if you have the `nl_langinfo' function. */
#define HAVE_NL_LANGINFO 1
/* Define to 1 if you have the <os2me.h> header file. */
/* #undef HAVE_OS2ME_H */
/* Define to 1 if you have the <os2.h> header file. */
/* #undef HAVE_OS2_H */
/* Define to 1 if you have the `random' function. */
#define HAVE_RANDOM 1
/* Define to 1 if you have the <sched.h> header file. */
#define HAVE_SCHED_H 1
/* Define to 1 if you have the `sched_setscheduler' function. */
#define HAVE_SCHED_SETSCHEDULER 1
/* Define to 1 if you have the `setlocale' function. */
#define HAVE_SETLOCALE 1
/* Define to 1 if you have the `setpriority' function. */
#define HAVE_SETPRIORITY 1
/* Define to 1 if you have the `setuid' function. */
#define HAVE_SETUID 1
/* Define to 1 if you have the <signal.h> header file. */
#define HAVE_SIGNAL_H 1
/* Define to 1 if you have the <sndio.h> header file. */
/* #undef HAVE_SNDIO_H */
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdio.h> header file. */
#define HAVE_STDIO_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the `strdup' function. */
#define HAVE_STRDUP 1
/* Define to 1 if you have the `strerror' function. */
#define HAVE_STRERROR 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the <sun/audioio.h> header file. */
/* #undef HAVE_SUN_AUDIOIO_H */
/* Define to 1 if you have the <sys/audioio.h> header file. */
/* #undef HAVE_SYS_AUDIOIO_H */
/* Define to 1 if you have the <sys/audio.h> header file. */
/* #undef HAVE_SYS_AUDIO_H */
/* Define to 1 if you have the <sys/ioctl.h> header file. */
#define HAVE_SYS_IOCTL_H 1
/* Define to 1 if you have the <sys/param.h> header file. */
#define HAVE_SYS_PARAM_H 1
/* Define to 1 if you have the <sys/resource.h> header file. */
#define HAVE_SYS_RESOURCE_H 1
/* Define to 1 if you have the <sys/signal.h> header file. */
#define HAVE_SYS_SIGNAL_H 1
/* Define to 1 if you have the <sys/socket.h> header file. */
#define HAVE_SYS_SOCKET_H 1
/* Define to 1 if you have the <sys/soundcard.h> header file. */
#define HAVE_SYS_SOUNDCARD_H 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/time.h> header file. */
#define HAVE_SYS_TIME_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <sys/wait.h> header file. */
#define HAVE_SYS_WAIT_H 1
/* Define this if you have the POSIX termios library */
#define HAVE_TERMIOS 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define to 1 if you have the <windows.h> header file. */
/* #undef HAVE_WINDOWS_H */
/* Define to indicate that float storage follows IEEE754. */
#define IEEE_FLOAT 1
/* size of the frame index seek table */
#define INDEX_SIZE 1000
/* Define if IPV6 support is enabled. */
#define IPV6 1
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#define LT_OBJDIR ".libs/"
/* Define if network support is enabled. */
/* #define NETWORK 1 */
/* Define to disable 16 bit integer output. */
/* #undef NO_16BIT */
/* Define to disable 32 bit integer output. */
/* define NO_32BIT 1 */
/* Define to disable 8 bit integer output. */
/* #undef NO_8BIT */
/* Define to disable downsampled decoding. */
/* #undef NO_DOWNSAMPLE */
/* Define to disable error messages in combination with a return value (the
return is left intact). */
/* #undef NO_ERETURN */
/* Define to disable error messages. */
/* #undef NO_ERRORMSG */
/* Define to disable feeder and buffered readers. */
/* #undef NO_FEEDER */
/* Define to disable ICY handling. */
/* #undef NO_ICY */
/* Define to disable ID3v2 parsing. */
/* #undef NO_ID3V2 */
/* Define to disable layer I. */
/* #undef NO_LAYER1 */
/* Define to disable layer II. */
/* #undef NO_LAYER2 */
/* Define to disable layer III. */
/* #undef NO_LAYER3 */
/* Define to disable ntom resampling. */
/* #undef NO_NTOM */
/* Define to disable real output. */
/* define NO_REAL 1 */
/* Define to disable string functions. */
/* #undef NO_STRING */
/* Define to disable warning messages. */
/* #undef NO_WARNING */
/* Name of package */
#define PACKAGE "mpg123"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "mpg123-devel@lists.sourceforge.net"
/* Define to the full name of this package. */
#define PACKAGE_NAME "mpg123"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "mpg123 1.8rc5"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "mpg123"
/* Define to the version of this package. */
#define PACKAGE_VERSION "1.8rc5"
/* Define if portaudio v18 API is wanted. */
/* #undef PORTAUDIO18 */
/* The size of `int32_t', as computed by sizeof. */
#define SIZEOF_INT32_T 4
/* The size of `long', as computed by sizeof. */
#define SIZEOF_LONG 4
/* The size of `off_t', as computed by sizeof. */
#define SIZEOF_OFF_T 4
/* The size of `size_t', as computed by sizeof. */
#define SIZEOF_SIZE_T 4
/* The size of `ssize_t', as computed by sizeof. */
#define SIZEOF_SSIZE_T 4
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Define if modules are enabled */
#define USE_MODULES 1
/* Version number of package */
#define VERSION "1.8rc5"
/* Number of bits in a file offset, on hosts where this is settable. */
/* #undef _FILE_OFFSET_BITS */
/* Define for large files, on AIX-style hosts. */
/* #undef _LARGE_FILES */
/* Define to empty if `const' does not conform to ANSI C. */
/* #undef const */
/* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef __cplusplus
/* #undef inline */
#endif
/* Define to `short' if <sys/types.h> does not define. */
/* #undef int16_t */
/* Define to `int' if <sys/types.h> does not define. */
/* #undef int32_t */
/* Define to `long int' if <sys/types.h> does not define. */
/* #undef off_t */
/* Define to `unsigned long' if <sys/types.h> does not define. */
/* #undef size_t */
/* Define to `long' if <sys/types.h> does not define. */
/* #undef ssize_t */
/* Define to `unsigned short' if <sys/types.h> does not define. */
/* #undef uint16_t */
/* Define to `unsigned int' if <sys/types.h> does not define. */
/* #undef uint32_t */

View File

@@ -1,2 +0,0 @@
14a15
> #include <sys/fd_set.h>

View File

@@ -8,6 +8,8 @@ include(CheckSymbolExists)
include(CMakeDependentOption) include(CMakeDependentOption)
include(TestBigEndian) include(TestBigEndian)
option(PORTABLE_API "Only build portable library API (no off_t, no internal I/O." OFF)
check_include_file("arpa/inet.h" HAVE_ARPA_INET_H) check_include_file("arpa/inet.h" HAVE_ARPA_INET_H)
check_include_file("dirent.h" HAVE_DIRENT_H) check_include_file("dirent.h" HAVE_DIRENT_H)
check_include_file("dlfcn.h" HAVE_DLFCN_H) check_include_file("dlfcn.h" HAVE_DLFCN_H)
@@ -64,6 +66,8 @@ check_function_exists(fork HAVE_FORK)
check_function_exists(execvp HAVE_EXECVP) check_function_exists(execvp HAVE_EXECVP)
check_function_exists(ctermid HAVE_CTERMID) check_function_exists(ctermid HAVE_CTERMID)
check_function_exists(lseek64 LFS_LARGEFILE_64)
search_libs(gethostbyname GETHOSTBYNAME_LIB nsl socket network) search_libs(gethostbyname GETHOSTBYNAME_LIB nsl socket network)
search_libs(socket SOCKET_LIB socket) search_libs(socket SOCKET_LIB socket)
@@ -83,26 +87,6 @@ check_c_source_compiles(
"int main() { __attribute__((aligned(16))) float var; return 0; }" "int main() { __attribute__((aligned(16))) float var; return 0; }"
CCALIGN) CCALIGN)
if(MSVC)
# Here, off_t is always 32 bit, the whole machinery doesn't work without explicit
# API for 64 bit file access.
unset(_FILE_OFFSET_BITS)
set(LFS_SENSITIVE OFF)
set(LFS_INSENSITIVE ON)
set(MPG123_LARGE_FILE_SUPPORT OFF)
# We disable all the dynamic naming with MSVC to avoid confusing consumers.
# Maybe it would be more proper to conditionit on LFS_INSENSTIIVE.
set(BUILD_NO_LARGENAME 1)
else()
option(MPG123_LARGE_FILE_SUPPORT "Support large files (define _FILE_OFFSET_BITS)" ON)
if(MPG123_LARGE_FILE_SUPPORT)
set(_FILE_OFFSET_BITS 64)
else()
unset(_FILE_OFFSET_BITS)
endif()
set(BUILD_NO_LARGENAME 0)
endif()
if(NOT LFS_INSENSITIVE) if(NOT LFS_INSENSITIVE)
check_c_source_compiles(" check_c_source_compiles("
#include <sys/types.h> #include <sys/types.h>
@@ -133,18 +117,6 @@ endif()
check_type_size(long SIZEOF_LONG) check_type_size(long SIZEOF_LONG)
check_type_size(off_t SIZEOF_OFF_T) check_type_size(off_t SIZEOF_OFF_T)
if(LFS_SENSITIVE)
set(LFS_ALIAS_TYPE long)
math(EXPR LFS_ALIAS_BITS "${SIZEOF_LONG} * 8")
elseif(CMAKE_ANDROID_ARCH_ABI)
check_type_size(off64_t SIZEOF_OFF64_T)
set(LFS_ALIAS_TYPE off64_t)
math(EXPR LFS_ALIAS_BITS "${SIZEOF_OFF64_T} * 8")
else()
set(LFS_ALIAS_TYPE off_t)
math(EXPR LFS_ALIAS_BITS "${SIZEOF_OFF_T} * 8")
endif()
if(WIN32 AND HAVE_WINDOWS_H) if(WIN32 AND HAVE_WINDOWS_H)
check_c_source_compiles(" check_c_source_compiles("
#include <windows.h> #include <windows.h>
@@ -331,13 +303,6 @@ cmake_dependent_option(NO_BUFFER "enable audio buffer code (default uses system
option(NO_DOWNSAMPLE "no downsampled decoding" OFF) option(NO_DOWNSAMPLE "no downsampled decoding" OFF)
option(NO_EQUALIZER "no equalizer support" OFF) option(NO_EQUALIZER "no equalizer support" OFF)
option(NO_FEEDER "no feeder decoding, no buffered readers" OFF) option(NO_FEEDER "no feeder decoding, no buffered readers" OFF)
if(CYGWIN)
option(NO_LFS_ALIAS "disable alias wrappers for largefile bitness (mpg123_seek_32 or mpg123_seek_64 in addition to mpg123_seek, or the other way around; It is a mess, do not play with this!)" ON)
elseif(MSVC)
set(NO_LFS_ALIAS ON)
else()
option(NO_LFS_ALIAS "disable alias wrappers for largefile bitness (mpg123_seek_32 or mpg123_seek_64 in addition to mpg123_seek, or the other way around; It is a mess, do not play with this!)" OFF)
endif()
option(NO_ICY "ICY metainfo parsing/conversion" OFF) option(NO_ICY "ICY metainfo parsing/conversion" OFF)
option(NO_LAYER1 "no layer I decoding" OFF) option(NO_LAYER1 "no layer I decoding" OFF)
option(NO_LAYER2 "no layer II decoding" OFF) option(NO_LAYER2 "no layer II decoding" OFF)
@@ -379,7 +344,7 @@ if(BUILD_LIBOUT123)
endif() endif()
add_subdirectory("libsyn123") add_subdirectory("libsyn123")
if(UNIX) if(UNIX AND NOT PORTABLE_API)
option(BUILD_PROGRAMS "Build programs" ON) option(BUILD_PROGRAMS "Build programs" ON)
if(BUILD_PROGRAMS) if(BUILD_PROGRAMS)

View File

@@ -1,3 +1,6 @@
// Define to only include portable API in libraries.
#cmakedefine PORTABLE_API 1
// Define to use proper rounding. // Define to use proper rounding.
#cmakedefine ACCURATE_ROUNDING 1 #cmakedefine ACCURATE_ROUNDING 1
@@ -42,6 +45,9 @@
#cmakedefine HAVE_STDINT_H 1 #cmakedefine HAVE_STDINT_H 1
#cmakedefine HAVE_STDLIB_H 1 #cmakedefine HAVE_STDLIB_H 1
#cmakedefine HAVE_STRERROR 1 #cmakedefine HAVE_STRERROR 1
#cmakedefine HAVE_FORK 1
#cmakedefine HAVE_EXECVP 1
#cmakedefine HAVE_CTERMID 1
#cmakedefine HAVE_STRING_H 1 #cmakedefine HAVE_STRING_H 1
#cmakedefine HAVE_STRINGS_H 1 #cmakedefine HAVE_STRINGS_H 1
#cmakedefine HAVE_SYS_IOCTL_H 1 #cmakedefine HAVE_SYS_IOCTL_H 1
@@ -67,7 +73,6 @@
// Define if IPV6 support is enabled. // Define if IPV6 support is enabled.
#cmakedefine IPV6 1 #cmakedefine IPV6 1
#define LFS_ALIAS_BITS @LFS_ALIAS_BITS@
#define LT_MODULE_EXT "@CMAKE_SHARED_MODULE_SUFFIX@" #define LT_MODULE_EXT "@CMAKE_SHARED_MODULE_SUFFIX@"
// Define if network support is enabled. // Define if network support is enabled.
@@ -143,6 +148,7 @@
// CMake leaves it emtpy for non-existing type. Autoconf sets it to 0. // CMake leaves it emtpy for non-existing type. Autoconf sets it to 0.
#define SIZEOF_LONG (@SIZEOF_LONG@+0) #define SIZEOF_LONG (@SIZEOF_LONG@+0)
#define SIZEOF_OFF_T (@SIZEOF_OFF_T@+0) #define SIZEOF_OFF_T (@SIZEOF_OFF_T@+0)
#define SIZEOF_OFF64_T (@SIZEOF_OFF64_T@+0)
#cmakedefine STDERR_FILENO @STDERR_FILENO@ #cmakedefine STDERR_FILENO @STDERR_FILENO@
#cmakedefine STDIN_FILENO @STDIN_FILENO@ #cmakedefine STDIN_FILENO @STDIN_FILENO@
@@ -169,8 +175,5 @@
#cmakedefine WORDS_BIGENDIAN 1 #cmakedefine WORDS_BIGENDIAN 1
// Number of bits in a file offset, on hosts where this is settable. #cmakedefine LFS_LARGEFILE_64 1
#cmakedefine _FILE_OFFSET_BITS @_FILE_OFFSET_BITS@ #cmakedefine LFS_SENSITIVE 1
// Define to the native offset type (long or actually off_t).
#define lfs_alias_t @LFS_ALIAS_TYPE@

View File

@@ -1,7 +1,6 @@
cmake_minimum_required(VERSION 3.12) cmake_minimum_required(VERSION 3.12)
option(NO_FEATURE_REPORT "Disable feature report function" OFF) option(NO_FEATURE_REPORT "Disable feature report function" OFF)
option(NO_LFS_ALIAS "disable alias wrappers for largefile bitness (mpg123_seek_32 or mpg123_seek_64 in addition to mpg123_seek, or the other way around; It is a mess, do not play with this!)" OFF)
include_directories("${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/libmpg123/") include_directories("${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/libmpg123/")
@@ -40,8 +39,6 @@ else()
endif() endif()
message(STATUS "Detected machine: ${MACHINE}") message(STATUS "Detected machine: ${MACHINE}")
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/libmpg123/mpg123.h.in" mpg123.h)
set(TARGET lib${PROJECT_NAME}) set(TARGET lib${PROJECT_NAME})
add_library(${TARGET} add_library(${TARGET}
"${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/libmpg123/parse.c" "${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/libmpg123/parse.c"
@@ -60,7 +57,6 @@ add_library(${TARGET}
"${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/libmpg123/$<$<NOT:$<BOOL:${NO_LAYER1}>>:layer1.c>" "${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/libmpg123/$<$<NOT:$<BOOL:${NO_LAYER1}>>:layer1.c>"
"${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/libmpg123/$<$<NOT:$<OR:$<BOOL:${NO_LAYER1}>,$<BOOL:${NO_LAYER2}>>>:layer2.c>" "${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/libmpg123/$<$<NOT:$<OR:$<BOOL:${NO_LAYER1}>,$<BOOL:${NO_LAYER2}>>>:layer2.c>"
"${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/libmpg123/$<$<NOT:$<BOOL:${NO_LAYER3}>>:layer3.c>" "${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/libmpg123/$<$<NOT:$<BOOL:${NO_LAYER3}>>:layer3.c>"
"${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/libmpg123/$<$<NOT:$<BOOL:${NO_LFS_ALIAS}>>:lfs_alias.c>"
"${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/libmpg123/$<$<NOT:$<BOOL:${NO_NTOM}>>:ntom.c>" "${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/libmpg123/$<$<NOT:$<BOOL:${NO_NTOM}>>:ntom.c>"
"${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/libmpg123/$<$<NOT:$<BOOL:${NO_8BIT}>>:synth_8bit.c>" "${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/libmpg123/$<$<NOT:$<BOOL:${NO_8BIT}>>:synth_8bit.c>"
"${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/libmpg123/$<$<NOT:$<BOOL:${NO_16BIT}>>:synth.c>" "${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/libmpg123/$<$<NOT:$<BOOL:${NO_16BIT}>>:synth.c>"
@@ -68,7 +64,7 @@ add_library(${TARGET}
"${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/libmpg123/$<$<AND:$<BOOL:${HAVE_FPU}>,$<NOT:$<BOOL:${NO_REAL}>>>:synth_real.c>" "${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/libmpg123/$<$<AND:$<BOOL:${HAVE_FPU}>,$<NOT:$<BOOL:${NO_REAL}>>>:synth_real.c>"
"${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/libmpg123/$<$<NOT:$<BOOL:${NO_STRING}>>:stringbuf.c>" "${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/libmpg123/$<$<NOT:$<BOOL:${NO_STRING}>>:stringbuf.c>"
"${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/libmpg123/$<$<NOT:$<BOOL:${NO_FEATURE_REPORT}>>:feature.c>" "${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/libmpg123/$<$<NOT:$<BOOL:${NO_FEATURE_REPORT}>>:feature.c>"
"${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/libmpg123/$<$<BOOL:${LFS_SENSITIVE}>:lfs_wrap.c>" "${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/libmpg123/$<$<NOT:$<BOOL:${PORTABLE_API}>>:lfs_wrap.c>"
$<TARGET_OBJECTS:compat>) $<TARGET_OBJECTS:compat>)
if(MSVC) if(MSVC)
@@ -252,7 +248,7 @@ install(TARGETS ${TARGET} EXPORT targets
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}/" ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}/"
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/" LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/"
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}/") RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}/")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/mpg123.h" install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/libmpg123/mpg123.h"
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/libmpg123/fmt123.h" install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../../../../src/libmpg123/fmt123.h"
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")

View File

@@ -52,6 +52,7 @@ for my $i (@instances)
my %ident; my %ident;
my @symbols = @{$i->{symbols}}; my @symbols = @{$i->{symbols}};
my $apiex = qr/^$i->{apiprefix}/; my $apiex = qr/^$i->{apiprefix}/;
my $preex = qr/^$i->{prefix}/;
foreach my $header (@{$i->{headers}}) foreach my $header (@{$i->{headers}})
{ {
@@ -62,7 +63,7 @@ for my $i (@instances)
if(/^([^\s\(#][^\(]*)\s\*?([a-z][a-z_0-9]+)\s*\(/) if(/^([^\s\(#][^\(]*)\s\*?([a-z][a-z_0-9]+)\s*\(/)
{ {
# Skip preprocessing/comment stuff and official API. # Skip preprocessing/comment stuff and official API.
unless($1 =~ '^#' or $1 =~ '/[/\*]' or $2 =~ $apiex or $1 =~ /\bstatic\b/) unless($1 =~ '^#' or $1 =~ '/[/\*]' or $2 =~ $apiex or $2 =~ $preex or $1 =~ /\bstatic\b/)
{ {
die "second definition of $2 in $header\n" die "second definition of $2 in $header\n"
if grep {$_ eq $2} @symbols; if grep {$_ eq $2} @symbols;

View File

@@ -6,11 +6,13 @@ include src/libmpg123/Makemodule.am
include src/libout123/Makemodule.am include src/libout123/Makemodule.am
include src/libsyn123/Makemodule.am include src/libsyn123/Makemodule.am
bin_PROGRAMS += src/out123
if HAVE_LFS_WRAP
bin_PROGRAMS += \ bin_PROGRAMS += \
src/mpg123 \ src/mpg123 \
src/out123 \
src/mpg123-id3dump \ src/mpg123-id3dump \
src/mpg123-strip src/mpg123-strip
endif
src_mpg123_LDADD = \ src_mpg123_LDADD = \
src/compat/libcompat.la \ src/compat/libcompat.la \

View File

@@ -161,7 +161,7 @@ void print_buf(const char* prefix, out123_handle *ao)
// This is a massively complicated function just for telling where we are. // This is a massively complicated function just for telling where we are.
// Blame buffering. Blame format conversion. Blame the universe. // Blame buffering. Blame format conversion. Blame the universe.
int position_info( mpg123_handle *fr, long offset, out123_handle *ao int position_info( mpg123_handle *fr, off_t offset, out123_handle *ao
, off_t *frame, off_t *frame_remain , off_t *frame, off_t *frame_remain
, double *seconds, double *seconds_remain, double *seconds_buffered, double *seconds_total ) , double *seconds, double *seconds_remain, double *seconds_buffered, double *seconds_total )
{ {

View File

@@ -4,7 +4,7 @@
The mpg123 code is determined to keep it's legacy. A legacy of old, old UNIX. The mpg123 code is determined to keep it's legacy. A legacy of old, old UNIX.
So anything possibly somewhat advanced should be considered to be put here, with proper #ifdef;-) So anything possibly somewhat advanced should be considered to be put here, with proper #ifdef;-)
copyright 2007-2020 by the mpg123 project - free software under the terms of the LGPL 2.1 copyright 2007-2023 by the mpg123 project - free software under the terms of the LGPL 2.1
see COPYING and AUTHORS files in distribution or http://mpg123.org see COPYING and AUTHORS files in distribution or http://mpg123.org
initially written by Thomas Orgis, Windows Unicode stuff by JonY. initially written by Thomas Orgis, Windows Unicode stuff by JonY.
*/ */

View File

@@ -66,17 +66,33 @@
#define SSIZE_MAX ((size_t)-1/2) #define SSIZE_MAX ((size_t)-1/2)
#endif #endif
#ifndef PTRDIFF_MAX #ifndef PTRDIFF_MAX
#define PTRDIFF_MAX ((size_t)-1/2) #define PTRDIFF_MAX SSIZE_MAX
#endif #endif
#ifndef ULONG_MAX #ifndef ULONG_MAX
#define ULONG_MAX ((unsigned long)-1) #define ULONG_MAX ((unsigned long)-1)
#endif #endif
#ifndef INT64_MAX
#define INT64_MAX 9223372036854775807LL
#endif
#ifndef INT64_MIN
#define INT64_MIN (-INT64_MAX - 1)
#endif
#ifndef INT32_MAX
#define INT32_MAX 2147483647L
#endif
#ifndef INT32_MIN
#define INT32_MIN (-INT32_MAX - 1)
#endif
#ifndef OFF_MAX #ifndef OFF_MAX
#undef OFF_MIN
#if SIZEOF_OFF_T == 4 #if SIZEOF_OFF_T == 4
#define OFF_MAX ((uint32_t)-1/2) #define OFF_MAX INT32_MAX
#define OFF_MIN INT32_MIN
#elif SIZEOF_OFF_T == 8 #elif SIZEOF_OFF_T == 8
#define OFF_MAX ((uint64_t)-1/2) #define OFF_MAX INT64_MAX
#define OFF_MIN INT64_MIN
#else #else
#error "Unexpected width of off_t." #error "Unexpected width of off_t."
#endif #endif
@@ -84,6 +100,7 @@
// Add two values (themselves assumed to be < limit), saturating to given limit. // Add two values (themselves assumed to be < limit), saturating to given limit.
#define SATURATE_ADD(inout, add, limit) inout = (limit-add >= inout) ? inout+add : limit; #define SATURATE_ADD(inout, add, limit) inout = (limit-add >= inout) ? inout+add : limit;
#define SATURATE_SUB(inout, sub, limit) inout = (limit+sub >= inout) ? inout-sub : limit;
#ifdef HAVE_STRING_H #ifdef HAVE_STRING_H
#include <string.h> #include <string.h>

View File

@@ -250,7 +250,6 @@
#define bc_cleanup INT123_bc_cleanup #define bc_cleanup INT123_bc_cleanup
#define bc_poolsize INT123_bc_poolsize #define bc_poolsize INT123_bc_poolsize
#define bc_fill INT123_bc_fill #define bc_fill INT123_bc_fill
#define open_stream INT123_open_stream
#define open_stream_handle INT123_open_stream_handle #define open_stream_handle INT123_open_stream_handle
#define open_feed INT123_open_feed #define open_feed INT123_open_feed
#define feed_more INT123_feed_more #define feed_more INT123_feed_more

View File

@@ -1,7 +1,5 @@
# Module for non-recursive mpg123 build system. # Module for non-recursive mpg123 build system.
EXTRA_DIST += src/libmpg123/mpg123.h.in
EXTRA_PROGRAMS += src/libmpg123/testcpu EXTRA_PROGRAMS += src/libmpg123/testcpu
src_libmpg123_testcpu_DEPENDENCIES = src/libmpg123/getcpuflags.$(OBJEXT) src_libmpg123_testcpu_DEPENDENCIES = src/libmpg123/getcpuflags.$(OBJEXT)
src_libmpg123_testcpu_SOURCES = src/libmpg123/testcpu.c src_libmpg123_testcpu_SOURCES = src/libmpg123/testcpu.c
@@ -21,7 +19,7 @@ src_libmpg123_calctables_LDADD = @LIBM@
#CLEANFILES += src/libmpg123/*.a #CLEANFILES += src/libmpg123/*.a
lib_LTLIBRARIES += src/libmpg123/libmpg123.la lib_LTLIBRARIES += src/libmpg123/libmpg123.la
nodist_include_HEADERS += src/libmpg123/mpg123.h include_HEADERS += src/libmpg123/mpg123.h
include_HEADERS += src/libmpg123/fmt123.h include_HEADERS += src/libmpg123/fmt123.h
src_libmpg123_libmpg123_la_CFLAGS = @LIB_CFLAGS@ src_libmpg123_libmpg123_la_CFLAGS = @LIB_CFLAGS@
@@ -66,6 +64,7 @@ src_libmpg123_libmpg123_la_SOURCES = \
src/libmpg123/optimize.h \ src/libmpg123/optimize.h \
src/libmpg123/optimize.c \ src/libmpg123/optimize.c \
src/libmpg123/readers.c \ src/libmpg123/readers.c \
src/libmpg123/lfs_wrap.h \
src/libmpg123/costabs.h \ src/libmpg123/costabs.h \
src/libmpg123/tabinit.c \ src/libmpg123/tabinit.c \
src/libmpg123/libmpg123.c \ src/libmpg123/libmpg123.c \
@@ -110,7 +109,6 @@ src_libmpg123_libmpg123_la_SOURCES = \
#SYNTH16 synth.c #SYNTH16 synth.c
#SYNTH32 synth_s32.c #SYNTH32 synth_s32.c
#SYNTHREAL synth_real.c #SYNTHREAL synth_real.c
#LFS_ALIAS lfs_alias.c
#LFS_WRAP lfs_wrap.c #LFS_WRAP lfs_wrap.c
#ICY icy.c icy2utf8.c #ICY icy.c icy2utf8.c
#FEATURE feature.c #FEATURE feature.c
@@ -206,10 +204,6 @@ if HAVE_SYNTHREAL
src_libmpg123_libmpg123_la_SOURCES += src/libmpg123/synth_real.c src_libmpg123_libmpg123_la_SOURCES += src/libmpg123/synth_real.c
endif endif
if HAVE_LFS_ALIAS
src_libmpg123_libmpg123_la_SOURCES += src/libmpg123/lfs_alias.c
endif
if HAVE_LFS_WRAP if HAVE_LFS_WRAP
src_libmpg123_libmpg123_la_SOURCES += src/libmpg123/lfs_wrap.c src_libmpg123_libmpg123_la_SOURCES += src/libmpg123/lfs_wrap.c
endif endif

View File

@@ -4,7 +4,7 @@
This file is strongly tied with optimize.h concerning the synth functions. This file is strongly tied with optimize.h concerning the synth functions.
Perhaps one should restructure that a bit. Perhaps one should restructure that a bit.
copyright 2007-8 by the mpg123 project - free software under the terms of the LGPL 2.1 copyright 2007-2023 by the mpg123 project - free software under the terms of the LGPL 2.1
see COPYING and AUTHORS files in distribution or http://mpg123.org see COPYING and AUTHORS files in distribution or http://mpg123.org
initially written by Thomas Orgis, taking WRITE_SAMPLE from decode.c initially written by Thomas Orgis, taking WRITE_SAMPLE from decode.c
*/ */
@@ -30,7 +30,7 @@
#define NTOM_MAX 8 /* maximum allowed factor for upsampling */ #define NTOM_MAX 8 /* maximum allowed factor for upsampling */
#define NTOM_MAX_FREQ 96000 /* maximum frequency to upsample to / downsample from */ #define NTOM_MAX_FREQ 96000 /* maximum frequency to upsample to / downsample from */
#define NTOM_MUL (32768) #define NTOM_MUL (32768)
void ntom_set_ntom(mpg123_handle *fr, off_t num); void ntom_set_ntom(mpg123_handle *fr, int64_t num);
#endif #endif
/* Let's collect all possible synth functions here, for an overview. /* Let's collect all possible synth functions here, for an overview.
@@ -215,18 +215,18 @@ void dct36_neon64 (real *,real *,real *,const real *,real *);
/* Tools for NtoM resampling synth, defined in ntom.c . */ /* Tools for NtoM resampling synth, defined in ntom.c . */
int synth_ntom_set_step(mpg123_handle *fr); /* prepare ntom decoding */ int synth_ntom_set_step(mpg123_handle *fr); /* prepare ntom decoding */
unsigned long ntom_val(mpg123_handle *fr, off_t frame); /* compute ntom_val for frame offset */ unsigned long ntom_val(mpg123_handle *fr, int64_t frame); /* compute ntom_val for frame offset */
/* Frame and sample offsets. */ /* Frame and sample offsets. */
#ifndef NO_NTOM #ifndef NO_NTOM
/* /*
Outsamples of _this_ frame. Outsamples of _this_ frame.
To be exact: The samples to be expected from the next frame decode (using the current ntom_val). When you already decoded _this_ frame, this is the number of samples to be expected from the next one. To be exact: The samples to be expected from the next frame decode (using the current ntom_val). When you already decoded _this_ frame, this is the number of samples to be expected from the next one.
*/ */
off_t ntom_frame_outsamples(mpg123_handle *fr); int64_t ntom_frame_outsamples(mpg123_handle *fr);
/* Total out/insample offset. */ /* Total out/insample offset. */
off_t ntom_frmouts(mpg123_handle *fr, off_t frame); int64_t ntom_frmouts(mpg123_handle *fr, int64_t frame);
off_t ntom_ins2outs(mpg123_handle *fr, off_t ins); int64_t ntom_ins2outs(mpg123_handle *fr, int64_t ins);
off_t ntom_frameoff(mpg123_handle *fr, off_t soff); int64_t ntom_frameoff(mpg123_handle *fr, int64_t soff);
#endif #endif
/* Initialization of any static data that majy be needed at runtime. /* Initialization of any static data that majy be needed at runtime.

View File

@@ -1,7 +1,7 @@
/* /*
format: routines to deal with audio (output) format format: routines to deal with audio (output) format
copyright 2008-20 by the mpg123 project - free software under the terms of the LGPL 2.1 copyright 2008-23 by the mpg123 project - free software under the terms of the LGPL 2.1
see COPYING and AUTHORS files in distribution or http://mpg123.org see COPYING and AUTHORS files in distribution or http://mpg123.org
initially written by Thomas Orgis, starting with parts of the old audio.c, with only faintly manage to show now initially written by Thomas Orgis, starting with parts of the old audio.c, with only faintly manage to show now
@@ -557,25 +557,25 @@ void invalidate_format(struct audioformat *af)
} }
/* Number of bytes the decoder produces. */ /* Number of bytes the decoder produces. */
off_t decoder_synth_bytes(mpg123_handle *fr, off_t s) int64_t decoder_synth_bytes(mpg123_handle *fr, int64_t s)
{ {
return s * fr->af.dec_encsize * fr->af.channels; return s * fr->af.dec_encsize * fr->af.channels;
} }
/* Samples/bytes for output buffer after post-processing. */ /* Samples/bytes for output buffer after post-processing. */
/* take into account: channels, bytes per sample -- NOT resampling!*/ /* take into account: channels, bytes per sample -- NOT resampling!*/
off_t samples_to_bytes(mpg123_handle *fr , off_t s) int64_t samples_to_bytes(mpg123_handle *fr , int64_t s)
{ {
return s * fr->af.encsize * fr->af.channels; return s * fr->af.encsize * fr->af.channels;
} }
off_t bytes_to_samples(mpg123_handle *fr , off_t b) int64_t bytes_to_samples(mpg123_handle *fr , int64_t b)
{ {
return b / fr->af.encsize / fr->af.channels; return b / fr->af.encsize / fr->af.channels;
} }
/* Number of bytes needed for decoding _and_ post-processing. */ /* Number of bytes needed for decoding _and_ post-processing. */
off_t outblock_bytes(mpg123_handle *fr, off_t s) int64_t outblock_bytes(mpg123_handle *fr, int64_t s)
{ {
int encsize = (fr->af.encoding & MPG123_ENC_24) int encsize = (fr->af.encoding & MPG123_ENC_24)
? 4 /* Intermediate 32 bit. */ ? 4 /* Intermediate 32 bit. */

View File

@@ -1,7 +1,7 @@
/* /*
frame: Heap of routines dealing with the core mpg123 data structure. frame: Heap of routines dealing with the core mpg123 data structure.
copyright 2008-2021 by the mpg123 project - free software under the terms of the LGPL 2.1 copyright 2008-2023 by the mpg123 project - free software under the terms of the LGPL 2.1
see COPYING and AUTHORS files in distribution or http://mpg123.org see COPYING and AUTHORS files in distribution or http://mpg123.org
initially written by Thomas Orgis initially written by Thomas Orgis
*/ */
@@ -114,14 +114,11 @@ void frame_init_par(mpg123_handle *fr, mpg123_pars *mp)
/* frame_buffers is missing... that one needs cpu opt setting! */ /* frame_buffers is missing... that one needs cpu opt setting! */
/* after these... frame_reset is needed before starting full decode */ /* after these... frame_reset is needed before starting full decode */
invalidate_format(&fr->af); invalidate_format(&fr->af);
fr->rdat.r_read = NULL;
fr->rdat.r_lseek = NULL;
fr->rdat.iohandle = NULL; fr->rdat.iohandle = NULL;
fr->rdat.r_read_handle = NULL; fr->rdat.r_read64 = NULL;
fr->rdat.r_lseek_handle = NULL; fr->rdat.r_lseek64 = NULL;
fr->rdat.cleanup_handle = NULL; fr->rdat.cleanup_handle = NULL;
fr->wrapperdata = NULL; fr->wrapperdata = NULL;
fr->wrapperclean = NULL;
fr->decoder_change = 1; fr->decoder_change = 1;
fr->err = MPG123_OK; fr->err = MPG123_OK;
if(mp == NULL) frame_default_pars(&fr->p); if(mp == NULL) frame_default_pars(&fr->p);
@@ -619,12 +616,6 @@ void frame_exit(mpg123_handle *fr)
#endif #endif
exit_id3(fr); exit_id3(fr);
clear_icy(&fr->icy); clear_icy(&fr->icy);
/* Clean up possible mess from LFS wrapper. */
if(fr->wrapperclean != NULL)
{
fr->wrapperclean(fr->wrapperdata);
fr->wrapperdata = NULL;
}
#ifndef NO_FEEDER #ifndef NO_FEEDER
bc_cleanup(&fr->rdat.buffer); bc_cleanup(&fr->rdat.buffer);
#endif #endif
@@ -662,10 +653,10 @@ int attribute_align_arg mpg123_set_moreinfo( mpg123_handle *mh
- guess wildly from mean framesize and offset of first frame / beginning of file. - guess wildly from mean framesize and offset of first frame / beginning of file.
*/ */
static off_t frame_fuzzy_find(mpg123_handle *fr, off_t want_frame, off_t* get_frame) static int64_t frame_fuzzy_find(mpg123_handle *fr, int64_t want_frame, int64_t* get_frame)
{ {
/* Default is to go to the beginning. */ /* Default is to go to the beginning. */
off_t ret = fr->audio_start; int64_t ret = fr->audio_start;
*get_frame = 0; *get_frame = 0;
/* But we try to find something better. */ /* But we try to find something better. */
@@ -681,12 +672,12 @@ static off_t frame_fuzzy_find(mpg123_handle *fr, off_t want_frame, off_t* get_fr
if(toc_entry > 99) toc_entry = 99; if(toc_entry > 99) toc_entry = 99;
/* Now estimate back what frame we get. */ /* Now estimate back what frame we get. */
*get_frame = (off_t) ((double)toc_entry/100. * fr->track_frames); *get_frame = (int64_t) ((double)toc_entry/100. * fr->track_frames);
fr->state_flags &= ~FRAME_ACCURATE; fr->state_flags &= ~FRAME_ACCURATE;
fr->silent_resync = 1; fr->silent_resync = 1;
/* Question: Is the TOC for whole file size (with/without ID3) or the "real" audio data only? /* Question: Is the TOC for whole file size (with/without ID3) or the "real" audio data only?
ID3v1 info could also matter. */ ID3v1 info could also matter. */
ret = (off_t) ((double)fr->xing_toc[toc_entry]/256.* fr->rdat.filelen); ret = (int64_t) ((double)fr->xing_toc[toc_entry]/256.* fr->rdat.filelen);
} }
else if(fr->mean_framesize > 0) else if(fr->mean_framesize > 0)
{ /* Just guess with mean framesize (may be exact with CBR files). */ { /* Just guess with mean framesize (may be exact with CBR files). */
@@ -694,10 +685,12 @@ static off_t frame_fuzzy_find(mpg123_handle *fr, off_t want_frame, off_t* get_fr
fr->state_flags &= ~FRAME_ACCURATE; /* Fuzzy! */ fr->state_flags &= ~FRAME_ACCURATE; /* Fuzzy! */
fr->silent_resync = 1; fr->silent_resync = 1;
*get_frame = want_frame; *get_frame = want_frame;
ret = (off_t) (fr->audio_start+fr->mean_framesize*want_frame); ret = (int64_t) (fr->audio_start+fr->mean_framesize*want_frame);
} }
debug5("fuzzy: want %li of %li, get %li at %li B of %li B", debug5("fuzzy: want %" PRIi64 " of %" PRIi64
(long)want_frame, (long)fr->track_frames, (long)*get_frame, (long)ret, (long)(fr->rdat.filelen-fr->audio_start)); ", get %" PRIi64 " at %" PRIi64 " B of %" PRIi64 " B"
, want_frame, fr->track_frames, *get_frame, ret
, (fr->rdat.filelen-fr->audio_start));
return ret; return ret;
} }
@@ -710,10 +703,10 @@ static off_t frame_fuzzy_find(mpg123_handle *fr, off_t want_frame, off_t* get_fr
Decide if you want low latency reaction and accurate timing info or stable long-time playback with buffer! Decide if you want low latency reaction and accurate timing info or stable long-time playback with buffer!
*/ */
off_t frame_index_find(mpg123_handle *fr, off_t want_frame, off_t* get_frame) int64_t frame_index_find(mpg123_handle *fr, int64_t want_frame, int64_t* get_frame)
{ {
/* default is file start if no index position */ /* default is file start if no index position */
off_t gopos = 0; int64_t gopos = 0;
*get_frame = 0; *get_frame = 0;
#ifdef FRAME_INDEX #ifdef FRAME_INDEX
/* Possibly use VBRI index, too? I'd need an example for this... */ /* Possibly use VBRI index, too? I'd need an example for this... */
@@ -751,13 +744,13 @@ off_t frame_index_find(mpg123_handle *fr, off_t want_frame, off_t* get_frame)
#ifdef FRAME_INDEX #ifdef FRAME_INDEX
} }
#endif #endif
debug2("index: 0x%lx for frame %li", (unsigned long)gopos, (long) *get_frame); debug2("index: 0x%" PRIx64 " for frame %" PRIi64, (uint64_t)gopos, *get_frame);
return gopos; return gopos;
} }
off_t frame_ins2outs(mpg123_handle *fr, off_t ins) int64_t frame_ins2outs(mpg123_handle *fr, int64_t ins)
{ {
off_t outs = 0; int64_t outs = 0;
switch(fr->down_sample) switch(fr->down_sample)
{ {
case 0: case 0:
@@ -777,9 +770,9 @@ off_t frame_ins2outs(mpg123_handle *fr, off_t ins)
return outs; return outs;
} }
off_t frame_outs(mpg123_handle *fr, off_t num) int64_t frame_outs(mpg123_handle *fr, int64_t num)
{ {
off_t outs = 0; int64_t outs = 0;
switch(fr->down_sample) switch(fr->down_sample)
{ {
case 0: case 0:
@@ -801,9 +794,9 @@ off_t frame_outs(mpg123_handle *fr, off_t num)
/* Compute the number of output samples we expect from this frame. /* Compute the number of output samples we expect from this frame.
This is either simple spf() or a tad more elaborate for ntom. */ This is either simple spf() or a tad more elaborate for ntom. */
off_t frame_expect_outsamples(mpg123_handle *fr) int64_t frame_expect_outsamples(mpg123_handle *fr)
{ {
off_t outs = 0; int64_t outs = 0;
switch(fr->down_sample) switch(fr->down_sample)
{ {
case 0: case 0:
@@ -823,9 +816,9 @@ off_t frame_expect_outsamples(mpg123_handle *fr)
return outs; return outs;
} }
off_t frame_offset(mpg123_handle *fr, off_t outs) int64_t frame_offset(mpg123_handle *fr, int64_t outs)
{ {
off_t num = 0; int64_t num = 0;
switch(fr->down_sample) switch(fr->down_sample)
{ {
case 0: case 0:
@@ -846,9 +839,9 @@ off_t frame_offset(mpg123_handle *fr, off_t outs)
#ifdef GAPLESS #ifdef GAPLESS
/* input in _input_ samples */ /* input in _input_ samples */
void frame_gapless_init(mpg123_handle *fr, off_t framecount, off_t bskip, off_t eskip) void frame_gapless_init(mpg123_handle *fr, int64_t framecount, int64_t bskip, int64_t eskip)
{ {
debug3("frame_gapless_init: given %"OFF_P" frames, skip %"OFF_P" and %"OFF_P, (off_p)framecount, (off_p)bskip, (off_p)eskip); debug3("frame_gapless_init: given %"PRIi64" frames, skip %"PRIi64" and %"PRIi64, framecount, bskip, eskip);
fr->gapless_frames = framecount; fr->gapless_frames = framecount;
if(fr->gapless_frames > 0 && bskip >=0 && eskip >= 0) if(fr->gapless_frames > 0 && bskip >=0 && eskip >= 0)
{ {
@@ -860,7 +853,7 @@ void frame_gapless_init(mpg123_handle *fr, off_t framecount, off_t bskip, off_t
fr->begin_os = 0; fr->begin_os = 0;
fr->end_os = 0; fr->end_os = 0;
fr->fullend_os = 0; fr->fullend_os = 0;
debug2("frame_gapless_init: from %"OFF_P" to %"OFF_P" samples", (off_p)fr->begin_s, (off_p)fr->end_s); debug2("frame_gapless_init: from %"PRIi64" to %"PRIi64" samples", fr->begin_s, fr->end_s);
} }
void frame_gapless_realinit(mpg123_handle *fr) void frame_gapless_realinit(mpg123_handle *fr)
@@ -871,26 +864,28 @@ void frame_gapless_realinit(mpg123_handle *fr)
fr->fullend_os = frame_ins2outs(fr, fr->gapless_frames*fr->spf); fr->fullend_os = frame_ins2outs(fr, fr->gapless_frames*fr->spf);
else fr->fullend_os = 0; else fr->fullend_os = 0;
debug4("frame_gapless_realinit: from %"OFF_P" to %"OFF_P" samples (%"OFF_P", %"OFF_P")", (off_p)fr->begin_os, (off_p)fr->end_os, (off_p)fr->fullend_os, (off_p)fr->gapless_frames); debug4("frame_gapless_realinit: from %"PRIi64" to %"PRIi64" samples (%"PRIi64", %"PRIi64")"
, fr->begin_os, fr->end_os, fr->fullend_os, fr->gapless_frames);
} }
/* At least note when there is trouble... */ /* At least note when there is trouble... */
void frame_gapless_update(mpg123_handle *fr, off_t total_samples) void frame_gapless_update(mpg123_handle *fr, int64_t total_samples)
{ {
off_t gapless_samples = fr->gapless_frames*fr->spf; int64_t gapless_samples = fr->gapless_frames*fr->spf;
if(fr->gapless_frames < 1) return; if(fr->gapless_frames < 1) return;
debug2("gapless update with new sample count %"OFF_P" as opposed to known %"OFF_P, (off_p)total_samples, (off_p)gapless_samples); debug2("gapless update with new sample count %"PRIi64" as opposed to known %"PRIi64, total_samples, gapless_samples);
if(NOQUIET && total_samples != gapless_samples) if(NOQUIET && total_samples != gapless_samples)
fprintf(stderr, "\nWarning: Real sample count %"OFF_P" differs from given gapless sample count %"OFF_P". Frankenstein stream?\n" fprintf(stderr, "\nWarning: Real sample count %" PRIi64
, (off_p)total_samples, (off_p)gapless_samples); " differs from given gapless sample count %" PRIi64
". Frankenstein stream?\n", total_samples, gapless_samples);
if(gapless_samples > total_samples) if(gapless_samples > total_samples)
{ {
if(NOQUIET) if(NOQUIET)
merror( "End sample count smaller than gapless end! (%"OFF_P merror( "End sample count smaller than gapless end! (%" PRIi64
" < %"OFF_P"). Disabling gapless mode from now on." " < %"PRIi64"). Disabling gapless mode from now on."
, (off_p)total_samples, (off_p)fr->end_s ); , total_samples, fr->end_s );
/* This invalidates the current position... but what should I do? */ /* This invalidates the current position... but what should I do? */
frame_gapless_init(fr, -1, 0, 0); frame_gapless_init(fr, -1, 0, 0);
frame_gapless_realinit(fr); frame_gapless_realinit(fr);
@@ -902,9 +897,9 @@ void frame_gapless_update(mpg123_handle *fr, off_t total_samples)
#endif #endif
/* Compute the needed frame to ignore from, for getting accurate/consistent output for intended firstframe. */ /* Compute the needed frame to ignore from, for getting accurate/consistent output for intended firstframe. */
static off_t ignoreframe(mpg123_handle *fr) static int64_t ignoreframe(mpg123_handle *fr)
{ {
off_t preshift = fr->p.preframes; int64_t preshift = fr->p.preframes;
/* Layer 3 _really_ needs at least one frame before. */ /* Layer 3 _really_ needs at least one frame before. */
if(fr->lay==3 && preshift < 1) preshift = 1; if(fr->lay==3 && preshift < 1) preshift = 1;
/* Layer 1 & 2 reall do not need more than 2. */ /* Layer 1 & 2 reall do not need more than 2. */
@@ -917,14 +912,14 @@ static off_t ignoreframe(mpg123_handle *fr)
Seek to frame offset 1 may be just seek to 200 samples offset in output since the beginning of first frame is delay/padding. Seek to frame offset 1 may be just seek to 200 samples offset in output since the beginning of first frame is delay/padding.
Hm, is that right? OK for the padding stuff, but actually, should the decoder delay be better totally hidden or not? Hm, is that right? OK for the padding stuff, but actually, should the decoder delay be better totally hidden or not?
With gapless, even the whole frame position could be advanced further than requested (since Homey don't play dat). */ With gapless, even the whole frame position could be advanced further than requested (since Homey don't play dat). */
void frame_set_frameseek(mpg123_handle *fr, off_t fe) void frame_set_frameseek(mpg123_handle *fr, int64_t fe)
{ {
fr->firstframe = fe; fr->firstframe = fe;
#ifdef GAPLESS #ifdef GAPLESS
if(fr->p.flags & MPG123_GAPLESS && fr->gapless_frames > 0) if(fr->p.flags & MPG123_GAPLESS && fr->gapless_frames > 0)
{ {
/* Take care of the beginning... */ /* Take care of the beginning... */
off_t beg_f = frame_offset(fr, fr->begin_os); int64_t beg_f = frame_offset(fr, fr->begin_os);
if(fe <= beg_f) if(fe <= beg_f)
{ {
fr->firstframe = beg_f; fr->firstframe = beg_f;
@@ -941,12 +936,14 @@ void frame_set_frameseek(mpg123_handle *fr, off_t fe)
#endif #endif
fr->ignoreframe = ignoreframe(fr); fr->ignoreframe = ignoreframe(fr);
#ifdef GAPLESS #ifdef GAPLESS
debug5("frame_set_frameseek: begin at %li frames and %li samples, end at %li and %li; ignore from %li", debug5("frame_set_frameseek: begin at %" PRIi64 " frames and %" PRIi64
(long) fr->firstframe, (long) fr->firstoff, " samples, end at %" PRIi64 " and %" PRIi64 "; ignore from %" PRIi64,
(long) fr->lastframe, (long) fr->lastoff, (long) fr->ignoreframe); fr->firstframe, fr->firstoff
, fr->lastframe, fr->lastoff, fr->ignoreframe);
#else #else
debug3("frame_set_frameseek: begin at %li frames, end at %li; ignore from %li", debug3("frame_set_frameseek: begin at %" PRIi64 " frames, end at %" PRIi64
(long) fr->firstframe, (long) fr->lastframe, (long) fr->ignoreframe); "; ignore from %" PRIi64
, fr->firstframe, fr->lastframe, fr->ignoreframe);
#endif #endif
} }
@@ -959,22 +956,24 @@ void frame_skip(mpg123_handle *fr)
/* Sample accurate seek prepare for decoder. */ /* Sample accurate seek prepare for decoder. */
/* This gets unadjusted output samples and takes resampling into account */ /* This gets unadjusted output samples and takes resampling into account */
void frame_set_seek(mpg123_handle *fr, off_t sp) void frame_set_seek(mpg123_handle *fr, int64_t sp)
{ {
fr->firstframe = frame_offset(fr, sp); fr->firstframe = frame_offset(fr, sp);
debug1("frame_set_seek: from %"OFF_P, fr->num); debug1("frame_set_seek: from %" PRIi64, fr->num);
#ifndef NO_NTOM #ifndef NO_NTOM
if(fr->down_sample == 3) ntom_set_ntom(fr, fr->firstframe); if(fr->down_sample == 3) ntom_set_ntom(fr, fr->firstframe);
#endif #endif
fr->ignoreframe = ignoreframe(fr); fr->ignoreframe = ignoreframe(fr);
#ifdef GAPLESS /* The sample offset is used for non-gapless mode, too! */ #ifdef GAPLESS /* The sample offset is used for non-gapless mode, too! */
fr->firstoff = sp - frame_outs(fr, fr->firstframe); fr->firstoff = sp - frame_outs(fr, fr->firstframe);
debug5("frame_set_seek: begin at %li frames and %li samples, end at %li and %li; ignore from %li", debug5("frame_set_seek: begin at %" PRIi64 " frames and %" PRIi64
(long) fr->firstframe, (long) fr->firstoff, " samples, end at %" PRIi64 " and %" PRIi64 "; ignore from %" PRIi64,
(long) fr->lastframe, (long) fr->lastoff, (long) fr->ignoreframe); fr->firstframe, fr->firstoff
, fr->lastframe, fr->lastoff, fr->ignoreframe);
#else #else
debug3("frame_set_seek: begin at %li frames, end at %li; ignore from %li", debug3("frame_set_seek: begin at %" PRIi64 " frames, end at %" PRIi64
(long) fr->firstframe, (long) fr->lastframe, (long) fr->ignoreframe); "; ignore from %" PRIi64
, fr->firstframe, fr->lastframe, fr->ignoreframe);
#endif #endif
} }
@@ -1064,7 +1063,7 @@ int attribute_align_arg mpg123_getvolume(mpg123_handle *mh, double *base, double
return MPG123_OK; return MPG123_OK;
} }
off_t attribute_align_arg mpg123_framepos(mpg123_handle *mh) int64_t attribute_align_arg mpg123_framepos64(mpg123_handle *mh)
{ {
if(mh == NULL) return MPG123_ERR; if(mh == NULL) return MPG123_ERR;

View File

@@ -1,7 +1,7 @@
/* /*
frame: Central data structures and opmitization hooks. frame: Central data structures and opmitization hooks.
copyright 2007 by the mpg123 project - free software under the terms of the LGPL 2.1 copyright 2007-2023 by the mpg123 project - free software under the terms of the LGPL 2.1
see COPYING and AUTHORS files in distribution or http://mpg123.org see COPYING and AUTHORS files in distribution or http://mpg123.org
initially written by Thomas Orgis initially written by Thomas Orgis
*/ */
@@ -220,10 +220,10 @@ struct mpg123_handle_struct
int framesize; /* computed framesize */ int framesize; /* computed framesize */
int freesize; /* free format frame size */ int freesize; /* free format frame size */
enum mpg123_vbr vbr; /* 1 if variable bitrate was detected */ enum mpg123_vbr vbr; /* 1 if variable bitrate was detected */
off_t num; /* frame offset ... */ int64_t num; /* frame offset ... */
off_t input_offset; /* byte offset of this frame in input stream */ int64_t input_offset; /* byte offset of this frame in input stream */
off_t playnum; /* playback offset... includes repetitions, reset at seeks */ int64_t playnum; /* playback offset... includes repetitions, reset at seeks */
off_t audio_start; /* The byte offset in the file where audio data begins. */ int64_t audio_start; /* The byte offset in the file where audio data begins. */
int state_flags; int state_flags;
char silent_resync; /* Do not complain for the next n resyncs. */ char silent_resync; /* Do not complain for the next n resyncs. */
unsigned char* xing_toc; /* The seek TOC from Xing header. */ unsigned char* xing_toc; /* The seek TOC from Xing header. */
@@ -250,10 +250,10 @@ struct mpg123_handle_struct
} rva; } rva;
/* input data */ /* input data */
off_t track_frames; int64_t track_frames;
off_t track_samples; int64_t track_samples;
double mean_framesize; double mean_framesize;
off_t mean_frames; int64_t mean_frames;
int fsizeold; int fsizeold;
int ssize; int ssize;
unsigned int bitreservoir; unsigned int bitreservoir;
@@ -277,18 +277,18 @@ struct mpg123_handle_struct
size_t outblock; /* number of bytes that this frame produces (upper bound) */ size_t outblock; /* number of bytes that this frame produces (upper bound) */
int to_decode; /* this frame holds data to be decoded */ int to_decode; /* this frame holds data to be decoded */
int to_ignore; /* the same, somehow */ int to_ignore; /* the same, somehow */
off_t firstframe; /* start decoding from here */ int64_t firstframe; /* start decoding from here */
off_t lastframe; /* last frame to decode (for gapless or num_frames limit) */ int64_t lastframe; /* last frame to decode (for gapless or num_frames limit) */
off_t ignoreframe; /* frames to decode but discard before firstframe */ int64_t ignoreframe; /* frames to decode but discard before firstframe */
#ifdef GAPLESS #ifdef GAPLESS
off_t gapless_frames; /* frame count for the gapless part */ int64_t gapless_frames; /* frame count for the gapless part */
off_t firstoff; /* number of samples to ignore from firstframe */ int64_t firstoff; /* number of samples to ignore from firstframe */
off_t lastoff; /* number of samples to use from lastframe */ int64_t lastoff; /* number of samples to use from lastframe */
off_t begin_s; /* overall begin offset in samples */ int64_t begin_s; /* overall begin offset in samples */
off_t begin_os; int64_t begin_os;
off_t end_s; /* overall end offset in samples */ int64_t end_s; /* overall end offset in samples */
off_t end_os; int64_t end_os;
off_t fullend_os; /* gapless_frames translated to output samples */ int64_t fullend_os; /* gapless_frames translated to output samples */
#endif #endif
unsigned int crc; /* Well, I need a safe 16bit type, actually. But wider doesn't hurt. */ unsigned int crc; /* Well, I need a safe 16bit type, actually. But wider doesn't hurt. */
struct reader *rd; /* pointer to the reading functions */ struct reader *rd; /* pointer to the reading functions */
@@ -342,8 +342,6 @@ struct mpg123_handle_struct
/* A place for storing additional data for the large file wrapper. /* A place for storing additional data for the large file wrapper.
This is cruft! */ This is cruft! */
void *wrapperdata; void *wrapperdata;
/* A callback used to properly destruct the wrapper data. */
void (*wrapperclean)(void*);
int enc_delay; int enc_delay;
int enc_padding; int enc_padding;
#ifndef NO_MOREINFO #ifndef NO_MOREINFO
@@ -367,7 +365,7 @@ void frame_exit(mpg123_handle *fr); /* end, free all buffers */
/* Well... print it... */ /* Well... print it... */
int mpg123_print_index(mpg123_handle *fr, FILE* out); int mpg123_print_index(mpg123_handle *fr, FILE* out);
/* Find a seek position in index. */ /* Find a seek position in index. */
off_t frame_index_find(mpg123_handle *fr, off_t want_frame, off_t* get_frame); int64_t frame_index_find(mpg123_handle *fr, int64_t want_frame, int64_t* get_frame);
/* Apply index_size setting. */ /* Apply index_size setting. */
int frame_index_setup(mpg123_handle *fr); int frame_index_setup(mpg123_handle *fr);
@@ -396,17 +394,17 @@ MPEG 2.5
// The value is needed for mpg123_getstate() in any build. // The value is needed for mpg123_getstate() in any build.
#define GAPLESS_DELAY 529 #define GAPLESS_DELAY 529
#ifdef GAPLESS #ifdef GAPLESS
void frame_gapless_init(mpg123_handle *fr, off_t framecount, off_t bskip, off_t eskip); void frame_gapless_init(mpg123_handle *fr, int64_t framecount, int64_t bskip, int64_t eskip);
void frame_gapless_realinit(mpg123_handle *fr); void frame_gapless_realinit(mpg123_handle *fr);
void frame_gapless_update(mpg123_handle *mh, off_t total_samples); void frame_gapless_update(mpg123_handle *mh, int64_t total_samples);
/*void frame_gapless_position(mpg123_handle* fr); /*void frame_gapless_position(mpg123_handle* fr);
void frame_gapless_bytify(mpg123_handle *fr); void frame_gapless_bytify(mpg123_handle *fr);
void frame_gapless_ignore(mpg123_handle *fr, off_t frames);*/ void frame_gapless_ignore(mpg123_handle *fr, int64_t frames);*/
/* void frame_gapless_buffercheck(mpg123_handle *fr); */ /* void frame_gapless_buffercheck(mpg123_handle *fr); */
#endif #endif
/* Number of samples the decoding of the current frame should yield. */ /* Number of samples the decoding of the current frame should yield. */
off_t frame_expect_outsamples(mpg123_handle *fr); int64_t frame_expect_outsamples(mpg123_handle *fr);
/* Skip this frame... do some fake action to get away without actually decoding it. */ /* Skip this frame... do some fake action to get away without actually decoding it. */
void frame_skip(mpg123_handle *fr); void frame_skip(mpg123_handle *fr);
@@ -418,14 +416,14 @@ void frame_skip(mpg123_handle *fr);
- get leading frame offset for output sample offset - get leading frame offset for output sample offset
The offsets are "unadjusted"/internal; resampling is being taken care of. The offsets are "unadjusted"/internal; resampling is being taken care of.
*/ */
off_t frame_ins2outs(mpg123_handle *fr, off_t ins); int64_t frame_ins2outs(mpg123_handle *fr, int64_t ins);
off_t frame_outs(mpg123_handle *fr, off_t num); int64_t frame_outs(mpg123_handle *fr, int64_t num);
/* This one just computes the expected sample count for _this_ frame. */ /* This one just computes the expected sample count for _this_ frame. */
off_t frame_expect_outsampels(mpg123_handle *fr); int64_t frame_expect_outsampels(mpg123_handle *fr);
off_t frame_offset(mpg123_handle *fr, off_t outs); int64_t frame_offset(mpg123_handle *fr, int64_t outs);
void frame_set_frameseek(mpg123_handle *fr, off_t fe); void frame_set_frameseek(mpg123_handle *fr, int64_t fe);
void frame_set_seek(mpg123_handle *fr, off_t sp); void frame_set_seek(mpg123_handle *fr, int64_t sp);
off_t frame_tell_seek(mpg123_handle *fr); int64_t frame_tell_seek(mpg123_handle *fr);
/* Take a copy of the Xing VBR TOC for fuzzy seeking. */ /* Take a copy of the Xing VBR TOC for fuzzy seeking. */
int frame_fill_toc(mpg123_handle *fr, unsigned char* in); int frame_fill_toc(mpg123_handle *fr, unsigned char* in);
#endif #endif

View File

@@ -1,7 +1,7 @@
/* /*
sampleadjust: gapless sample offset math sampleadjust: gapless sample offset math
copyright 1995-2012 by the mpg123 project - free software under the terms of the LGPL 2.1 copyright 1995-2023 by the mpg123 project - free software under the terms of the LGPL 2.1
see COPYING and AUTHORS files in distribution or http://mpg123.org see COPYING and AUTHORS files in distribution or http://mpg123.org
This is no stand-alone header, precisely to be able to fool it into using fake handle types for testing the math. This is no stand-alone header, precisely to be able to fool it into using fake handle types for testing the math.
@@ -11,9 +11,9 @@
#ifdef GAPLESS #ifdef GAPLESS
/* From internal sample number to external. */ /* From internal sample number to external. */
static off_t sample_adjust(mpg123_handle *mh, off_t x) static int64_t sample_adjust(mpg123_handle *mh, int64_t x)
{ {
off_t s; int64_t s;
if(mh->p.flags & MPG123_GAPLESS) if(mh->p.flags & MPG123_GAPLESS)
{ {
/* It's a bit tricky to do this computation for the padding samples. /* It's a bit tricky to do this computation for the padding samples.
@@ -35,9 +35,9 @@ static off_t sample_adjust(mpg123_handle *mh, off_t x)
} }
/* from external samples to internal */ /* from external samples to internal */
static off_t sample_unadjust(mpg123_handle *mh, off_t x) static int64_t sample_unadjust(mpg123_handle *mh, int64_t x)
{ {
off_t s; int64_t s;
if(mh->p.flags & MPG123_GAPLESS) if(mh->p.flags & MPG123_GAPLESS)
{ {
s = x + mh->begin_os; s = x + mh->begin_os;
@@ -74,24 +74,29 @@ static void frame_buffercheck(mpg123_handle *fr)
if(fr->lastframe > -1 && fr->num >= fr->lastframe) if(fr->lastframe > -1 && fr->num >= fr->lastframe)
{ {
/* There can be more than one frame of padding at the end, so we ignore the whole frame if we are beyond lastframe. */ /* There can be more than one frame of padding at the end, so we ignore the whole frame if we are beyond lastframe. */
off_t byteoff = (fr->num == fr->lastframe) ? samples_to_bytes(fr, fr->lastoff) : 0; int64_t byteoff = (fr->num == fr->lastframe) ? samples_to_bytes(fr, fr->lastoff) : 0;
if((off_t)fr->buffer.fill > byteoff) if((int64_t)fr->buffer.fill > byteoff)
{ {
fr->buffer.fill = byteoff; fr->buffer.fill = byteoff;
} }
if(VERBOSE3) fprintf(stderr, "\nNote: Cut frame %"OFF_P" buffer on end of stream to %"OFF_P" samples, fill now %"SIZE_P" bytes.\n", (off_p)fr->num, (off_p)(fr->num == fr->lastframe ? fr->lastoff : 0), (size_p)fr->buffer.fill); if(VERBOSE3)
fprintf(stderr, "\nNote: Cut frame %" PRIi64 " buffer on end of stream to %"
PRIi64 " samples, fill now %"SIZE_P" bytes.\n"
, fr->num, (fr->num == fr->lastframe ? fr->lastoff : 0), (size_p)fr->buffer.fill);
} }
/* The first interesting frame: Skip some leading samples. */ /* The first interesting frame: Skip some leading samples. */
if(fr->firstoff && fr->num == fr->firstframe) if(fr->firstoff && fr->num == fr->firstframe)
{ {
off_t byteoff = samples_to_bytes(fr, fr->firstoff); int64_t byteoff = samples_to_bytes(fr, fr->firstoff);
if((off_t)fr->buffer.fill > byteoff) if((int64_t)fr->buffer.fill > byteoff)
{ {
fr->buffer.fill -= byteoff; fr->buffer.fill -= byteoff;
/* buffer.p != buffer.data only for own buffer */ /* buffer.p != buffer.data only for own buffer */
debug6("cutting %li samples/%li bytes on begin, own_buffer=%i at %p=%p, buf[1]=%i", debug6("cutting %" PRIi64 " samples/%" PRIi64
(long)fr->firstoff, (long)byteoff, fr->own_buffer, (void*)fr->buffer.p, (void*)fr->buffer.data, ((short*)fr->buffer.p)[2]); " bytes on begin, own_buffer=%i at %p=%p, buf[1]=%i"
, fr->firstoff, byteoff, fr->own_buffer
, (void*)fr->buffer.p, (void*)fr->buffer.data, ((short*)fr->buffer.p)[2]);
if(fr->own_buffer) fr->buffer.p = fr->buffer.data + byteoff; if(fr->own_buffer) fr->buffer.p = fr->buffer.data + byteoff;
else memmove(fr->buffer.data, fr->buffer.data + byteoff, fr->buffer.fill); else memmove(fr->buffer.data, fr->buffer.data + byteoff, fr->buffer.fill);
debug3("done cutting, buffer at %p =? %p, buf[1]=%i", debug3("done cutting, buffer at %p =? %p, buf[1]=%i",
@@ -99,7 +104,10 @@ static void frame_buffercheck(mpg123_handle *fr)
} }
else fr->buffer.fill = 0; else fr->buffer.fill = 0;
if(VERBOSE3) fprintf(stderr, "\nNote: Cut frame %"OFF_P" buffer on beginning of stream by %"OFF_P" samples, fill now %"SIZE_P" bytes.\n", (off_p)fr->num, (off_p)fr->firstoff, (size_p)fr->buffer.fill); if(VERBOSE3)
fprintf(stderr, "\nNote: Cut frame %" PRIi64
" buffer on beginning of stream by %" PRIi64 " samples, fill now %zu bytes.\n"
, fr->num, fr->firstoff, fr->buffer.fill);
/* We can only reach this frame again by seeking. And on seeking, firstoff will be recomputed. /* We can only reach this frame again by seeking. And on seeking, firstoff will be recomputed.
So it is safe to null it here (and it makes the if() decision abort earlier). */ So it is safe to null it here (and it makes the if() decision abort earlier). */
fr->firstoff = 0; fr->firstoff = 0;

View File

@@ -1,7 +1,7 @@
/* /*
icy: support for SHOUTcast ICY meta info, an attempt to keep it organized icy: support for SHOUTcast ICY meta info, an attempt to keep it organized
copyright 2006-7 by the mpg123 project - free software under the terms of the LGPL 2.1 copyright 2006-2023 by the mpg123 project - free software under the terms of the LGPL 2.1
see COPYING and AUTHORS files in distribution or http://mpg123.org see COPYING and AUTHORS files in distribution or http://mpg123.org
initially written by Thomas Orgis and modelled after patch by Honza initially written by Thomas Orgis and modelled after patch by Honza
*/ */
@@ -16,8 +16,8 @@
struct icy_meta struct icy_meta
{ {
char* data; char* data;
off_t interval; int64_t interval;
off_t next; int64_t next;
}; };
void init_icy(struct icy_meta *); void init_icy(struct icy_meta *);

View File

@@ -1,7 +1,7 @@
/* /*
id3: ID3v2.3 and ID3v2.4 parsing (a relevant subset) id3: ID3v2.3 and ID3v2.4 parsing (a relevant subset)
copyright 2006-2020 by the mpg123 project - free software under the terms of the LGPL 2.1 copyright 2006-2023 by the mpg123 project - free software under the terms of the LGPL 2.1
see COPYING and AUTHORS files in distribution or http://mpg123.org see COPYING and AUTHORS files in distribution or http://mpg123.org
initially written by Thomas Orgis initially written by Thomas Orgis
@@ -798,7 +798,7 @@ int store_id3v2( mpg123_handle *fr
, unsigned long first4bytes, unsigned char buf[6], unsigned long length ) , unsigned long first4bytes, unsigned char buf[6], unsigned long length )
{ {
int ret = 1; int ret = 1;
off_t ret2; int64_t ret2;
unsigned long fullen = 10+length; unsigned long fullen = 10+length;
if(fr->id3v2_raw) if(fr->id3v2_raw)
free(fr->id3v2_raw); free(fr->id3v2_raw);
@@ -858,7 +858,7 @@ int parse_new_id3(mpg123_handle *fr, unsigned long first4bytes)
unsigned long length=0; unsigned long length=0;
unsigned char flags = 0; unsigned char flags = 0;
int ret = 1; int ret = 1;
off_t ret2; int64_t ret2;
int storetag = 0; int storetag = 0;
unsigned int footlen = 0; unsigned int footlen = 0;
#ifndef NO_ID3V2 #ifndef NO_ID3V2

View File

@@ -1,7 +1,7 @@
/* /*
index: frame index data structure and functions index: frame index data structure and functions
copyright 2007-2020 by the mpg123 project copyright 2007-2023 by the mpg123 project
-= free software under the terms of the LGPL 2.1 =- -= free software under the terms of the LGPL 2.1 =-
see COPYING and AUTHORS files in distribution or http://mpg123.org see COPYING and AUTHORS files in distribution or http://mpg123.org
initially written by Thomas Orgis initially written by Thomas Orgis
@@ -12,9 +12,9 @@
#include "debug.h" #include "debug.h"
/* The next expected frame offset, one step ahead. */ /* The next expected frame offset, one step ahead. */
static off_t fi_next(struct frame_index *fi) static int64_t fi_next(struct frame_index *fi)
{ {
return (off_t)fi->fill*fi->step; return (int64_t)fi->fill*fi->step;
} }
/* Shrink down the used index to the half. /* Shrink down the used index to the half.
@@ -56,7 +56,7 @@ void fi_exit(struct frame_index *fi)
int fi_resize(struct frame_index *fi, size_t newsize) int fi_resize(struct frame_index *fi, size_t newsize)
{ {
off_t *newdata = NULL; int64_t *newdata = NULL;
if(newsize == fi->size) return 0; if(newsize == fi->size) return 0;
if(newsize > 0 && newsize < fi->size) if(newsize > 0 && newsize < fi->size)
@@ -64,7 +64,7 @@ int fi_resize(struct frame_index *fi, size_t newsize)
while(fi->fill > newsize){ fi_shrink(fi); } while(fi->fill > newsize){ fi_shrink(fi); }
} }
newdata = safe_realloc(fi->data, newsize*sizeof(off_t)); newdata = safe_realloc(fi->data, newsize*sizeof(int64_t));
if(newsize == 0 || newdata != NULL) if(newsize == 0 || newdata != NULL)
{ {
fi->data = newdata; fi->data = newdata;
@@ -78,13 +78,13 @@ int fi_resize(struct frame_index *fi, size_t newsize)
return -1; return -1;
} }
void fi_add(struct frame_index *fi, off_t pos) void fi_add(struct frame_index *fi, int64_t pos)
{ {
debug3("wanting to add to fill %lu, step %lu, size %lu", (unsigned long)fi->fill, (unsigned long)fi->step, (unsigned long)fi->size); debug3("wanting to add to fill %lu, step %lu, size %lu", (unsigned long)fi->fill, (unsigned long)fi->step, (unsigned long)fi->size);
if(fi->fill == fi->size) if(fi->fill == fi->size)
{ /* Index is full, we need to shrink... or grow. */ { /* Index is full, we need to shrink... or grow. */
/* Store the current frame number to check later if we still want it. */ /* Store the current frame number to check later if we still want it. */
off_t framenum = fi->fill*fi->step; int64_t framenum = fi->fill*fi->step;
/* If we want not / cannot grow, we shrink. */ /* If we want not / cannot grow, we shrink. */
if( !(fi->grow_size && fi_resize(fi, fi->size+fi->grow_size)==0) ) if( !(fi->grow_size && fi_resize(fi, fi->size+fi->grow_size)==0) )
fi_shrink(fi); fi_shrink(fi);
@@ -103,13 +103,13 @@ void fi_add(struct frame_index *fi, off_t pos)
} }
} }
int fi_set(struct frame_index *fi, off_t *offsets, off_t step, size_t fill) int fi_set(struct frame_index *fi, int64_t *offsets, int64_t step, size_t fill)
{ {
if(fi_resize(fi, fill) == -1) return -1; if(fi_resize(fi, fill) == -1) return -1;
fi->step = step; fi->step = step;
if(offsets != NULL) if(offsets != NULL)
{ {
memcpy(fi->data, offsets, fill*sizeof(off_t)); memcpy(fi->data, offsets, fill*sizeof(int64_t));
fi->fill = fill; fi->fill = fill;
} }
else else

View File

@@ -15,7 +15,7 @@
In this manner we maintain a good resolution with the given In this manner we maintain a good resolution with the given
maximum index size while covering the whole stream. maximum index size while covering the whole stream.
copyright 2007-8 by the mpg123 project - free software under the terms of the LGPL 2.1 copyright 2007-2023 by the mpg123 project - free software under the terms of the LGPL 2.1
see COPYING and AUTHORS files in distribution or http://mpg123.org see COPYING and AUTHORS files in distribution or http://mpg123.org
initially written by Thomas Orgis initially written by Thomas Orgis
*/ */
@@ -25,9 +25,9 @@
struct frame_index struct frame_index
{ {
off_t *data; /* actual data, the frame positions */ int64_t *data; /* actual data, the frame positions */
off_t step; /* advancement in frame number per index point */ int64_t step; /* advancement in frame number per index point */
off_t next; /* frame offset supposed to come next into the index */ int64_t next; /* frame offset supposed to come next into the index */
size_t size; /* total number of possible entries */ size_t size; /* total number of possible entries */
size_t fill; /* number of used entries */ size_t fill; /* number of used entries */
size_t grow_size; /* if > 0: index allowed to grow on need with these steps, instead of lowering resolution */ size_t grow_size; /* if > 0: index allowed to grow on need with these steps, instead of lowering resolution */
@@ -48,10 +48,10 @@ void fi_exit(struct frame_index *fi);
int fi_resize(struct frame_index *fi, size_t newsize); int fi_resize(struct frame_index *fi, size_t newsize);
/* Append a frame position, reducing index density if needed. */ /* Append a frame position, reducing index density if needed. */
void fi_add(struct frame_index *fi, off_t pos); void fi_add(struct frame_index *fi, int64_t pos);
/* Replace the frame index */ /* Replace the frame index */
int fi_set(struct frame_index *fi, off_t *offsets, off_t step, size_t fill); int fi_set(struct frame_index *fi, int64_t *offsets, int64_t step, size_t fill);
/* Empty the index (setting fill=0 and step=1), but keep current size. */ /* Empty the index (setting fill=0 and step=1), but keep current size. */
void fi_reset(struct frame_index *fi); void fi_reset(struct frame_index *fi);

View File

@@ -1,233 +0,0 @@
/*
lfs_alias: Aliases to the small/native API functions with the size of long int as suffix.
copyright 2010-2020 by the mpg123 project - free software under the terms of the LGPL 2.1
see COPYING and AUTHORS files in distribution or http://mpg123.org
initially written by Thomas Orgis
Use case: Client code on Linux/x86-64 that defines _FILE_OFFSET_BITS to 64,
which is the only choice on that platform anyway. It should be no-op, but
prompts the platform-agnostic header of mpg123 to define API calls with the
corresponding suffix. This file provides the names for this case. It's cruft,
but glibc does it, too -- so people rely on it.
Oh, and it also caters for the lunatics that define _FILE_OFFSET_BITS=32 on
32 bit platforms. In addition, it's needed for platforms that always have
off_t /= long, and clients still insisting on defining _FILE_OFFSET_BITS.
Depending on use case, the aliases map to 32 (small) or 64 bit (large) offset
functions, to the ones from libmpg123 or the ones from lfs_wrap.
So, two basic cases:
1. mpg123_bla_32 alias for mpg123_bla (native)
2. mpg123_bla alias for mpg123_bla_32 (wrapper)
Same for 64 bits. Confusing, I know. It sucks.
Note that the mpg123 header is _not_ used here to avoid definition with whacky off_t.
The aliases are always about arguments of native alias_t type. This can be off_t, but
on Linux/x86, this is long int. The off_t declarations in mpg123.h confuse things,
so reproduce definitions for the wrapper functions in that case. The definitions are
pulled by an inline Perl script in any case ... no need to copy anything manually!
As a benefit, one can skip undefining possible largefile namings.
*/
#include "config.h"
/* Hack for Solaris: Some system headers included from compat.h might force _FILE_OFFSET_BITS. Need to follow that here.
Also, want it around to have types defined. */
#include "compat.h"
#include "mpg123.h"
#ifndef LFS_ALIAS_BITS
#error "I need the count of alias bits here."
#endif
#define MACROCAT_REALLY(a, b) a ## b
#define MACROCAT(a, b) MACROCAT_REALLY(a, b)
/* This is wicked switchery: Decide which way the aliases are facing. */
#if !(defined BUILD_NO_LARGENAME) && (_FILE_OFFSET_BITS+0 == LFS_ALIAS_BITS)
/* The native functions have suffix, the aliases not. */
#define NATIVE_SUFFIX MACROCAT(_, _FILE_OFFSET_BITS)
#define NATIVE_NAME(func) MACROCAT(func, NATIVE_SUFFIX)
#define ALIAS_NAME(func) func
#else
/* The alias functions have suffix, the native ones not. */
#define ALIAS_SUFFIX MACROCAT(_, LFS_ALIAS_BITS)
#define ALIAS_NAME(func) MACROCAT(func, ALIAS_SUFFIX)
#define NATIVE_NAME(func) func
#endif
/* Get attribute_align_arg, to stay safe. */
#include "abi_align.h"
/*
Extract the list of functions we need wrappers for, pregenerating the wrappers for simple cases (inline script for nedit):
perl -ne '
if(/^\s*MPG123_EXPORT\s+(\S+)\s+(mpg123_\S+)\((.*)\);\s*$/)
{
my $type = $1;
my $name = $2;
my $args = $3;
next unless ($type =~ /off_t/ or $args =~ /off_t/ or ($name =~ /open/ and $name ne mpg123_open_feed));
$type =~ s/off_t/lfs_alias_t/g;
my @nargs = ();
$args =~ s/off_t/lfs_alias_t/g;
foreach my $a (split(/,/, $args))
{
$a =~ s/^.*\s\**([a-z_]+)$/$1/;
push(@nargs, $a);
}
my $nargs = join(", ", @nargs);
$nargs = "Human: figure me out." if($nargs =~ /\(/);
print <<EOT
$type NATIVE_NAME($name)($args);
$type attribute_align_arg ALIAS_NAME($name)($args)
{
return NATIVE_NAME($name)($nargs);
}
EOT
}' < mpg123.h.in
*/
int NATIVE_NAME(mpg123_open_fixed)( mpg123_handle *mh, const char *path
, int channels, int encoding );
int attribute_align_arg ALIAS_NAME(mpg123_open_fixed)( mpg123_handle *mh, const char *path
, int channels, int encoding )
{
return NATIVE_NAME(mpg123_open_fixed)(mh, path, channels, encoding);
}
int NATIVE_NAME(mpg123_open)(mpg123_handle *mh, const char *path);
int attribute_align_arg ALIAS_NAME(mpg123_open)(mpg123_handle *mh, const char *path)
{
return NATIVE_NAME(mpg123_open)(mh, path);
}
int NATIVE_NAME(mpg123_open_fd)(mpg123_handle *mh, int fd);
int attribute_align_arg ALIAS_NAME(mpg123_open_fd)(mpg123_handle *mh, int fd)
{
return NATIVE_NAME(mpg123_open_fd)(mh, fd);
}
int NATIVE_NAME(mpg123_open_handle)(mpg123_handle *mh, void *iohandle);
int attribute_align_arg ALIAS_NAME(mpg123_open_handle)(mpg123_handle *mh, void *iohandle)
{
return NATIVE_NAME(mpg123_open_handle)(mh, iohandle);
}
int NATIVE_NAME(mpg123_decode_frame)(mpg123_handle *mh, lfs_alias_t *num, unsigned char **audio, size_t *bytes);
int attribute_align_arg ALIAS_NAME(mpg123_decode_frame)(mpg123_handle *mh, lfs_alias_t *num, unsigned char **audio, size_t *bytes)
{
return NATIVE_NAME(mpg123_decode_frame)(mh, num, audio, bytes);
}
int NATIVE_NAME(mpg123_framebyframe_decode)(mpg123_handle *mh, lfs_alias_t *num, unsigned char **audio, size_t *bytes);
int attribute_align_arg ALIAS_NAME(mpg123_framebyframe_decode)(mpg123_handle *mh, lfs_alias_t *num, unsigned char **audio, size_t *bytes)
{
return NATIVE_NAME(mpg123_framebyframe_decode)(mh, num, audio, bytes);
}
lfs_alias_t NATIVE_NAME(mpg123_framepos)(mpg123_handle *mh);
lfs_alias_t attribute_align_arg ALIAS_NAME(mpg123_framepos)(mpg123_handle *mh)
{
return NATIVE_NAME(mpg123_framepos)(mh);
}
lfs_alias_t NATIVE_NAME(mpg123_tell)(mpg123_handle *mh);
lfs_alias_t attribute_align_arg ALIAS_NAME(mpg123_tell)(mpg123_handle *mh)
{
return NATIVE_NAME(mpg123_tell)(mh);
}
lfs_alias_t NATIVE_NAME(mpg123_tellframe)(mpg123_handle *mh);
lfs_alias_t attribute_align_arg ALIAS_NAME(mpg123_tellframe)(mpg123_handle *mh)
{
return NATIVE_NAME(mpg123_tellframe)(mh);
}
lfs_alias_t NATIVE_NAME(mpg123_tell_stream)(mpg123_handle *mh);
lfs_alias_t attribute_align_arg ALIAS_NAME(mpg123_tell_stream)(mpg123_handle *mh)
{
return NATIVE_NAME(mpg123_tell_stream)(mh);
}
lfs_alias_t NATIVE_NAME(mpg123_seek)(mpg123_handle *mh, lfs_alias_t sampleoff, int whence);
lfs_alias_t attribute_align_arg ALIAS_NAME(mpg123_seek)(mpg123_handle *mh, lfs_alias_t sampleoff, int whence)
{
return NATIVE_NAME(mpg123_seek)(mh, sampleoff, whence);
}
lfs_alias_t NATIVE_NAME(mpg123_feedseek)(mpg123_handle *mh, lfs_alias_t sampleoff, int whence, lfs_alias_t *input_offset);
lfs_alias_t attribute_align_arg ALIAS_NAME(mpg123_feedseek)(mpg123_handle *mh, lfs_alias_t sampleoff, int whence, lfs_alias_t *input_offset)
{
return NATIVE_NAME(mpg123_feedseek)(mh, sampleoff, whence, input_offset);
}
lfs_alias_t NATIVE_NAME(mpg123_seek_frame)(mpg123_handle *mh, lfs_alias_t frameoff, int whence);
lfs_alias_t attribute_align_arg ALIAS_NAME(mpg123_seek_frame)(mpg123_handle *mh, lfs_alias_t frameoff, int whence)
{
return NATIVE_NAME(mpg123_seek_frame)(mh, frameoff, whence);
}
lfs_alias_t NATIVE_NAME(mpg123_timeframe)(mpg123_handle *mh, double sec);
lfs_alias_t attribute_align_arg ALIAS_NAME(mpg123_timeframe)(mpg123_handle *mh, double sec)
{
return NATIVE_NAME(mpg123_timeframe)(mh, sec);
}
int NATIVE_NAME(mpg123_index)(mpg123_handle *mh, lfs_alias_t **offsets, lfs_alias_t *step, size_t *fill);
int attribute_align_arg ALIAS_NAME(mpg123_index)(mpg123_handle *mh, lfs_alias_t **offsets, lfs_alias_t *step, size_t *fill)
{
return NATIVE_NAME(mpg123_index)(mh, offsets, step, fill);
}
int NATIVE_NAME(mpg123_set_index)(mpg123_handle *mh, lfs_alias_t *offsets, lfs_alias_t step, size_t fill);
int attribute_align_arg ALIAS_NAME(mpg123_set_index)(mpg123_handle *mh, lfs_alias_t *offsets, lfs_alias_t step, size_t fill)
{
return NATIVE_NAME(mpg123_set_index)(mh, offsets, step, fill);
}
int NATIVE_NAME(mpg123_position)( mpg123_handle *mh, lfs_alias_t frame_offset, lfs_alias_t buffered_bytes, lfs_alias_t *current_frame, lfs_alias_t *frames_left, double *current_seconds, double *seconds_left);
int attribute_align_arg ALIAS_NAME(mpg123_position)( mpg123_handle *mh, lfs_alias_t frame_offset, lfs_alias_t buffered_bytes, lfs_alias_t *current_frame, lfs_alias_t *frames_left, double *current_seconds, double *seconds_left)
{
return NATIVE_NAME(mpg123_position)(mh, frame_offset, buffered_bytes, current_frame, frames_left, current_seconds, seconds_left);
}
lfs_alias_t NATIVE_NAME(mpg123_framelength)(mpg123_handle *mh);
lfs_alias_t attribute_align_arg ALIAS_NAME(mpg123_framelength)(mpg123_handle *mh)
{
return NATIVE_NAME(mpg123_framelength)(mh);
}
lfs_alias_t NATIVE_NAME(mpg123_length)(mpg123_handle *mh);
lfs_alias_t attribute_align_arg ALIAS_NAME(mpg123_length)(mpg123_handle *mh)
{
return NATIVE_NAME(mpg123_length)(mh);
}
int NATIVE_NAME(mpg123_set_filesize)(mpg123_handle *mh, lfs_alias_t size);
int attribute_align_arg ALIAS_NAME(mpg123_set_filesize)(mpg123_handle *mh, lfs_alias_t size)
{
return NATIVE_NAME(mpg123_set_filesize)(mh, size);
}
int NATIVE_NAME(mpg123_replace_reader)(mpg123_handle *mh, mpg123_ssize_t (*r_read) (int, void *, size_t), lfs_alias_t (*r_lseek)(int, lfs_alias_t, int));
int attribute_align_arg ALIAS_NAME(mpg123_replace_reader)(mpg123_handle *mh, mpg123_ssize_t (*r_read) (int, void *, size_t), lfs_alias_t (*r_lseek)(int, lfs_alias_t, int))
{
return NATIVE_NAME(mpg123_replace_reader)(mh, r_read, r_lseek);
}
int NATIVE_NAME(mpg123_replace_reader_handle)(mpg123_handle *mh, mpg123_ssize_t (*r_read) (void *, void *, size_t), lfs_alias_t (*r_lseek)(void *, lfs_alias_t, int), void (*cleanup)(void*));
int attribute_align_arg ALIAS_NAME(mpg123_replace_reader_handle)(mpg123_handle *mh, mpg123_ssize_t (*r_read) (void *, void *, size_t), lfs_alias_t (*r_lseek)(void *, lfs_alias_t, int), void (*cleanup)(void*))
{
return NATIVE_NAME(mpg123_replace_reader_handle)(mh, r_read, r_lseek, cleanup);
}

File diff suppressed because it is too large Load Diff

37
src/libmpg123/lfs_wrap.h Normal file
View File

@@ -0,0 +1,37 @@
/*
lfs_wrap: I/O wrapper code
copyright 2010-2023 by the mpg123 project
free software under the terms of the LGPL 2.1
see COPYING and AUTHORS files in distribution or http://mpg123.org
initially written by Thomas Orgis (after code from Michael Hipp)
This is the interface to the implementation of internal reading/seeking
as well as wrapping of client callbacks to the one and only 64 bit
callback API on opaque handles.
Code outside of this shall not be concerned with I/O details, and
code inside of this shall not be concerned with other
libmpg123 internals. Just the public portable API interface.
*/
// This is to be offered by libmpg123 code that has access to frame struct
// details. It returns the address to load/store the pointer to the
// wrapper handle from/into. A little hack to keep things disentangled.
void ** INT123_wrap_handle(mpg123_handle *mh);
// Set error code in the mpg123 handle and return MPG123_ERR.
int INT123_set_err(mpg123_handle *mh, int err);
// These are offered by the source associated with this header.
// This is one open routine for all ways. One of the given resource arguments is active:
// 1. handle: if path == NULL && fd < 0
// 2. path: if path != NULL
// 3. fd: if fd >= 0
int INT123_wrap_open(mpg123_handle *mh, void *handle, const char *path, int fd, long timeout, int quiet);
// Deallocate all associated resources and handle memory itself.
void INT123_wrap_destroy(void * handle);
// The bulk of functions are implementations of the non-portable
// libmpg123 API declared or implied in the main header.

View File

@@ -1,7 +1,7 @@
/* /*
libmpg123: MPEG Audio Decoder library libmpg123: MPEG Audio Decoder library
copyright 1995-2020 by the mpg123 project - free software under the terms of the LGPL 2.1 copyright 1995-2023 by the mpg123 project - free software under the terms of the LGPL 2.1
see COPYING and AUTHORS files in distribution or http://mpg123.org see COPYING and AUTHORS files in distribution or http://mpg123.org
*/ */
@@ -15,11 +15,15 @@
#define FORCE_ACCURATE #define FORCE_ACCURATE
#include "sample.h" #include "sample.h"
#include "parse.h" #include "parse.h"
#ifndef PORTABLE_API
#include "lfs_wrap.h"
#endif
#include "debug.h" #include "debug.h"
#define SEEKFRAME(mh) ((mh)->ignoreframe < 0 ? 0 : (mh)->ignoreframe) #define SEEKFRAME(mh) ((mh)->ignoreframe < 0 ? 0 : (mh)->ignoreframe)
const char * attribute_align_arg mpg123_distversion(unsigned int *major, unsigned int *minor, unsigned int *patch) const char * attribute_align_arg mpg123_distversion(unsigned int *major, unsigned int *minor, unsigned int *patch)
{ {
if(major) if(major)
@@ -555,13 +559,21 @@ double attribute_align_arg mpg123_geteq2(mpg123_handle *mh, int channel, int ban
return mpg123_geteq(mh, channel, band); return mpg123_geteq(mh, channel, band);
} }
#ifndef PORTABLE_API
/* plain file access, no http! */ /* plain file access, no http! */
int attribute_align_arg mpg123_open(mpg123_handle *mh, const char *path) int attribute_align_arg mpg123_open(mpg123_handle *mh, const char *path)
{ {
if(mh == NULL) return MPG123_BAD_HANDLE; if(mh == NULL) return MPG123_BAD_HANDLE;
mpg123_close(mh); mpg123_close(mh);
return open_stream(mh, path, -1); if(!path)
return MPG123_ERR;
// sets callbacks, only allocating wrapperdata handle if internal callbacks involved
int ret = INT123_wrap_open( mh, NULL, path, -1
, mh->p.timeout, mh->p.flags & MPG123_QUIET );
if(!ret)
ret = INT123_open_stream_handle(mh, mh->wrapperdata);
return ret;
} }
// The convenience function mpg123_open_fixed() wraps over acual mpg123_open // The convenience function mpg123_open_fixed() wraps over acual mpg123_open
@@ -617,20 +629,29 @@ int attribute_align_arg mpg123_open_fd(mpg123_handle *mh, int fd)
if(mh == NULL) return MPG123_BAD_HANDLE; if(mh == NULL) return MPG123_BAD_HANDLE;
mpg123_close(mh); mpg123_close(mh);
return open_stream(mh, NULL, fd); if(fd < 0)
return MPG123_ERR;
int ret = INT123_wrap_open( mh, NULL, NULL, fd
, mh->p.timeout, mh->p.flags & MPG123_QUIET );
if(!ret)
ret = INT123_open_stream_handle(mh, mh->wrapperdata);
return ret;
} }
#endif
int attribute_align_arg mpg123_open_handle(mpg123_handle *mh, void *iohandle) int attribute_align_arg mpg123_open_handle(mpg123_handle *mh, void *iohandle)
{ {
if(mh == NULL) return MPG123_BAD_HANDLE; if(mh == NULL) return MPG123_BAD_HANDLE;
mpg123_close(mh); mpg123_close(mh);
if(mh->rdat.r_read_handle == NULL) int ret;
{ #ifndef PORTABLE_API
mh->err = MPG123_BAD_CUSTOM_IO; ret = INT123_wrap_open( mh, iohandle, NULL, -1
return MPG123_ERR; , mh->p.timeout, mh->p.flags & MPG123_QUIET );
} if(!ret)
return open_stream_handle(mh, iohandle); #endif
ret = INT123_open_stream_handle(mh, mh->wrapperdata);
return ret;
} }
int attribute_align_arg mpg123_open_feed(mpg123_handle *mh) int attribute_align_arg mpg123_open_feed(mpg123_handle *mh)
@@ -638,35 +659,36 @@ int attribute_align_arg mpg123_open_feed(mpg123_handle *mh)
if(mh == NULL) return MPG123_BAD_HANDLE; if(mh == NULL) return MPG123_BAD_HANDLE;
mpg123_close(mh); mpg123_close(mh);
return open_feed(mh); return INT123_open_feed(mh);
} }
int attribute_align_arg mpg123_replace_reader( mpg123_handle *mh, static int64_t no_lseek64(void *handle, int64_t off, int whence)
mpg123_ssize_t (*r_read) (int, void *, size_t),
off_t (*r_lseek)(int, off_t, int) )
{ {
if(mh == NULL) return MPG123_BAD_HANDLE; return -1;
mpg123_close(mh);
mh->rdat.r_read = r_read;
mh->rdat.r_lseek = r_lseek;
return MPG123_OK;
} }
int attribute_align_arg mpg123_replace_reader_handle( mpg123_handle *mh, // The simplest direct wrapper, actually no wrapping at all.
mpg123_ssize_t (*r_read) (void*, void *, size_t), int attribute_align_arg mpg123_reader64( mpg123_handle *mh
off_t (*r_lseek)(void*, off_t, int), , int (*r_read) (void *, void *, size_t, size_t *)
void (*cleanup)(void*) ) , int64_t (*r_lseek)(void *, int64_t, int)
, void (*cleanup)(void*) )
{ {
if(mh == NULL) return MPG123_BAD_HANDLE; if(mh == NULL)
return MPG123_BAD_HANDLE;
mpg123_close(mh); mpg123_close(mh);
mh->rdat.r_read_handle = r_read;
mh->rdat.r_lseek_handle = r_lseek; if(!r_read)
return MPG123_NULL_POINTER;
mh->rdat.r_read64 = r_read;
mh->rdat.r_lseek64 = r_lseek ? r_lseek : no_lseek64;
mh->rdat.cleanup_handle = cleanup; mh->rdat.cleanup_handle = cleanup;
return MPG123_OK; return MPG123_OK;
} }
// All other I/O gets routed through predefined wrapper.
/* Update decoding engine for /* Update decoding engine for
a) a new choice of decoder a) a new choice of decoder
b) a changed native format of the MPEG stream b) a changed native format of the MPEG stream
@@ -796,7 +818,7 @@ static int get_next_frame(mpg123_handle *mh)
debug("read frame"); debug("read frame");
mh->to_decode = FALSE; mh->to_decode = FALSE;
b = read_frame(mh); /* That sets to_decode only if a full frame was read. */ b = read_frame(mh); /* That sets to_decode only if a full frame was read. */
debug4("read of frame %li returned %i (to_decode=%i) at sample %li", (long)mh->num, b, mh->to_decode, (long)mpg123_tell(mh)); debug4("read of frame %"PRIi64" returned %i (to_decode=%i) at sample %"PRIi64, mh->num, b, mh->to_decode, mpg123_tell64(mh));
if(b == MPG123_NEED_MORE) return MPG123_NEED_MORE; /* need another call with data */ if(b == MPG123_NEED_MORE) return MPG123_NEED_MORE; /* need another call with data */
else if(b <= 0) else if(b <= 0)
{ {
@@ -880,7 +902,6 @@ static void decode_the_frame(mpg123_handle *fr)
{ {
size_t needed_bytes = decoder_synth_bytes(fr, frame_expect_outsamples(fr)); size_t needed_bytes = decoder_synth_bytes(fr, frame_expect_outsamples(fr));
fr->clip += (fr->do_layer)(fr); fr->clip += (fr->do_layer)(fr);
/*fprintf(stderr, "frame %"OFF_P": got %"SIZE_P" / %"SIZE_P"\n", fr->num,(size_p)fr->buffer.fill, (size_p)needed_bytes);*/
/* There could be less data than promised. /* There could be less data than promised.
Also, then debugging, we look out for coding errors that could result in _more_ data than expected. */ Also, then debugging, we look out for coding errors that could result in _more_ data than expected. */
#ifdef DEBUG #ifdef DEBUG
@@ -929,7 +950,7 @@ static void decode_the_frame(mpg123_handle *fr)
MPG123_BAD_HANDLE -- mh has not been initialized MPG123_BAD_HANDLE -- mh has not been initialized
MPG123_NO_SPACE -- not enough space in buffer for safe decoding, should not happen MPG123_NO_SPACE -- not enough space in buffer for safe decoding, should not happen
*/ */
int attribute_align_arg mpg123_framebyframe_decode(mpg123_handle *mh, off_t *num, unsigned char **audio, size_t *bytes) int attribute_align_arg mpg123_framebyframe_decode64(mpg123_handle *mh, int64_t *num, unsigned char **audio, size_t *bytes)
{ {
if(bytes == NULL) return MPG123_ERR_NULL; if(bytes == NULL) return MPG123_ERR_NULL;
if(audio == NULL) return MPG123_ERR_NULL; if(audio == NULL) return MPG123_ERR_NULL;
@@ -1001,7 +1022,7 @@ int attribute_align_arg mpg123_framebyframe_next(mpg123_handle *mh)
num will be updated to the last decoded frame number (may possibly _not_ increase, p.ex. when format changed). num will be updated to the last decoded frame number (may possibly _not_ increase, p.ex. when format changed).
*/ */
int attribute_align_arg mpg123_decode_frame(mpg123_handle *mh, off_t *num, unsigned char **audio, size_t *bytes) int attribute_align_arg mpg123_decode_frame64(mpg123_handle *mh, int64_t *num, unsigned char **audio, size_t *bytes)
{ {
if(bytes != NULL) *bytes = 0; if(bytes != NULL) *bytes = 0;
if(mh == NULL) return MPG123_BAD_HANDLE; if(mh == NULL) return MPG123_BAD_HANDLE;
@@ -1046,6 +1067,7 @@ int attribute_align_arg mpg123_decode_frame(mpg123_handle *mh, off_t *num, unsig
} }
} }
int attribute_align_arg mpg123_read(mpg123_handle *mh, void *out, size_t size, size_t *done) int attribute_align_arg mpg123_read(mpg123_handle *mh, void *out, size_t size, size_t *done)
{ {
return mpg123_decode(mh, NULL, 0, out, size, done); return mpg123_decode(mh, NULL, 0, out, size, done);
@@ -1258,14 +1280,15 @@ int attribute_align_arg mpg123_getformat(mpg123_handle *mh, long *rate, int *cha
return mpg123_getformat2(mh, rate, channels, encoding, 1); return mpg123_getformat2(mh, rate, channels, encoding, 1);
} }
off_t attribute_align_arg mpg123_timeframe(mpg123_handle *mh, double seconds) int64_t attribute_align_arg mpg123_timeframe64(mpg123_handle *mh, double seconds)
{ {
off_t b; int64_t b;
if(mh == NULL) return MPG123_ERR; if(mh == NULL) return MPG123_ERR;
b = init_track(mh); b = init_track(mh);
if(b<0) return b; if(b<0) return b;
return (off_t)(seconds/mpg123_tpf(mh)); // Overflow checking here would be a bit more elaborate. TODO?
return (int64_t)(seconds/mpg123_tpf(mh));
} }
/* /*
@@ -1276,7 +1299,7 @@ off_t attribute_align_arg mpg123_timeframe(mpg123_handle *mh, double seconds)
Then, there is firstframe...when we didn't reach it yet, then the next data will come from there. Then, there is firstframe...when we didn't reach it yet, then the next data will come from there.
mh->num starts with -1 mh->num starts with -1
*/ */
off_t attribute_align_arg mpg123_tell(mpg123_handle *mh) int64_t attribute_align_arg mpg123_tell64(mpg123_handle *mh)
{ {
if(mh == NULL) return MPG123_ERR; if(mh == NULL) return MPG123_ERR;
if(track_need_init(mh)) return 0; if(track_need_init(mh)) return 0;
@@ -1284,7 +1307,7 @@ off_t attribute_align_arg mpg123_tell(mpg123_handle *mh)
debug5("tell: %li/%i first %li buffer %lu; frame_outs=%li", (long)mh->num, mh->to_decode, (long)mh->firstframe, (unsigned long)mh->buffer.fill, (long)frame_outs(mh, mh->num)); debug5("tell: %li/%i first %li buffer %lu; frame_outs=%li", (long)mh->num, mh->to_decode, (long)mh->firstframe, (unsigned long)mh->buffer.fill, (long)frame_outs(mh, mh->num));
{ /* Funny block to keep C89 happy. */ { /* Funny block to keep C89 happy. */
off_t pos = 0; int64_t pos = 0;
if((mh->num < mh->firstframe) || (mh->num == mh->firstframe && mh->to_decode)) if((mh->num < mh->firstframe) || (mh->num == mh->firstframe && mh->to_decode))
{ /* We are at the beginning, expect output from firstframe on. */ { /* We are at the beginning, expect output from firstframe on. */
pos = frame_outs(mh, mh->firstframe); pos = frame_outs(mh, mh->firstframe);
@@ -1307,7 +1330,7 @@ off_t attribute_align_arg mpg123_tell(mpg123_handle *mh)
} }
} }
off_t attribute_align_arg mpg123_tellframe(mpg123_handle *mh) int64_t attribute_align_arg mpg123_tellframe64(mpg123_handle *mh)
{ {
if(mh == NULL) return MPG123_ERR; if(mh == NULL) return MPG123_ERR;
if(mh->num < mh->firstframe) return mh->firstframe; if(mh->num < mh->firstframe) return mh->firstframe;
@@ -1316,7 +1339,7 @@ off_t attribute_align_arg mpg123_tellframe(mpg123_handle *mh)
return mh->buffer.fill ? mh->num : mh->num + 1; return mh->buffer.fill ? mh->num : mh->num + 1;
} }
off_t attribute_align_arg mpg123_tell_stream(mpg123_handle *mh) int64_t attribute_align_arg mpg123_tell_stream64(mpg123_handle *mh)
{ {
if(mh == NULL) return MPG123_ERR; if(mh == NULL) return MPG123_ERR;
/* mh->rd is at least a bad_reader, so no worry. */ /* mh->rd is at least a bad_reader, so no worry. */
@@ -1326,7 +1349,7 @@ off_t attribute_align_arg mpg123_tell_stream(mpg123_handle *mh)
static int do_the_seek(mpg123_handle *mh) static int do_the_seek(mpg123_handle *mh)
{ {
int b; int b;
off_t fnum = SEEKFRAME(mh); int64_t fnum = SEEKFRAME(mh);
mh->buffer.fill = 0; mh->buffer.fill = 0;
/* If we are inside the ignoreframe - firstframe window, we may get away without actual seeking. */ /* If we are inside the ignoreframe - firstframe window, we may get away without actual seeking. */
@@ -1351,7 +1374,7 @@ static int do_the_seek(mpg123_handle *mh)
if(mh->down_sample == 3) if(mh->down_sample == 3)
{ {
ntom_set_ntom(mh, fnum); ntom_set_ntom(mh, fnum);
debug3("fixed ntom for frame %"OFF_P" to %lu, num=%"OFF_P, (off_p)fnum, mh->ntom_val[0], (off_p)mh->num); debug3("fixed ntom for frame %"PRIi64" to %lu, num=%"PRIi64, fnum, mh->ntom_val[0], mh->num);
} }
#endif #endif
b = mh->rd->seek_frame(mh, fnum); b = mh->rd->seek_frame(mh, fnum);
@@ -1369,12 +1392,12 @@ static int do_the_seek(mpg123_handle *mh)
return 0; return 0;
} }
off_t attribute_align_arg mpg123_seek(mpg123_handle *mh, off_t sampleoff, int whence) int64_t attribute_align_arg mpg123_seek64(mpg123_handle *mh, int64_t sampleoff, int whence)
{ {
int b; int b;
off_t pos; int64_t pos;
pos = mpg123_tell(mh); /* adjusted samples */ pos = mpg123_tell64(mh); /* adjusted samples */
/* pos < 0 also can mean that simply a former seek failed at the lower levels. /* pos < 0 also can mean that simply a former seek failed at the lower levels.
In that case, we only allow absolute seeks. */ In that case, we only allow absolute seeks. */
if(pos < 0 && whence != SEEK_SET) if(pos < 0 && whence != SEEK_SET)
@@ -1409,7 +1432,7 @@ off_t attribute_align_arg mpg123_seek(mpg123_handle *mh, off_t sampleoff, int wh
pos = do_the_seek(mh); pos = do_the_seek(mh);
if(pos < 0) return pos; if(pos < 0) return pos;
return mpg123_tell(mh); return mpg123_tell64(mh);
} }
/* /*
@@ -1417,13 +1440,18 @@ off_t attribute_align_arg mpg123_seek(mpg123_handle *mh, off_t sampleoff, int wh
All it can do is to ignore frames until the wanted one is there. All it can do is to ignore frames until the wanted one is there.
The caller doesn't know where a specific frame starts and mpg123 also only knows the general region after it scanned the file. The caller doesn't know where a specific frame starts and mpg123 also only knows the general region after it scanned the file.
Well, it is tricky... Well, it is tricky...
Wow, there was no input checking at all ... I'll better add it.
*/ */
off_t attribute_align_arg mpg123_feedseek(mpg123_handle *mh, off_t sampleoff, int whence, off_t *input_offset) int64_t attribute_align_arg mpg123_feedseek64(mpg123_handle *mh, int64_t sampleoff, int whence, int64_t *input_offset)
{ {
int b; int b;
off_t pos; int64_t pos;
int64_t inoff = 0;
if(!mh)
return MPG123_BAD_HANDLE;
pos = mpg123_tell(mh); /* adjusted samples */ pos = mpg123_tell64(mh); /* adjusted samples */
debug3("seek from %li to %li (whence=%i)", (long)pos, (long)sampleoff, whence); debug3("seek from %li to %li (whence=%i)", (long)pos, (long)sampleoff, whence);
/* The special seek error handling does not apply here... there is no lowlevel I/O. */ /* The special seek error handling does not apply here... there is no lowlevel I/O. */
if(pos < 0) return pos; /* mh == NULL is covered in mpg123_tell() */ if(pos < 0) return pos; /* mh == NULL is covered in mpg123_tell() */
@@ -1459,27 +1487,30 @@ off_t attribute_align_arg mpg123_feedseek(mpg123_handle *mh, off_t sampleoff, in
mh->buffer.fill = 0; mh->buffer.fill = 0;
/* Shortcuts without modifying input stream. */ /* Shortcuts without modifying input stream. */
*input_offset = mh->rdat.buffer.fileoff + mh->rdat.buffer.size; inoff = mh->rdat.buffer.fileoff + mh->rdat.buffer.size;
if(mh->num < mh->firstframe) mh->to_decode = FALSE; if(mh->num < mh->firstframe) mh->to_decode = FALSE;
if(mh->num == pos && mh->to_decode) goto feedseekend; if(mh->num == pos && mh->to_decode) goto feedseekend;
if(mh->num == pos-1) goto feedseekend; if(mh->num == pos-1) goto feedseekend;
/* Whole way. */ /* Whole way. */
*input_offset = feed_set_pos(mh, frame_index_find(mh, SEEKFRAME(mh), &pos)); inoff = feed_set_pos(mh, frame_index_find(mh, SEEKFRAME(mh), &pos));
mh->num = pos-1; /* The next read frame will have num = pos. */ mh->num = pos-1; /* The next read frame will have num = pos. */
if(*input_offset < 0) return MPG123_ERR; if(input_offset)
*input_offset = inoff;
if(inoff < 0)
return MPG123_ERR;
feedseekend: feedseekend:
return mpg123_tell(mh); return mpg123_tell64(mh);
#else #else
mh->err = MPG123_MISSING_FEATURE; mh->err = MPG123_MISSING_FEATURE;
return MPG123_ERR; return MPG123_ERR;
#endif #endif
} }
off_t attribute_align_arg mpg123_seek_frame(mpg123_handle *mh, off_t offset, int whence) int64_t attribute_align_arg mpg123_seek_frame64(mpg123_handle *mh, int64_t offset, int whence)
{ {
int b; int b;
off_t pos = 0; int64_t pos = 0;
if(mh == NULL) return MPG123_ERR; if(mh == NULL) return MPG123_ERR;
if((b=init_track(mh)) < 0) return b; if((b=init_track(mh)) < 0) return b;
@@ -1509,10 +1540,10 @@ off_t attribute_align_arg mpg123_seek_frame(mpg123_handle *mh, off_t offset, int
pos = do_the_seek(mh); pos = do_the_seek(mh);
if(pos < 0) return pos; if(pos < 0) return pos;
return mpg123_tellframe(mh); return mpg123_tellframe64(mh);
} }
int attribute_align_arg mpg123_set_filesize(mpg123_handle *mh, off_t size) int attribute_align_arg mpg123_set_filesize64(mpg123_handle *mh, int64_t size)
{ {
if(mh == NULL) return MPG123_BAD_HANDLE; if(mh == NULL) return MPG123_BAD_HANDLE;
@@ -1520,7 +1551,7 @@ int attribute_align_arg mpg123_set_filesize(mpg123_handle *mh, off_t size)
return MPG123_OK; return MPG123_OK;
} }
off_t attribute_align_arg mpg123_framelength(mpg123_handle *mh) int64_t attribute_align_arg mpg123_framelength64(mpg123_handle *mh)
{ {
int b; int b;
if(mh == NULL) if(mh == NULL)
@@ -1535,7 +1566,7 @@ off_t attribute_align_arg mpg123_framelength(mpg123_handle *mh)
double bpf = mh->mean_framesize > 0. double bpf = mh->mean_framesize > 0.
? mh->mean_framesize ? mh->mean_framesize
: compute_bpf(mh); : compute_bpf(mh);
return (off_t)((double)(mh->rdat.filelen)/bpf+0.5); return (int64_t)((double)(mh->rdat.filelen)/bpf+0.5);
} }
/* Last resort: No view of the future, can at least count the frames that /* Last resort: No view of the future, can at least count the frames that
were already parsed. */ were already parsed. */
@@ -1545,10 +1576,10 @@ off_t attribute_align_arg mpg123_framelength(mpg123_handle *mh)
return MPG123_ERR; return MPG123_ERR;
} }
off_t attribute_align_arg mpg123_length(mpg123_handle *mh) int64_t attribute_align_arg mpg123_length64(mpg123_handle *mh)
{ {
int b; int b;
off_t length; int64_t length;
if(mh == NULL) return MPG123_ERR; if(mh == NULL) return MPG123_ERR;
b = init_track(mh); b = init_track(mh);
@@ -1559,26 +1590,25 @@ off_t attribute_align_arg mpg123_length(mpg123_handle *mh)
{ {
/* A bad estimate. Ignoring tags 'n stuff. */ /* A bad estimate. Ignoring tags 'n stuff. */
double bpf = mh->mean_framesize ? mh->mean_framesize : compute_bpf(mh); double bpf = mh->mean_framesize ? mh->mean_framesize : compute_bpf(mh);
length = (off_t)((double)(mh->rdat.filelen)/bpf*mh->spf); length = (int64_t)((double)(mh->rdat.filelen)/bpf*mh->spf);
} }
else if(mh->rdat.filelen == 0) return mpg123_tell(mh); /* we could be in feeder mode */ else if(mh->rdat.filelen == 0) return mpg123_tell64(mh); /* we could be in feeder mode */
else return MPG123_ERR; /* No length info there! */ else return MPG123_ERR; /* No length info there! */
debug1("mpg123_length: internal sample length: %"OFF_P, (off_p)length); debug1("mpg123_length: internal sample length: %"PRIi64, length);
length = frame_ins2outs(mh, length); length = frame_ins2outs(mh, length);
debug1("mpg123_length: external sample length: %"OFF_P, (off_p)length); debug1("mpg123_length: external sample length: %"PRIi64, length);
length = SAMPLE_ADJUST(mh,length); length = SAMPLE_ADJUST(mh,length);
return length; return length;
} }
int attribute_align_arg mpg123_scan(mpg123_handle *mh) int attribute_align_arg mpg123_scan(mpg123_handle *mh)
{ {
int b; int b;
off_t oldpos; int64_t oldpos;
off_t track_frames = 0; int64_t track_frames = 0;
off_t track_samples = 0; int64_t track_samples = 0;
if(mh == NULL) return MPG123_BAD_HANDLE; if(mh == NULL) return MPG123_BAD_HANDLE;
if(!(mh->rdat.flags & READER_SEEKABLE)){ mh->err = MPG123_NO_SEEK; return MPG123_ERR; } if(!(mh->rdat.flags & READER_SEEKABLE)){ mh->err = MPG123_NO_SEEK; return MPG123_ERR; }
@@ -1591,7 +1621,7 @@ int attribute_align_arg mpg123_scan(mpg123_handle *mh)
if(b == MPG123_DONE) return MPG123_OK; if(b == MPG123_DONE) return MPG123_OK;
else return MPG123_ERR; /* Must be error here, NEED_MORE is not for seekable streams. */ else return MPG123_ERR; /* Must be error here, NEED_MORE is not for seekable streams. */
} }
oldpos = mpg123_tell(mh); oldpos = mpg123_tell64(mh);
b = mh->rd->seek_frame(mh, 0); b = mh->rd->seek_frame(mh, 0);
if(b<0 || mh->num != 0) return MPG123_ERR; if(b<0 || mh->num != 0) return MPG123_ERR;
/* One frame must be there now. */ /* One frame must be there now. */
@@ -1607,12 +1637,13 @@ int attribute_align_arg mpg123_scan(mpg123_handle *mh)
} }
mh->track_frames = track_frames; mh->track_frames = track_frames;
mh->track_samples = track_samples; mh->track_samples = track_samples;
debug2("Scanning yielded %"OFF_P" track samples, %"OFF_P" frames.", (off_p)mh->track_samples, (off_p)mh->track_frames); debug2("Scanning yielded %"PRIi64" track samples, %"PRIi64" frames."
, mh->track_samples, mh->track_frames);
#ifdef GAPLESS #ifdef GAPLESS
/* Also, think about usefulness of that extra value track_samples ... it could be used for consistency checking. */ /* Also, think about usefulness of that extra value track_samples ... it could be used for consistency checking. */
if(mh->p.flags & MPG123_GAPLESS) frame_gapless_update(mh, mh->track_samples); if(mh->p.flags & MPG123_GAPLESS) frame_gapless_update(mh, mh->track_samples);
#endif #endif
return mpg123_seek(mh, oldpos, SEEK_SET) >= 0 ? MPG123_OK : MPG123_ERR; return mpg123_seek64(mh, oldpos, SEEK_SET) >= 0 ? MPG123_OK : MPG123_ERR;
} }
int attribute_align_arg mpg123_meta_check(mpg123_handle *mh) int attribute_align_arg mpg123_meta_check(mpg123_handle *mh)
@@ -1775,9 +1806,7 @@ int attribute_align_arg mpg123_store_utf8_2(mpg123_string *sb, int enc, const un
} }
#endif #endif
int attribute_align_arg mpg123_index64(mpg123_handle *mh, int64_t **offsets, int64_t *step, size_t *fill)
int attribute_align_arg mpg123_index(mpg123_handle *mh, off_t **offsets, off_t *step, size_t *fill)
{ {
if(mh == NULL) return MPG123_BAD_HANDLE; if(mh == NULL) return MPG123_BAD_HANDLE;
if(offsets == NULL || step == NULL || fill == NULL) if(offsets == NULL || step == NULL || fill == NULL)
@@ -1797,7 +1826,7 @@ int attribute_align_arg mpg123_index(mpg123_handle *mh, off_t **offsets, off_t *
return MPG123_OK; return MPG123_OK;
} }
int attribute_align_arg mpg123_set_index(mpg123_handle *mh, off_t *offsets, off_t step, size_t fill) int attribute_align_arg mpg123_set_index64(mpg123_handle *mh, int64_t *offsets, int64_t step, size_t fill)
{ {
if(mh == NULL) return MPG123_BAD_HANDLE; if(mh == NULL) return MPG123_BAD_HANDLE;
#ifdef FRAME_INDEX #ifdef FRAME_INDEX
@@ -1818,6 +1847,7 @@ int attribute_align_arg mpg123_set_index(mpg123_handle *mh, off_t *offsets, off_
#endif #endif
} }
int attribute_align_arg mpg123_close(mpg123_handle *mh) int attribute_align_arg mpg123_close(mpg123_handle *mh)
{ {
if(mh == NULL) return MPG123_BAD_HANDLE; if(mh == NULL) return MPG123_BAD_HANDLE;
@@ -1841,6 +1871,9 @@ void attribute_align_arg mpg123_delete(mpg123_handle *mh)
if(mh != NULL) if(mh != NULL)
{ {
mpg123_close(mh); mpg123_close(mh);
#ifndef PORTABLE_API
INT123_wrap_destroy(mh->wrapperdata);
#endif
frame_exit(mh); /* free buffers in frame */ frame_exit(mh); /* free buffers in frame */
free(mh); /* free struct; cast? */ free(mh); /* free struct; cast? */
} }
@@ -1877,7 +1910,7 @@ static const char *mpg123_error[] =
"Build does not support stream timeouts. (code 21)", "Build does not support stream timeouts. (code 21)",
"File access error. (code 22)", "File access error. (code 22)",
"Seek not supported by stream. (code 23)", "Seek not supported by stream. (code 23)",
"No stream opened. (code 24)", "No stream opened or missing reader setup while opening. (code 24)",
"Bad parameter handle. (code 25)", "Bad parameter handle. (code 25)",
"Invalid parameter addresses for index retrieval. (code 26)", "Invalid parameter addresses for index retrieval. (code 26)",
"Lost track in the bytestream and did not attempt resync. (code 27)", "Lost track in the bytestream and did not attempt resync. (code 27)",
@@ -1929,3 +1962,22 @@ const char* attribute_align_arg mpg123_strerror(mpg123_handle *mh)
{ {
return mpg123_plain_strerror(mpg123_errcode(mh)); return mpg123_plain_strerror(mpg123_errcode(mh));
} }
#ifndef PORTABLE_API
// Isolation of lfs_wrap.c code, limited hook to get at its data and
// for storing error codes.
void ** INT123_wrap_handle(mpg123_handle *mh)
{
if(mh == NULL)
return NULL;
return &(mh->wrapperdata);
}
int INT123_set_err(mpg123_handle *mh, int err)
{
if(mh)
mh->err = err;
return MPG123_ERR;
}
#endif

View File

@@ -82,38 +82,21 @@ typedef ptrdiff_t mpg123_ssize_t;
typedef ssize_t mpg123_ssize_t; typedef ssize_t mpg123_ssize_t;
#endif #endif
/* You can use this file directly, avoiding the autoconf replacements. /* Handling of large file offsets.
Might have to set MPG123_NO_LARGENAME, too, in case you have When client code defines _FILE_OFFSET_BITS, it wants non-default large file support,
_FILE_OFFSET_BITS defined where it does not make sense. */ and thus functions with added suffix (mpg123_open_64). The default library build provides
#ifndef MPG123_NO_CONFIGURE wrapper and alias functions to accomodate client code variations (dual-mode library like glibc).
/* You can always enforce largefile hackery by setting MPG123_LARGESUFFIX. */ Client code can definie MPG123_NO_LARGENAME and MPG123_LARGESUFFIX, respectively, for disabling
/* Otherwise, this header disables it if the build system decided so. */ or enforcing the suffixes. If explicit usage of 64 bit offsets is desired, the int64_t API
#if !defined(MPG123_LARGESUFFIX) && @BUILD_NO_LARGENAME@ (functions with 64 suffix without underscore, notablly mpg123_reader64()) can be used since
#ifndef MPG123_NO_LARGENAME API version 48 (mpg123 1.32).
#define MPG123_NO_LARGENAME
#endif
#endif
#endif /* MPG123_NO_CONFIGURE */ When in doubt, use the explicit 64 bit functions and avoid off_t in the API. You can define
MPG123_PORTABLE_API to ensure that.
/* Simplified large file handling.
I used to have a check here that prevents building for a library with conflicting large file setup
(application that uses 32 bit offsets with library that uses 64 bits).
While that was perfectly fine in an environment where there is one incarnation of the library,
it hurt GNU/Linux and Solaris systems with multilib where the distribution fails to provide the
correct header matching the 32 bit library (where large files need explicit support) or
the 64 bit library (where there is no distinction).
New approach: When the app defines _FILE_OFFSET_BITS, it wants non-default large file support,
and thus functions with added suffix (mpg123_open_64).
Any mismatch will be caught at link time because of the _FILE_OFFSET_BITS setting used when
building libmpg123. Plus, there's dual mode large file support in mpg123 since 1.12 now.
Link failure is not the expected outcome of any half-sane usage anymore.
More complication: What about client code defining _LARGEFILE64_SOURCE? It might want direct access to the _64 functions, along with the ones without suffix. Well, that's possible now via defining MPG123_NO_LARGENAME and MPG123_LARGESUFFIX, respectively, for disabling or enforcing the suffix names.
*/ */
#ifndef MPG123_PORTABLE_API
/* /*
Now, the renaming of large file aware functions. Now, the renaming of large file aware functions.
By default, it appends underscore _FILE_OFFSET_BITS (so, mpg123_seek_64 for mpg123_seek), if _FILE_OFFSET_BITS is defined. You can force a different suffix via MPG123_LARGESUFFIX (that must include the underscore), or you can just disable the whole mess by defining MPG123_NO_LARGENAME. By default, it appends underscore _FILE_OFFSET_BITS (so, mpg123_seek_64 for mpg123_seek), if _FILE_OFFSET_BITS is defined. You can force a different suffix via MPG123_LARGESUFFIX (that must include the underscore), or you can just disable the whole mess by defining MPG123_NO_LARGENAME.
@@ -152,6 +135,7 @@ typedef ssize_t mpg123_ssize_t;
#define mpg123_framepos MPG123_LARGENAME(mpg123_framepos) #define mpg123_framepos MPG123_LARGENAME(mpg123_framepos)
#endif /* largefile hackery */ #endif /* largefile hackery */
#endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@@ -503,7 +487,7 @@ enum mpg123_errors
MPG123_NO_TIMEOUT, /**< Build does not support stream timeouts. */ MPG123_NO_TIMEOUT, /**< Build does not support stream timeouts. */
MPG123_BAD_FILE, /**< File access error. */ MPG123_BAD_FILE, /**< File access error. */
MPG123_NO_SEEK, /**< Seek not supported by stream. */ MPG123_NO_SEEK, /**< Seek not supported by stream. */
MPG123_NO_READER, /**< No stream opened. */ MPG123_NO_READER, /**< No stream opened or no reader callback setup. */
MPG123_BAD_PARS, /**< Bad parameter handle. */ MPG123_BAD_PARS, /**< Bad parameter handle. */
MPG123_BAD_INDEX_PAR, /**< Bad parameters to mpg123_index() and mpg123_set_index() */ MPG123_BAD_INDEX_PAR, /**< Bad parameters to mpg123_index() and mpg123_set_index() */
MPG123_OUT_OF_SYNC, /**< Lost track in bytestream and did not try to resync. */ MPG123_OUT_OF_SYNC, /**< Lost track in bytestream and did not try to resync. */
@@ -726,6 +710,7 @@ MPG123_EXPORT int mpg123_getformat2( mpg123_handle *mh
* @{ * @{
*/ */
#ifndef MPG123_PORTABLE_API
/** Open a simple MPEG file with fixed properties. /** Open a simple MPEG file with fixed properties.
* *
* This function shall simplify the common use case of a plain MPEG * This function shall simplify the common use case of a plain MPEG
@@ -796,10 +781,12 @@ MPG123_EXPORT int mpg123_open(mpg123_handle *mh, const char *path);
* \return MPG123_OK on success * \return MPG123_OK on success
*/ */
MPG123_EXPORT int mpg123_open_fd(mpg123_handle *mh, int fd); MPG123_EXPORT int mpg123_open_fd(mpg123_handle *mh, int fd);
#endif
/** Use an opaque handle as bitstream input. This works only with the /** Use an opaque handle as bitstream input. This works only with the
* replaced I/O from mpg123_replace_reader_handle()! * replaced I/O from mpg123_replace_reader_handle() or mpg123_reader64()!
* mpg123_close() will call the cleanup callback for your handle (if you gave one). * mpg123_close() will call the cleanup callback for your non-NULL
* handle (if you gave one).
* \param mh handle * \param mh handle
* \param iohandle your handle * \param iohandle your handle
* \return MPG123_OK on success * \return MPG123_OK on success
@@ -868,6 +855,7 @@ MPG123_EXPORT int mpg123_decode( mpg123_handle *mh
, const unsigned char *inmemory, size_t inmemsize , const unsigned char *inmemory, size_t inmemsize
, void *outmemory, size_t outmemsize, size_t *done ); , void *outmemory, size_t outmemsize, size_t *done );
#ifndef MPG123_PORTABLE_API
/** Decode next MPEG frame to internal buffer /** Decode next MPEG frame to internal buffer
* or read a frame and return after setting a new format. * or read a frame and return after setting a new format.
* \param mh handle * \param mh handle
@@ -890,6 +878,30 @@ MPG123_EXPORT int mpg123_decode_frame( mpg123_handle *mh
*/ */
MPG123_EXPORT int mpg123_framebyframe_decode( mpg123_handle *mh MPG123_EXPORT int mpg123_framebyframe_decode( mpg123_handle *mh
, off_t *num, unsigned char **audio, size_t *bytes ); , off_t *num, unsigned char **audio, size_t *bytes );
#endif /* un-portable API */
/** Decode next MPEG frame to internal buffer
* or read a frame and return after setting a new format.
* \param mh handle
* \param num current frame offset gets stored there
* \param audio This pointer is set to the internal buffer to read the decoded audio from.
* \param bytes number of output bytes ready in the buffer
* \return MPG123_OK or error/message code
*/
MPG123_EXPORT int mpg123_decode_frame64( mpg123_handle *mh
, int64_t *num, unsigned char **audio, size_t *bytes );
/** Decode current MPEG frame to internal buffer.
* Warning: This is experimental API that might change in future releases!
* Please watch mpg123 development closely when using it.
* \param mh handle
* \param num last frame offset gets stored there
* \param audio this pointer is set to the internal buffer to read the decoded audio from.
* \param bytes number of output bytes ready in the buffer
* \return MPG123_OK or error/message code
*/
MPG123_EXPORT int mpg123_framebyframe_decode64( mpg123_handle *mh
, int64_t *num, unsigned char **audio, size_t *bytes );
/** Find, read and parse the next mp3 frame /** Find, read and parse the next mp3 frame
* Warning: This is experimental API that might change in future releases! * Warning: This is experimental API that might change in future releases!
@@ -917,6 +929,7 @@ MPG123_EXPORT int mpg123_framebyframe_next(mpg123_handle *mh);
MPG123_EXPORT int mpg123_framedata( mpg123_handle *mh MPG123_EXPORT int mpg123_framedata( mpg123_handle *mh
, unsigned long *header, unsigned char **bodydata, size_t *bodybytes ); , unsigned long *header, unsigned char **bodydata, size_t *bodybytes );
#ifndef MPG123_PORTABLE_API
/** Get the input position (byte offset in stream) of the last parsed frame. /** Get the input position (byte offset in stream) of the last parsed frame.
* This can be used for external seek index building, for example. * This can be used for external seek index building, for example.
* It just returns the internally stored offset, regardless of validity -- * It just returns the internally stored offset, regardless of validity --
@@ -925,6 +938,16 @@ MPG123_EXPORT int mpg123_framedata( mpg123_handle *mh
* \return byte offset in stream * \return byte offset in stream
*/ */
MPG123_EXPORT off_t mpg123_framepos(mpg123_handle *mh); MPG123_EXPORT off_t mpg123_framepos(mpg123_handle *mh);
#endif
/** Get the 64 bit input position (byte offset in stream) of the last parsed frame.
* This can be used for external seek index building, for example.
* It just returns the internally stored offset, regardless of validity --
* you ensure that a valid frame has been parsed before!
* \param mh handle
* \return byte offset in stream
*/
MPG123_EXPORT int64_t mpg123_framepos64(mpg123_handle *mh);
/** @} */ /** @} */
@@ -971,25 +994,52 @@ MPG123_EXPORT off_t mpg123_framepos(mpg123_handle *mh);
* @{ * @{
*/ */
#ifndef MPG123_PORTABLE_API
/** Returns the current position in samples. /** Returns the current position in samples.
* On the next successful read, you'd get audio data with that offset. * On the next successful read, you'd get audio data with that offset.
* \param mh handle * \param mh handle
* \return sample (PCM frame) offset or MPG123_ERR (null handle) * \return sample (PCM frame) offset or MPG123_ERR (null handle)
*/ */
MPG123_EXPORT off_t mpg123_tell(mpg123_handle *mh); MPG123_EXPORT off_t mpg123_tell(mpg123_handle *mh);
#endif
/** Returns the current 64 bit position in samples.
* On the next successful read, you'd get audio data with that offset.
* \param mh handle
* \return sample (PCM frame) offset or MPG123_ERR (null handle)
*/
MPG123_EXPORT int64_t mpg123_tell64(mpg123_handle *mh);
#ifndef MPG123_PORTABLE_API
/** Returns the frame number that the next read will give you data from. /** Returns the frame number that the next read will give you data from.
* \param mh handle * \param mh handle
* \return frame offset or MPG123_ERR (null handle) * \return frame offset or MPG123_ERR (null handle)
*/ */
MPG123_EXPORT off_t mpg123_tellframe(mpg123_handle *mh); MPG123_EXPORT off_t mpg123_tellframe(mpg123_handle *mh);
#endif
/** Returns the 64 bit frame number that the next read will give you data from.
* \param mh handle
* \return frame offset or MPG123_ERR (null handle)
*/
MPG123_EXPORT int64_t mpg123_tellframe64(mpg123_handle *mh);
#ifndef MPG123_PORTABLE_API
/** Returns the current byte offset in the input stream. /** Returns the current byte offset in the input stream.
* \param mh handle * \param mh handle
* \return byte offset or MPG123_ERR (null handle) * \return byte offset or MPG123_ERR (null handle)
*/ */
MPG123_EXPORT off_t mpg123_tell_stream(mpg123_handle *mh); MPG123_EXPORT off_t mpg123_tell_stream(mpg123_handle *mh);
#endif
/** Returns the current 64 bit byte offset in the input stream.
* \param mh handle
* \return byte offset or MPG123_ERR (null handle)
*/
MPG123_EXPORT int64_t mpg123_tell_stream64(mpg123_handle *mh);
#ifndef MPG123_PORTABLE_API
/** Seek to a desired sample offset. /** Seek to a desired sample offset.
* Usage is modelled afer the standard lseek(). * Usage is modelled afer the standard lseek().
* \param mh handle * \param mh handle
@@ -999,7 +1049,19 @@ MPG123_EXPORT off_t mpg123_tell_stream(mpg123_handle *mh);
*/ */
MPG123_EXPORT off_t mpg123_seek( mpg123_handle *mh MPG123_EXPORT off_t mpg123_seek( mpg123_handle *mh
, off_t sampleoff, int whence ); , off_t sampleoff, int whence );
#endif
/** Seek to a desired 64 bit sample offset.
* Usage is modelled afer the standard lseek().
* \param mh handle
* \param sampleoff offset in samples (PCM frames)
* \param whence one of SEEK_SET, SEEK_CUR or SEEK_END
* \return The resulting offset >= 0 or error/message code
*/
MPG123_EXPORT int64_t mpg123_seek64( mpg123_handle *mh
, int64_t sampleoff, int whence );
#ifndef MPG123_PORTABLE_API
/** Seek to a desired sample offset in data feeding mode. /** Seek to a desired sample offset in data feeding mode.
* This just prepares things to be right only if you ensure that the next chunk * This just prepares things to be right only if you ensure that the next chunk
* of input data will be from input_offset byte position. * of input data will be from input_offset byte position.
@@ -1012,7 +1074,22 @@ MPG123_EXPORT off_t mpg123_seek( mpg123_handle *mh
*/ */
MPG123_EXPORT off_t mpg123_feedseek( mpg123_handle *mh MPG123_EXPORT off_t mpg123_feedseek( mpg123_handle *mh
, off_t sampleoff, int whence, off_t *input_offset ); , off_t sampleoff, int whence, off_t *input_offset );
#endif
/** Seek to a desired 64 bit sample offset in data feeding mode.
* This just prepares things to be right only if you ensure that the next chunk
* of input data will be from input_offset byte position.
* \param mh handle
* \param sampleoff offset in samples (PCM frames)
* \param whence one of SEEK_SET, SEEK_CUR or SEEK_END
* \param input_offset The position it expects to be at the
* next time data is fed to mpg123_decode().
* \return The resulting offset >= 0 or error/message code
*/
MPG123_EXPORT int64_t mpg123_feedseek64( mpg123_handle *mh
, int64_t sampleoff, int whence, int64_t *input_offset );
#ifndef MPG123_PORTABLE_API
/** Seek to a desired MPEG frame offset. /** Seek to a desired MPEG frame offset.
* Usage is modelled afer the standard lseek(). * Usage is modelled afer the standard lseek().
* \param mh handle * \param mh handle
@@ -1021,7 +1098,18 @@ MPG123_EXPORT off_t mpg123_feedseek( mpg123_handle *mh
* \return The resulting offset >= 0 or error/message code */ * \return The resulting offset >= 0 or error/message code */
MPG123_EXPORT off_t mpg123_seek_frame( mpg123_handle *mh MPG123_EXPORT off_t mpg123_seek_frame( mpg123_handle *mh
, off_t frameoff, int whence ); , off_t frameoff, int whence );
#endif
/** Seek to a desired 64 bit MPEG frame offset.
* Usage is modelled afer the standard lseek().
* \param mh handle
* \param frameoff offset in MPEG frames
* \param whence one of SEEK_SET, SEEK_CUR or SEEK_END
* \return The resulting offset >= 0 or error/message code */
MPG123_EXPORT int64_t mpg123_seek_frame64( mpg123_handle *mh
, int64_t frameoff, int whence );
#ifndef MPG123_PORTABLE_API
/** Return a MPEG frame offset corresponding to an offset in seconds. /** Return a MPEG frame offset corresponding to an offset in seconds.
* This assumes that the samples per frame do not change in the file/stream, which is a good assumption for any sane file/stream only. * This assumes that the samples per frame do not change in the file/stream, which is a good assumption for any sane file/stream only.
* \return frame offset >= 0 or error/message code */ * \return frame offset >= 0 or error/message code */
@@ -1029,7 +1117,9 @@ MPG123_EXPORT off_t mpg123_timeframe(mpg123_handle *mh, double sec);
/** Give access to the frame index table that is managed for seeking. /** Give access to the frame index table that is managed for seeking.
* You are asked not to modify the values... Use mpg123_set_index to set the * You are asked not to modify the values... Use mpg123_set_index to set the
* seek index * seek index.
* Note: This can be just a copy of the data in case a conversion is done
* from the internal 64 bit values.
* \param mh handle * \param mh handle
* \param offsets pointer to the index array * \param offsets pointer to the index array
* \param step one index byte offset advances this many MPEG frames * \param step one index byte offset advances this many MPEG frames
@@ -1038,10 +1128,31 @@ MPG123_EXPORT off_t mpg123_timeframe(mpg123_handle *mh, double sec);
*/ */
MPG123_EXPORT int mpg123_index( mpg123_handle *mh MPG123_EXPORT int mpg123_index( mpg123_handle *mh
, off_t **offsets, off_t *step, size_t *fill ); , off_t **offsets, off_t *step, size_t *fill );
#endif
/** Return a 64 bit MPEG frame offset corresponding to an offset in seconds.
* This assumes that the samples per frame do not change in the file/stream, which is a good assumption for any sane file/stream only.
* \return frame offset >= 0 or error/message code */
MPG123_EXPORT int64_t mpg123_timeframe64(mpg123_handle *mh, double sec);
/** Give access to the 64 bit frame index table that is managed for seeking.
* You are asked not to modify the values... Use mpg123_set_index to set the
* seek index.
* \param mh handle
* \param offsets pointer to the index array
* \param step one index byte offset advances this many MPEG frames
* \param fill number of recorded index offsets; size of the array
* \return MPG123_OK on success
*/
MPG123_EXPORT int mpg123_index64( mpg123_handle *mh
, int64_t **offsets, int64_t *step, size_t *fill );
#ifndef MPG123_PORTABLE_API
/** Set the frame index table /** Set the frame index table
* Setting offsets to NULL and fill > 0 will allocate fill entries. Setting offsets * Setting offsets to NULL and fill > 0 will allocate fill entries. Setting offsets
* to NULL and fill to 0 will clear the index and free the allocated memory used by the index. * to NULL and fill to 0 will clear the index and free the allocated memory used by the index.
* Note that this function might involve conversion/copying of data because of
* the varying nature of off_t. Better use mpg123_set_index64().
* \param mh handle * \param mh handle
* \param offsets pointer to the index array * \param offsets pointer to the index array
* \param step one index byte offset advances this many MPEG frames * \param step one index byte offset advances this many MPEG frames
@@ -1050,15 +1161,31 @@ MPG123_EXPORT int mpg123_index( mpg123_handle *mh
*/ */
MPG123_EXPORT int mpg123_set_index( mpg123_handle *mh MPG123_EXPORT int mpg123_set_index( mpg123_handle *mh
, off_t *offsets, off_t step, size_t fill ); , off_t *offsets, off_t step, size_t fill );
#endif
/** Set the 64 bit frame index table
* Setting offsets to NULL and fill > 0 will allocate fill entries. Setting offsets
* to NULL and fill to 0 will clear the index and free the allocated memory used by the index.
* \param mh handle
* \param offsets pointer to the index array
* \param step one index byte offset advances this many MPEG frames
* \param fill number of recorded index offsets; size of the array
* \return MPG123_OK on success
*/
MPG123_EXPORT int mpg123_set_index64( mpg123_handle *mh
, int64_t *offsets, int64_t step, size_t fill );
#ifndef MPG123_PORTABLE_API
/** An old crutch to keep old mpg123 binaries happy. /** An old crutch to keep old mpg123 binaries happy.
* WARNING: This function is there only to avoid runtime linking errors with * WARNING: This function is there only to avoid runtime linking errors with
* standalone mpg123 before version 1.23.0 (if you strangely update the * standalone mpg123 before version 1.32.0 (if you strangely update the
* library but not the end-user program) and actually is broken * library but not the end-user program) and actually is broken
* for various cases (p.ex. 24 bit output). Do never use. It might eventually * for various cases (p.ex. 24 bit output). Do never use. It might eventually
* be purged from the library. * be purged from the library.
*/ */
MPG123_EXPORT 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); MPG123_EXPORT 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);
#endif
/** @} */ /** @} */
@@ -1348,6 +1475,7 @@ MPG123_EXPORT size_t mpg123_safe_buffer(void);
*/ */
MPG123_EXPORT int mpg123_scan(mpg123_handle *mh); MPG123_EXPORT int mpg123_scan(mpg123_handle *mh);
#ifndef MPG123_PORTABLE_API
/** Return, if possible, the full (expected) length of current track in /** Return, if possible, the full (expected) length of current track in
* MPEG frames. * MPEG frames.
* \param mh handle * \param mh handle
@@ -1376,6 +1504,36 @@ MPG123_EXPORT off_t mpg123_length(mpg123_handle *mh);
* \return MPG123_OK on success * \return MPG123_OK on success
*/ */
MPG123_EXPORT int mpg123_set_filesize(mpg123_handle *mh, off_t size); MPG123_EXPORT int mpg123_set_filesize(mpg123_handle *mh, off_t size);
#endif
/** Return, if possible, the full (expected) length of current track in
* MPEG frames as 64 bit number.
* \param mh handle
* \return length >= 0 or MPG123_ERR if there is no length guess possible.
*/
MPG123_EXPORT int64_t mpg123_framelength64(mpg123_handle *mh);
/** Return, if possible, the full (expected) length of current
* track in samples (PCM frames) as 64 bit value.
*
* This relies either on an Info frame at the beginning or a previous
* call to mpg123_scan() to get the real number of MPEG frames in a
* file. It will guess based on file size if neither Info frame nor
* scan data are present. In any case, there is no guarantee that the
* decoder will not give you more data, for example in case the open
* file gets appended to during decoding.
* \param mh handle
* \return length >= 0 or MPG123_ERR if there is no length guess possible.
*/
MPG123_EXPORT int64_t mpg123_length64(mpg123_handle *mh);
/** Override the 64 bit value for file size in bytes.
* Useful for getting sensible track length values in feed mode or for HTTP streams.
* \param mh handle
* \param size file size in bytes
* \return MPG123_OK on success
*/
MPG123_EXPORT int mpg123_set_filesize64(mpg123_handle *mh, int64_t size);
/** Get MPEG frame duration in seconds. /** Get MPEG frame duration in seconds.
* \param mh handle * \param mh handle
@@ -1999,12 +2157,13 @@ MPG123_EXPORT int mpg123_replace_buffer(mpg123_handle *mh
*/ */
MPG123_EXPORT size_t mpg123_outblock(mpg123_handle *mh); MPG123_EXPORT size_t mpg123_outblock(mpg123_handle *mh);
#ifndef MPG123_PORTABLE_API
/** Replace low-level stream access functions; read and lseek as known in POSIX. /** Replace low-level stream access functions; read and lseek as known in POSIX.
* You can use this to make any fancy file opening/closing yourself, * You can use this to make any fancy file opening/closing yourself,
* using mpg123_open_fd() to set the file descriptor for your read/lseek * using mpg123_open_fd() to set the file descriptor for your read/lseek
* (doesn't need to be a "real" file descriptor...). * (doesn't need to be a "real" file descriptor...).
* Setting a function to NULL means that the default internal read is * Setting a function to NULL means that just a call to POSIX read/lseek is
* used (active from next mpg123_open call on). * done (without handling signals).
* Note: As it would be troublesome to mess with this while having a file open, * Note: As it would be troublesome to mess with this while having a file open,
* this implies mpg123_close(). * this implies mpg123_close().
* \param mh handle * \param mh handle
@@ -2031,7 +2190,7 @@ MPG123_EXPORT int mpg123_replace_reader( mpg123_handle *mh
* \param mh handle * \param mh handle
* \param r_read callback for reading (behaviour like POSIX read) * \param r_read callback for reading (behaviour like POSIX read)
* \param r_lseek callback for seeking (like POSIX lseek) * \param r_lseek callback for seeking (like POSIX lseek)
* \param cleanup A callback to clean up an I/O handle on mpg123_close, * \param cleanup A callback to clean up a non-NULL I/O handle on mpg123_close,
* can be NULL for none (you take care of cleaning your handles). * can be NULL for none (you take care of cleaning your handles).
* \return MPG123_OK on success * \return MPG123_OK on success
*/ */
@@ -2039,6 +2198,7 @@ MPG123_EXPORT int mpg123_replace_reader_handle( mpg123_handle *mh
, mpg123_ssize_t (*r_read) (void *, void *, size_t) , mpg123_ssize_t (*r_read) (void *, void *, size_t)
, off_t (*r_lseek)(void *, off_t, int) , off_t (*r_lseek)(void *, off_t, int)
, void (*cleanup)(void*) ); , void (*cleanup)(void*) );
#endif
/** Set up portable read functions on an opaque handle. /** Set up portable read functions on an opaque handle.
* The handle is a void pointer, so you can pass any data you want... * The handle is a void pointer, so you can pass any data you want...
@@ -2052,15 +2212,13 @@ MPG123_EXPORT int mpg123_replace_reader_handle( mpg123_handle *mh
* address to store the returned byte count. Return value is zero for * address to store the returned byte count. Return value is zero for
* no issue, non-zero for some error. Recoverable signal handling has to happen * no issue, non-zero for some error. Recoverable signal handling has to happen
* inside the callback. * inside the callback.
* \param r_lseek callback for seeking (like POSIX lseek) * \param r_lseek callback for seeking (like POSIX lseek), maybe NULL for
* \param cleanup A callback to clean up an I/O handle on mpg123_close, * non-seekable streams
* can be NULL for none (you take care of cleaning your handles). * \param cleanup A callback to clean up a non-NULL I/O handle on mpg123_close,
* maybe NULL for none
* \return MPG123_OK on success * \return MPG123_OK on success
*/ */
MPG123_EXPORT int mpg123_reader64( mpg123_handle *mh MPG123_EXPORT int mpg123_reader64( mpg123_handle *mh, int (*r_read) (void *, void *, size_t, size_t *), int64_t (*r_lseek)(void *, int64_t, int), void (*cleanup)(void*) );
, int (*r_read) (void *, void *, size_t, size_t *)
, int64_t (*r_lseek)(void *, int64_t, int)
, void (*cleanup)(void*) );
/** @} */ /** @} */

View File

@@ -1,7 +1,7 @@
/* /*
mpg123lib_intern: Common non-public stuff for libmpg123 mpg123lib_intern: Common non-public stuff for libmpg123
copyright 1995-2021 by the mpg123 project - free software under the terms of the LGPL 2.1 copyright 1995-2023 by the mpg123 project - free software under the terms of the LGPL 2.1
see COPYING and AUTHORS files in distribution or http://mpg123.org see COPYING and AUTHORS files in distribution or http://mpg123.org
derived from the old mpg123.h derived from the old mpg123.h
@@ -323,10 +323,10 @@ static inline int32_t scale_rounded(int32_t x, int shift)
int decode_update(mpg123_handle *mh); int decode_update(mpg123_handle *mh);
/* residing in format.c */ /* residing in format.c */
off_t decoder_synth_bytes(mpg123_handle *fr , off_t s); int64_t decoder_synth_bytes(mpg123_handle *fr , int64_t s);
off_t samples_to_bytes(mpg123_handle *fr , off_t s); int64_t samples_to_bytes(mpg123_handle *fr , int64_t s);
off_t bytes_to_samples(mpg123_handle *fr , off_t b); int64_t bytes_to_samples(mpg123_handle *fr , int64_t b);
off_t outblock_bytes(mpg123_handle *fr, off_t s); int64_t outblock_bytes(mpg123_handle *fr, int64_t s);
/* Postprocessing format conversion of freshly decoded buffer. */ /* Postprocessing format conversion of freshly decoded buffer. */
void postprocess_buffer(mpg123_handle *fr); void postprocess_buffer(mpg123_handle *fr);

View File

@@ -1,12 +1,12 @@
/* /*
ntom.c: N->M down/up sampling; the setup code. ntom.c: N->M down/up sampling; the setup code.
copyright 1995-2008 by the mpg123 project - free software under the terms of the LGPL 2.1 copyright 1995-2023 by the mpg123 project - free software under the terms of the LGPL 2.1
see COPYING and AUTHORS files in distribution or http://mpg123.org see COPYING and AUTHORS files in distribution or http://mpg123.org
initially written by Michael Hipp initially written by Michael Hipp
*/ */
#define SAFE_NTOM /* Do not depend on off_t*off_t with big values still being in the range... */ #define SAFE_NTOM /* Do not depend on int64_t*int64_t with big values still being in the range... */
#include "mpg123lib_intern.h" #include "mpg123lib_intern.h"
#include "debug.h" #include "debug.h"
@@ -40,14 +40,14 @@ int synth_ntom_set_step(mpg123_handle *fr)
/* /*
The SAFE_NTOM does iterative loops instead of straight multiplication. The SAFE_NTOM does iterative loops instead of straight multiplication.
The safety is not just about the algorithm closely mimicking the decoder instead of applying some formula, The safety is not just about the algorithm closely mimicking the decoder instead of applying some formula,
it is more about avoiding multiplication of possibly big sample offsets (a 32bit off_t could overflow too easily). it is more about avoiding multiplication of possibly big sample offsets (a 32bit int64_t could overflow too easily).
*/ */
unsigned long ntom_val(mpg123_handle *fr, off_t frame) unsigned long ntom_val(mpg123_handle *fr, int64_t frame)
{ {
off_t ntm; int64_t ntm;
#ifdef SAFE_NTOM /* Carry out the loop, without the threatening integer overflow. */ #ifdef SAFE_NTOM /* Carry out the loop, without the threatening integer overflow. */
off_t f; int64_t f;
ntm = NTOM_MUL>>1; /* for frame 0 */ ntm = NTOM_MUL>>1; /* for frame 0 */
for(f=0; f<frame; ++f) /* for frame > 0 */ for(f=0; f<frame; ++f) /* for frame > 0 */
{ {
@@ -63,14 +63,14 @@ unsigned long ntom_val(mpg123_handle *fr, off_t frame)
/* Set the ntom value for next expected frame to be decoded. /* Set the ntom value for next expected frame to be decoded.
This is for keeping output consistent across seeks. */ This is for keeping output consistent across seeks. */
void ntom_set_ntom(mpg123_handle *fr, off_t num) void ntom_set_ntom(mpg123_handle *fr, int64_t num)
{ {
fr->ntom_val[1] = fr->ntom_val[0] = ntom_val(fr, num); fr->ntom_val[1] = fr->ntom_val[0] = ntom_val(fr, num);
} }
/* Carry out the ntom sample count operation for this one frame. /* Carry out the ntom sample count operation for this one frame.
No fear of integer overflow here. */ No fear of integer overflow here. */
off_t ntom_frame_outsamples(mpg123_handle *fr) int64_t ntom_frame_outsamples(mpg123_handle *fr)
{ {
/* The do this before decoding the separate channels, so there is only one common ntom value. */ /* The do this before decoding the separate channels, so there is only one common ntom value. */
int ntm = fr->ntom_val[0]; int ntm = fr->ntom_val[0];
@@ -79,13 +79,13 @@ off_t ntom_frame_outsamples(mpg123_handle *fr)
} }
/* Convert frame offset to unadjusted output sample offset. */ /* Convert frame offset to unadjusted output sample offset. */
off_t ntom_frmouts(mpg123_handle *fr, off_t frame) int64_t ntom_frmouts(mpg123_handle *fr, int64_t frame)
{ {
#ifdef SAFE_NTOM #ifdef SAFE_NTOM
off_t f; int64_t f;
#endif #endif
off_t soff = 0; int64_t soff = 0;
off_t ntm = ntom_val(fr,0); int64_t ntm = ntom_val(fr,0);
#ifdef SAFE_NTOM #ifdef SAFE_NTOM
if(frame <= 0) return 0; if(frame <= 0) return 0;
for(f=0; f<frame; ++f) for(f=0; f<frame; ++f)
@@ -95,23 +95,23 @@ off_t ntom_frmouts(mpg123_handle *fr, off_t frame)
ntm -= (ntm/NTOM_MUL)*NTOM_MUL; ntm -= (ntm/NTOM_MUL)*NTOM_MUL;
} }
#else #else
soff = (ntm + frame*(off_t)fr->spf*(off_t)fr->ntom_step)/(off_t)NTOM_MUL; soff = (ntm + frame*(int64_t)fr->spf*(int64_t)fr->ntom_step)/(int64_t)NTOM_MUL;
#endif #endif
return soff; return soff;
} }
/* Convert input samples to unadjusted output samples. */ /* Convert input samples to unadjusted output samples. */
off_t ntom_ins2outs(mpg123_handle *fr, off_t ins) int64_t ntom_ins2outs(mpg123_handle *fr, int64_t ins)
{ {
off_t soff = 0; int64_t soff = 0;
off_t ntm = ntom_val(fr,0); int64_t ntm = ntom_val(fr,0);
#ifdef SAFE_NTOM #ifdef SAFE_NTOM
{ {
off_t block = fr->spf; int64_t block = fr->spf;
if(ins <= 0) return 0; if(ins <= 0) return 0;
do do
{ {
off_t nowblock = ins > block ? block : ins; int64_t nowblock = ins > block ? block : ins;
ntm += nowblock*fr->ntom_step; ntm += nowblock*fr->ntom_step;
soff += ntm/NTOM_MUL; soff += ntm/NTOM_MUL;
ntm -= (ntm/NTOM_MUL)*NTOM_MUL; ntm -= (ntm/NTOM_MUL)*NTOM_MUL;
@@ -119,18 +119,18 @@ off_t ntom_ins2outs(mpg123_handle *fr, off_t ins)
} while(ins > 0); } while(ins > 0);
} }
#else #else
/* Beware of overflows: when off_t is 32bits, the multiplication blows too easily. /* Beware of overflows: when int64_t is 32bits, the multiplication blows too easily.
Of course, it blows for 64bits, too, in theory, but that's for _really_ large files. */ Of course, it blows for 64bits, too, in theory, but that's for _really_ large files. */
soff = ((off_t)ntm + (off_t)ins*(off_t)fr->ntom_step)/(off_t)NTOM_MUL; soff = ((int64_t)ntm + (int64_t)ins*(int64_t)fr->ntom_step)/(int64_t)NTOM_MUL;
#endif #endif
return soff; return soff;
} }
/* Determine frame offset from unadjusted output sample offset. */ /* Determine frame offset from unadjusted output sample offset. */
off_t ntom_frameoff(mpg123_handle *fr, off_t soff) int64_t ntom_frameoff(mpg123_handle *fr, int64_t soff)
{ {
off_t ioff = 0; /* frames or samples */ int64_t ioff = 0; /* frames or samples */
off_t ntm = ntom_val(fr,0); int64_t ntm = ntom_val(fr,0);
#ifdef SAFE_NTOM #ifdef SAFE_NTOM
if(soff <= 0) return 0; if(soff <= 0) return 0;
for(ioff=0; 1; ++ioff) for(ioff=0; 1; ++ioff)
@@ -142,7 +142,7 @@ off_t ntom_frameoff(mpg123_handle *fr, off_t soff)
} }
return ioff; return ioff;
#else #else
ioff = (soff*(off_t)NTOM_MUL-ntm)/(off_t)fr->ntom_step; ioff = (soff*(int64_t)NTOM_MUL-ntm)/(int64_t)fr->ntom_step;
return ioff/(off_t)fr->spf; return ioff/(int64_t)fr->spf;
#endif #endif
} }

View File

@@ -203,7 +203,7 @@ static int check_lame_tag(mpg123_handle *fr)
else else
{ {
/* Check for endless stream, but: TRACK_MAX_FRAMES sensible at all? */ /* Check for endless stream, but: TRACK_MAX_FRAMES sensible at all? */
fr->track_frames = long_tmp > TRACK_MAX_FRAMES ? 0 : (off_t) long_tmp; fr->track_frames = long_tmp > TRACK_MAX_FRAMES ? 0 : (int64_t) long_tmp;
#ifdef GAPLESS #ifdef GAPLESS
/* All or nothing: Only if encoder delay/padding is known, we'll cut /* All or nothing: Only if encoder delay/padding is known, we'll cut
samples for gapless. */ samples for gapless. */
@@ -228,14 +228,14 @@ static int check_lame_tag(mpg123_handle *fr)
ignoring leading ID3v2 data. Trailing tags (ID3v1) seem to be ignoring leading ID3v2 data. Trailing tags (ID3v1) seem to be
included, though. */ included, though. */
if(fr->rdat.filelen < 1) if(fr->rdat.filelen < 1)
fr->rdat.filelen = (off_t) long_tmp + fr->audio_start; /* Overflow? */ fr->rdat.filelen = (int64_t) long_tmp + fr->audio_start; /* Overflow? */
else else
{ {
if((off_t)long_tmp != fr->rdat.filelen - fr->audio_start && NOQUIET) if((int64_t)long_tmp != fr->rdat.filelen - fr->audio_start && NOQUIET)
{ /* 1/filelen instead of 1/(filelen-start), my decision */ { /* 1/filelen instead of 1/(filelen-start), my decision */
double diff = 100.0/fr->rdat.filelen double diff = 100.0/fr->rdat.filelen
* ( fr->rdat.filelen - fr->audio_start * ( fr->rdat.filelen - fr->audio_start
- (off_t)long_tmp ); - (int64_t)long_tmp );
if(diff < 0.) diff = -diff; if(diff < 0.) diff = -diff;
if(VERBOSE3) fprintf(stderr if(VERBOSE3) fprintf(stderr
@@ -279,8 +279,8 @@ static int check_lame_tag(mpg123_handle *fr)
float peak = 0; float peak = 0;
float gain_offset = 0; /* going to be +6 for old lame that used 83dB */ float gain_offset = 0; /* going to be +6 for old lame that used 83dB */
char nb[10]; char nb[10];
off_t pad_in; int64_t pad_in;
off_t pad_out; int64_t pad_out;
memcpy(nb, fr->bsbuf+lame_offset, 9); memcpy(nb, fr->bsbuf+lame_offset, 9);
nb[9] = 0; nb[9] = 0;
if(VERBOSE3) fprintf(stderr, "Note: Info: Encoder: %s\n", nb); if(VERBOSE3) fprintf(stderr, "Note: Info: Encoder: %s\n", nb);
@@ -496,7 +496,7 @@ int read_frame(mpg123_handle *fr)
/* TODO: rework this thing */ /* TODO: rework this thing */
int freeformat_count = 0; int freeformat_count = 0;
unsigned long newhead; unsigned long newhead;
off_t framepos; int64_t framepos;
int ret; int ret;
/* stuff that needs resetting if complete frame reading fails */ /* stuff that needs resetting if complete frame reading fails */
int oldsize = fr->framesize; int oldsize = fr->framesize;
@@ -521,9 +521,9 @@ int read_frame(mpg123_handle *fr)
#endif #endif
) ) ) )
{ {
mdebug( "stopping parsing at %"OFF_P mdebug( "stopping parsing at %"PRIi64
" frames as indicated fixed track length" " frames as indicated fixed track length"
, (off_p)fr->num+1 ); , fr->num+1 );
return 0; return 0;
} }
@@ -532,7 +532,7 @@ read_again:
This is essential to prevent endless looping, always going back to the beginning when feeder buffer is exhausted. */ This is essential to prevent endless looping, always going back to the beginning when feeder buffer is exhausted. */
if(fr->rd->forget != NULL) fr->rd->forget(fr); if(fr->rd->forget != NULL) fr->rd->forget(fr);
debug2("trying to get frame %"OFF_P" at %"OFF_P, (off_p)fr->num+1, (off_p)fr->rd->tell(fr)); debug2("trying to get frame %"PRIi64" at %"PRIi64, fr->num+1, fr->rd->tell(fr));
if((ret = fr->rd->head_read(fr,&newhead)) <= 0){ debug1("need more? (%i)", ret); goto read_frame_bad;} if((ret = fr->rd->head_read(fr,&newhead)) <= 0){ debug1("need more? (%i)", ret); goto read_frame_bad;}
init_resync: init_resync:
@@ -573,8 +573,8 @@ init_resync:
{ {
if(fr->firsthead && !head_compatible(fr->firsthead, newhead)) if(fr->firsthead && !head_compatible(fr->firsthead, newhead))
{ {
mdebug( "stopping before reading frame %"OFF_P mdebug( "stopping before reading frame %"PRIi64
" as its header indicates Frankenstein coming for you", (off_p)fr->num ); " as its header indicates Frankenstein coming for you", fr->num );
return 0; return 0;
} }
} }
@@ -585,7 +585,7 @@ init_resync:
{ {
unsigned char *newbuf = fr->bsspace[fr->bsnum]+512; unsigned char *newbuf = fr->bsspace[fr->bsnum]+512;
/* read main data into memory */ /* read main data into memory */
debug2("read frame body of %i at %"OFF_P, fr->framesize, framepos+4); debug2("read frame body of %i at %"PRIi64, fr->framesize, framepos+4);
if((ret=fr->rd->read_frame_body(fr,newbuf,fr->framesize))<0) if((ret=fr->rd->read_frame_body(fr,newbuf,fr->framesize))<0)
{ {
/* if failed: flip back */ /* if failed: flip back */
@@ -631,8 +631,7 @@ init_resync:
fr->mean_framesize = ((fr->mean_frames-1)*fr->mean_framesize+compute_bpf(fr)) / fr->mean_frames ; fr->mean_framesize = ((fr->mean_frames-1)*fr->mean_framesize+compute_bpf(fr)) / fr->mean_frames ;
} }
++fr->num; /* 0 for first frame! */ ++fr->num; /* 0 for first frame! */
debug4("Frame %"OFF_P" %08lx %i, next filepos=%"OFF_P, debug4("Frame %"PRIi64" %08lx %i, next filepos=%"PRIi64, fr->num, newhead, fr->framesize, fr->rd->tell(fr));
(off_p)fr->num, newhead, fr->framesize, (off_p)fr->rd->tell(fr));
if(!(fr->state_flags & FRAME_FRANKENSTEIN) && ( if(!(fr->state_flags & FRAME_FRANKENSTEIN) && (
(fr->track_frames > 0 && fr->num >= fr->track_frames) (fr->track_frames > 0 && fr->num >= fr->track_frames)
#ifdef GAPLESS #ifdef GAPLESS
@@ -641,11 +640,13 @@ init_resync:
)) ))
{ {
fr->state_flags |= FRAME_FRANKENSTEIN; fr->state_flags |= FRAME_FRANKENSTEIN;
if(NOQUIET) fprintf(stderr, "\nWarning: Encountered more data after announced end of track (frame %"OFF_P"/%"OFF_P"). Frankenstein!\n", (off_p)fr->num, if(NOQUIET)
fprintf(stderr, "\nWarning: Encountered more data after announced"
" end of track (frame %"PRIi64"/%"PRIi64"). Frankenstein!\n", fr->num,
#ifdef GAPLESS #ifdef GAPLESS
fr->gapless_frames > 0 ? (off_p)fr->gapless_frames : fr->gapless_frames > 0 ? fr->gapless_frames :
#endif #endif
(off_p)fr->track_frames); fr->track_frames);
} }
halfspeed_prepare(fr); halfspeed_prepare(fr);
@@ -982,13 +983,13 @@ double attribute_align_arg mpg123_tpf(mpg123_handle *fr)
return tpf; return tpf;
} }
int attribute_align_arg mpg123_position(mpg123_handle *fr, off_t no, off_t buffsize, int attribute_align_arg mpg123_position64(mpg123_handle *fr, int64_t no, int64_t buffsize,
off_t *current_frame, off_t *frames_left, int64_t *current_frame, int64_t *frames_left,
double *current_seconds, double *seconds_left) double *current_seconds, double *seconds_left)
{ {
double tpf; double tpf;
double dt = 0.0; double dt = 0.0;
off_t cur, left; int64_t cur, left;
double curs, lefts; double curs, lefts;
if(!fr || !fr->rd) return MPG123_ERR; if(!fr || !fr->rd) return MPG123_ERR;
@@ -1009,9 +1010,9 @@ int attribute_align_arg mpg123_position(mpg123_handle *fr, off_t no, off_t buffs
if(fr->rdat.filelen >= 0) if(fr->rdat.filelen >= 0)
{ {
double bpf; double bpf;
off_t t = fr->rd->tell(fr); int64_t t = fr->rd->tell(fr);
bpf = fr->mean_framesize ? fr->mean_framesize : compute_bpf(fr); bpf = fr->mean_framesize ? fr->mean_framesize : compute_bpf(fr);
left = (off_t)((double)(fr->rdat.filelen-t)/bpf); left = (int64_t)((double)(fr->rdat.filelen-t)/bpf);
/* no can be different for prophetic purposes, file pointer is always associated with fr->num! */ /* no can be different for prophetic purposes, file pointer is always associated with fr->num! */
if(fr->num != no) if(fr->num != no)
{ {
@@ -1066,7 +1067,7 @@ static int do_readahead(mpg123_handle *fr, unsigned long newhead)
{ {
unsigned long nexthead = 0; unsigned long nexthead = 0;
int hd = 0; int hd = 0;
off_t start, oret; int64_t start, oret;
int ret; int ret;
if( ! (!fr->firsthead && fr->rdat.flags & (READER_SEEKABLE|READER_BUFFERED)) ) if( ! (!fr->firsthead && fr->rdat.flags & (READER_SEEKABLE|READER_BUFFERED)) )
@@ -1074,7 +1075,7 @@ static int do_readahead(mpg123_handle *fr, unsigned long newhead)
start = fr->rd->tell(fr); start = fr->rd->tell(fr);
debug2("doing ahead check with BPF %d at %"OFF_P, fr->framesize+4, (off_p)start); debug2("doing ahead check with BPF %d at %"PRIi64, fr->framesize+4, start);
/* step framesize bytes forward and read next possible header*/ /* step framesize bytes forward and read next possible header*/
if((oret=fr->rd->skip_bytes(fr, fr->framesize))<0) if((oret=fr->rd->skip_bytes(fr, fr->framesize))<0)
{ {
@@ -1093,7 +1094,7 @@ static int do_readahead(mpg123_handle *fr, unsigned long newhead)
} }
if(hd == MPG123_NEED_MORE) return PARSE_MORE; if(hd == MPG123_NEED_MORE) return PARSE_MORE;
debug1("After fetching next header, at %"OFF_P, (off_p)fr->rd->tell(fr)); debug1("After fetching next header, at %"PRIi64, fr->rd->tell(fr));
if(!hd) if(!hd)
{ {
if(NOQUIET) warning("Cannot read next header, a one-frame stream? Duh..."); if(NOQUIET) warning("Cannot read next header, a one-frame stream? Duh...");
@@ -1140,7 +1141,7 @@ static int handle_apetag(mpg123_handle *fr, unsigned long newhead)
int back_bytes = 3; int back_bytes = 3;
fr->oldhead = 0; fr->oldhead = 0;
debug1("trying to read remaining APE header at %"OFF_P, (off_p)fr->rd->tell(fr)); debug1("trying to read remaining APE header at %"PRIi64, fr->rd->tell(fr));
/* Apetag headers are 32 bytes, newhead contains 4, read the rest */ /* Apetag headers are 32 bytes, newhead contains 4, read the rest */
if((ret=fr->rd->fullread(fr,apebuf,28)) < 0) if((ret=fr->rd->fullread(fr,apebuf,28)) < 0)
return ret; return ret;
@@ -1148,7 +1149,7 @@ static int handle_apetag(mpg123_handle *fr, unsigned long newhead)
if(ret < 28) if(ret < 28)
goto apetag_bad; goto apetag_bad;
debug1("trying to parse APE header at %"OFF_P, (off_p)fr->rd->tell(fr)); debug1("trying to parse APE header at %"PRIi64, fr->rd->tell(fr));
/* Apetags start with "APETAGEX", "APET" is already tested. */ /* Apetags start with "APETAGEX", "APET" is already tested. */
if(strncmp((char *)apebuf,"AGEX",4) != 0) if(strncmp((char *)apebuf,"AGEX",4) != 0)
goto apetag_bad; goto apetag_bad;
@@ -1171,8 +1172,8 @@ static int handle_apetag(mpg123_handle *fr, unsigned long newhead)
| ((unsigned long)apebuf[10]<<16) | ((unsigned long)apebuf[10]<<16)
| ((unsigned long)apebuf[9]<<8) | ((unsigned long)apebuf[9]<<8)
| apebuf[8]; | apebuf[8];
debug2( "skipping %lu bytes of APE data at %"OFF_P debug2( "skipping %lu bytes of APE data at %"PRIi64
, val, (off_p)fr->rd->tell(fr) ); , val, fr->rd->tell(fr) );
/* If encountering EOF here, things are just at an end. */ /* If encountering EOF here, things are just at an end. */
if((ret=fr->rd->skip_bytes(fr,val)) < 0) if((ret=fr->rd->skip_bytes(fr,val)) < 0)
return ret; return ret;
@@ -1277,7 +1278,7 @@ static int skip_junk(mpg123_handle *fr, unsigned long *newheadp, long *headcount
fr->err = MPG123_RESYNC_FAIL; fr->err = MPG123_RESYNC_FAIL;
return PARSE_ERR; return PARSE_ERR;
} }
else debug1("hopefully found one at %"OFF_P, (off_p)fr->rd->tell(fr)); else debug1("hopefully found one at %"PRIi64, fr->rd->tell(fr));
/* If the new header ist good, it is already decoded. */ /* If the new header ist good, it is already decoded. */
*newheadp = newhead; *newheadp = newhead;
@@ -1320,8 +1321,8 @@ static int wetwork(mpg123_handle *fr, unsigned long *newheadp)
} }
else if(NOQUIET && fr->silent_resync == 0) else if(NOQUIET && fr->silent_resync == 0)
{ {
fprintf(stderr,"Note: Illegal Audio-MPEG-Header 0x%08lx at offset %"OFF_P".\n", fprintf(stderr,"Note: Illegal Audio-MPEG-Header 0x%08lx at offset %"PRIi64".\n",
newhead, (off_p)fr->rd->tell(fr)-4); newhead, fr->rd->tell(fr)-4);
} }
/* Now we got something bad at hand, try to recover. */ /* Now we got something bad at hand, try to recover. */
@@ -1352,7 +1353,7 @@ static int wetwork(mpg123_handle *fr, unsigned long *newheadp)
return ret ? ret : PARSE_END; return ret ? ret : PARSE_END;
} }
if(VERBOSE3) debug3("resync try %li at %"OFF_P", got newhead 0x%08lx", try, (off_p)fr->rd->tell(fr), newhead); if(VERBOSE3) debug3("resync try %li at %"PRIi64", got newhead 0x%08lx", try, fr->rd->tell(fr), newhead);
} while(!head_check(newhead)); } while(!head_check(newhead));
*newheadp = newhead; *newheadp = newhead;

View File

@@ -32,7 +32,9 @@ struct bufferchain
ptrdiff_t pos; /* Position in whole chain. */ ptrdiff_t pos; /* Position in whole chain. */
ptrdiff_t firstpos; /* The point of return on non-forget() */ ptrdiff_t firstpos; /* The point of return on non-forget() */
/* The "real" filepos is fileoff + pos. */ /* The "real" filepos is fileoff + pos. */
off_t fileoff; /* Beginning of chain is at this file offset. */ int64_t fileoff; /* Beginning of chain is at this file offset. */
// Unsigned since no direct arithmetic with offsets. Overflow of overall
// size needs to be checked anyway.
size_t bufblock; /* Default (minimal) size of buffers. */ size_t bufblock; /* Default (minimal) size of buffers. */
size_t pool_size; /* Keep that many buffers in storage. */ size_t pool_size; /* Keep that many buffers in storage. */
size_t pool_fill; /* That many buffers are there. */ size_t pool_fill; /* That many buffers are there. */
@@ -53,26 +55,16 @@ size_t bc_fill(struct bufferchain *bc);
struct reader_data struct reader_data
{ {
off_t filelen; /* total file length or total buffer size */ int64_t filelen; /* total file length or total buffer size */
off_t filepos; /* position in file or position in buffer chain */ int64_t filepos; /* position in file or position in buffer chain */
int filept;
/* Custom opaque I/O handle from the client. */ /* Custom opaque I/O handle from the client. */
void *iohandle; void *iohandle;
int flags; int flags;
long timeout_sec; // The one and only lowlevel reader wrapper, wrapping over all others.
ptrdiff_t (*fdread) (mpg123_handle *, void *, size_t); // This is either libmpg123's wrapper or directly the user-supplied functions.
/* User can replace the read and lseek functions. The r_* are the stored replacement functions or NULL. */ int (*r_read64) (void *, void *, size_t, size_t *);
ptrdiff_t (*r_read) (int fd, void *buf, size_t count); int64_t (*r_lseek64)(void *, int64_t, int);
off_t (*r_lseek)(int fd, off_t offset, int whence);
/* These are custom I/O routines for opaque user handles.
They get picked if there's some iohandle set. */
ptrdiff_t (*r_read_handle)(void *handle, void *buf, size_t count); // TODO: convert to int return and separate *size_t arg
off_t (*r_lseek_handle)(void *handle, off_t offset, int whence);
/* An optional cleaner for the handle on closing the stream. */
void (*cleanup_handle)(void *handle); void (*cleanup_handle)(void *handle);
/* These two pointers are the actual workers (default map to POSIX read/lseek). */
ptrdiff_t (*read) (int fd, void *buf, size_t count);
off_t (*lseek)(int fd, off_t offset, int whence);
#ifndef NO_FEEDER #ifndef NO_FEEDER
struct bufferchain buffer; /* Not dynamically allocated, these few struct bytes aren't worth the trouble. */ struct bufferchain buffer; /* Not dynamically allocated, these few struct bytes aren't worth the trouble. */
#endif #endif
@@ -89,36 +81,32 @@ struct reader
ptrdiff_t (*fullread) (mpg123_handle *, unsigned char *, ptrdiff_t); ptrdiff_t (*fullread) (mpg123_handle *, unsigned char *, ptrdiff_t);
int (*head_read) (mpg123_handle *, unsigned long *newhead); /* succ: TRUE, else <= 0 (FALSE or READER_MORE) */ int (*head_read) (mpg123_handle *, unsigned long *newhead); /* succ: TRUE, else <= 0 (FALSE or READER_MORE) */
int (*head_shift) (mpg123_handle *, unsigned long *head); /* succ: TRUE, else <= 0 (FALSE or READER_MORE) */ int (*head_shift) (mpg123_handle *, unsigned long *head); /* succ: TRUE, else <= 0 (FALSE or READER_MORE) */
off_t (*skip_bytes) (mpg123_handle *, off_t len); /* succ: >=0, else error or READER_MORE */ int64_t (*skip_bytes) (mpg123_handle *, int64_t len); /* succ: >=0, else error or READER_MORE */
int (*read_frame_body)(mpg123_handle *, unsigned char *, int size); int (*read_frame_body)(mpg123_handle *, unsigned char *, int size);
int (*back_bytes) (mpg123_handle *, off_t bytes); int (*back_bytes) (mpg123_handle *, int64_t bytes);
int (*seek_frame) (mpg123_handle *, off_t num); int (*seek_frame) (mpg123_handle *, int64_t num);
off_t (*tell) (mpg123_handle *); int64_t (*tell) (mpg123_handle *);
void (*rewind) (mpg123_handle *); void (*rewind) (mpg123_handle *);
void (*forget) (mpg123_handle *); void (*forget) (mpg123_handle *);
}; };
/* Open a file by path or use an opened file descriptor. */
int open_stream(mpg123_handle *, const char *path, int fd);
/* Open an external handle. */ /* Open an external handle. */
int open_stream_handle(mpg123_handle *, void *iohandle); int open_stream_handle(mpg123_handle *, void *iohandle);
/* feed based operation has some specials */ /* feed based operation has some specials */
int open_feed(mpg123_handle *); int open_feed(mpg123_handle *);
/* externally called function, returns 0 on success, -1 on error */ /* externally called function, returns 0 on success, -1 on error */
int feed_more(mpg123_handle *fr, const unsigned char *in, long count); int feed_more(mpg123_handle *fr, const unsigned char *in, size_t count);
void feed_forget(mpg123_handle *fr); /* forget the data that has been read (free some buffers) */ void feed_forget(mpg123_handle *fr); /* forget the data that has been read (free some buffers) */
off_t feed_set_pos(mpg123_handle *fr, off_t pos); /* Set position (inside available data if possible), return wanted byte offset of next feed. */ int64_t feed_set_pos(mpg123_handle *fr, int64_t pos); /* Set position (inside available data if possible), return wanted byte offset of next feed. */
void open_bad(mpg123_handle *); void open_bad(mpg123_handle *);
#define READER_FD_OPENED 0x1
#define READER_ID3TAG 0x2 #define READER_ID3TAG 0x2
#define READER_SEEKABLE 0x4 #define READER_SEEKABLE 0x4
#define READER_BUFFERED 0x8 #define READER_BUFFERED 0x8
#define READER_NONBLOCK 0x20 #define READER_NOSEEK 0x10
#define READER_HANDLEIO 0x40 #define READER_HANDLEIO 0x40
#define READER_STREAM 0 #define READER_STREAM 0
#define READER_ICY_STREAM 1 #define READER_ICY_STREAM 1
#define READER_FEED 2 #define READER_FEED 2

View File

@@ -11,24 +11,13 @@
#include "mpg123lib_intern.h" #include "mpg123lib_intern.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include "debug.h" #include "debug.h"
static int default_init(mpg123_handle *fr); static int stream_init(mpg123_handle *fr);
static off_t get_fileinfo(mpg123_handle *); static int64_t get_fileinfo(mpg123_handle *);
static ptrdiff_t posix_read(int fd, void *buf, size_t count){ return read(fd, buf, count); }
static off_t posix_lseek(int fd, off_t offset, int whence){ return lseek(fd, offset, whence); }
static off_t nix_lseek(int fd, off_t offset, int whence){ return -1; }
static ptrdiff_t plain_fullread(mpg123_handle *fr,unsigned char *buf, ptrdiff_t count); static ptrdiff_t plain_fullread(mpg123_handle *fr,unsigned char *buf, ptrdiff_t count);
/* Wrapper to decide between descriptor-based and external handle-based I/O. */
static off_t io_seek(struct reader_data *rdat, off_t offset, int whence);
static ptrdiff_t io_read(struct reader_data *rdat, void *buf, size_t count);
#ifndef NO_FEEDER #ifndef NO_FEEDER
/* Bufferchain methods. */ /* Bufferchain methods. */
static void bc_init(struct bufferchain *bc); static void bc_init(struct bufferchain *bc);
@@ -44,38 +33,35 @@ static ptrdiff_t bc_seekback(struct bufferchain *bc, ptrdiff_t count);
static void bc_forget(struct bufferchain *bc); static void bc_forget(struct bufferchain *bc);
#endif #endif
/* A normal read and a read with timeout. */ // This is only for streams, so READER_HANDLEIO must be set.
static ptrdiff_t plain_read(mpg123_handle *fr, void *buf, size_t count) static ptrdiff_t fdread(mpg123_handle *fr, void *buf, size_t count)
{ {
ptrdiff_t ret = io_read(&fr->rdat, buf, count); if((fr->rdat.flags & READER_HANDLEIO) && fr->rdat.r_read64)
if(VERBOSE3) debug2("read %li bytes of %li", (long)ret, (long)count);
return ret;
}
#ifdef TIMEOUT_READ
/* Wait for data becoming available, allowing soft-broken network connection to die
This is needed for Shoutcast servers that have forgotten about us while connection was temporarily down. */
static ptrdiff_t timeout_read(mpg123_handle *fr, void *buf, size_t count)
{
struct timeval tv;
ptrdiff_t ret = 0;
fd_set fds;
tv.tv_sec = fr->rdat.timeout_sec;
tv.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(fr->rdat.filept, &fds);
ret = select(fr->rdat.filept+1, &fds, NULL, NULL, &tv);
/* This works only with "my" read function. Not user-replaced. */
if(ret > 0) ret = read(fr->rdat.filept, buf, count);
else
{ {
ret=-1; /* no activity is the error */ size_t got = 0;
if(NOQUIET) error("stream timed out"); int ret = fr->rdat.r_read64(fr->rdat.iohandle, buf, count, &got);
if(ret<0)
{
if(NOQUIET) merror("error reading %zu bytes", count);
return -1;
}
if(VERBOSE3) mdebug("read %zu bytes of %zu", got, count);
// Stupid handling, but at least some handling of never-occuring case.
return (ptrdiff_t)(got > PTRDIFF_MAX ? PTRDIFF_MAX : got);
} }
return ret; if(NOQUIET) error("no reader setup");
return -1;
}
static int64_t fdseek(mpg123_handle *fr, int64_t offset, int whence)
{
if((fr->rdat.flags & READER_HANDLEIO) && fr->rdat.r_lseek64)
return (fr->rdat.flags & READER_NOSEEK)
? -1
: fr->rdat.r_lseek64(fr->rdat.iohandle, offset, whence);
if(NOQUIET) error("no reader setup");
return -1;
} }
#endif
#ifndef NO_ICY #ifndef NO_ICY
/* stream based operation with icy meta data*/ /* stream based operation with icy meta data*/
@@ -110,7 +96,7 @@ static ptrdiff_t icy_fullread(mpg123_handle *fr, unsigned char *buf, ptrdiff_t c
if(fr->icy.next > 0) if(fr->icy.next > 0)
{ {
cut_pos = fr->icy.next; cut_pos = fr->icy.next;
ret = fr->rdat.fdread(fr,buf+cnt,cut_pos); ret = fdread(fr,buf+cnt,cut_pos);
if(ret < 1) if(ret < 1)
{ {
if(ret == 0) break; /* Just EOF. */ if(ret == 0) break; /* Just EOF. */
@@ -120,7 +106,7 @@ static ptrdiff_t icy_fullread(mpg123_handle *fr, unsigned char *buf, ptrdiff_t c
} }
if(!(fr->rdat.flags & READER_BUFFERED)) if(!(fr->rdat.flags & READER_BUFFERED))
SATURATE_ADD(fr->rdat.filepos, ret, OFF_MAX); SATURATE_ADD(fr->rdat.filepos, ret, INT64_MAX);
cnt += ret; cnt += ret;
fr->icy.next -= ret; fr->icy.next -= ret;
if(fr->icy.next > 0) if(fr->icy.next > 0)
@@ -133,13 +119,13 @@ static ptrdiff_t icy_fullread(mpg123_handle *fr, unsigned char *buf, ptrdiff_t c
/* one byte icy-meta size (must be multiplied by 16 to get icy-meta length) */ /* one byte icy-meta size (must be multiplied by 16 to get icy-meta length) */
ret = fr->rdat.fdread(fr,&temp_buff,1); /* Getting one single byte hast to suceed. */ ret = fdread(fr,&temp_buff,1); /* Getting one single byte hast to suceed. */
if(ret < 0){ if(NOQUIET) error("reading icy size"); return READER_ERROR; } if(ret < 0){ if(NOQUIET) error("reading icy size"); return READER_ERROR; }
if(ret == 0) break; if(ret == 0) break;
debug2("got meta-size byte: %u, at filepos %li", temp_buff, (long)fr->rdat.filepos ); debug2("got meta-size byte: %u, at filepos %li", temp_buff, (long)fr->rdat.filepos );
if(!(fr->rdat.flags & READER_BUFFERED)) if(!(fr->rdat.flags & READER_BUFFERED))
SATURATE_ADD(fr->rdat.filepos, ret, OFF_MAX); /* 1... */ SATURATE_ADD(fr->rdat.filepos, ret, INT64_MAX); /* 1... */
if((meta_size = ((size_t) temp_buff) * 16)) if((meta_size = ((size_t) temp_buff) * 16))
{ {
@@ -152,14 +138,14 @@ static ptrdiff_t icy_fullread(mpg123_handle *fr, unsigned char *buf, ptrdiff_t c
ptrdiff_t left = meta_size; ptrdiff_t left = meta_size;
while(left > 0) while(left > 0)
{ {
ret = fr->rdat.fdread(fr,meta_buff+meta_size-left,left); ret = fdread(fr,meta_buff+meta_size-left,left);
/* 0 is error here, too... there _must_ be the ICY data, the server promised! */ /* 0 is error here, too... there _must_ be the ICY data, the server promised! */
if(ret < 1){ if(NOQUIET) error("reading icy-meta"); return READER_ERROR; } if(ret < 1){ if(NOQUIET) error("reading icy-meta"); return READER_ERROR; }
left -= ret; left -= ret;
} }
meta_buff[meta_size] = 0; /* string paranoia */ meta_buff[meta_size] = 0; /* string paranoia */
if(!(fr->rdat.flags & READER_BUFFERED)) if(!(fr->rdat.flags & READER_BUFFERED))
SATURATE_ADD(fr->rdat.filepos, ret, OFF_MAX); SATURATE_ADD(fr->rdat.filepos, ret, INT64_MAX);
if(fr->icy.data) free(fr->icy.data); if(fr->icy.data) free(fr->icy.data);
fr->icy.data = meta_buff; fr->icy.data = meta_buff;
@@ -197,7 +183,7 @@ static ptrdiff_t plain_fullread(mpg123_handle *fr,unsigned char *buf, ptrdiff_t
ptrdiff_t ret,cnt=0; ptrdiff_t ret,cnt=0;
#ifdef EXTRA_DEBUG #ifdef EXTRA_DEBUG
debug1("plain fullread of %"SSIZE_P, (size_p)count); mdebug("plain fullread of %td", count);
#endif #endif
/* /*
There used to be a check for expected file end here (length value or ID3 flag). There used to be a check for expected file end here (length value or ID3 flag).
@@ -208,21 +194,21 @@ static ptrdiff_t plain_fullread(mpg123_handle *fr,unsigned char *buf, ptrdiff_t
*/ */
while(cnt < count) while(cnt < count)
{ {
ret = fr->rdat.fdread(fr,buf+cnt,count-cnt); ret = fdread(fr,buf+cnt,count-cnt);
if(ret < 0) return READER_ERROR; if(ret < 0) return READER_ERROR;
if(ret == 0) break; if(ret == 0) break;
if(!(fr->rdat.flags & READER_BUFFERED)) if(!(fr->rdat.flags & READER_BUFFERED))
SATURATE_ADD(fr->rdat.filepos, ret, OFF_MAX); SATURATE_ADD(fr->rdat.filepos, ret, INT64_MAX);
cnt += ret; cnt += ret;
} }
return cnt; return cnt;
} }
static off_t stream_lseek(mpg123_handle *fr, off_t pos, int whence) static int64_t stream_lseek(mpg123_handle *fr, int64_t pos, int whence)
{ {
off_t ret; int64_t ret = fdseek(fr, pos, whence);
ret = io_seek(&fr->rdat, pos, whence); if (ret >= 0)
if (ret >= 0) fr->rdat.filepos = ret; fr->rdat.filepos = ret;
else else
{ {
fr->err = MPG123_LSEEK_FAILED; fr->err = MPG123_LSEEK_FAILED;
@@ -233,31 +219,28 @@ static off_t stream_lseek(mpg123_handle *fr, off_t pos, int whence)
static void stream_close(mpg123_handle *fr) static void stream_close(mpg123_handle *fr)
{ {
if(fr->rdat.flags & READER_FD_OPENED) compat_close(fr->rdat.filept);
fr->rdat.filept = 0;
#ifndef NO_FEEDER #ifndef NO_FEEDER
if(fr->rdat.flags & READER_BUFFERED) bc_reset(&fr->rdat.buffer); if(fr->rdat.flags & READER_BUFFERED) bc_reset(&fr->rdat.buffer);
#endif #endif
if(fr->rdat.flags & READER_HANDLEIO) if(fr->rdat.flags & READER_HANDLEIO)
{ {
if(fr->rdat.cleanup_handle != NULL) fr->rdat.cleanup_handle(fr->rdat.iohandle); if(fr->rdat.cleanup_handle != NULL)
fr->rdat.cleanup_handle(fr->rdat.iohandle);
fr->rdat.iohandle = NULL; fr->rdat.iohandle = NULL;
} }
} }
static int stream_seek_frame(mpg123_handle *fr, off_t newframe) static int stream_seek_frame(mpg123_handle *fr, int64_t newframe)
{ {
debug2("seek_frame to %"OFF_P" (from %"OFF_P")", (off_p)newframe, (off_p)fr->num); debug2("seek_frame to %"PRIi64" (from %"PRIi64")", newframe, fr->num);
/* Seekable streams can go backwards and jump forwards. /* Seekable streams can go backwards and jump forwards.
Non-seekable streams still can go forward, just not jump. */ Non-seekable streams still can go forward, just not jump. */
if((fr->rdat.flags & READER_SEEKABLE) || (newframe >= fr->num)) if((fr->rdat.flags & READER_SEEKABLE) || (newframe >= fr->num))
{ {
off_t preframe; /* a leading frame we jump to */ int64_t preframe; /* a leading frame we jump to */
off_t seek_to; /* the byte offset we want to reach */ int64_t seek_to; /* the byte offset we want to reach */
off_t to_skip; /* bytes to skip to get there (can be negative) */ int64_t to_skip; /* bytes to skip to get there (can be negative) */
/* /*
now seek to nearest leading index position and read from there until newframe is reached. now seek to nearest leading index position and read from there until newframe is reached.
We use skip_bytes, which handles seekable and non-seekable streams We use skip_bytes, which handles seekable and non-seekable streams
@@ -282,7 +265,7 @@ static int stream_seek_frame(mpg123_handle *fr, off_t newframe)
if(!read_frame(fr)) break; if(!read_frame(fr)) break;
} }
/* Now the wanted frame should be ready for decoding. */ /* Now the wanted frame should be ready for decoding. */
debug1("arrived at %lu", (long unsigned)fr->num); debug1("arrived at %"PRIi64, fr->num);
return MPG123_OK; return MPG123_OK;
} }
@@ -324,11 +307,11 @@ static int generic_head_shift(mpg123_handle *fr,unsigned long *head)
} }
/* returns reached position... negative ones are bad... */ /* returns reached position... negative ones are bad... */
static off_t stream_skip_bytes(mpg123_handle *fr,off_t len) static int64_t stream_skip_bytes(mpg123_handle *fr, int64_t len)
{ {
if(fr->rdat.flags & READER_SEEKABLE) if(fr->rdat.flags & READER_SEEKABLE)
{ {
off_t ret = stream_lseek(fr, len, SEEK_CUR); int64_t ret = stream_lseek(fr, len, SEEK_CUR);
return (ret < 0) ? READER_ERROR : ret; return (ret < 0) ? READER_ERROR : ret;
} }
else if(len >= 0) else if(len >= 0)
@@ -337,7 +320,7 @@ static off_t stream_skip_bytes(mpg123_handle *fr,off_t len)
ptrdiff_t ret; ptrdiff_t ret;
while (len > 0) while (len > 0)
{ {
ptrdiff_t num = len < (off_t)sizeof(buf) ? (ptrdiff_t)len : (ptrdiff_t)sizeof(buf); ptrdiff_t num = len < (ptrdiff_t)sizeof(buf) ? (ptrdiff_t)len : (ptrdiff_t)sizeof(buf);
ret = fr->rd->fullread(fr, buf, num); ret = fr->rd->fullread(fr, buf, num);
if (ret < 0) return ret; if (ret < 0) return ret;
else if(ret == 0) break; /* EOF... an error? interface defined to tell the actual position... */ else if(ret == 0) break; /* EOF... an error? interface defined to tell the actual position... */
@@ -368,9 +351,9 @@ static off_t stream_skip_bytes(mpg123_handle *fr,off_t len)
} }
/* Return 0 on success... */ /* Return 0 on success... */
static int stream_back_bytes(mpg123_handle *fr, off_t bytes) static int stream_back_bytes(mpg123_handle *fr, int64_t bytes)
{ {
off_t want = fr->rd->tell(fr)-bytes; int64_t want = fr->rd->tell(fr)-bytes;
if(want < 0) return READER_ERROR; if(want < 0) return READER_ERROR;
if(stream_skip_bytes(fr,-bytes) != want) return READER_ERROR; if(stream_skip_bytes(fr,-bytes) != want) return READER_ERROR;
@@ -381,18 +364,18 @@ static int stream_back_bytes(mpg123_handle *fr, off_t bytes)
/* returns size on success... otherwise an error code < 0 */ /* returns size on success... otherwise an error code < 0 */
static int generic_read_frame_body(mpg123_handle *fr,unsigned char *buf, int size) static int generic_read_frame_body(mpg123_handle *fr,unsigned char *buf, int size)
{ {
long l; ptrdiff_t l;
l=fr->rd->fullread(fr,buf,size); l=fr->rd->fullread(fr,buf,size);
return (l >= 0 && l<size) ? READER_ERROR : l; return (l >= 0 && l<size) ? READER_ERROR : (int)l;
} }
static off_t generic_tell(mpg123_handle *fr) static int64_t generic_tell(mpg123_handle *fr)
{ {
#ifndef NO_FEEDER #ifndef NO_FEEDER
if(fr->rdat.flags & READER_BUFFERED) if(fr->rdat.flags & READER_BUFFERED)
{ {
fr->rdat.filepos = fr->rdat.buffer.fileoff; fr->rdat.filepos = fr->rdat.buffer.fileoff;
SATURATE_ADD(fr->rdat.filepos, fr->rdat.buffer.pos, OFF_MAX); SATURATE_ADD(fr->rdat.filepos, fr->rdat.buffer.pos, INT64_MAX);
} }
#endif #endif
@@ -424,17 +407,17 @@ static void stream_rewind(mpg123_handle *fr)
* reads the last 128 bytes information into buffer * reads the last 128 bytes information into buffer
* ... that is not totally safe... * ... that is not totally safe...
*/ */
static off_t get_fileinfo(mpg123_handle *fr) static int64_t get_fileinfo(mpg123_handle *fr)
{ {
off_t len; int64_t len;
if((len=io_seek(&fr->rdat,0,SEEK_END)) < 0) if((len=fdseek(fr,0,SEEK_END)) < 0)
{ {
debug("cannot seek to end"); debug("cannot seek to end");
return -1; return -1;
} else if(len >= 128) } else if(len >= 128)
{ {
if(io_seek(&fr->rdat,-128,SEEK_END) < 0) if(fdseek(fr,-128,SEEK_END) < 0)
{ {
debug("cannot seek to END-128"); debug("cannot seek to END-128");
return -1; return -1;
@@ -450,14 +433,14 @@ static off_t get_fileinfo(mpg123_handle *fr)
debug("stream too short for ID3"); debug("stream too short for ID3");
} }
if(io_seek(&fr->rdat,0,SEEK_SET) < 0) if(fdseek(fr,0,SEEK_SET) < 0)
{ {
debug("cannot seek back"); debug("cannot seek back");
return -1; return -1;
} }
fr->rdat.filepos = 0; // un-do our seeking here fr->rdat.filepos = 0; // un-do our seeking here
debug1("returning length: %"OFF_P, (off_p)len); debug1("returning length: %"PRIi64, len);
return len; return len;
} }
@@ -465,14 +448,16 @@ static off_t get_fileinfo(mpg123_handle *fr)
/* Methods for the buffer chain, mainly used for feed reader, but not just that. */ /* Methods for the buffer chain, mainly used for feed reader, but not just that. */
static struct buffy* buffy_new(size_t size, size_t minsize) static struct buffy* buffy_new(ptrdiff_t size, ptrdiff_t minsize)
{ {
struct buffy *newbuf; struct buffy *newbuf;
if(size > PTRDIFF_MAX)
return NULL;
newbuf = malloc(sizeof(struct buffy)); newbuf = malloc(sizeof(struct buffy));
if(newbuf == NULL) return NULL; if(newbuf == NULL) return NULL;
newbuf->realsize = size > minsize ? size : minsize; newbuf->realsize = size > minsize ? size : minsize;
newbuf->data = malloc(newbuf->realsize); newbuf->data = malloc((size_t)newbuf->realsize);
if(newbuf->data == NULL) if(newbuf->data == NULL)
{ {
free(newbuf); free(newbuf);
@@ -627,7 +612,7 @@ static int bc_append(struct bufferchain *bc, ptrdiff_t size)
else if(bc->first == NULL) bc->first = newbuf; else if(bc->first == NULL) bc->first = newbuf;
bc->last = newbuf; bc->last = newbuf;
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); debug3("bc_append: new last buffer %p with %td B (really %td)", (void*)bc->last, bc->last->size, bc->last->realsize);
return 0; return 0;
} }
@@ -636,7 +621,9 @@ static int bc_add(struct bufferchain *bc, const unsigned char *data, ptrdiff_t s
{ {
int ret = 0; int ret = 0;
ptrdiff_t part = 0; ptrdiff_t part = 0;
debug2("bc_add: adding %"SSIZE_P" bytes at %"OFF_P, (ssize_p)size, (off_p)(bc->fileoff+bc->size)); if((size_t)(PTRDIFF_MAX - bc->size) < size)
return -1;
debug2("bc_add: adding %zu bytes at %"PRIi64, size, (int64_t)(bc->fileoff+bc->size));
if(size >=4) debug4("first bytes: %02x %02x %02x %02x", data[0], data[1], data[2], data[3]); if(size >=4) debug4("first bytes: %02x %02x %02x %02x", data[0], data[1], data[2], data[3]);
while(size > 0) while(size > 0)
@@ -647,7 +634,7 @@ static int bc_add(struct bufferchain *bc, const unsigned char *data, ptrdiff_t s
part = bc->last->realsize - bc->last->size; part = bc->last->realsize - bc->last->size;
if(part > size) part = size; if(part > size) part = size;
debug2("bc_add: adding %"SSIZE_P" B to existing block %p", (ssize_p)part, (void*)bc->last); debug2("bc_add: adding %td B to existing block %p", part, (void*)bc->last);
memcpy(bc->last->data+bc->last->size, data, part); memcpy(bc->last->data+bc->last->size, data, part);
bc->last->size += part; bc->last->size += part;
size -= part; size -= part;
@@ -664,9 +651,9 @@ static int bc_add(struct bufferchain *bc, const unsigned char *data, ptrdiff_t s
} }
/* Common handler for "You want more than I can give." situation. */ /* Common handler for "You want more than I can give." situation. */
static ptrdiff_t bc_need_more(struct bufferchain *bc) static ptrdiff_t bc_need_more(struct bufferchain *bc, ptrdiff_t size)
{ {
debug3("hit end, back to beginning (%li - %li < %li)", (long)bc->size, (long)bc->pos, (long)bc->size); debug3("hit end, back to beginning (%td - %td < %td)", bc->size, bc->pos, size);
/* go back to firstpos, undo the previous reads */ /* go back to firstpos, undo the previous reads */
bc->pos = bc->firstpos; bc->pos = bc->firstpos;
return READER_MORE; return READER_MORE;
@@ -678,7 +665,7 @@ static ptrdiff_t bc_give(struct bufferchain *bc, unsigned char *out, ptrdiff_t s
struct buffy *b = bc->first; struct buffy *b = bc->first;
ptrdiff_t gotcount = 0; ptrdiff_t gotcount = 0;
ptrdiff_t offset = 0; ptrdiff_t offset = 0;
if(bc->size - bc->pos < size) return bc_need_more(bc); if(bc->size - bc->pos < size) return bc_need_more(bc, size);
/* find the current buffer */ /* find the current buffer */
while(b != NULL && (offset + b->size) <= bc->pos) while(b != NULL && (offset + b->size) <= bc->pos)
@@ -716,7 +703,7 @@ static ptrdiff_t bc_skip(struct bufferchain *bc, ptrdiff_t count)
{ {
if(count >= 0) if(count >= 0)
{ {
if(bc->size - bc->pos < count) return bc_need_more(bc); if(bc->size - bc->pos < count) return bc_need_more(bc, count);
else return bc->pos += count; else return bc->pos += count;
} }
else return READER_ERROR; else return READER_ERROR;
@@ -734,7 +721,7 @@ static void bc_forget(struct bufferchain *bc)
struct buffy *b = bc->first; struct buffy *b = bc->first;
/* free all buffers that are def'n'tly outdated */ /* free all buffers that are def'n'tly outdated */
/* we have buffers until filepos... delete all buffers fully below it */ /* we have buffers until filepos... delete all buffers fully below it */
if(b) debug2("bc_forget: block %lu pos %lu", (unsigned long)b->size, (unsigned long)bc->pos); if(b) debug2("bc_forget: block %td pos %td", b->size, bc->pos);
else debug("forget with nothing there!"); else debug("forget with nothing there!");
while(b != NULL && bc->pos >= b->size) while(b != NULL && bc->pos >= b->size)
@@ -745,7 +732,8 @@ static void bc_forget(struct bufferchain *bc)
bc->pos -= b->size; bc->pos -= b->size;
bc->size -= b->size; bc->size -= b->size;
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); debug5("bc_forget: forgot %p with %td, pos=%td, size=%td, fileoff=%td"
, (void*)b->data, b->size, bc->pos, bc->size, bc->fileoff);
bc_free(bc, b); bc_free(bc, b);
b = n; b = n;
@@ -767,11 +755,15 @@ static int feed_init(mpg123_handle *fr)
} }
/* externally called function, returns 0 on success, -1 on error */ /* externally called function, returns 0 on success, -1 on error */
int feed_more(mpg123_handle *fr, const unsigned char *in, long count) // External API uses size_t, we use signed ptrdiff_t internally. Overflow
// is a theoretical possibility.
int feed_more(mpg123_handle *fr, const unsigned char *in, size_t count)
{ {
int ret = 0; int ret = 0;
if(VERBOSE3) debug("feed_more"); if(VERBOSE3) debug("feed_more");
if((ret = bc_add(&fr->rdat.buffer, in, count)) != 0) if(count > PTRDIFF_MAX)
return READER_ERROR;
if((ret = bc_add(&fr->rdat.buffer, in, (ptrdiff_t)count)) != 0)
{ {
ret = READER_ERROR; ret = READER_ERROR;
if(NOQUIET) error1("Failed to add buffer, return: %i", ret); if(NOQUIET) error1("Failed to add buffer, return: %i", ret);
@@ -791,16 +783,16 @@ static ptrdiff_t feed_read(mpg123_handle *fr, unsigned char *out, ptrdiff_t coun
} }
/* returns reached position... negative ones are bad... */ /* returns reached position... negative ones are bad... */
static off_t feed_skip_bytes(mpg123_handle *fr,off_t len) static int64_t feed_skip_bytes(mpg123_handle *fr, int64_t len)
{ {
/* This is either the new buffer offset or some negative error value. */ /* This is either the new buffer offset or some negative error value. */
off_t res = bc_skip(&fr->rdat.buffer, (ptrdiff_t)len); int64_t res = bc_skip(&fr->rdat.buffer, (ptrdiff_t)len);
if(res < 0) return res; if(res < 0) return res;
return fr->rdat.buffer.fileoff+res; return fr->rdat.buffer.fileoff+res;
} }
static int feed_back_bytes(mpg123_handle *fr, off_t bytes) static int feed_back_bytes(mpg123_handle *fr, int64_t bytes)
{ {
if(bytes >=0) if(bytes >=0)
return bc_seekback(&fr->rdat.buffer, (ptrdiff_t)bytes) >= 0 ? 0 : READER_ERROR; return bc_seekback(&fr->rdat.buffer, (ptrdiff_t)bytes) >= 0 ? 0 : READER_ERROR;
@@ -808,30 +800,30 @@ static int feed_back_bytes(mpg123_handle *fr, off_t bytes)
return feed_skip_bytes(fr, -bytes) >= 0 ? 0 : READER_ERROR; return feed_skip_bytes(fr, -bytes) >= 0 ? 0 : READER_ERROR;
} }
static int feed_seek_frame(mpg123_handle *fr, off_t num){ return READER_ERROR; } static int feed_seek_frame(mpg123_handle *fr, int64_t num){ return READER_ERROR; }
/* Not just for feed reader, also for self-feeding buffered reader. */ /* Not just for feed reader, also for self-feeding buffered reader. */
static void buffered_forget(mpg123_handle *fr) static void buffered_forget(mpg123_handle *fr)
{ {
bc_forget(&fr->rdat.buffer); bc_forget(&fr->rdat.buffer);
fr->rdat.filepos = fr->rdat.buffer.fileoff; fr->rdat.filepos = fr->rdat.buffer.fileoff;
SATURATE_ADD(fr->rdat.filepos, fr->rdat.buffer.pos, OFF_MAX); SATURATE_ADD(fr->rdat.filepos, fr->rdat.buffer.pos, INT64_MAX);
} }
off_t feed_set_pos(mpg123_handle *fr, off_t pos) int64_t feed_set_pos(mpg123_handle *fr, int64_t pos)
{ {
struct bufferchain *bc = &fr->rdat.buffer; struct bufferchain *bc = &fr->rdat.buffer;
if(pos >= bc->fileoff && pos-bc->fileoff < bc->size) if(pos >= bc->fileoff && pos-bc->fileoff < bc->size)
{ /* We have the position! */ { /* We have the position! */
bc->pos = (ptrdiff_t)(pos - bc->fileoff); bc->pos = (ptrdiff_t)(pos - bc->fileoff);
debug1("feed_set_pos inside, next feed from %"OFF_P, (off_p)(bc->fileoff+bc->size)); debug1("feed_set_pos inside, next feed from %"PRIi64, (int64_t)(bc->fileoff+bc->size));
return bc->fileoff+bc->size; /* Next input after end of buffer... */ return bc->fileoff+bc->size; /* Next input after end of buffer... */
} }
else else
{ /* I expect to get the specific position on next feed. Forget what I have now. */ { /* I expect to get the specific position on next feed. Forget what I have now. */
bc_reset(bc); bc_reset(bc);
bc->fileoff = pos; bc->fileoff = pos;
debug1("feed_set_pos outside, buffer reset, next feed from %"OFF_P, (off_p)pos); debug1("feed_set_pos outside, buffer reset, next feed from %"PRIi64, pos);
return pos; /* Next input from exactly that position. */ return pos; /* Next input from exactly that position. */
} }
} }
@@ -859,7 +851,8 @@ static ptrdiff_t buffered_fullread(mpg123_handle *fr, unsigned char *out, ptrdif
return READER_ERROR; return READER_ERROR;
} }
if(VERBOSE3) debug1("buffered_fullread: buffering %li bytes from stream (if > 0)", (long)got); if(VERBOSE3)
debug1("buffered_fullread: buffering %td bytes from stream (if > 0)", got);
if(got > 0 && (ret=bc_add(bc, readbuf, got)) != 0) if(got > 0 && (ret=bc_add(bc, readbuf, got)) != 0)
{ {
if(NOQUIET) error1("unable to add to chain, return: %i", ret); if(NOQUIET) error1("unable to add to chain, return: %i", ret);
@@ -878,7 +871,7 @@ static ptrdiff_t buffered_fullread(mpg123_handle *fr, unsigned char *out, ptrdif
} }
gotcount = bc_give(bc, out, count); gotcount = bc_give(bc, out, count);
if(VERBOSE3) if(VERBOSE3)
mdebug("buffered_fullread: got %zd", gotcount); mdebug("buffered_fullread: got %td", gotcount);
if(gotcount != count){ if(NOQUIET) error("gotcount != count"); return READER_ERROR; } if(gotcount != count){ if(NOQUIET) error("gotcount != count"); return READER_ERROR; }
else return gotcount; else return gotcount;
} }
@@ -894,12 +887,12 @@ static ptrdiff_t buffered_icy_fullread(mpg123_handle *fr, unsigned char *out, pt
} }
#else #else
int feed_more(mpg123_handle *fr, const unsigned char *in, long count) int feed_more(mpg123_handle *fr, const unsigned char *in, size_t count)
{ {
fr->err = MPG123_MISSING_FEATURE; fr->err = MPG123_MISSING_FEATURE;
return -1; return -1;
} }
off_t feed_set_pos(mpg123_handle *fr, off_t pos) int64_t feed_set_pos(mpg123_handle *fr, int64_t pos)
{ {
fr->err = MPG123_MISSING_FEATURE; fr->err = MPG123_MISSING_FEATURE;
return -1; return -1;
@@ -916,11 +909,11 @@ static void bad_close(mpg123_handle *mh){}
static ptrdiff_t bad_fullread(mpg123_handle *mh, unsigned char *data, ptrdiff_t count) bugger_off static ptrdiff_t bad_fullread(mpg123_handle *mh, unsigned char *data, ptrdiff_t count) bugger_off
static int bad_head_read(mpg123_handle *mh, unsigned long *newhead) bugger_off static int bad_head_read(mpg123_handle *mh, unsigned long *newhead) bugger_off
static int bad_head_shift(mpg123_handle *mh, unsigned long *head) bugger_off static int bad_head_shift(mpg123_handle *mh, unsigned long *head) bugger_off
static off_t bad_skip_bytes(mpg123_handle *mh, off_t len) bugger_off static int64_t bad_skip_bytes(mpg123_handle *mh, int64_t len) bugger_off
static int bad_read_frame_body(mpg123_handle *mh, unsigned char *data, int size) bugger_off static int bad_read_frame_body(mpg123_handle *mh, unsigned char *data, int size) bugger_off
static int bad_back_bytes(mpg123_handle *mh, off_t bytes) bugger_off static int bad_back_bytes(mpg123_handle *mh, int64_t bytes) bugger_off
static int bad_seek_frame(mpg123_handle *mh, off_t num) bugger_off static int bad_seek_frame(mpg123_handle *mh, int64_t num) bugger_off
static off_t bad_tell(mpg123_handle *mh) bugger_off static int64_t bad_tell(mpg123_handle *mh) bugger_off
static void bad_rewind(mpg123_handle *mh){} static void bad_rewind(mpg123_handle *mh){}
#undef bugger_off #undef bugger_off
@@ -932,7 +925,7 @@ static void bad_rewind(mpg123_handle *mh){}
static struct reader readers[] = static struct reader readers[] =
{ {
{ /* READER_STREAM */ { /* READER_STREAM */
default_init, stream_init,
stream_close, stream_close,
plain_fullread, plain_fullread,
generic_head_read, generic_head_read,
@@ -946,7 +939,7 @@ static struct reader readers[] =
NULL NULL
} , } ,
{ /* READER_ICY_STREAM */ { /* READER_ICY_STREAM */
default_init, stream_init,
stream_close, stream_close,
icy_fullread, icy_fullread,
generic_head_read, generic_head_read,
@@ -985,7 +978,7 @@ static struct reader readers[] =
buffered_forget buffered_forget
}, },
{ /* READER_BUF_STREAM */ { /* READER_BUF_STREAM */
default_init, stream_init,
stream_close, stream_close,
buffered_plain_fullread, buffered_plain_fullread,
generic_head_read, generic_head_read,
@@ -999,7 +992,7 @@ static struct reader readers[] =
buffered_forget buffered_forget
} , } ,
{ /* READER_BUF_ICY_STREAM */ { /* READER_BUF_ICY_STREAM */
default_init, stream_init,
stream_close, stream_close,
buffered_icy_fullread, buffered_icy_fullread,
generic_head_read, generic_head_read,
@@ -1030,41 +1023,20 @@ static struct reader bad_reader =
NULL NULL
}; };
static int default_init(mpg123_handle *fr) static int stream_init(mpg123_handle *fr)
{ {
#ifdef TIMEOUT_READ
if(fr->p.timeout > 0)
{
int flags;
if(fr->rdat.r_read != NULL)
{
if(NOQUIET)
error( "Timeout reading does not work with user-provided"
" read function. Implement it yourself!" );
return -1;
}
flags = fcntl(fr->rdat.filept, F_GETFL);
flags |= O_NONBLOCK;
fcntl(fr->rdat.filept, F_SETFL, flags);
fr->rdat.fdread = timeout_read;
fr->rdat.timeout_sec = fr->p.timeout;
fr->rdat.flags |= READER_NONBLOCK;
}
else
#endif
fr->rdat.fdread = plain_read;
fr->rdat.read = fr->rdat.r_read != NULL ? fr->rdat.r_read : posix_read;
fr->rdat.lseek = fr->rdat.r_lseek != NULL ? fr->rdat.r_lseek : posix_lseek;
#ifndef NO_ICY #ifndef NO_ICY
/* ICY streams of any sort shall not be seekable. */ /* ICY streams of any sort shall not be seekable. */
if(fr->p.icy_interval > 0) fr->rdat.lseek = nix_lseek; if(fr->p.icy_interval > 0) fr->rdat.flags |= READER_NOSEEK;
#endif #endif
fr->rdat.filepos = 0; fr->rdat.filepos = 0;
fr->rdat.filelen = fr->p.flags & MPG123_NO_PEEK_END ? -1 : get_fileinfo(fr); fr->rdat.filelen = fr->p.flags & MPG123_NO_PEEK_END ? -1 : get_fileinfo(fr);
if(fr->p.flags & MPG123_FORCE_SEEKABLE) if(fr->p.flags & MPG123_FORCE_SEEKABLE)
{
fr->rdat.flags |= READER_SEEKABLE; fr->rdat.flags |= READER_SEEKABLE;
fr->rdat.flags &= ~READER_NOSEEK;
}
/* /*
Don't enable seeking on ICY streams, just plain normal files. Don't enable seeking on ICY streams, just plain normal files.
This check is necessary since the client can enforce ICY parsing on files that would otherwise be seekable. This check is necessary since the client can enforce ICY parsing on files that would otherwise be seekable.
@@ -1129,7 +1101,7 @@ void open_bad(mpg123_handle *mh)
mh->rdat.filelen = -1; mh->rdat.filelen = -1;
} }
int open_feed(mpg123_handle *fr) int INT123_open_feed(mpg123_handle *fr)
{ {
debug("feed reader"); debug("feed reader");
#ifdef NO_FEEDER #ifdef NO_FEEDER
@@ -1157,8 +1129,14 @@ int open_feed(mpg123_handle *fr)
} }
/* Final code common to open_stream and open_stream_handle. */ /* Final code common to open_stream and open_stream_handle. */
static int open_finish(mpg123_handle *fr) int INT123_open_stream_handle(mpg123_handle *fr, void *iohandle)
{ {
clear_icy(&fr->icy); /* can be done inside frame_clear ...? */
fr->rdat.filelen = -1;
fr->rdat.iohandle = iohandle;
fr->rdat.flags = 0;
fr->rdat.flags |= READER_HANDLEIO;
#ifndef NO_ICY #ifndef NO_ICY
if(fr->p.icy_interval > 0) if(fr->p.icy_interval > 0)
{ {
@@ -1178,75 +1156,3 @@ static int open_finish(mpg123_handle *fr)
return MPG123_OK; return MPG123_OK;
} }
int open_stream(mpg123_handle *fr, const char *bs_filenam, int fd)
{
int filept_opened = 1;
int filept; /* descriptor of opened file/stream */
clear_icy(&fr->icy); /* can be done inside frame_clear ...? */
if(!bs_filenam) /* no file to open, got a descriptor (stdin) */
{
filept = fd;
filept_opened = 0; /* and don't try to close it... */
}
#ifndef O_BINARY
#define O_BINARY (0)
#endif
else if((filept = compat_open(bs_filenam, O_RDONLY|O_BINARY)) < 0) /* a plain old file to open... */
{
if(NOQUIET) error2("Cannot open file %s: %s", bs_filenam, strerror(errno));
fr->err = MPG123_BAD_FILE;
return MPG123_ERR; /* error... */
}
/* now we have something behind filept and can init the reader */
fr->rdat.filelen = -1;
fr->rdat.filept = filept;
fr->rdat.flags = 0;
if(filept_opened) fr->rdat.flags |= READER_FD_OPENED;
return open_finish(fr);
}
int open_stream_handle(mpg123_handle *fr, void *iohandle)
{
clear_icy(&fr->icy); /* can be done inside frame_clear ...? */
fr->rdat.filelen = -1;
fr->rdat.filept = -1;
fr->rdat.iohandle = iohandle;
fr->rdat.flags = 0;
fr->rdat.flags |= READER_HANDLEIO;
return open_finish(fr);
}
/* Wrappers for actual reading/seeking... I'm full of wrappers here. */
static off_t io_seek(struct reader_data *rdat, off_t offset, int whence)
{
if(rdat->flags & READER_HANDLEIO)
{
if(rdat->r_lseek_handle != NULL)
{
return rdat->r_lseek_handle(rdat->iohandle, offset, whence);
}
else return -1;
}
else
return rdat->lseek(rdat->filept, offset, whence);
}
static ptrdiff_t io_read(struct reader_data *rdat, void *buf, size_t count)
{
if(rdat->flags & READER_HANDLEIO)
{
if(rdat->r_read_handle != NULL)
{
return rdat->r_read_handle(rdat->iohandle, buf, count);
}
else return -1;
}
else
return rdat->read(rdat->filept, buf, count);
}

View File

@@ -2014,6 +2014,7 @@ syn123_resample_intotal64(long inrate, long outrate, int64_t outs)
return (tot <= INT64_MAX) ? (int64_t)tot : SYN123_OVERFLOW; return (tot <= INT64_MAX) ? (int64_t)tot : SYN123_OVERFLOW;
} }
#ifndef PORTABLE_API
// Again the dreadful business of dealing with shape-shifting off_t API. // Again the dreadful business of dealing with shape-shifting off_t API.
// The real implementation is the function with suffix 64, using int64_t. // The real implementation is the function with suffix 64, using int64_t.
// Depending on your OS, there is a native off_t with 32 or 64 bits, and // Depending on your OS, there is a native off_t with 32 or 64 bits, and
@@ -2036,37 +2037,21 @@ type attribute_align_arg name(long inrate, long outrate, type io) \
return name64(inrate, outrate, io); \ return name64(inrate, outrate, io); \
} }
#if LFS_ALIAS_BITS+0 == 64 #if SIZEOF_OFF_T == 8
resample_total_alias(lfs_alias_t, syn123_resample_total, syn123_resample_total64) resample_total_alias(off_t, syn123_resample_total, syn123_resample_total64)
resample_total_alias(lfs_alias_t, syn123_resample_intotal, syn123_resample_intotal64) resample_total_alias(off_t, syn123_resample_intotal, syn123_resample_intotal64)
#elif LFS_ALIAS_BITS+0 == 32 #elif SIZEOF_OFF_T == 4
resample_total_wrap(lfs_alias_t, INT32_MAX, syn123_resample_total, syn123_resample_total64) resample_total_wrap(off_t, INT32_MAX, syn123_resample_total, syn123_resample_total64)
resample_total_wrap(lfs_alias_t, INT32_MAX, syn123_resample_intotal, syn123_resample_intotal64) resample_total_wrap(off_t, INT32_MAX, syn123_resample_intotal, syn123_resample_intotal64)
#if LFS_LARGEFILE_64
resample_total_alias(off64_t, syn123_resample_total_64, syn123_resample_total64)
resample_total_alias(off64_t, syn123_resample_intotal_64, syn123_resample_intotal64)
#endif
#else #else
#error "Unexpected LFS_ALIAS_BITS value." #error "Unexpected LFS_ALIAS_BITS value."
#endif #endif
// Try to keep it minimal. Ensure correct type for largefile off_t, define the other
// using fixed integer type. This is not totally proper, but it is just annoying
// to do overly correct definitions matching all possible prototypes.
#if SIZEOF_OFF_T == 4
// This used to have int32_t in the rate arguments. This does not match the header
// prototype. But in practice, relevant platforms with 32 bit off_t by default
// also have long == int32_t.
resample_total_wrap(off_t, INT32_MAX, syn123_resample_total_32, syn123_resample_total64)
resample_total_wrap(off_t, INT32_MAX, syn123_resample_intotal_32, syn123_resample_intotal64)
// If we didn't enable largefile support at all, user cannot expect _64 aliases.
#elif (SIZEOF_OFF_T == 8)
resample_total_alias(off_t, syn123_resample_total_64, syn123_resample_total64)
resample_total_alias(off_t, syn123_resample_intotal_64, syn123_resample_intotal64)
#if LFS_ALIAS_BITS+0 == 32
// This platform has smaller native off_t, give it the wrapper.
resample_total_wrap(int32_t, INT32_MAX, syn123_resample_total_32, syn123_resample_total64)
resample_total_wrap(int32_t, INT32_MAX, syn123_resample_intotal_32, syn123_resample_intotal64)
#endif #endif
#endif
// As any sensible return value is at least 1, this uses the unsigned // As any sensible return value is at least 1, this uses the unsigned
// type and 0 for error/pathological input. // type and 0 for error/pathological input.

View File

@@ -14,6 +14,9 @@
#define _ISOC99_SOURCE #define _ISOC99_SOURCE
#include "config.h" #include "config.h"
#ifdef LFS_LARGEFILE_64
#define _LARGEFILE64_SOURCE
#endif
#include "intsym.h" #include "intsym.h"
#include "compat.h" #include "compat.h"
#include "abi_align.h" #include "abi_align.h"

View File

@@ -13,6 +13,12 @@
#define MPG123_H #define MPG123_H
#include "config.h" #include "config.h"
#ifdef LFS_SENSITIVE
#ifdef LFS_LARGEFILE_64
#define _FILE_OFFSET_BITS 64
#endif
#endif
/* everyone needs it */ /* everyone needs it */
#include "compat.h" #include "compat.h"
/* import DLL symbols on windows */ /* import DLL symbols on windows */