OSDN Git Service

Import mpg123 1.26rc3
authorStarg <starg@users.osdn.me>
Sat, 16 May 2020 11:25:50 +0000 (20:25 +0900)
committerStarg <starg@users.osdn.me>
Sat, 16 May 2020 11:25:50 +0000 (20:25 +0900)
28 files changed:
libmpg123/AUTHORS
libmpg123/README
libmpg123/src/compat/compat.c
libmpg123/src/compat/compat.h
libmpg123/src/intsym.h
libmpg123/src/libmpg123/debug.h
libmpg123/src/libmpg123/feature.c
libmpg123/src/libmpg123/fmt123.h
libmpg123/src/libmpg123/format.c
libmpg123/src/libmpg123/frame.c
libmpg123/src/libmpg123/frame.h
libmpg123/src/libmpg123/getbits.h
libmpg123/src/libmpg123/id3.c
libmpg123/src/libmpg123/index.c
libmpg123/src/libmpg123/layer1.c
libmpg123/src/libmpg123/layer2.c
libmpg123/src/libmpg123/layer3.c
libmpg123/src/libmpg123/lfs_alias.c
libmpg123/src/libmpg123/lfs_wrap.c
libmpg123/src/libmpg123/libmpg123.c
libmpg123/src/libmpg123/mpg123.h.in
libmpg123/src/libmpg123/mpg123lib_intern.h
libmpg123/src/libmpg123/parse.c
libmpg123/src/libmpg123/parse.h
libmpg123/src/libmpg123/readers.c
libmpg123/src/libmpg123/sample.h
libmpg123/src/libmpg123/stringbuf.c
libmpg123/src/libmpg123/swap_bytes_impl.h [new file with mode: 0644]

index c1eac97..3321f0b 100644 (file)
@@ -30,6 +30,7 @@ The creator: Michael Hipp (email: hippm@informatik.uni-tuebingen.de - please bot
 
 Contributions/ideas Thomas Orgis era (includes backports from mhipp trunk):
 
+Vitaly Kirsanov <krokoziabla@gmail.com>: ports/cmake (optional CMake build)
 Won-Kyu Park <wkpark@gmail.com>: patch to get rid of asm textrels (x86 PIC)
 Michael Weiser <michaelweiser@users.sf.net>: update of coreaudio output to AudioComponents API
 Bent Bisballe Nyeng <bbn@dynastrom.com>: patch for MPG123_NO_PEEK_END and MPG123_FORCE_SEEKABLE
@@ -165,7 +166,7 @@ Hur TaeSung <saturn@arari.snu.ac.kr>: 'http accept' patch
 (from post-0.59 changes that yet have to go into new trunk:)
 
 Hans Schwengeler <schweng@astro.unibas.ch>: audio_dec additions
-Wojciech Barañski's Mp3Play (check the tools folder): Mp3Play frontend
+Wojciech Barañski's Mp3Play (check the tools folder): Mp3Play frontend
 Daniel Koukola: audio_oss.c patch
 Munechika SUMIKAWA <sumikawa@ebina.hitachi.co.jp>: IPv6
 TEMNOTA <temnota@kmv.ru>: HTTP,FTP patch/playlist fix
index 830b0ab..c0a4029 100644 (file)
@@ -73,13 +73,14 @@ Note that this Ctrl+C behaviour is special to this mode; when any of the followi
 3.2 Advanced Console Usage
 
 You can specify the option -C to enable a terminal control interface enabling to influence playback on current title/playlist by pressing some key:
-
  -= terminal control keys =-
-[s] or [ ]     interrupt/restart playback (i.e. 'pause')
+[s] or [ ]     interrupt/restart playback (i.e. '(un)pause')
 [f]    next track
 [d]    previous track
+[]]    next directory (next track until directory part changes)
+[[]    previous directory (previous track until directory part changes)
 [b]    back to beginning of track
-[p]    pause while looping current sound chunk
+[p]    loop around current position (don't combine with output buffer)
 [.]    forward
 [,]    rewind
 [:]    fast forward
@@ -88,11 +89,16 @@ You can specify the option -C to enable a terminal control interface enabling to
 [<]    fine rewind
 [+]    volume up
 [-]    volume down
+[u]    (un)mute volume
 [r]    RVA switch
 [v]    verbose switch
 [l]    list current playlist, indicating current track there
 [t]    display tag info (again)
 [m]    print MPEG header info (again)
+[c] or [C]     pitch up (small step, big step)
+[x] or [X]     pitch down (small step, big step)
+[w]    reset pitch to zero
+[k]    print out current position in playlist and track, for the benefit of some external tool to store bookmarks
 [h]    this help
 [q]    quit
 
index 675a2da..043d8cb 100644 (file)
@@ -4,7 +4,7 @@
        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;-)
 
-       copyright 2007-2016 by the mpg123 project - free software under the terms of the LGPL 2.1
+       copyright 2007-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, Windows Unicode stuff by JonY.
 */
 #include <shlwapi.h>
 #endif
 
-#ifdef USE_MODULES
-#  ifdef HAVE_DLFCN_H
-#    include <dlfcn.h>
-#  endif
-#endif
-
 #include "debug.h"
 
 #ifndef WINDOWS_UWP
@@ -70,112 +64,9 @@ char *compat_getenv(const char* name)
        return ret;
 }
 
-#ifdef WANT_WIN32_UNICODE
-
-/* Convert unix UTF-8 (or ASCII) paths to Windows wide character paths. */
-static wchar_t* u2wpath(const char *upath)
-{
-       wchar_t* wpath, *p;
-       if(!upath || win32_utf8_wide(upath, &wpath, NULL) < 1)
-               return NULL;
-       for(p=wpath; *p; ++p)
-               if(*p == L'/')
-                       *p = L'\\';
-       return wpath;
-}
-
-/* Convert Windows wide character paths to unix UTF-8. */
-static char* w2upath(const wchar_t *wpath)
-{
-       char* upath, *p;
-       if(!wpath || win32_wide_utf8(wpath, &upath, NULL) < 1)
-               return NULL;
-       for(p=upath; *p; ++p)
-               if(*p == '\\')
-                       *p = '/';
-       return upath;
-}
-
-/* An absolute path that is too long and not already marked with
-   \\?\ can be marked as a long one and still work. */
-static int wpath_need_elongation(wchar_t *wpath)
-{
-       if( wpath && !PathIsRelativeW(wpath)
-       &&      wcslen(wpath) > MAX_PATH-1
-       &&      wcsncmp(L"\\\\?\\", wpath, 4) )
-               return 1;
-       else
-               return 0;
-}
-
-/* Take any wide windows path and turn it into a path that is allowed
-   to be longer than MAX_PATH, if it is not already. */
-static wchar_t* wlongpath(wchar_t *wpath)
-{
-       size_t len, plen;
-       const wchar_t *prefix = L"";
-       wchar_t *wlpath = NULL;
-       if(!wpath)
-               return NULL;
-
-       /* Absolute paths that do not start with \\?\ get that prepended
-          to allow them being long. */
-       if(!PathIsRelativeW(wpath) && wcsncmp(L"\\\\?\\", wpath, 4))
-       {
-               if(wcslen(wpath) >= 2 && PathIsUNCW(wpath))
-               {
-                       /* \\server\path -> \\?\UNC\server\path */
-                       prefix = L"\\\\?\\UNC";
-                       ++wpath; /* Skip the first \. */
-               }
-               else /* c:\some/path -> \\?\c:\some\path */
-                       prefix = L"\\\\?\\";
-       }
-       plen = wcslen(prefix);
-       len = plen + wcslen(wpath);
-       wlpath = malloc(len+1*sizeof(wchar_t));
-       if(wlpath)
-       {
-               /* Brute force memory copying, swprintf is too dandy. */
-               memcpy(wlpath, prefix, sizeof(wchar_t)*plen);
-               memcpy(wlpath+plen, wpath, sizeof(wchar_t)*(len-plen));
-               wlpath[len] = 0;
-       }
-       return wlpath;
-}
-
-/* Convert unix path to wide windows path, optionally marking
-   it as long path if necessary. */
-static wchar_t* u2wlongpath(const char *upath)
-{
-       wchar_t *wpath  = NULL;
-       wchar_t *wlpath = NULL;
-       wpath = u2wpath(upath);
-       if(wpath_need_elongation(wpath))
-       {
-               wlpath = wlongpath(wpath);
-               free(wpath);
-               wpath = wlpath;
-       }
-       return wpath;
-}
-
 #endif
 
-#else
-
-static wchar_t* u2wlongpath(const char *upath)
-{
-       wchar_t* wpath, *p;
-       if (!upath || win32_utf8_wide(upath, &wpath, NULL) < 1)
-               return NULL;
-       for (p = wpath; *p; ++p)
-               if (*p == L'/')
-                       *p = L'\\';
-       return wpath;
-}
-
-#endif
+#include "wpathconv.h"
 
 /* Always add a default permission mask in case of flags|O_CREAT. */
 int compat_open(const char *filename, int flags)
@@ -562,67 +453,38 @@ char* compat_nextdir(struct compat_dir *cd)
 
 #endif
 
-#ifdef USE_MODULES
-/*
-       This is what I expected the platform-specific dance for dynamic module
-       support to be. Little did I know about the peculiarities of (long)
-       paths and directory/file search on Windows.
-*/
-
-void *compat_dlopen(const char *path)
-{
-       void *handle = NULL;
-#ifdef WANT_WIN32_UNICODE
-       wchar_t *wpath;
-       wpath = u2wlongpath(path);
-       if(wpath)
-               handle = LoadLibraryW(wpath);
-       free(wpath);
-#else
-       handle = dlopen(path, RTLD_NOW);
-#endif
-       return handle;
-}
-
-void *compat_dlsym(void *handle, const char *name)
-{
-       void *sym = NULL;
-       if(!handle)
-               return NULL;
-#ifdef WANT_WIN32_UNICODE
-       sym = GetProcAddress(handle, name);
-#else
-       sym = dlsym(handle, name);
-#endif
-       return sym;
-}
+// Revisit logic of write():
+// Return -1 if interrupted before any data was written,
+// set errno to EINTR. Any other error value is serious
+// for blocking I/O, which we assume here. EAGAIN should be
+// handed through.
+// Reaction to zero-sized write attempts could also be funky, so avoid that.
+// May return short count for various reasons. I assume that
+// any serious condition will show itself as return value -1
+// eventually.
+
+// These uninterruptible write/read functions shall persist as long as
+// possible to finish the desired operation. A short byte count is short
+// because of a serious reason (maybe EOF, maybe out of disk space). You
+// can inspect errno.
 
-void compat_dlclose(void *handle)
-{
-       if(!handle)
-               return;
-#ifdef WANT_WIN32_UNICODE
-       FreeLibrary(handle);
-#else
-       dlclose(handle);
-#endif
-}
-
-#endif /* USE_MODULES */
-
-
-/* This shall survive signals and any return value less than given byte count
-   is an error */
 size_t unintr_write(int fd, void const *buffer, size_t bytes)
 {
        size_t written = 0;
+       errno = 0;
        while(bytes)
        {
+               errno = 0;
                ssize_t part = write(fd, (char*)buffer+written, bytes);
-               if(part < 0 && errno != EINTR)
+               // Just on short writes, we do not abort. Only when
+               // there was no successful operation (even zero write) at all.
+               // Any other error than EINTR ends things here.
+               if(part >= 0)
+               {
+                       bytes   -= part;
+                       written += part;
+               } else if(errno != EINTR)
                        break;
-               bytes   -= part;
-               written += part;
        }
        return written;
 }
@@ -631,17 +493,40 @@ size_t unintr_write(int fd, void const *buffer, size_t bytes)
 size_t unintr_read(int fd, void *buffer, size_t bytes)
 {
        size_t got = 0;
+       errno = 0;
        while(bytes)
        {
+               errno = 0;
                ssize_t part = read(fd, (char*)buffer+got, bytes);
-               if(part < 0 && errno != EINTR)
+               if(part >= 0)
+               {
+                       bytes -= part;
+                       got   += part;
+               } else if(errno != EINTR)
                        break;
-               bytes -= part;
-               got   += part;
        }
        return got;
 }
 
+// and again for streams
+size_t unintr_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
+{
+       size_t written = 0;
+       errno = 0;
+       while(size && nmemb)
+       {
+               errno = 0;
+               size_t part = fwrite((char*)ptr+written*size, size, nmemb, stream);
+               if(part > 0)
+               {
+                       nmemb   -= part;
+                       written += part;
+               } else if(errno != EINTR)
+                       break;
+       }
+       return written;
+}
+
 #ifndef NO_CATCHSIGNAL
 #if (!defined(WIN32) || defined (__CYGWIN__)) && defined(HAVE_SIGNAL_H)
 void (*catchsignal(int signum, void(*handler)()))()
index 481fc70..2af9312 100644 (file)
@@ -17,9 +17,8 @@
 #include "config.h"
 #include "intsym.h"
 
-/* For --nagging compilation with -std=c89, we need
-   to disable the inline keyword. */
-#ifdef PLAIN_C89
+/* Disable inline for non-C99 compilers. */
+#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L
 #ifndef inline
 #define inline
 #endif
@@ -66,6 +65,9 @@
 #ifndef SIZE_MAX
 #define SIZE_MAX ((size_t)-1)
 #endif
+#ifndef SSIZE_MAX
+#define SSIZE_MAX ((size_t)-1/2)
+#endif
 #ifndef ULONG_MAX
 #define ULONG_MAX ((unsigned long)-1)
 #endif
@@ -120,7 +122,7 @@ char* compat_strdup(const char *s);
 /* If we have the size checks enabled, try to derive some sane printfs.
    Simple start: Use max integer type and format if long is not big enough.
    I am hesitating to use %ll without making sure that it's there... */
-#if !(defined PLAIN_C89) && (defined SIZEOF_OFF_T) && (SIZEOF_OFF_T > SIZEOF_LONG) && (defined PRIiMAX)
+#if (defined SIZEOF_OFF_T) && (SIZEOF_OFF_T > SIZEOF_LONG) && (defined PRIiMAX)
 # define OFF_P PRIiMAX
 typedef intmax_t off_p;
 #else
@@ -128,7 +130,7 @@ typedef intmax_t off_p;
 typedef long off_p;
 #endif
 
-#if !(defined PLAIN_C89) && (defined SIZEOF_SIZE_T) && (SIZEOF_SIZE_T > SIZEOF_LONG) && (defined PRIuMAX)
+#if (defined SIZEOF_SIZE_T) && (SIZEOF_SIZE_T > SIZEOF_LONG) && (defined PRIuMAX)
 # define SIZE_P PRIuMAX
 typedef uintmax_t size_p;
 #else
@@ -136,7 +138,7 @@ typedef uintmax_t size_p;
 typedef unsigned long size_p;
 #endif
 
-#if !(defined PLAIN_C89) && (defined SIZEOF_SSIZE_T) && (SIZEOF_SSIZE_T > SIZEOF_LONG) && (defined PRIiMAX)
+#if (defined SIZEOF_SSIZE_T) && (SIZEOF_SSIZE_T > SIZEOF_LONG) && (defined PRIiMAX)
 # define SSIZE_P PRIuMAX
 typedef intmax_t ssize_p;
 #else
@@ -264,10 +266,11 @@ void  compat_dlclose(void *handle);
 #endif
 
 /* Blocking write/read of data with signal resilience.
-   Both continue after being interrupted by signals and always return the
+   They continue after being interrupted by signals and always return the
    amount of processed data (shortage indicating actual problem or EOF). */
 size_t unintr_write(int fd, void const *buffer, size_t bytes);
 size_t unintr_read (int fd, void *buffer, size_t bytes);
+size_t unintr_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
 
 /* That one comes from Tellie on OS/2, needed in resolver. */
 #ifdef __KLIBC__
index 74b0388..2f99fdc 100644 (file)
@@ -9,6 +9,7 @@
 #define catchsignal INT123_catchsignal
 #define safe_realloc INT123_safe_realloc
 #define compat_strdup INT123_compat_strdup
+#define compat_getenv INT123_compat_getenv
 #define compat_open INT123_compat_open
 #define compat_fopen INT123_compat_fopen
 #define compat_fdopen INT123_compat_fdopen
 #define compat_fclose INT123_compat_fclose
 #define win32_wide_utf8 INT123_win32_wide_utf8
 #define win32_utf8_wide INT123_win32_utf8_wide
+#define compat_catpath INT123_compat_catpath
+#define compat_isdir INT123_compat_isdir
+#define compat_diropen INT123_compat_diropen
+#define compat_dirclose INT123_compat_dirclose
+#define compat_nextfile INT123_compat_nextfile
+#define compat_nextdir INT123_compat_nextdir
+#define compat_dlopen INT123_compat_dlopen
+#define compat_dlsym INT123_compat_dlsym
+#define compat_dlclose INT123_compat_dlclose
 #define unintr_write INT123_unintr_write
 #define unintr_read INT123_unintr_read
+#define unintr_fwrite INT123_unintr_fwrite
 #define ntom_set_ntom INT123_ntom_set_ntom
 #define synth_1to1 INT123_synth_1to1
 #define synth_1to1_dither INT123_synth_1to1_dither
 #define frame_set_seek INT123_frame_set_seek
 #define frame_tell_seek INT123_frame_tell_seek
 #define frame_fill_toc INT123_frame_fill_toc
-#define getbits INT123_getbits
 #define getcpuflags INT123_getcpuflags
 #define icy2utf8 INT123_icy2utf8
 #define init_icy INT123_init_icy
 #define fi_add INT123_fi_add
 #define fi_set INT123_fi_set
 #define fi_reset INT123_fi_reset
-#define double_to_long_rounded INT123_double_to_long_rounded
-#define scale_rounded INT123_scale_rounded
 #define decode_update INT123_decode_update
 #define decoder_synth_bytes INT123_decoder_synth_bytes
 #define samples_to_bytes INT123_samples_to_bytes
 #define bytes_to_samples INT123_bytes_to_samples
 #define outblock_bytes INT123_outblock_bytes
 #define postprocess_buffer INT123_postprocess_buffer
+#define open_fixed_pre INT123_open_fixed_pre
+#define open_fixed_post INT123_open_fixed_post
 #define frame_cpu_opt INT123_frame_cpu_opt
 #define set_synth_functions INT123_set_synth_functions
 #define dectype INT123_dectype
index 0d3cf70..e203c98 100644 (file)
@@ -20,6 +20,8 @@
        Variadic macros are a C99 feature...
        Now just predefining stuff non-variadic for up to 15 arguments.
        It's cumbersome to have them all with different names, though...
+
+       Update: Also adding variadic macros now. We star to use some C99.
 */
 
 #ifdef ME
 #ifdef DEBUG
 
 #include <stdio.h>
+
+// The future (from about 20 years ago;-):
+#define mdebug(s, ...) fprintf(stderr, DBGPRFX "[" __FILE__ ":%i] debug: " s "\n", __LINE__, __VA_ARGS__)
+
 #define debug(s) fprintf(stderr, DBGPRFX"[" __FILE__ ":%i] debug: " s "\n", __LINE__)
 #define debug1(s, a) fprintf(stderr, DBGPRFX"[" __FILE__ ":%i] debug: " s "\n", __LINE__, a)
 #define debug2(s, a, b) fprintf(stderr, DBGPRFX"[" __FILE__ ":%i] debug: " s "\n", __LINE__, a, b)
@@ -48,6 +54,9 @@
 #define debug14(s, a, b, c, d, e, f, g, h, i, j, k, l, m, n) fprintf(stderr, DBGPRFX"[" __FILE__ ":%i] debug: " s "\n", __LINE__, a, b, c, d, e, f, g, h, i, j, k, l, m, n)
 #define debug15(s, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) fprintf(stderr, DBGPRFX"[" __FILE__ ":%i] debug: " s "\n", __LINE__, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o)
 #else
+
+#define mdebug(s, ...) 
+
 #define debug(s) 
 #define debug1(s, a) 
 #define debug2(s, a, b) 
@@ -68,6 +77,9 @@
 
 /* warning macros also here... */
 #ifndef NO_WARNING
+
+#define mwarning(s, ...) fprintf(stderr, DBGPRFX "[" __FILE__ ":%i] warning: " s "\n", __LINE__, __VA_ARGS__)
+
 #define warning(s) fprintf(stderr, DBGPRFX"[" __FILE__ ":%i] warning: " s "\n", __LINE__)
 #define warning1(s, a) fprintf(stderr, DBGPRFX"[" __FILE__ ":%i] warning: " s "\n", __LINE__, a)
 #define warning2(s, a, b) fprintf(stderr, DBGPRFX"[" __FILE__ ":%i] warning: " s "\n", __LINE__, a, b)
@@ -85,6 +97,7 @@
 #define warning14(s, a, b, c, d, e, f, g, h, i, j, k, l, m, n) fprintf(stderr, DBGPRFX"[" __FILE__ ":%i] warning: " s "\n", __LINE__, a, b, c, d, e, f, g, h, i, j, k, l, m, n)
 #define warning15(s, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) fprintf(stderr, DBGPRFX"[" __FILE__ ":%i] warning: " s "\n", __LINE__, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o)
 #else
+#define mwarning(s, ...) 
 #define warning(s) 
 #define warning1(s, a) 
 #define warning2(s, a, b) 
 #endif
 
 /* error macros also here... */
-#ifndef NO_ERROR
+#ifndef NO_ERRORMSG
+
+#define merror(s, ...) fprintf(stderr, DBGPRFX "[" __FILE__ ":%i] error: " s "\n", __LINE__, __VA_ARGS__)
+
 #define error(s) fprintf(stderr, DBGPRFX"[" __FILE__ ":%i] error: " s "\n", __LINE__)
 #define error1(s, a) fprintf(stderr, DBGPRFX"[" __FILE__ ":%i] error: " s "\n", __LINE__, a)
 #define error2(s, a, b) fprintf(stderr, DBGPRFX"[" __FILE__ ":%i] error: " s "\n", __LINE__, a, b)
 #define error14(s, a, b, c, d, e, f, g, h, i, j, k, l, m, n) fprintf(stderr, DBGPRFX"[" __FILE__ ":%i] error: " s "\n", __LINE__, a, b, c, d, e, f, g, h, i, j, k, l, m, n)
 #define error15(s, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) fprintf(stderr, DBGPRFX"[" __FILE__ ":%i] error: " s "\n", __LINE__, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o)
 #else
+#define merror(s, ...) 
 #define error(s) 
 #define error1(s, a) 
 #define error2(s, a, b) 
 
 /* ereturn macros also here... */
 #ifndef NO_ERETURN
+
+#define mereturn(rv, s, ...) do{ fprintf(stderr, DBGPRFX "[" __FILE__ ":%i] ereturn: " s "\n", __LINE__, __VA_ARGS__); return rv; }while(0)
+
 #define ereturn(rv, s) do{ fprintf(stderr, DBGPRFX"[" __FILE__ ":%i] ereturn: " s "\n", __LINE__); return rv; }while(0)
 #define ereturn1(rv, s, a) do{ fprintf(stderr, DBGPRFX"[" __FILE__ ":%i] ereturn: " s "\n", __LINE__, a); return rv; }while(0)
 #define ereturn2(rv, s, a, b) do{ fprintf(stderr, DBGPRFX"[" __FILE__ ":%i] ereturn: " s "\n", __LINE__, a, b); return rv; }while(0)
 #define ereturn14(rv, s, a, b, c, d, e, f, g, h, i, j, k, l, m, n) do{ fprintf(stderr, DBGPRFX"[" __FILE__ ":%i] ereturn: " s "\n", __LINE__, a, b, c, d, e, f, g, h, i, j, k, l, m, n); return rv; }while(0)
 #define ereturn15(rv, s, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) do{ fprintf(stderr, DBGPRFX"[" __FILE__ ":%i] ereturn: " s "\n", __LINE__, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o); return rv; }while(0)
 #else
+#define mereturn(rv, s, ...) return rv
 #define ereturn(rv, s) return rv
 #define ereturn1(rv, s, a) return rv
 #define ereturn2(rv, s, a, b) return rv
index 03ec676..317dfcd 100644 (file)
@@ -1,6 +1,11 @@
 #include "mpg123lib_intern.h"
 
-int mpg123_feature(const enum mpg123_feature_set key)
+int attribute_align_arg mpg123_feature2(int key)
+{
+       return mpg123_feature(key);
+}
+
+int attribute_align_arg mpg123_feature(const enum mpg123_feature_set key)
 {
        switch(key)
        {
@@ -32,6 +37,20 @@ int mpg123_feature(const enum mpg123_feature_set key)
                return 1;
 #endif /* mpg123_output_32bit */
 
+               case MPG123_FEATURE_OUTPUT_FLOAT32:
+#if defined(NO_REAL) || defined(REAL_IS_DOUBLE)
+               return 0;
+#else
+               return 1;
+#endif
+
+               case MPG123_FEATURE_OUTPUT_FLOAT64:
+#if defined(NO_REAL) || !defined(REAL_IS_DOUBLE)
+               return 0;
+#else
+               return 1;
+#endif
+
                case MPG123_FEATURE_PARSE_ID3V2:
 #ifdef NO_ID3V2
                return 0;
@@ -106,6 +125,12 @@ int mpg123_feature(const enum mpg123_feature_set key)
 #else
                return 0;
 #endif
+               case MPG123_FEATURE_MOREINFO:
+#ifndef NO_MOREINFO
+               return 1;
+#else
+               return 0;
+#endif
 
                default: return 0;
        }
index cc30a06..dcabf5e 100644 (file)
@@ -4,7 +4,7 @@
        separate header just for audio format definitions not tied to
        library code
 
-       copyright 1995-2015 by the mpg123 project
+       copyright 1995-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
 */
@@ -99,19 +99,43 @@ enum mpg123_enc_enum
  * \return size of one sample in bytes
  */
 #define MPG123_SAMPLESIZE(enc) ( \
-       (enc) & MPG123_ENC_8 \
-       ?       1 \
-       :       ( (enc) & MPG123_ENC_16 \
-               ?       2 \
-               :       ( (enc) & MPG123_ENC_24 \
-                       ?       3 \
-                       :       ( (  (enc) & MPG123_ENC_32 \
-                                 || (enc) == MPG123_ENC_FLOAT_32 ) \
-                               ?       4 \
-                               :       ( (enc) == MPG123_ENC_FLOAT_64 \
-                                       ?       8 \
-                                       :       0 \
-)      )       )       )       )
+       (enc) < 1 \
+       ?       0 \
+       :       ( (enc) & MPG123_ENC_8 \
+               ?       1 \
+               :       ( (enc) & MPG123_ENC_16 \
+                       ?       2 \
+                       :       ( (enc) & MPG123_ENC_24 \
+                               ?       3 \
+                               :       ( (  (enc) & MPG123_ENC_32 \
+                                         || (enc) == MPG123_ENC_FLOAT_32 ) \
+                                       ?       4 \
+                                       :       ( (enc) == MPG123_ENC_FLOAT_64 \
+                                               ?       8 \
+                                               :       0 \
+)      )       )       )       )       )
+
+/** Representation of zero in differing encodings.
+ *  This exists to define proper silence in various encodings without
+ *  having to link to libsyn123 to do actual conversions at runtime.
+ *  You have to handle big/little endian order yourself, though.
+ *  This takes the shortcut that any signed encoding has a zero with
+ *  all-zero bits. Unsigned linear encodings just have the highest bit set
+ *  (2^(n-1) for n bits), while the nonlinear 8-bit ones are special.
+ *  \param enc the encoding (mpg123_enc_enum value)
+ *  \param siz bytes per sample (return value of MPG123_SAMPLESIZE(enc))
+ *  \param off byte (octet) offset counted from LSB
+ *  \return unsigned byte value for the designated octet
+ */
+#define MPG123_ZEROSAMPLE(enc, siz, off) ( \
+       (enc) == MPG123_ENC_ULAW_8 \
+       ?       (off == 0 ? 0xff : 0x00) \
+       :       ( (enc) == MPG123_ENC_ALAW_8 \
+               ?       (off == 0 ? 0xd5 : 0x00) \
+               :       ( (((enc) & (MPG123_ENC_SIGNED|MPG123_ENC_FLOAT)) || (siz) != ((off)+1)) \
+                       ?       0x00 \
+                       :       0x80 \
+       )       )       )
 
 /** Structure defining an audio format.
  *  Providing the members as individual function arguments to define a certain
index 6a17ce1..0ae7750 100644 (file)
@@ -1,7 +1,7 @@
 /*
-       format:routines to deal with audio (output) format
+       format: routines to deal with audio (output) format
 
-       copyright 2008-14 by the mpg123 project - free software under the terms of the LGPL 2.1
+       copyright 2008-20 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, starting with parts of the old audio.c, with only faintly manage to show now
 
@@ -26,6 +26,7 @@
 */
 
 #include "mpg123lib_intern.h"
+#include "sample.h"
 #include "debug.h"
 
 /* static int chans[NUM_CHANNELS] = { 1 , 2 }; */
@@ -60,6 +61,10 @@ static const int my_encodings[MPG123_ENCODINGS] =
 static const int enc_float_range[2] = { 6, 8 };
 /* same for 8 bit encodings */
 static const int enc_8bit_range[2] = { 8, 12 };
+// for 24 bit quality (24 and 32 bit integers)
+static const int enc_24bit_range[2] = { 2, 6 };
+// for completeness, the 16 bits
+static const int enc_16bit_range[2] = { 0, 2};
 
 /*
        Only one type of float is supported.
@@ -150,14 +155,14 @@ static int enc2num(int encoding)
        return -1;
 }
 
-static int cap_fit(mpg123_handle *fr, struct audioformat *nf, int f0, int f2)
+static int cap_fit(mpg123_pars *p, struct audioformat *nf, int f0, int f2)
 {
        int i;
        int c  = nf->channels-1;
-       int rn = rate2num(&fr->p, nf->rate);
+       int rn = rate2num(p, nf->rate);
        if(rn >= 0)     for(i=f0;i<f2;i++)
        {
-               if(fr->p.audio_caps[c][rn][i])
+               if(p->audio_caps[c][rn][i])
                {
                        nf->encoding = my_encodings[i];
                        return 1;
@@ -166,48 +171,54 @@ static int cap_fit(mpg123_handle *fr, struct audioformat *nf, int f0, int f2)
        return 0;
 }
 
-static int freq_fit(mpg123_handle *fr, struct audioformat *nf, int f0, int f2)
+static int imin(int a, int b)
 {
-       nf->rate = frame_freq(fr)>>fr->p.down_sample;
-       if(cap_fit(fr,nf,f0,f2)) return 1;
-       if(fr->p.flags & MPG123_AUTO_RESAMPLE)
-       {
-               nf->rate>>=1;
-               if(cap_fit(fr,nf,f0,f2)) return 1;
-               nf->rate>>=1;
-               if(cap_fit(fr,nf,f0,f2)) return 1;
-       }
-#ifndef NO_NTOM
-       /* If nothing worked, try the other rates, only without constrains from user.
-          In case you didn't guess: We enable flexible resampling if we find a working rate. */
-       if(  fr->p.flags & MPG123_AUTO_RESAMPLE &&
-           !fr->p.force_rate && fr->p.down_sample == 0)
-       {
-               int i;
-               int c  = nf->channels-1;
-               int rn = rate2num(&fr->p, frame_freq(fr));
-               int rrn;
-               if(rn < 0) return 0;
-               /* Try higher rates first. */
-               for(i=f0;i<f2;i++) for(rrn=rn+1; rrn<MPG123_RATES; ++rrn)
-               if(fr->p.audio_caps[c][rrn][i])
-               {
-                       nf->rate = my_rates[rrn];
-                       nf->encoding = my_encodings[i];
-                       return 1;
-               }
-               /* Then lower rates. */
-               for(i=f0;i<f2;i++) for(rrn=rn-1; rrn>=0; --rrn)
-               if(fr->p.audio_caps[c][rrn][i])
-               {
-                       nf->rate = my_rates[rrn];
-                       nf->encoding = my_encodings[i];
-                       return 1;
-               }
-       }
-#endif
+       return a < b ? a : b;
+}
 
-       return 0;
+static int imax(int a, int b)
+{
+       return a > b ? a : b;
+}
+
+// Find a possible encoding with given rate and channel count,
+// try differing channel count, too.
+// This updates the given format and returns TRUE if an encoding
+// was found.
+static int enc_chan_fit( mpg123_pars *p, long rate, struct audioformat *nnf
+,      int f0, int f2, int try_float )
+{
+#define ENCRANGE(range) imax(f0, range[0]), imin(f2, range[1])
+       struct audioformat nf = *nnf;
+       nf.rate = rate;
+       if(cap_fit(p, &nf, ENCRANGE(enc_16bit_range)))
+               goto eend;
+       if(cap_fit(p, &nf, ENCRANGE(enc_24bit_range)))
+               goto eend;
+       if(try_float &&
+               cap_fit(p, &nf, ENCRANGE(enc_float_range)))
+               goto eend;
+       if(cap_fit(p, &nf, ENCRANGE(enc_8bit_range)))
+               goto eend;
+
+       /* try again with different stereoness */
+       if(nf.channels == 2 && !(p->flags & MPG123_FORCE_STEREO)) nf.channels = 1;
+       else if(nf.channels == 1 && !(p->flags & MPG123_FORCE_MONO)) nf.channels = 2;
+
+       if(cap_fit(p, &nf, ENCRANGE(enc_16bit_range)))
+               goto eend;
+       if(cap_fit(p, &nf, ENCRANGE(enc_24bit_range)))
+               goto eend;
+       if(try_float &&
+               cap_fit(p, &nf, ENCRANGE(enc_float_range)))
+               goto eend;
+       if(cap_fit(p, &nf, ENCRANGE(enc_8bit_range)))
+               goto eend;
+       return FALSE;
+eend:
+       *nnf = nf;
+       return TRUE;
+#undef ENCRANGE
 }
 
 /* match constraints against supported audio formats, store possible setup in frame
@@ -216,12 +227,17 @@ int frame_output_format(mpg123_handle *fr)
 {
        struct audioformat nf;
        int f0=0;
-       int f2=MPG123_ENCODINGS; /* Omit the 32bit and float encodings. */
+       int f2=MPG123_ENCODINGS+1; // Include all encodings by default.
        mpg123_pars *p = &fr->p;
+       int try_float = (p->flags & MPG123_FLOAT_FALLBACK) ? 0 : 1;
        /* initialize new format, encoding comes later */
        nf.channels = fr->stereo;
 
-       /* All this forcing should be removed in favour of the capabilities table... */
+       // I intended the forcing stuff to be weaved into the format support table,
+       // but this probably will never happen, as this would change library behaviour.
+       // One could introduce an additional effective format table that takes for
+       // forcings into account, but that would have to be updated on any flag
+       // change. Tedious.
        if(p->flags & MPG123_FORCE_8BIT)
        {
                f0 = enc_8bit_range[0];
@@ -229,6 +245,7 @@ int frame_output_format(mpg123_handle *fr)
        }
        if(p->flags & MPG123_FORCE_FLOAT)
        {
+               try_float = 1;
                f0 = enc_float_range[0];
                f2 = enc_float_range[1];
        }
@@ -237,52 +254,105 @@ int frame_output_format(mpg123_handle *fr)
        if(p->flags & MPG123_FORCE_MONO)   nf.channels = 1;
        if(p->flags & MPG123_FORCE_STEREO) nf.channels = 2;
 
+       // Strategy update: Avoid too early triggering of the NtoM decoder.
+       // Main target is the native rate, with any encoding.
+       // Then, native rate with any channel count and any encoding.
+       // Then, it's down_sample from native rate.
+       // As last resort: NtoM rate.
+       // So the priority is 1. rate 2. channels 3. encoding.
+       // As encodings go, 16 bit is tranditionally preferred as efficient choice.
+       // Next in line are wider float and integer encodings, then 8 bit as
+       // last resort.
+
 #ifndef NO_NTOM
        if(p->force_rate)
        {
-               nf.rate = p->force_rate;
-               if(cap_fit(fr,&nf,f0,2)) goto end;            /* 16bit encodings */
-               if(cap_fit(fr,&nf,f0<=2 ? 2 : f0,f2)) goto end; /*  8bit encodings */
-
-               /* try again with different stereoness */
-               if(nf.channels == 2 && !(p->flags & MPG123_FORCE_STEREO)) nf.channels = 1;
-               else if(nf.channels == 1 && !(p->flags & MPG123_FORCE_MONO)) nf.channels = 2;
-
-               if(cap_fit(fr,&nf,f0,2)) goto end;            /* 16bit encodings */
-               if(cap_fit(fr,&nf,f0<=2 ? 2 : f0,f2)) goto end; /*  8bit encodings */
-
-               if(NOQUIET)
-               error3( "Unable to set up output format! Constraints: %s%s%liHz.",
-                       ( p->flags & MPG123_FORCE_STEREO ? "stereo, " :
-                         (p->flags & MPG123_FORCE_MONO ? "mono, " : "") ),
-                       (p->flags & MPG123_FORCE_8BIT ? "8bit, " : ""),
-                       p->force_rate );
+               if(enc_chan_fit(p, p->force_rate, &nf, f0, f2, try_float))
+                       goto end;
+               // Keep the order consistent if float is considered fallback only.
+               if(!try_float && 
+                       enc_chan_fit(p, p->force_rate, &nf, f0, f2, TRUE))
+                               goto end;
+
+               merror( "Unable to set up output format! Constraints: %s%s%liHz."
+               ,       ( p->flags & MPG123_FORCE_STEREO ? "stereo, " :
+                               (p->flags & MPG123_FORCE_MONO ? "mono, " : "") )
+               ,       ( p->flags & MPG123_FORCE_FLOAT ? "float, " :
+                               (p->flags & MPG123_FORCE_8BIT ? "8bit, " : "") )
+               ,       p->force_rate );
 /*             if(NOQUIET && p->verbose <= 1) print_capabilities(fr); */
 
                fr->err = MPG123_BAD_OUTFORMAT;
                return -1;
        }
 #endif
-
-       if(freq_fit(fr, &nf, f0, 2)) goto end; /* try rates with 16bit */
-       if(freq_fit(fr, &nf, f0<=2 ? 2 : f0, f2)) goto end; /* ... 8bit */
-
-       /* try again with different stereoness */
-       if(nf.channels == 2 && !(p->flags & MPG123_FORCE_STEREO)) nf.channels = 1;
-       else if(nf.channels == 1 && !(p->flags & MPG123_FORCE_MONO)) nf.channels = 2;
-
-       if(freq_fit(fr, &nf, f0, 2)) goto end; /* try rates with 16bit */
-       if(freq_fit(fr, &nf,  f0<=2 ? 2 : f0, f2)) goto end; /* ... 8bit */
-
-       /* Here is the _bad_ end. */
-       if(NOQUIET)
+       // Native decoder rate first.
+       if(enc_chan_fit(p, frame_freq(fr)>>p->down_sample, &nf, f0, f2, try_float))
+               goto end;
+       // Then downsamplings.
+       if(p->flags & MPG123_AUTO_RESAMPLE && p->down_sample < 2)
+       {
+               if(enc_chan_fit( p, frame_freq(fr)>>(p->down_sample+1), &nf
+               ,       f0, f2, try_float ))
+                       goto end;
+               if(p->down_sample < 1 && enc_chan_fit( p, frame_freq(fr)>>2, &nf
+               ,       f0, f2, try_float ))
+                       goto end;
+       }
+       // And again the whole deal with float fallback.
+       if(!try_float)
+       {
+               if(enc_chan_fit(p, frame_freq(fr)>>p->down_sample, &nf, f0, f2, TRUE))
+                       goto end;
+               // Then downsamplings.
+               if(p->flags & MPG123_AUTO_RESAMPLE && p->down_sample < 2)
+               {
+                       if(enc_chan_fit( p, frame_freq(fr)>>(p->down_sample+1), &nf
+                       ,       f0, f2, TRUE ))
+                               goto end;
+                       if(p->down_sample < 1 && enc_chan_fit( p, frame_freq(fr)>>2, &nf
+                       ,       f0, f2, TRUE ))
+                               goto end;
+               }
+       }
+#ifndef NO_NTOM
+       // Try to find any rate that works and resample using NtoM hackery.
+       if(  p->flags & MPG123_AUTO_RESAMPLE && fr->p.down_sample == 0)
        {
-               error5( "Unable to set up output format! Constraints: %s%s%li, %li or %liHz.",
-                       ( p->flags & MPG123_FORCE_STEREO ? "stereo, " :
-                         (p->flags & MPG123_FORCE_MONO ? "mono, "  : "") ),
-                       (p->flags & MPG123_FORCE_8BIT  ? "8bit, " : ""),
-                       frame_freq(fr),  frame_freq(fr)>>1, frame_freq(fr)>>2 );
+               int i;
+               int rn = rate2num(p, frame_freq(fr));
+               int rrn;
+               if(rn < 0) return 0;
+               /* Try higher rates first. */
+               for(rrn=rn+1; rrn<MPG123_RATES; ++rrn)
+                       if(enc_chan_fit(p, my_rates[rrn], &nf, f0, f2, try_float))
+                               goto end;
+               /* Then lower rates. */
+               for(i=f0;i<f2;i++) for(rrn=rn-1; rrn>=0; --rrn)
+                       if(enc_chan_fit(p, my_rates[rrn], &nf, f0, f2, try_float))
+                               goto end;
+               // And again for float fallback.
+               if(!try_float)
+               {
+                       /* Try higher rates first. */
+                       for(rrn=rn+1; rrn<MPG123_RATES; ++rrn)
+                               if(enc_chan_fit(p, my_rates[rrn], &nf, f0, f2, TRUE))
+                                       goto end;
+                       /* Then lower rates. */
+                       for(i=f0;i<f2;i++) for(rrn=rn-1; rrn>=0; --rrn)
+                               if(enc_chan_fit(p, my_rates[rrn], &nf, f0, f2, TRUE))
+                                       goto end;
+               }
        }
+#endif
+
+       /* Here is the _bad_ end. */
+       merror( "Unable to set up output format! Constraints: %s%s%li, %li or %liHz."
+       ,       ( p->flags & MPG123_FORCE_STEREO ? "stereo, " :
+                       (p->flags & MPG123_FORCE_MONO ? "mono, " : "") )
+       ,       ( p->flags & MPG123_FORCE_FLOAT ? "float, " :
+                       (p->flags & MPG123_FORCE_8BIT ? "8bit, " : "") )
+       ,       frame_freq(fr),  frame_freq(fr)>>1, frame_freq(fr)>>2 );
 /*     if(NOQUIET && p->verbose <= 1) print_capabilities(fr); */
 
        fr->err = MPG123_BAD_OUTFORMAT;
@@ -305,7 +375,7 @@ end: /* Here is the _good_ end. */
                fr->af.encsize = mpg123_encsize(fr->af.encoding);
                if(fr->af.encsize < 1)
                {
-                       if(NOQUIET) error1("Some unknown encoding??? (%i)", fr->af.encoding);
+                       error1("Some unknown encoding??? (%i)", fr->af.encoding);
 
                        fr->err = MPG123_BAD_OUTFORMAT;
                        return -1;
@@ -391,6 +461,17 @@ int attribute_align_arg mpg123_fmt_all(mpg123_pars *mp)
        return MPG123_OK;
 }
 
+int attribute_align_arg mpg123_format2(mpg123_handle *mh, long rate, int channels, int encodings)
+{
+       int r;
+       if(mh == NULL) return MPG123_BAD_HANDLE;
+       r = mpg123_fmt2(&mh->p, rate, channels, encodings);
+       if(r != MPG123_OK){ mh->err = r; r = MPG123_ERR; }
+
+       return r;
+}
+
+// Keep old behaviour.
 int attribute_align_arg mpg123_format(mpg123_handle *mh, long rate, int channels, int encodings)
 {
        int r;
@@ -401,9 +482,9 @@ int attribute_align_arg mpg123_format(mpg123_handle *mh, long rate, int channels
        return r;
 }
 
-int attribute_align_arg mpg123_fmt(mpg123_pars *mp, long rate, int channels, int encodings)
+int attribute_align_arg mpg123_fmt2(mpg123_pars *mp, long rate, int channels, int encodings)
 {
-       int ie, ic, ratei;
+       int ie, ic, ratei, r1, r2;
        int ch[2] = {0, 1};
        if(mp == NULL) return MPG123_BAD_PARS;
        if(!(channels & (MPG123_MONO|MPG123_STEREO))) return MPG123_BAD_CHANNEL;
@@ -412,10 +493,21 @@ int attribute_align_arg mpg123_fmt(mpg123_pars *mp, long rate, int channels, int
 
        if(!(channels & MPG123_STEREO)) ch[1] = 0;     /* {0,0} */
        else if(!(channels & MPG123_MONO)) ch[0] = 1; /* {1,1} */
-       ratei = rate2num(mp, rate);
-       if(ratei < 0) return MPG123_BAD_RATE;
+       if(rate)
+       {
+               r1 = rate2num(mp, rate);
+               r2 = r1+1;
+       }
+       else
+       {
+               r1 = 0;
+               r2 = MPG123_RATES+1; /* including forced rate */
+       }
+       
+       if(r1 < 0) return MPG123_BAD_RATE;
 
        /* now match the encodings */
+       for(ratei = r1; ratei < r2; ++ratei)
        for(ic = 0; ic < 2; ++ic)
        {
                for(ie = 0; ie < MPG123_ENCODINGS; ++ie)
@@ -428,6 +520,14 @@ int attribute_align_arg mpg123_fmt(mpg123_pars *mp, long rate, int channels, int
        return MPG123_OK;
 }
 
+// Keep old behaviour, error on rate=0.
+int attribute_align_arg mpg123_fmt(mpg123_pars *mp, long rate, int channels, int encodings)
+{
+       return (rate == 0)
+       ?       MPG123_BAD_RATE
+       :       mpg123_fmt2(mp, rate, channels, encodings);
+}
+
 int attribute_align_arg mpg123_format_support(mpg123_handle *mh, long rate, int encoding)
 {
        if(mh == NULL) return 0;
@@ -484,37 +584,17 @@ off_t outblock_bytes(mpg123_handle *fr, off_t s)
 }
 
 #ifndef NO_32BIT
+
 /* Remove every fourth byte, facilitating conversion from 32 bit to 24 bit integers.
    This has to be aware of endianness, of course. */
 static void chop_fourth_byte(struct outbuffer *buf)
 {
        unsigned char *wpos = buf->data;
        unsigned char *rpos = buf->data;
-#ifdef WORDS_BIGENDIAN
-       while((size_t) (rpos - buf->data + 4) <= buf->fill)
-       {
-               /* Really stupid: Copy, increment. Byte per byte. */
-               *wpos = *rpos;
-               wpos++; rpos++;
-               *wpos = *rpos;
-               wpos++; rpos++;
-               *wpos = *rpos;
-               wpos++; rpos++;
-               rpos++; /* Skip the lowest byte (last). */
-       }
-#else
-       while((size_t) (rpos - buf->data + 4) <= buf->fill)
-       {
-               /* Really stupid: Copy, increment. Byte per byte. */
-               rpos++; /* Skip the lowest byte (first). */
-               *wpos = *rpos;
-               wpos++; rpos++;
-               *wpos = *rpos;
-               wpos++; rpos++;
-               *wpos = *rpos;
-               wpos++; rpos++;
-       }
-#endif
+       size_t blocks = buf->fill/4;
+       size_t i;
+       for(i=0; i<blocks; ++i,wpos+=3,rpos+=4)
+               DROP4BYTE(wpos, rpos)
        buf->fill = wpos-buf->data;
 }
 
@@ -526,18 +606,7 @@ static void conv_s32_to_u32(struct outbuffer *buf)
        size_t count = buf->fill/sizeof(int32_t);
 
        for(i=0; i<count; ++i)
-       {
-               /* Different strategy since we don't have a larger type at hand.
-                        Also watch out for silly +-1 fun because integer constants are signed in C90! */
-               if(ssamples[i] >= 0)
-               usamples[i] = (uint32_t)ssamples[i] + 2147483647+1;
-               /* The smallest value goes zero. */
-               else if(ssamples[i] == ((int32_t)-2147483647-1))
-               usamples[i] = 0;
-               /* Now -value is in the positive range of signed int ... so it's a possible value at all. */
-               else
-               usamples[i] = (uint32_t)2147483647+1 - (uint32_t)(-ssamples[i]);
-       }
+               usamples[i] = CONV_SU32(ssamples[i]);
 }
 
 #endif
@@ -559,10 +628,7 @@ static void conv_s16_to_u16(struct outbuffer *buf)
        size_t count = buf->fill/sizeof(int16_t);
 
        for(i=0; i<count; ++i)
-       {
-               long tmp = (long)ssamples[i]+32768;
-               usamples[i] = (uint16_t)tmp;
-       }
+               usamples[i] = CONV_SU16(ssamples[i]);
 }
 
 #ifndef NO_REAL
@@ -618,6 +684,18 @@ static void conv_s16_to_s32(struct outbuffer *buf)
 #endif
 #endif
 
+#include "swap_bytes_impl.h"
+
+void swap_endian(struct outbuffer *buf, int block)
+{
+       size_t count;
+
+       if(block >= 2)
+       {
+               count = buf->fill/(unsigned int)block;
+               swap_bytes(buf->data, (size_t)block, count);
+       }
+}
 
 void postprocess_buffer(mpg123_handle *fr)
 {
@@ -680,4 +758,17 @@ void postprocess_buffer(mpg123_handle *fr)
        break;
 #endif
        }
+       if(fr->p.flags & MPG123_FORCE_ENDIAN)
+       {
+               if(
+#ifdef WORDS_BIGENDIAN
+                       !(
+#endif
+                               fr->p.flags & MPG123_BIG_ENDIAN
+#ifdef WORDS_BIGENDIAN
+                       )
+#endif
+               )
+                       swap_endian(&fr->buffer, mpg123_encsize(fr->af.encoding));
+       }
 }
index f714fb0..b842d27 100644 (file)
@@ -1,7 +1,7 @@
 /*
        frame: Heap of routines dealing with the core mpg123 data structure.
 
-       copyright 2008-2014 by the mpg123 project - free software under the terms of the LGPL 2.1
+       copyright 2008-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
 */
@@ -40,7 +40,7 @@ static void frame_default_pars(mpg123_pars *mp)
 #ifdef GAPLESS
        mp->flags |= MPG123_GAPLESS;
 #endif
-       mp->flags |= MPG123_AUTO_RESAMPLE;
+       mp->flags |= MPG123_AUTO_RESAMPLE|MPG123_FLOAT_FALLBACK;
 #ifndef NO_NTOM
        mp->force_rate = 0;
 #endif
@@ -64,6 +64,7 @@ static void frame_default_pars(mpg123_pars *mp)
        mp->feedpool = 5; 
        mp->feedbuffer = 4096;
 #endif
+       mp->freeformat_framesize = -1;
 }
 
 void frame_init(mpg123_handle *fr)
@@ -124,6 +125,7 @@ void frame_init_par(mpg123_handle *fr, mpg123_pars *mp)
 #endif
 
        fr->down_sample = 0; /* Initialize to silence harmless errors when debugging. */
+       fr->id3v2_raw = NULL;
        frame_fixed_reset(fr); /* Reset only the fixed data, dynamic buffers are not there yet! */
        fr->synth = NULL;
        fr->synth_mono = NULL;
@@ -132,6 +134,9 @@ void frame_init_par(mpg123_handle *fr, mpg123_pars *mp)
        fi_init(&fr->index);
        frame_index_setup(fr); /* Apply the size setting. */
 #endif
+#ifndef NO_MOREINFO
+       fr->pinfo = NULL;
+#endif
 }
 
 #ifdef OPT_DITHER
@@ -183,8 +188,9 @@ int frame_outbuffer(mpg123_handle *fr)
                if(fr->buffer.size < size)
                {
                        fr->err = MPG123_BAD_BUFFER;
-                       if(NOQUIET) error2("have external buffer of size %"SIZE_P", need %"SIZE_P, (size_p)fr->buffer.size, (size_p)size);
-
+                       if(NOQUIET)
+                               merror( "have external buffer of size %"SIZE_P", need %"SIZE_P
+                               ,       (size_p)fr->buffer.size, (size_p)size );
                        return MPG123_ERR;
                }
        }
@@ -210,7 +216,7 @@ int frame_outbuffer(mpg123_handle *fr)
        return MPG123_OK;
 }
 
-int attribute_align_arg mpg123_replace_buffer(mpg123_handle *mh, unsigned char *data, size_t size)
+int attribute_align_arg mpg123_replace_buffer(mpg123_handle *mh, void *data, size_t size)
 {
        debug2("replace buffer with %p size %"SIZE_P, data, (size_p)size);
        if(mh == NULL) return MPG123_BAD_HANDLE;
@@ -236,20 +242,19 @@ int frame_index_setup(mpg123_handle *fr)
        if(fr->p.index_size >= 0)
        { /* Simple fixed index. */
                fr->index.grow_size = 0;
-               debug1("resizing index to %li", fr->p.index_size);
                ret = fi_resize(&fr->index, (size_t)fr->p.index_size);
-               debug2("index resized... %lu at %p", (unsigned long)fr->index.size, (void*)fr->index.data);
        }
        else
        { /* A growing index. We give it a start, though. */
                fr->index.grow_size = (size_t)(- fr->p.index_size);
                if(fr->index.size < fr->index.grow_size)
-               ret = fi_resize(&fr->index, fr->index.grow_size);
+                       ret = fi_resize(&fr->index, fr->index.grow_size);
                else
-               ret = MPG123_OK; /* We have minimal size already... and since growing is OK... */
+                       ret = MPG123_OK; /* We have minimal size already... and since growing is OK... */
        }
        debug2("set up frame index of size %lu (ret=%i)", (unsigned long)fr->index.size, ret);
-
+       if(ret && NOQUIET)
+               error("frame index setup (initial resize) failed");
        return ret;
 }
 #endif
@@ -560,7 +565,14 @@ static void frame_fixed_reset(mpg123_handle *fr)
 #endif
        fr->halfphase = 0; /* here or indeed only on first-time init? */
        fr->error_protection = 0;
-       fr->freeformat_framesize = -1;
+       fr->freeformat_framesize = fr->p.freeformat_framesize;
+       fr->enc_delay = -1;
+       fr->enc_padding = -1;
+       memset(fr->id3buf, 0, sizeof(fr->id3buf));
+       if(fr->id3v2_raw)
+               free(fr->id3v2_raw);
+       fr->id3v2_raw = NULL;
+       fr->id3v2_size = 0;
 }
 
 static void frame_free_buffers(mpg123_handle *fr)
@@ -623,6 +635,18 @@ int attribute_align_arg mpg123_framedata(mpg123_handle *mh, unsigned long *heade
        return MPG123_OK;
 }
 
+int attribute_align_arg mpg123_set_moreinfo( mpg123_handle *mh
+,      struct mpg123_moreinfo *mi)
+{
+#ifndef NO_MOREINFO
+       mh->pinfo = mi;
+       return MPG123_OK;
+#else
+       mh->err = MPG123_MISSING_FEATURE;
+       return MPG123_ERR;
+#endif
+}
+
 /*
        Fuzzy frame offset searching (guessing).
        When we don't have an accurate position, we may use an inaccurate one.
@@ -739,7 +763,9 @@ off_t frame_ins2outs(mpg123_handle *fr, off_t ins)
 #              ifndef NO_NTOM
                case 3: outs = ntom_ins2outs(fr, ins); break;
 #              endif
-               default: error1("Bad down_sample (%i) ... should not be possible!!", fr->down_sample);
+               default: if(NOQUIET)
+                       merror( "Bad down_sample (%i) ... should not be possible!!"
+                       ,       fr->down_sample );
        }
        return outs;
 }
@@ -759,7 +785,9 @@ off_t frame_outs(mpg123_handle *fr, off_t num)
 #ifndef NO_NTOM
                case 3: outs = ntom_frmouts(fr, num); break;
 #endif
-               default: error1("Bad down_sample (%i) ... should not be possible!!", fr->down_sample);
+               default: if(NOQUIET)
+                       merror( "Bad down_sample (%i) ... should not be possible!!"
+                       ,       fr->down_sample );
        }
        return outs;
 }
@@ -781,7 +809,9 @@ off_t frame_expect_outsamples(mpg123_handle *fr)
 #ifndef NO_NTOM
                case 3: outs = ntom_frame_outsamples(fr); break;
 #endif
-               default: error1("Bad down_sample (%i) ... should not be possible!!", fr->down_sample);
+               default: if(NOQUIET)
+                       merror( "Bad down_sample (%i) ... should not be possible!!"
+                       ,       fr->down_sample );
        }
        return outs;
 }
@@ -801,7 +831,8 @@ off_t frame_offset(mpg123_handle *fr, off_t outs)
 #ifndef NO_NTOM
                case 3: num = ntom_frameoff(fr, outs); break;
 #endif
-               default: error("Bad down_sample ... should not be possible!!");
+               default: if(NOQUIET)
+                       error("Bad down_sample ... should not be possible!!");
        }
        return num;
 }
@@ -849,7 +880,10 @@ void frame_gapless_update(mpg123_handle *fr, off_t total_samples)
 
        if(gapless_samples > total_samples)
        {
-               if(NOQUIET) error2("End sample count smaller than gapless end! (%"OFF_P" < %"OFF_P"). Disabling gapless mode from now on.", (off_p)total_samples, (off_p)fr->end_s);
+               if(NOQUIET)
+                       merror( "End sample count smaller than gapless end! (%"OFF_P
+                               " < %"OFF_P"). Disabling gapless mode from now on."
+                       ,       (off_p)total_samples, (off_p)fr->end_s );
                /* This invalidates the current position... but what should I do? */
                frame_gapless_init(fr, -1, 0, 0);
                frame_gapless_realinit(fr);
@@ -912,7 +946,7 @@ void frame_set_frameseek(mpg123_handle *fr, off_t fe)
 void frame_skip(mpg123_handle *fr)
 {
 #ifndef NO_LAYER3
-       if(fr->lay == 3) set_pointer(fr, 512);
+       if(fr->lay == 3) set_pointer(fr, 1, 512);
 #endif
 }
 
index 1087090..375867c 100644 (file)
@@ -84,6 +84,7 @@ struct mpg123_pars_struct
        long feedpool;
        long feedbuffer;
 #endif
+       long freeformat_framesize;
 };
 
 enum frame_state_flags
@@ -224,6 +225,7 @@ struct mpg123_handle_struct
 
        /* bitstream info; bsi */
        int bitindex;
+       long bits_avail;
        unsigned char *wordpointer;
        /* temporary storage for getbits stuff */
        unsigned long ultmp;
@@ -248,7 +250,7 @@ struct mpg123_handle_struct
        int fsizeold;
        int ssize;
        unsigned int bitreservoir;
-       unsigned char bsspace[2][MAXFRAMESIZE+512]; /* MAXFRAMESIZE */
+       unsigned char bsspace[2][MAXFRAMESIZE+512+4]; /* MAXFRAMESIZE */
        unsigned char *bsbuf;
        unsigned char *bsbufold;
        int bsnum;
@@ -295,6 +297,8 @@ struct mpg123_handle_struct
 #ifndef NO_ID3V2
        mpg123_id3v2 id3v2;
 #endif
+       unsigned char *id3v2_raw;
+       size_t id3v2_size;
 #ifndef NO_ICY
        struct icy_meta icy;
 #endif
@@ -333,6 +337,11 @@ struct mpg123_handle_struct
        void *wrapperdata;
        /* A callback used to properly destruct the wrapper data. */
        void (*wrapperclean)(void*);
+       int enc_delay;
+       int enc_padding;
+#ifndef NO_MOREINFO
+       struct mpg123_moreinfo *pinfo;
+#endif
 };
 
 /* generic init, does not include dynamic buffers */
@@ -376,9 +385,10 @@ MPEG 2.5
 576
 */
 
-#ifdef GAPLESS
-/* well, I take that one for granted... at least layer3 */
+// Well, I take that one for granted... at least layer3.
+// The value is needed for mpg123_getstate() in any build.
 #define GAPLESS_DELAY 529
+#ifdef GAPLESS
 void frame_gapless_init(mpg123_handle *fr, off_t framecount, off_t bskip, off_t eskip);
 void frame_gapless_realinit(mpg123_handle *fr);
 void frame_gapless_update(mpg123_handle *mh, off_t total_samples);
index 4b452f9..6d0d548 100644 (file)
 #define _MPG123_GETBITS_H_
 
 #include "mpg123lib_intern.h"
+#include "debug.h"
 
 #define backbits(fr,nob) ((void)( \
+  fr->bits_avail  += nob, \
   fr->bitindex    -= nob, \
   fr->wordpointer += (fr->bitindex>>3), \
   fr->bitindex    &= 0x7 ))
 
 #define getbitoffset(fr) ((-fr->bitindex)&0x7)
-#define getbyte(fr)      (*fr->wordpointer++)
-
-/* There is something wrong with that macro... the function below works also for the layer1 test case. */
-#define macro_getbits(fr, nob) ( \
-  fr->ultmp = fr->wordpointer[0],\
-  fr->ultmp <<= 8, \
-  fr->ultmp |= fr->wordpointer[1], \
-  fr->ultmp <<= 8, \
-  fr->ultmp |= fr->wordpointer[2], \
-  fr->ultmp <<= fr->bitindex, \
-  fr->ultmp &= 0xffffff, \
-  fr->bitindex += nob, \
-  fr->ultmp >>= (24-nob), \
-  fr->wordpointer += (fr->bitindex>>3), \
-  fr->bitindex &= 7, \
-  fr->ultmp)
+/* Precomputing the bytes to be read is error-prone, and some over-read
+   is even expected for Huffman. Just play safe and return zeros in case
+   of overflow. This assumes you made bitindex zero already! */
+#define getbyte(fr) ( (fr)->bits_avail-=8, (fr)->bits_avail >= 0 \
+  ? *((fr)->wordpointer++) \
+  : 0 )
 
 static unsigned int getbits(mpg123_handle *fr, int number_of_bits)
 {
@@ -44,11 +36,16 @@ static unsigned int getbits(mpg123_handle *fr, int number_of_bits)
 #ifdef DEBUG_GETBITS
 fprintf(stderr,"g%d",number_of_bits);
 #endif
+  fr->bits_avail -= number_of_bits;
   /* Safety catch until we got the nasty code fully figured out. */
   /* No, that catch stays here, even if we think we got it figured out! */
-  if( (long)(fr->wordpointer-fr->bsbuf)*8
-      + fr->bitindex+number_of_bits > (long)fr->framesize*8 )
+  if(fr->bits_avail < 0)
+  {
+    if(NOQUIET)
+      error2( "Tried to read %i bits with %li available."
+      ,  number_of_bits, fr->bits_avail );
     return 0;
+  }
 /*  This is actually slow: if(!number_of_bits)
     return 0; */
 
@@ -85,7 +82,7 @@ fprintf(stderr,":%lx\n",rval);
 #define skipbits(fr, nob) fr->ultmp = ( \
   fr->ultmp = fr->wordpointer[0], fr->ultmp <<= 8, fr->ultmp |= fr->wordpointer[1], \
   fr->ultmp <<= 8, fr->ultmp |= fr->wordpointer[2], fr->ultmp <<= fr->bitindex, \
-  fr->ultmp &= 0xffffff, fr->bitindex += nob, \
+  fr->ultmp &= 0xffffff, fr->bitindex += nob, fr->bits_avail -= nob, \
   fr->ultmp >>= (24-nob), fr->wordpointer += (fr->bitindex>>3), \
   fr->bitindex &= 7 )
 
@@ -93,11 +90,13 @@ fprintf(stderr,":%lx\n",rval);
   fr->ultmp = (unsigned char) (fr->wordpointer[0] << fr->bitindex), \
   fr->ultmp |= ((unsigned long) fr->wordpointer[1]<<fr->bitindex)>>8, \
   fr->ultmp <<= nob, fr->ultmp >>= 8, \
-  fr->bitindex += nob, fr->wordpointer += (fr->bitindex>>3), \
+  fr->bitindex += nob, fr->bits_avail -= nob, \
+  fr->wordpointer += (fr->bitindex>>3), \
   fr->bitindex &= 7, fr->ultmp )
 
 #define get1bit(fr) ( \
-  fr->uctmp = *fr->wordpointer << fr->bitindex, fr->bitindex++, \
+  fr->uctmp = *fr->wordpointer << fr->bitindex, \
+  ++fr->bitindex, --fr->bits_avail, \
   fr->wordpointer += (fr->bitindex>>3), fr->bitindex &= 7, fr->uctmp>>7 )
 
 
index 1cc25af..3073007 100644 (file)
@@ -1,9 +1,86 @@
 /*
        id3: ID3v2.3 and ID3v2.4 parsing (a relevant subset)
 
-       copyright 2006-2013 by the mpg123 project - free software under the terms of the LGPL 2.1
+       copyright 2006-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
+
+       WIP: Handling of multiple ID3 tags in a stream.
+
+       1. With update flag: Add non-unique data, replace unique.
+       - Only one TALB, TPE1, etc.
+       - Only one TXXX with a certain description.
+       - Only one COMM with certain language and description.
+       - Only one APIC with certain type and description, generally only one
+         of type 1 and 2 each.
+       2. Without update flag: wipe whole data and only store new stuff.
+
+       BIG BAD BUT: How to properly handle seeks in a stream that make
+       the parser encounter the same tags again in random order? Is
+       there even a correct way to handle that without storing an
+       ordered list of all tags? I could simplify the code here and just
+       communicate that a frame should be an update to previous, and
+       at which stream position the frame was encountered. But since
+       libmpg123 is driven by MPEG frames, there could be multiple
+       ID3v2 tags in direct succession treated by the parser without
+       the library user being able to interfere.
+
+       This is severely fucked. All that complexity also doesn't matter
+       in practice, as streams use ICY and individual files have just one
+       ID3v2 tag (relevant for libmpg123).  It's an academic problem. But
+       for seekable files, I could implement some jumping logic to find
+       and parse all ID3v2 for once and then set a flag that only jumps
+       the frames on seeks. That covers all local disk playback. For
+       streams, seeking is no issue (seeking back, at least), so the
+       update/replace logic works.
+
+       Look at the standard:
+
+------
+5.   Tag location
+
+   The default location of an ID3v2 tag is prepended to the audio so
+   that players can benefit from the information when the data is
+   streamed. It is however possible to append the tag, or make a
+   prepend/append combination. When deciding upon where an unembedded
+   tag should be located, the following order of preference SHOULD be
+   considered.
+   
+     1. Prepend the tag.
+
+     2. Prepend a tag with all vital information and add a second tag at 
+        the end of the file, before tags from other tagging systems. The
+        first tag is required to have a SEEK frame.
+      
+     3. Add a tag at the end of the file, before tags from other tagging
+        systems.
+      
+   In case 2 and 3 the tag can simply be appended if no other known tags
+   are present. The suggested method to find ID3v2 tags are:
+   
+     1. Look for a prepended tag using the pattern found in section 3.1.
+
+     2. If a SEEK frame was found, use its values to guide further
+        searching.
+
+     3. Look for a tag footer, scanning from the back of the file.
+
+   For every new tag that is found, the old tag should be discarded
+   unless the update flag in the extended header (section 3.2) is set.
+------
+
+       For seekable streams, I simply need to implement explicit ID3v2 search along
+       that recommendation and keep the complete information. Streams that continue
+       growing during playback will not recognize added ID3v2 tags. So be it.
+       For non-seekable streams, a tag is always parsed when encountered, assuming
+       the order of update tags always matches.
+
+       First step for the 1.26 release shall be the implementaton of the update
+       logic and glossing over the theoretical problem of re-parsing update
+       frames in the wrong order by ignoring it. They are not that relevant.
+
+       TODO: Cave in and add the missing frames from the spec. Not that far to go.
+       But need another data structure to communicate those ...
 */
 
 #include "mpg123lib_intern.h"
@@ -128,12 +205,42 @@ static void free_id3_picture(mpg123_picture **list, size_t *size)
 }
 
 /* Add items to the list. */
-#define add_comment(mh) add_id3_text(&((mh)->id3v2.comment_list), &((mh)->id3v2.comments))
-#define add_text(mh)    add_id3_text(&((mh)->id3v2.text),         &((mh)->id3v2.texts))
-#define add_extra(mh)   add_id3_text(&((mh)->id3v2.extra),        &((mh)->id3v2.extras))
-#define add_picture(mh)   add_id3_picture(&((mh)->id3v2.picture),       &((mh)->id3v2.pictures))
-static mpg123_text *add_id3_text(mpg123_text **list, size_t *size)
+
+#define add_comment(mh, l, d) add_id3_text(&((mh)->id3v2.comment_list), &((mh)->id3v2.comments), NULL,    l, d)
+#define add_text(mh, id)      add_id3_text(&((mh)->id3v2.text),         &((mh)->id3v2.texts),      id, NULL, NULL)
+#define add_uslt(mh, l, d)    add_id3_text(&((mh)->id3v2.text),         &((mh)->id3v2.texts),      id, l, d)
+#define add_extra(mh, d)      add_id3_text(&((mh)->id3v2.extra),        &((mh)->id3v2.extras),   NULL, NULL, d)
+#define add_picture(mh, t, d) add_id3_picture(&((mh)->id3v2.picture), &((mh)->id3v2.pictures), t, d)
+static mpg123_text *add_id3_text( mpg123_text **list, size_t *size
+,      char id[4], char lang[3], mpg123_string *description )
 {
+       mdebug( "add_id3_text id=%s lang=%s, desc=%s"
+       ,       id ? (char[5]) { id[0], id[1], id[2], id[3], 0 } : "(nil)"
+       ,       lang ? (char[4]) { lang[0], lang[1], lang[2], 0 }  : "(nil)"
+       ,       description ? (description->fill ? description->p : "(empty)") : "(nil)" );
+       if(lang && !description)
+               return NULL; // no lone language intended
+       if(id || description)
+       {
+               // Look through list of existing texts and return an existing entry
+               // if it should be overwritten.
+               for(size_t i=0; i<*size; ++i)
+               {
+                       mpg123_text *entry = *list+i;
+                       if(description)
+                       { // Overwrite entry with same description and same ID and language.
+                               if( (!id || !memcmp(id, entry->id, 4))
+                                       && (!lang || !memcmp(entry->lang, lang, 3))
+                                       && mpg123_same_string(&(entry->description), description)
+                               )
+                               return entry;
+                       } else if(id && !memcmp(id, entry->id, 4))
+                               return entry; // Just ovewrite because of same ID.
+                       mdebug("add_id3_text: entry %zu was no match", i);
+               }
+       }
+       mdebug("add_id3_text: append to list of %zu", *size);
+       // Nothing found, add new one.
        mpg123_text *x = safe_realloc(*list, sizeof(mpg123_text)*(*size+1));
        if(x == NULL) return NULL; /* bad */
 
@@ -143,8 +250,25 @@ static mpg123_text *add_id3_text(mpg123_text **list, size_t *size)
 
        return &((*list)[*size-1]); /* Return pointer to the added text. */
 }
-static mpg123_picture *add_id3_picture(mpg123_picture **list, size_t *size)
+
+
+static mpg123_picture *add_id3_picture(mpg123_picture **list, size_t *size, char type, mpg123_string *description)
 {
+       if(!description)
+               return NULL;
+
+       // Return entry to overwrite, if appropriate.
+       for(size_t i=0; i<*size; ++i)
+       {
+               mpg123_picture *entry = *list+i;
+               if(  type == entry->type
+                       && ( type == 1 || type == 2 ||
+                               mpg123_same_string(&entry->description, description)
+                       )
+               )
+                       return entry;
+       }
+       // Append a new one.
        mpg123_picture *x = safe_realloc(*list, sizeof(mpg123_picture)*(*size+1));
        if(x == NULL) return NULL; /* bad */
 
@@ -155,49 +279,6 @@ static mpg123_picture *add_id3_picture(mpg123_picture **list, size_t *size)
        return &((*list)[*size-1]); /* Return pointer to the added picture. */
 }
 
-
-/* Remove the last item. */
-#define pop_comment(mh) pop_id3_text(&((mh)->id3v2.comment_list), &((mh)->id3v2.comments))
-#define pop_text(mh)    pop_id3_text(&((mh)->id3v2.text),         &((mh)->id3v2.texts))
-#define pop_extra(mh)   pop_id3_text(&((mh)->id3v2.extra),        &((mh)->id3v2.extras))
-#define pop_picture(mh)   pop_id3_picture(&((mh)->id3v2.picture),       &((mh)->id3v2.pictures))
-static void pop_id3_text(mpg123_text **list, size_t *size)
-{
-       mpg123_text *x;
-       if(*size < 1) return;
-
-       free_mpg123_text(&((*list)[*size-1]));
-       if(*size > 1)
-       {
-               x = safe_realloc(*list, sizeof(mpg123_text)*(*size-1));
-               if(x != NULL){ *list  = x; *size -= 1; }
-       }
-       else
-       {
-               free(*list);
-               *list = NULL;
-               *size = 0;
-       }
-}
-static void pop_id3_picture(mpg123_picture **list, size_t *size)
-{
-       mpg123_picture *x;
-       if(*size < 1) return;
-
-       free_mpg123_picture(&((*list)[*size-1]));
-       if(*size > 1)
-       {
-               x = safe_realloc(*list, sizeof(mpg123_picture)*(*size-1));
-               if(x != NULL){ *list  = x; *size -= 1; }
-       }
-       else
-       {
-               free(*list);
-               *list = NULL;
-               *size = 0;
-       }
-}
-
 /* OK, back to the higher level functions. */
 
 void exit_id3(mpg123_handle *fr)
@@ -242,15 +323,18 @@ void id3_link(mpg123_handle *fr)
 }
 
 /*
-       Store ID3 text data in an mpg123_string; either verbatim copy or everything translated to UTF-8 encoding.
+       Store ID3 text data in an mpg123_string; either verbatim copy or
+       everything translated to UTF-8 encoding.
        Preserve the zero string separator (I don't need strlen for the total size).
 
-       ID3v2 standard says that there should be one text frame of specific type per tag, and subsequent tags overwrite old values.
-       So, I always replace the text that may be stored already (perhaps with a list of zero-separated strings, though).
+       Since we can overwrite strings with ID3 update frames, don't free
+       memory, just grow strings.
 */
 static void store_id3_text(mpg123_string *sb, unsigned char *source, size_t source_size, const int noquiet, const int notranslate)
 {
        unsigned char encoding;
+       if(sb) // Always overwrite, even with nothing.
+               sb->fill = 0;
        if(!source_size)
        {
                debug("Empty id3 data!");
@@ -261,7 +345,7 @@ static void store_id3_text(mpg123_string *sb, unsigned char *source, size_t sour
        if(notranslate)
        {
                /* Future: Add a path for ID3 errors. */
-               if(!mpg123_resize_string(sb, source_size))
+               if(!mpg123_grow_string(sb, source_size))
                {
                        if(noquiet) error("Cannot resize target string, out of memory?");
                        return;
@@ -277,8 +361,6 @@ static void store_id3_text(mpg123_string *sb, unsigned char *source, size_t sour
        {
                if(noquiet)
                        error1("Unknown text encoding %u, I take no chances, sorry!", encoding);
-
-               mpg123_free_string(sb);
                return;
        }
        id3_to_utf8(sb, encoding, source+1, source_size-1, noquiet);
@@ -292,6 +374,8 @@ static void store_id3_text(mpg123_string *sb, unsigned char *source, size_t sour
 void id3_to_utf8(mpg123_string *sb, unsigned char encoding, const unsigned char *source, size_t source_size, int noquiet)
 {
        unsigned int bwidth;
+       if(sb)
+               sb->fill = 0;
        debug1("encoding: %u", encoding);
        /* A note: ID3v2.3 uses UCS-2 non-variable 16bit encoding, v2.4 uses UTF16.
           UTF-16 uses a reserved/private range in UCS-2 to add the magic, so we just always treat it as UTF. */
@@ -362,28 +446,38 @@ static void process_text(mpg123_handle *fr, unsigned char *realdata, size_t real
 {
        /* Text encoding          $xx */
        /* The text (encoded) ... */
-       mpg123_text *t = add_text(fr);
+       mpg123_text *t = add_text(fr, id);
        if(VERBOSE4) fprintf(stderr, "Note: Storing text from %s encoding\n", enc_name(realdata[0]));
        if(t == NULL)
        {
                if(NOQUIET) error("Unable to attach new text!");
                return;
        }
+       mdebug("process_text: (over)writing entry with ID %s", t->id
+       ?       (char[5]) { t->id[0], t->id[1], t->id[2], t->id[3], 0 }
+       :       "(nil)" );
        memcpy(t->id, id, 4);
        store_id3_text(&t->text, realdata, realsize, NOQUIET, fr->p.flags & MPG123_PLAIN_ID3TEXT);
-       if(VERBOSE4) fprintf(stderr, "Note: ID3v2 %c%c%c%c text frame: %s\n", id[0], id[1], id[2], id[3], t->text.p);
+       if(VERBOSE4) // Do not print unsanitized text to terminals!
+               fprintf(stderr, "Note: ID3v2 %c%c%c%c text frame stored\n", id[0], id[1], id[2], id[3]);
 }
 
 static void process_picture(mpg123_handle *fr, unsigned char *realdata, size_t realsize)
 {
-       unsigned char encoding = realdata[0];
+       unsigned char encoding;
        mpg123_picture *i = NULL;
-       unsigned char* workpoint;
-       if(realsize == 0)
+       unsigned char* workpoint = NULL;
+       mpg123_string mime; mpg123_init_string(&mime);
+       unsigned char image_type = 0;
+       mpg123_string description;      mpg123_init_string(&description);
+       unsigned char *image_data = NULL;
+       if(realsize < 1)
        {
                debug("Empty id3 data!");
                return;
        }
+       encoding = realdata[0];
+       realdata++; realsize--;
        if(encoding > mpg123_id3_enc_max)
        {
                if(NOQUIET)
@@ -391,51 +485,65 @@ static void process_picture(mpg123_handle *fr, unsigned char *realdata, size_t r
                return;
        }
        if(VERBOSE4) fprintf(stderr, "Note: Storing picture from APIC frame.\n");
-       /* decompose realdata accordingly */
-       i = add_picture(fr);
-       if(i == NULL)
-       {
-               if(NOQUIET) error("Unable to attach new picture!");
-               return;
-       }
-       realdata++; realsize--;
+
        /* get mime type (encoding is always latin-1) */
        workpoint = next_text(realdata, 0, realsize);
-       if (workpoint == NULL) {
-               pop_picture(fr);
-               if (NOQUIET) error("Unable to get mime type for picture; skipping picture.");
+       if(!workpoint)
+       {
+               if(NOQUIET)
+                       error("Unable to get mime type for picture; skipping picture.");
                return;
        }
-       id3_to_utf8(&i->mime_type, 0, realdata, workpoint - realdata, NOQUIET);
+       id3_to_utf8(&mime, 0, realdata, workpoint - realdata, NOQUIET);
        realsize -= workpoint - realdata;
        realdata = workpoint;
        /* get picture type */
-       i->type = realdata[0];
+       image_type = realdata[0];
        realdata++; realsize--;
        /* get description (encoding is encoding) */
        workpoint = next_text(realdata, encoding, realsize);
-       if (workpoint == NULL) {
-               if (NOQUIET) error("Unable to get description for picture; skipping picture.");
-               pop_picture(fr);
+       if(!workpoint)
+       {
+               if(NOQUIET)
+                       error("Unable to get description for picture; skipping picture.");
+               mpg123_free_string(&mime);
                return;
        }
-       id3_to_utf8(&i->description, encoding, realdata, workpoint - realdata, NOQUIET);
+       id3_to_utf8(&description, encoding, realdata, workpoint - realdata, NOQUIET);
        realsize -= workpoint - realdata;
-       if (realsize == 0) {
-               if (NOQUIET) error("No picture data defined; skipping picture.");
-               pop_picture(fr);
+       if(realsize)
+               image_data = (unsigned char*)malloc(realsize);
+       if(!realsize || !image_data) {
+               if(NOQUIET)
+                       error("No picture data or malloc failure; skipping picture.");
+               mpg123_free_string(&description);
+               mpg123_free_string(&mime);
                return;
        }
-       /* store_id3_picture(i, picture, realsize, NOQUIET)) */
-       i->data = (unsigned char*)malloc(realsize);
-       if (i->data == NULL) {
-               if (NOQUIET) error("Unable to allocate memory for picture; skipping picture");
-               pop_picture(fr);
+       memcpy(image_data, workpoint, realsize);
+
+       // All data ready now, append to/replace in list.
+       i = add_picture(fr, image_type, &description);
+       if(!i)
+       {
+               if(NOQUIET)
+                       error("Unable to attach new picture!");
+               free(image_data);
+               mpg123_free_string(&description);
+               mpg123_free_string(&mime);
                return;
        }
-       memcpy(i->data, workpoint, realsize);
+
+       // Either this is a fresh image, or one to be replaced.
+       // We hand over memory, so old storage needs to be freed.
+       free_mpg123_picture(i);
+       i->type = image_type;
        i->size = realsize;
-       if(VERBOSE4) fprintf(stderr, "Note: ID3v2 APIC picture frame of type: %d\n", i->type);
+       i->data = image_data;
+       mpg123_move_string(&mime, &i->mime_type);
+       mpg123_move_string(&description, &i->description);
+       if(VERBOSE4)
+               fprintf(stderr, "Note: ID3v2 APIC picture frame of type: %d\n", i->type);
 }
 
 /* Store a new comment that perhaps is a RVA / RVA_ALBUM/AUDIOPHILE / RVA_MIX/RADIO one
@@ -447,11 +555,12 @@ static void process_comment(mpg123_handle *fr, enum frame_types tt, unsigned cha
        /* Short description (encoded!)      <text> $00 (00) */
        /* Then the comment text (encoded) ... */
        unsigned char  encoding = realdata[0];
-       unsigned char *lang     = realdata+1; /* I'll only use the 3 bytes! */
+       char lang[3]; // realdata + 1
        unsigned char *descr    = realdata+4;
        unsigned char *text     = NULL;
        mpg123_text *xcom = NULL;
-       mpg123_text localcom; /* UTF-8 variant for local processing. */
+       mpg123_text localcom; // UTF-8 variant for local processing, remember to clean up!
+       init_mpg123_text(&localcom);
 
        if(realsize < (size_t)(descr-realdata))
        {
@@ -464,32 +573,45 @@ static void process_comment(mpg123_handle *fr, enum frame_types tt, unsigned cha
                        error1("Unknown text encoding %u, I take no chances, sorry!", encoding);
                return;
        }
-       xcom = (tt == uslt ? add_text(fr) : add_comment(fr));
-       if(VERBOSE4) fprintf(stderr, "Note: Storing comment from %s encoding\n", enc_name(realdata[0]));
-       if(xcom == NULL)
-       {
-               if(NOQUIET) error("Unable to attach new comment!");
-               return;
-       }
-       memcpy(xcom->lang, lang, 3);
-       memcpy(xcom->id, id, 4);
+       memcpy(lang, realdata+1, 3);
        /* Now I can abuse a byte from lang for the encoding. */
        descr[-1] = encoding;
        /* Be careful with finding the end of description, I have to honor encoding here. */
        text = next_text(descr, encoding, realsize-(descr-realdata));
        if(text == NULL)
        {
-               if(NOQUIET) error("No comment text / valid description?");
-               pop_comment(fr);
+               if(NOQUIET)
+                       error("No comment text / valid description?");
                return;
        }
-
-       init_mpg123_text(&localcom);
-       /* Store the text, without translation to UTF-8, but for comments always a local copy in UTF-8.
-          Reminder: No bailing out from here on without freeing the local comment data! */
-       store_id3_text(&xcom->description, descr-1, text-descr+1, NOQUIET, fr->p.flags & MPG123_PLAIN_ID3TEXT);
-       if(tt == comment)
-       store_id3_text(&localcom.description, descr-1, text-descr+1, NOQUIET, 0);
+       { // just vor variable scope
+               mpg123_string description;
+               mpg123_init_string(&description);
+               // Store the text, with desired encoding, but for comments always a local copy in UTF-8.
+               store_id3_text( &description, descr-1, text-descr+1
+               ,       NOQUIET, fr->p.flags & MPG123_PLAIN_ID3TEXT );
+               if(tt == comment)
+                       store_id3_text( &localcom.description, descr-1, text-descr+1
+                       ,       NOQUIET, 0 );
+               if(VERBOSE4)
+                       fprintf( stderr, "Note: Storing comment from %s encoding\n"
+                       ,       enc_name(realdata[0]) );
+               xcom = tt == uslt
+               ?       add_uslt(fr, lang, &description)
+               :       add_comment(fr, lang, &description);
+               if(xcom == NULL)
+               {
+                       if(NOQUIET)
+                               error("Unable to attach new comment!");
+                       mpg123_free_string(&description);
+                       free_mpg123_text(&localcom);
+                       return;
+               }
+               memcpy(xcom->id, id, 4);
+               memcpy(xcom->lang, lang, 3);
+               // That takes over the description allocation.
+               mpg123_move_string(&description, &xcom->description);
+       }
 
        text[-1] = encoding; /* Byte abusal for encoding... */
        store_id3_text(&xcom->text, text-1, realsize+1-(text-realdata), NOQUIET, fr->p.flags & MPG123_PLAIN_ID3TEXT);
@@ -559,7 +681,19 @@ static void process_extra(mpg123_handle *fr, unsigned char* realdata, size_t rea
                if(NOQUIET) error("No extra frame text / valid description?");
                return;
        }
-       xex = add_extra(fr);
+       { // just vor variable scope
+               mpg123_string description;
+               mpg123_init_string(&description);
+               /* The outside storage gets reencoded to UTF-8 only if not requested otherwise.
+                  Remember that we really need the -1 here to hand in the encoding byte!*/
+               store_id3_text( &description, descr-1, text-descr+1
+               ,       NOQUIET, fr->p.flags & MPG123_PLAIN_ID3TEXT );
+               xex = add_extra(fr, &description);
+               if(xex)
+                       mpg123_move_string(&description, &xex->description);
+               else
+                       mpg123_free_string(&description);
+       }
        if(xex == NULL)
        {
                if(NOQUIET) error("Unable to attach new extra text!");
@@ -568,9 +702,6 @@ static void process_extra(mpg123_handle *fr, unsigned char* realdata, size_t rea
        memcpy(xex->id, id, 4);
        init_mpg123_text(&localex); /* For our local copy. */
 
-       /* The outside storage gets reencoded to UTF-8 only if not requested otherwise.
-          Remember that we really need the -1 here to hand in the encoding byte!*/
-       store_id3_text(&xex->description, descr-1, text-descr+1, NOQUIET, fr->p.flags & MPG123_PLAIN_ID3TEXT);
        /* Our local copy is always stored in UTF-8! */
        store_id3_text(&localex.description, descr-1, text-descr+1, NOQUIET, 0);
        /* At first, only store the outside copy of the payload. We may not need the local copy. */
@@ -660,6 +791,50 @@ static int promote_framename(mpg123_handle *fr, char *id) /* fr because of VERBO
 
 #endif /* NO_ID3V2 */
 
+int store_id3v2( mpg123_handle *fr
+,      unsigned long first4bytes, unsigned char buf[6], unsigned long length )
+{
+       int ret = 1;
+       off_t ret2;
+       unsigned long fullen = 10+length;
+       if(fr->id3v2_raw)
+               free(fr->id3v2_raw);
+       fr->id3v2_size = 0;
+       /* Allocate one byte more for a closing zero as safety catch for strlen(). */
+       fr->id3v2_raw = malloc(fullen+1);
+       if(!fr->id3v2_raw)
+       {
+               fr->err = MPG123_OUT_OF_MEM;
+               if(NOQUIET)
+                       error1("ID3v2: Arrg! Unable to allocate %lu bytes"
+                               " for ID3v2 data - trying to skip instead.", length+1);
+               if((ret2=fr->rd->skip_bytes(fr,length)) < 0)
+                       ret = ret2;
+               else
+                       ret = 0;
+       }
+       else
+       {
+               fr->id3v2_raw[0] = (first4bytes>>24) & 0xff;
+               fr->id3v2_raw[1] = (first4bytes>>16) & 0xff;
+               fr->id3v2_raw[2] = (first4bytes>>8)  & 0xff;
+               fr->id3v2_raw[3] =  first4bytes      & 0xff;
+               memcpy(fr->id3v2_raw+4, buf, 6);
+               if((ret2=fr->rd->read_frame_body(fr, fr->id3v2_raw+10, length)) < 0)
+               {
+                       ret=ret2;
+                       free(fr->id3v2_raw);
+                       fr->id3v2_raw = NULL;
+               }
+               else
+               { /* Closing with a zero for paranoia. */
+                       fr->id3v2_raw[fullen] = 0;
+                       fr->id3v2_size = fullen;
+               }
+       }
+       return ret;
+}
+
 /*
        trying to parse ID3v2.3 and ID3v2.4 tags...
 
@@ -670,26 +845,33 @@ static int promote_framename(mpg123_handle *fr, char *id) /* fr because of VERBO
 int parse_new_id3(mpg123_handle *fr, unsigned long first4bytes)
 {
        #define UNSYNC_FLAG 128
-       #define EXTHEAD_FLAG 64
+       #define EXTHEAD_FLAG 64  /* ID3v2.3+ */
+       #define COMPRESS_FLAG 64 /* ID3v2.2 */
        #define EXP_FLAG 32
        #define FOOTER_FLAG 16
+       #define EXT_UPDATE_FLAG 64 /* ID3v2.4 only: extended header update flag */
        #define UNKNOWN_FLAGS 15 /* 00001111*/
        unsigned char buf[6];
        unsigned long length=0;
        unsigned char flags = 0;
        int ret = 1;
-       int ret2;
+       off_t ret2;
+       int storetag = 0;
+       unsigned int footlen = 0;
 #ifndef NO_ID3V2
        int skiptag = 0;
 #endif
        unsigned char major = first4bytes & 0xff;
        debug1("ID3v2: major tag version: %i", major);
+
        if(major == 0xff) return 0; /* Invalid... */
        if((ret2 = fr->rd->read_frame_body(fr, buf, 6)) < 0) /* read more header information */
        return ret2;
 
        if(buf[0] == 0xff) return 0; /* Revision, will never be 0xff. */
 
+       if(fr->p.flags & MPG123_STORE_RAW_ID3)
+               storetag = 1;
        /* second new byte are some nice flags, if these are invalid skip the whole thing */
        flags = buf[1];
        debug1("ID3v2: flags 0x%08x", flags);
@@ -731,6 +913,8 @@ int parse_new_id3(mpg123_handle *fr, unsigned long first4bytes)
                if(NOQUIET) error4("Bad tag length (not synchsafe): 0x%02x%02x%02x%02x; You got a bad ID3 tag here.", buf[2],buf[3],buf[4],buf[5]);
                return 0;
        }
+       if(flags & FOOTER_FLAG)
+               footlen = 10;
        debug1("ID3v2: tag data length %lu", length);
 #ifndef NO_ID3V2
        if(VERBOSE2) fprintf(stderr,"Note: ID3v2.%i rev %i tag of %lu bytes\n", major, buf[0], length);
@@ -749,277 +933,330 @@ int parse_new_id3(mpg123_handle *fr, unsigned long first4bytes)
                        ,       major, flags );
                skiptag = 1;
        }
+       // Standard says that compressed tags should be ignored as there isn't an agreed
+       // compressoion scheme.
+       if(major == 2 && flags & COMPRESS_FLAG)
+       {
+               if(NOQUIET)
+                       warning("ID3v2: ignoring compressed ID3v2.2 tag");
+               skiptag = 1;
+       }
        if(length < 10)
        {
                if(NOQUIET)
                        warning1("ID3v2: unrealistic small tag lengh %lu, skipping", length);
                skiptag = 1;
        }
+       if(!skiptag)
+               storetag = 1;
+#endif
+       if(storetag)
+       {
+               /* Stores whole tag with footer and an additonal trailing zero. */
+               if((ret2 = store_id3v2(fr, first4bytes, buf, length+footlen)) <= 0)
+                       return ret2;
+       }
+#ifndef NO_ID3V2
        if(skiptag)
        {
+               if(VERBOSE3)
+                       fprintf(stderr, "Note: skipped tag clearing possibly existing ID3v2 data");
+               reset_id3(fr); // Old data is invalid.
 #endif
-               if((ret2 = fr->rd->skip_bytes(fr,length)) < 0) /* will not store data in backbuff! */
-               ret = ret2;
+               if(!storetag && (ret2=fr->rd->skip_bytes(fr,length+footlen))<0)
+                       ret=ret2;
 #ifndef NO_ID3V2
        }
        else
        {
-               unsigned char* tagdata = NULL;
-               fr->id3v2.version = major;
+               unsigned char* tagdata = fr->id3v2_raw+10;
                /* try to interpret that beast */
-               if((tagdata = (unsigned char*) malloc(length+1)) != NULL)
+               debug("ID3v2: analysing frames...");
+               if(length > 0)
                {
-                       debug("ID3v2: analysing frames...");
-                       if((ret2 = fr->rd->read_frame_body(fr,tagdata,length)) > 0)
+                       unsigned char extflags = 0;
+                       unsigned long tagpos = 0;
+                       /* bytes of frame title and of framesize value */
+                       unsigned int head_part = major > 2 ? 4 : 3;
+                       unsigned int flag_part = major > 2 ? 2 : 0;
+                       /* The amount of bytes that are unconditionally read for each frame: */
+                       /* ID, size, flags. */
+                       unsigned int framebegin = head_part+head_part+flag_part;
+                       debug1("ID3v2: have read at all %lu bytes for the tag now", (unsigned long)length+6);
+                       if(flags & EXTHEAD_FLAG)
                        {
-                               unsigned long tagpos = 0;
-                               /* bytes of frame title and of framesize value */
-                               unsigned int head_part = fr->id3v2.version > 2 ? 4 : 3;
-                               unsigned int flag_part = fr->id3v2.version > 2 ? 2 : 0;
-                               /* The amount of bytes that are unconditionally read for each frame: */
-                               /* ID, size, flags. */
-                               unsigned int framebegin = head_part+head_part+flag_part;
-                               debug1("ID3v2: have read at all %lu bytes for the tag now", (unsigned long)length+6);
-                               /* going to apply strlen for strings inside frames, make sure that it doesn't overflow! */
-                               tagdata[length] = 0;
-                               if(flags & EXTHEAD_FLAG)
+                               debug("ID3v2: extended header");
+                               if(!bytes_to_long(tagdata, tagpos) || tagpos >= length)
                                {
-                                       debug("ID3v2: skipping extended header");
-                                       if(!bytes_to_long(tagdata, tagpos) || tagpos >= length)
+                                       ret = 0;
+                                       if(NOQUIET)
+                                               error4( "Bad (non-synchsafe/too large) tag offset from extended header:"
+                                                       "0x%02x%02x%02x%02x"
+                                               ,       tagdata[0], tagdata[1], tagdata[2], tagdata[3] );
+                               } else if(tagpos < 6)
+                               {
+                                       ret = 0;
+                                       if(NOQUIET)
+                                               merror("Extended header too small (%lu).", tagpos);
+                               }
+                               if(major == 3)
+                               {
+                                       tagpos += 4; // The size itself is not included.
+                                       if(tagpos >= length)
                                        {
                                                ret = 0;
                                                if(NOQUIET)
-                                                       error4( "Bad (non-synchsafe/too large) tag offset:"
-                                                               "0x%02x%02x%02x%02x"
-                                                       ,       tagdata[0], tagdata[1], tagdata[2], tagdata[3] );
+                                                       error("Too much extended v2.3 header.");
+                                       }
+                               } else if(ret) // v2.4 and at least got my 6 bytes of ext header
+                               {
+                                       // Only v4 knows update frames, check for that.
+                                       // Need to step back. Header is 4 bytes length, one byte flag size,
+                                       // one byte flags. Flag size has to be 1!
+                                       if(tagdata[4] == 1 && tagdata[5] & EXT_UPDATE_FLAG)
+                                       {
+                                               if(VERBOSE3)
+                                                       fprintf(stderr, "Note: ID3v2.4 update tag\n");
+                                               extflags |= EXT_UPDATE_FLAG;
                                        }
                                }
-                               if(ret > 0)
+                       }
+                       if(!(extflags & EXT_UPDATE_FLAG))
+                       {
+                               if(VERBOSE3)
+                                       fprintf(stderr, "Note: non-update tag replacing existing ID3v2 data\n");
+                               reset_id3(fr);
+                       }
+                       if(ret > 0)
+                       {
+                               char id[5];
+                               unsigned long framesize;
+                               unsigned long fflags; /* need 16 bits, actually */
+                               id[4] = 0;
+                               fr->id3v2.version = major;
+                               /* Pos now advanced after ext head, now a frame has to follow. */
+                               /* Note: tagpos <= length, which is 28 bit integer, so both */
+                               /* far away from overflow for adding known small values. */
+                               /* I want to read at least one full header now. */
+                               while(length >= tagpos+framebegin)
                                {
-                                       char id[5];
-                                       unsigned long framesize;
-                                       unsigned long fflags; /* need 16 bits, actually */
-                                       id[4] = 0;
-                                       /* Pos now advanced after ext head, now a frame has to follow. */
-                                       /* Note: tagpos <= length, which is 28 bit integer, so both */
-                                       /* far away from overflow for adding known small values. */
-                                       /* I want to read at least one full header now. */
-                                       while(length >= tagpos+framebegin)
+                                       int i = 0;
+                                       unsigned long pos = tagpos;
+                                       /* level 1,2,3 - 0 is info from lame/info tag! */
+                                       /* rva tags with ascending significance, then general frames */
+                                       enum frame_types tt = unknown;
+                                       /* we may have entered the padding zone or any other strangeness: check if we have valid frame id characters */
+                                       for(i=0; i< head_part; ++i)
+                                       if( !( ((tagdata[tagpos+i] > 47) && (tagdata[tagpos+i] < 58))
+                                                || ((tagdata[tagpos+i] > 64) && (tagdata[tagpos+i] < 91)) ) )
+                                       {
+                                               debug5("ID3v2: real tag data apparently ended after %lu bytes with 0x%02x%02x%02x%02x", tagpos, tagdata[tagpos], tagdata[tagpos+1], tagdata[tagpos+2], tagdata[tagpos+3]);
+                                               /* This is no hard error... let's just hope that we got something meaningful already (ret==1 in that case). */
+                                               goto tagparse_cleanup; /* Need to escape two loops here. */
+                                       }
+                                       if(ret > 0)
                                        {
-                                               int i = 0;
-                                               unsigned long pos = tagpos;
-                                               /* level 1,2,3 - 0 is info from lame/info tag! */
-                                               /* rva tags with ascending significance, then general frames */
-                                               enum frame_types tt = unknown;
-                                               /* we may have entered the padding zone or any other strangeness: check if we have valid frame id characters */
-                                               for(i=0; i< head_part; ++i)
-                                               if( !( ((tagdata[tagpos+i] > 47) && (tagdata[tagpos+i] < 58))
-                                                   || ((tagdata[tagpos+i] > 64) && (tagdata[tagpos+i] < 91)) ) )
+                                               /* 4 or 3 bytes id */
+                                               strncpy(id, (char*) tagdata+pos, head_part);
+                                               id[head_part] = 0; /* terminate for 3 or 4 bytes */
+                                               pos += head_part;
+                                               tagpos += head_part;
+                                               /* size as 32 bits or 28 bits */
+                                               if(fr->id3v2.version == 2) threebytes_to_long(tagdata+pos, framesize);
+                                               else
+                                               if(!bytes_to_long(tagdata+pos, framesize))
                                                {
-                                                       debug5("ID3v2: real tag data apparently ended after %lu bytes with 0x%02x%02x%02x%02x", tagpos, tagdata[tagpos], tagdata[tagpos+1], tagdata[tagpos+2], tagdata[tagpos+3]);
-                                                       /* This is no hard error... let's just hope that we got something meaningful already (ret==1 in that case). */
-                                                       goto tagparse_cleanup; /* Need to escape two loops here. */
+                                                       /* Just assume that up to now there was some good data. */
+                                                       if(NOQUIET) error1("ID3v2: non-syncsafe size of %s frame, skipping the remainder of tag", id);
+                                                       break;
                                                }
-                                               if(ret > 0)
+                                               if(VERBOSE3) fprintf(stderr, "Note: ID3v2 %s frame of size %lu\n", id, framesize);
+                                               tagpos += head_part;
+                                               pos += head_part;
+                                               if(fr->id3v2.version > 2)
                                                {
-                                                       /* 4 or 3 bytes id */
-                                                       strncpy(id, (char*) tagdata+pos, head_part);
-                                                       id[head_part] = 0; /* terminate for 3 or 4 bytes */
-                                                       pos += head_part;
-                                                       tagpos += head_part;
-                                                       /* size as 32 bits or 28 bits */
-                                                       if(fr->id3v2.version == 2) threebytes_to_long(tagdata+pos, framesize);
-                                                       else
-                                                       if(!bytes_to_long(tagdata+pos, framesize))
-                                                       {
-                                                               /* Just assume that up to now there was some good data. */
-                                                               if(NOQUIET) error1("ID3v2: non-syncsafe size of %s frame, skipping the remainder of tag", id);
-                                                               break;
-                                                       }
-                                                       if(VERBOSE3) fprintf(stderr, "Note: ID3v2 %s frame of size %lu\n", id, framesize);
-                                                       tagpos += head_part;
-                                                       pos += head_part;
-                                                       if(fr->id3v2.version > 2)
-                                                       {
-                                                               fflags  = (((unsigned long) tagdata[pos]) << 8) | ((unsigned long) tagdata[pos+1]);
-                                                               pos    += 2;
-                                                               tagpos += 2;
-                                                       }
-                                                       else fflags = 0;
+                                                       fflags  = (((unsigned long) tagdata[pos]) << 8) | ((unsigned long) tagdata[pos+1]);
+                                                       pos    += 2;
+                                                       tagpos += 2;
+                                               }
+                                               else fflags = 0;
 
-                                                       if(length - tagpos < framesize)
-                                                       {
-                                                               if(NOQUIET) error("Whoa! ID3v2 frame claims to be larger than the whole rest of the tag.");
-                                                               break;
-                                                       }
-                                                       tagpos += framesize; /* the important advancement in whole tag */
-                                                       /* for sanity, after full parsing tagpos should be == pos */
-                                                       /* debug4("ID3v2: found %s frame, size %lu (as bytes: 0x%08lx), flags 0x%016lx", id, framesize, framesize, fflags); */
-                                                       /* %0abc0000 %0h00kmnp */
-                                                       #define BAD_FFLAGS (unsigned long) 36784
-                                                       #define PRES_TAG_FFLAG 16384
-                                                       #define PRES_FILE_FFLAG 8192
-                                                       #define READ_ONLY_FFLAG 4096
-                                                       #define GROUP_FFLAG 64
-                                                       #define COMPR_FFLAG 8
-                                                       #define ENCR_FFLAG 4
-                                                       #define UNSYNC_FFLAG 2
-                                                       #define DATLEN_FFLAG 1
-                                                       if(head_part < 4 && promote_framename(fr, id) != 0) continue;
-
-                                                       /* shall not or want not handle these */
-                                                       if(fflags & (BAD_FFLAGS | COMPR_FFLAG | ENCR_FFLAG))
-                                                       {
-                                                               if(NOQUIET) warning("ID3v2: skipping invalid/unsupported frame");
-                                                               continue;
-                                                       }
+                                               if(length - tagpos < framesize)
+                                               {
+                                                       if(NOQUIET) error("Whoa! ID3v2 frame claims to be larger than the whole rest of the tag.");
+                                                       break;
+                                               }
+                                               tagpos += framesize; /* the important advancement in whole tag */
+                                               /* for sanity, after full parsing tagpos should be == pos */
+                                               /* debug4("ID3v2: found %s frame, size %lu (as bytes: 0x%08lx), flags 0x%016lx", id, framesize, framesize, fflags); */
+                                               /* %0abc0000 %0h00kmnp */
+                                               #define BAD_FFLAGS (unsigned long) 36784
+                                               #define PRES_TAG_FFLAG 16384
+                                               #define PRES_FILE_FFLAG 8192
+                                               #define READ_ONLY_FFLAG 4096
+                                               #define GROUP_FFLAG 64
+                                               #define COMPR_FFLAG 8
+                                               #define ENCR_FFLAG 4
+                                               #define UNSYNC_FFLAG 2
+                                               #define DATLEN_FFLAG 1
+                                               if(head_part < 4 && promote_framename(fr, id) != 0) continue;
+
+                                               /* shall not or want not handle these */
+                                               if(fflags & (BAD_FFLAGS | COMPR_FFLAG | ENCR_FFLAG))
+                                               {
+                                                       if(NOQUIET) warning("ID3v2: skipping invalid/unsupported frame");
+                                                       continue;
+                                               }
 
-                                                       for(i = 0; i < KNOWN_FRAMES; ++i)
-                                                       if(!strncmp(frame_type[i], id, 4)){ tt = i; break; }
+                                               for(i = 0; i < KNOWN_FRAMES; ++i)
+                                               if(!strncmp(frame_type[i], id, 4)){ tt = i; break; }
 
-                                                       if(id[0] == 'T' && tt != extra) tt = text;
+                                               if(id[0] == 'T' && tt != extra) tt = text;
 
-                                                       if(tt != unknown)
+                                               if(tt != unknown)
+                                               {
+                                                       int rva_mode = -1; /* mix / album */
+                                                       unsigned long realsize = framesize;
+                                                       unsigned char* realdata = tagdata+pos;
+                                                       unsigned char* unsyncbuffer = NULL;
+                                                       if(((flags & UNSYNC_FLAG) || (fflags & UNSYNC_FFLAG)) && framesize > 0)
                                                        {
-                                                               int rva_mode = -1; /* mix / album */
-                                                               unsigned long realsize = framesize;
-                                                               unsigned char* realdata = tagdata+pos;
-                                                               unsigned char* unsyncbuffer = NULL;
-                                                               if(((flags & UNSYNC_FLAG) || (fflags & UNSYNC_FFLAG)) && framesize > 0)
+                                                               unsigned long ipos = 0;
+                                                               unsigned long opos = 0;
+                                                               debug("Id3v2: going to de-unsync the frame data");
+                                                               /* de-unsync: FF00 -> FF; real FF00 is simply represented as FF0000 ... */
+                                                               /* damn, that means I have to delete bytes from withing the data block... thus need temporal storage */
+                                                               /* standard mandates that de-unsync should always be safe if flag is set */
+                                                               realdata = unsyncbuffer = malloc(framesize+1); /* will need <= bytes, plus a safety zero */
+                                                               if(realdata == NULL)
                                                                {
-                                                                       unsigned long ipos = 0;
-                                                                       unsigned long opos = 0;
-                                                                       debug("Id3v2: going to de-unsync the frame data");
-                                                                       /* de-unsync: FF00 -> FF; real FF00 is simply represented as FF0000 ... */
-                                                                       /* damn, that means I have to delete bytes from withing the data block... thus need temporal storage */
-                                                                       /* standard mandates that de-unsync should always be safe if flag is set */
-                                                                       realdata = unsyncbuffer = malloc(framesize+1); /* will need <= bytes, plus a safety zero */
-                                                                       if(realdata == NULL)
-                                                                       {
-                                                                               if(NOQUIET) error("ID3v2: unable to allocate working buffer for de-unsync");
-                                                                               continue;
-                                                                       }
-                                                                       /* now going byte per byte through the data... */
-                                                                       realdata[0] = tagdata[pos];
-                                                                       opos = 1;
-                                                                       for(ipos = pos+1; ipos < pos+framesize; ++ipos)
+                                                                       if(NOQUIET) error("ID3v2: unable to allocate working buffer for de-unsync");
+                                                                       continue;
+                                                               }
+                                                               /* now going byte per byte through the data... */
+                                                               realdata[0] = tagdata[pos];
+                                                               opos = 1;
+                                                               for(ipos = pos+1; ipos < pos+framesize; ++ipos)
+                                                               {
+                                                                       if(!((tagdata[ipos] == 0) && (tagdata[ipos-1] == 0xff)))
                                                                        {
-                                                                               if(!((tagdata[ipos] == 0) && (tagdata[ipos-1] == 0xff)))
-                                                                               {
-                                                                                       realdata[opos++] = tagdata[ipos];
-                                                                               }
+                                                                               realdata[opos++] = tagdata[ipos];
                                                                        }
-                                                                       realsize = opos;
-                                                                       /* Append a zero to keep strlen() safe. */
-                                                                       realdata[realsize] = 0;
-                                                                       debug2("ID3v2: de-unsync made %lu out of %lu bytes", realsize, framesize);
                                                                }
-                                                               pos = 0; /* now at the beginning again... */
-                                                               /* Avoid reading over boundary, even if there is a */
-                                                               /* zero byte of padding for safety. */
-                                                               if(realsize) switch(tt)
+                                                               realsize = opos;
+                                                               /* Append a zero to keep strlen() safe. */
+                                                               realdata[realsize] = 0;
+                                                               debug2("ID3v2: de-unsync made %lu out of %lu bytes", realsize, framesize);
+                                                       }
+                                                       pos = 0; /* now at the beginning again... */
+                                                       /* Avoid reading over boundary, even if there is a */
+                                                       /* zero byte of padding for safety. */
+                                                       if(realsize) switch(tt)
+                                                       {
+                                                               case comment:
+                                                               case uslt:
+                                                                       process_comment(fr, tt, realdata, realsize, comment+1, id);
+                                                               break;
+                                                               case extra: /* perhaps foobar2000's work */
+                                                                       process_extra(fr, realdata, realsize, extra+1, id);
+                                                               break;
+                                                               case rva2: /* "the" RVA tag */
                                                                {
-                                                                       case comment:
-                                                                       case uslt:
-                                                                               process_comment(fr, tt, realdata, realsize, comment+1, id);
-                                                                       break;
-                                                                       case extra: /* perhaps foobar2000's work */
-                                                                               process_extra(fr, realdata, realsize, extra+1, id);
-                                                                       break;
-                                                                       case rva2: /* "the" RVA tag */
+                                                                       /* starts with null-terminated identification */
+                                                                       if(VERBOSE3) fprintf(stderr, "Note: RVA2 identification \"%s\"\n", realdata);
+                                                                       /* default: some individual value, mix mode */
+                                                                       rva_mode = 0;
+                                                                       if( !strncasecmp((char*)realdata, "album", 5)
+                                                                                || !strncasecmp((char*)realdata, "audiophile", 10)
+                                                                                || !strncasecmp((char*)realdata, "user", 4))
+                                                                       rva_mode = 1;
+                                                                       if(fr->rva.level[rva_mode] <= rva2+1)
                                                                        {
-                                                                               /* starts with null-terminated identification */
-                                                                               if(VERBOSE3) fprintf(stderr, "Note: RVA2 identification \"%s\"\n", realdata);
-                                                                               /* default: some individual value, mix mode */
-                                                                               rva_mode = 0;
-                                                                               if( !strncasecmp((char*)realdata, "album", 5)
-                                                                                   || !strncasecmp((char*)realdata, "audiophile", 10)
-                                                                                   || !strncasecmp((char*)realdata, "user", 4))
-                                                                               rva_mode = 1;
-                                                                               if(fr->rva.level[rva_mode] <= rva2+1)
+                                                                               pos += strlen((char*) realdata) + 1;
+                                                                               debug2("got my pos: %zu - %zu", realsize, pos);
+                                                                               // channel and two bytes for RVA value
+                                                                               // pos possibly just past the safety zero, so one more than realsize
+                                                                               if(pos > realsize || realsize-pos < 3)
                                                                                {
-                                                                                       pos += strlen((char*) realdata) + 1;
-                                                                                       // channel and two bytes for RVA value
-                                                                                       // pos possibly just past the safety zero, so one more than realsize
-                                                                                       if(pos > realsize || realsize-pos < 3)
-                                                                                       {
-                                                                                               if(NOQUIET)
-                                                                                                       error("bad RVA2 tag (truncated?)");
-                                                                                       }
-                                                                                       else if(realdata[pos] == 1)
-                                                                                       {
-                                                                                               ++pos;
-                                                                                               /* only handle master channel */
-                                                                                               debug("ID3v2: it is for the master channel");
-                                                                                               /* two bytes adjustment, one byte for bits representing peak - n bytes, eh bits, for peak */
-                                                                                               /* 16 bit signed integer = dB * 512. Do not shift signed integers! Multiply instead.
-                                                                                                  Also no implementation-defined casting. Reinterpret the pointer to signed char, then do
-                                                                                                  proper casting. */
-                                                                                               fr->rva.gain[rva_mode] = (float) (
-                                                                                                       ((short)((signed char*)realdata)[pos]) * 256 + (short)realdata[pos+1] ) / 512;
-                                                                                               pos += 2;
-                                                                                               if(VERBOSE3) fprintf(stderr, "Note: RVA value %fdB\n", fr->rva.gain[rva_mode]);
-                                                                                               /* heh, the peak value is represented by a number of bits - but in what manner? Skipping that part */
-                                                                                               fr->rva.peak[rva_mode] = 0;
-                                                                                               fr->rva.level[rva_mode] = rva2+1;
-                                                                                       }
+                                                                                       if(NOQUIET)
+                                                                                               error("bad RVA2 tag (truncated?)");
+                                                                               }
+                                                                               else if(realdata[pos] == 1)
+                                                                               {
+                                                                                       ++pos;
+                                                                                       /* only handle master channel */
+                                                                                       debug("ID3v2: it is for the master channel");
+                                                                                       /* two bytes adjustment, one byte for bits representing peak - n bytes, eh bits, for peak */
+                                                                                       /* 16 bit signed integer = dB * 512. Do not shift signed integers! Multiply instead.
+                                                                                          Also no implementation-defined casting. Reinterpret the pointer to signed char, then do
+                                                                                          proper casting. */
+                                                                                       fr->rva.gain[rva_mode] = (float) (
+                                                                                               ((short)((signed char*)realdata)[pos]) * 256 + (short)realdata[pos+1] ) / 512;
+                                                                                       pos += 2;
+                                                                                       if(VERBOSE3) fprintf(stderr, "Note: RVA value %fdB\n", fr->rva.gain[rva_mode]);
+                                                                                       /* heh, the peak value is represented by a number of bits - but in what manner? Skipping that part */
+                                                                                       fr->rva.peak[rva_mode] = 0;
+                                                                                       fr->rva.level[rva_mode] = rva2+1;
                                                                                }
                                                                        }
-                                                                       break;
-                                                                       /* non-rva metainfo, simply store... */
-                                                                       case text:
-                                                                               process_text(fr, realdata, realsize, id);
-                                                                       break;
-                                                                       case picture:
-                                                                               if (fr->p.flags & MPG123_PICTURE)
-                                                                               process_picture(fr, realdata, realsize);
-
-                                                                               break;
-                                                                       default: if(NOQUIET) error1("ID3v2: unknown frame type %i", tt);
                                                                }
-                                                               if(unsyncbuffer)
-                                                                       free(unsyncbuffer);
+                                                               break;
+                                                               /* non-rva metainfo, simply store... */
+                                                               case text:
+                                                                       process_text(fr, realdata, realsize, id);
+                                                               break;
+                                                               case picture:
+                                                                       if (fr->p.flags & MPG123_PICTURE)
+                                                                       process_picture(fr, realdata, realsize);
+
+                                                                       break;
+                                                               default: if(NOQUIET) error1("ID3v2: unknown frame type %i", tt);
                                                        }
-                                                       #undef BAD_FFLAGS
-                                                       #undef PRES_TAG_FFLAG
-                                                       #undef PRES_FILE_FFLAG
-                                                       #undef READ_ONLY_FFLAG
-                                                       #undef GROUP_FFLAG
-                                                       #undef COMPR_FFLAG
-                                                       #undef ENCR_FFLAG
-                                                       #undef UNSYNC_FFLAG
-                                                       #undef DATLEN_FFLAG
+                                                       if(unsyncbuffer)
+                                                               free(unsyncbuffer);
                                                }
-                                               else break;
-                                               #undef KNOWN_FRAMES
+                                               #undef BAD_FFLAGS
+                                               #undef PRES_TAG_FFLAG
+                                               #undef PRES_FILE_FFLAG
+                                               #undef READ_ONLY_FFLAG
+                                               #undef GROUP_FFLAG
+                                               #undef COMPR_FFLAG
+                                               #undef ENCR_FFLAG
+                                               #undef UNSYNC_FFLAG
+                                               #undef DATLEN_FFLAG
                                        }
+                                       else break;
+                                       #undef KNOWN_FRAMES
                                }
-                       }
-                       else
+                       } else
                        {
-                               /* There are tags with zero length. Strictly not an error, then. */
-                               if(length > 0 && NOQUIET && ret2 != MPG123_NEED_MORE) error("ID3v2: Duh, not able to read ID3v2 tag data.");
-                               ret = ret2;
+                               if(VERBOSE3)
+                                       fprintf(stderr, "Note: faulty ID3v2 tag still clearing old data\n");
+                               reset_id3(fr);
                        }
-tagparse_cleanup:
-                       free(tagdata);
+               } else // No new data, but still there was a tag that invalidates old data.
+               {
+                       if(VERBOSE3)
+                               fprintf(stderr, "Note: empty ID3v2 clearing old data\n");
+                       reset_id3(fr);
                }
-               else
+tagparse_cleanup:
+               /* Get rid of stored raw data that should not be kept. */
+               if(!(fr->p.flags & MPG123_STORE_RAW_ID3))
                {
-                       if(NOQUIET) error1("ID3v2: Arrg! Unable to allocate %lu bytes for interpreting ID3v2 data - trying to skip instead.", length);
-                       if((ret2 = fr->rd->skip_bytes(fr,length)) < 0) ret = ret2; /* will not store data in backbuff! */
-                       else ret = 0;
+                       free(fr->id3v2_raw);
+                       fr->id3v2_raw = NULL;
+                       fr->id3v2_size = 0;
                }
        }
 #endif /* NO_ID3V2 */
-       /* skip footer if present */
-       if((ret > 0) && (flags & FOOTER_FLAG) && ((ret2 = fr->rd->skip_bytes(fr,length)) < 0)) ret = ret2;
-
        return ret;
        #undef UNSYNC_FLAG
        #undef EXTHEAD_FLAG
+       #undef COMPRESS_FLAG
        #undef EXP_FLAG
        #undef FOOTER_FLAG
+       #undef EXT_UPDATE_FLAG
        #undef UNKOWN_FLAGS
 }
 
@@ -1036,7 +1273,8 @@ static void convert_latin1(mpg123_string *sb, const unsigned char* s, size_t l,
 
        debug1("UTF-8 length: %lu", (unsigned long)length);
        /* one extra zero byte for paranoia */
-       if(!mpg123_resize_string(sb, length+1)){ mpg123_free_string(sb); return ; }
+       if(!mpg123_grow_string(sb, length+1))
+               return;
 
        p = (unsigned char*) sb->p; /* Signedness doesn't matter but it shows I thought about the non-issue */
        for(i=0; i<l; ++i)
@@ -1139,7 +1377,8 @@ static void convert_utf16bom(mpg123_string *sb, const unsigned char* s, size_t l
                else length += UTF8LEN(point); /* 1,2 or 3 bytes */
        }
 
-       if(!mpg123_resize_string(sb, length+1)){ mpg123_free_string(sb); return ; }
+       if(!mpg123_grow_string(sb, length+1))
+               return;
 
        /* Now really convert, skip checks as these have been done just before. */
        p = (unsigned char*) sb->p; /* Signedness doesn't matter but it shows I thought about the non-issue */
@@ -1180,13 +1419,12 @@ static void convert_utf16bom(mpg123_string *sb, const unsigned char* s, size_t l
 
 static void convert_utf8(mpg123_string *sb, const unsigned char* source, size_t len, const int noquiet)
 {
-       if(mpg123_resize_string(sb, len+1))
+       if(mpg123_grow_string(sb, len+1))
        {
                memcpy(sb->p, source, len);
                sb->p[len] = 0;
                sb->fill = len+1;
        }
-       else mpg123_free_string(sb);
 }
 
 #endif
index 162237a..f8d94de 100644 (file)
@@ -1,7 +1,7 @@
 /*
        index: frame index data structure and functions
 
-       copyright 2007-2015 by the mpg123 project
+       copyright 2007-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
@@ -74,12 +74,8 @@ int fi_resize(struct frame_index *fi, size_t newsize)
                fi->next = fi_next(fi);
                debug2("new index of size %lu at %p", (unsigned long)fi->size, (void*)fi->data);
                return 0;
-       }
-       else
-       {
-               error("failed to resize index!");
+       } else
                return -1;
-       }
 }
 
 void fi_add(struct frame_index *fi, off_t pos)
index d8782e0..c5bfc75 100644 (file)
@@ -34,6 +34,14 @@ static int check_balloc(mpg123_handle *fr, unsigned int *balloc, unsigned int *e
        return 0;
 }
 
+#define NEED_BITS(fr, num) \
+       if((fr)->bits_avail < num) \
+       { \
+               if(NOQUIET) \
+                       error2("%u bits needed, %li available", num, (fr)->bits_avail); \
+               return -1; \
+       } \
+
 static int I_step_one(unsigned int balloc[], unsigned int scale_index[2][SBLIMIT],mpg123_handle *fr)
 {
        unsigned int *ba=balloc;
@@ -43,42 +51,62 @@ static int I_step_one(unsigned int balloc[], unsigned int scale_index[2][SBLIMIT
        {
                int i;
                int jsbound = fr->jsbound;
+               unsigned int needbits = jsbound*2*4 + (SBLIMIT-jsbound)*4;
+
+               NEED_BITS(fr, needbits);
+               needbits = 0;
                for(i=0;i<jsbound;i++)
                {
-                       *ba++ = getbits(fr, 4);
-                       *ba++ = getbits(fr, 4);
+                       ba[0] = getbits_fast(fr, 4);
+                       ba[1] = getbits_fast(fr, 4);
+                       needbits += ((ba[0]?1:0)+(ba[1]?1:0))*6;
+                       ba+=2;
+               }
+               for(i=jsbound;i<SBLIMIT;i++)
+               {
+                       *ba = getbits_fast(fr, 4);
+                       needbits += (*ba?1:0)*12;
+                       ++ba;
                }
-               for(i=jsbound;i<SBLIMIT;i++) *ba++ = getbits(fr, 4);
 
                if(check_balloc(fr, balloc, ba)) return -1;
 
                ba = balloc;
-
+               NEED_BITS(fr, needbits)
                for(i=0;i<jsbound;i++)
                {
                        if ((*ba++))
-                               *sca++ = getbits(fr, 6);
+                               *sca++ = getbits_fast(fr, 6);
                        if ((*ba++))
-                               *sca++ = getbits(fr, 6);
+                               *sca++ = getbits_fast(fr, 6);
                }
-               for (i=jsbound;i<SBLIMIT;i++)
-               if((*ba++))
+               for (i=jsbound;i<SBLIMIT;i++) if((*ba++))
                {
-                       *sca++ =  getbits(fr, 6);
-                       *sca++ =  getbits(fr, 6);
+                       *sca++ =  getbits_fast(fr, 6);
+                       *sca++ =  getbits_fast(fr, 6);
                }
        }
        else
        {
                int i;
-               for(i=0;i<SBLIMIT;i++) *ba++ = getbits(fr, 4);
+               unsigned int needbits = SBLIMIT*4;
+
+               NEED_BITS(fr, needbits)
+               needbits = 0;
+               for(i=0;i<SBLIMIT;i++)
+               {
+                       *ba = getbits_fast(fr, 4);
+                       needbits += (*ba?1:0)*6;
+                       ++ba;
+               }
 
                if(check_balloc(fr, balloc, ba)) return -1;
 
                ba = balloc;
+               NEED_BITS(fr, needbits)
                for (i=0;i<SBLIMIT;i++)
-               if ((*ba++))
-               *sca++ = getbits(fr, 6);
+                       if ((*ba++))
+                               *sca++ = getbits_fast(fr, 6);
        }
 
        return 0;
@@ -87,7 +115,7 @@ static int I_step_one(unsigned int balloc[], unsigned int scale_index[2][SBLIMIT
 /* Something sane in place of undefined (-1)<<n. Well, not really. */
 #define MINUS_SHIFT(n) ( (int)(((unsigned int)-1)<<(n)) )
 
-static void I_step_two(real fraction[2][SBLIMIT],unsigned int balloc[2*SBLIMIT], unsigned int scale_index[2][SBLIMIT],mpg123_handle *fr)
+static int I_step_two(real fraction[2][SBLIMIT],unsigned int balloc[2*SBLIMIT], unsigned int scale_index[2][SBLIMIT],mpg123_handle *fr)
 {
        int i,n;
        int smpb[2*SBLIMIT]; /* values: 0-65535 */
@@ -97,9 +125,24 @@ static void I_step_two(real fraction[2][SBLIMIT],unsigned int balloc[2*SBLIMIT],
 
        if(fr->stereo == 2)
        {
+               unsigned int needbits = 0;
                int jsbound = fr->jsbound;
                register real *f0 = fraction[0];
                register real *f1 = fraction[1];
+
+               ba = balloc;
+               for(sample=smpb,i=0;i<jsbound;i++)
+               {
+                       if((n=*ba++))
+                               needbits += n+1;
+                       if((n=*ba++))
+                               needbits += n+1;
+               }
+               for(i=jsbound;i<SBLIMIT;i++) 
+                       if((n = *ba++))
+                               needbits += n+1;
+               NEED_BITS(fr, needbits)
+
                ba = balloc;
                for(sample=smpb,i=0;i<jsbound;i++)
                {
@@ -137,12 +180,21 @@ static void I_step_two(real fraction[2][SBLIMIT],unsigned int balloc[2*SBLIMIT],
        }
        else
        {
+               unsigned int needbits = 0;
                register real *f0 = fraction[0];
+
+               ba = balloc;
+               for(sample=smpb,i=0;i<SBLIMIT;i++)
+                       if((n = *ba++))
+                               needbits += n+1;
+               NEED_BITS(fr, needbits);
+
                ba = balloc;
                for(sample=smpb,i=0;i<SBLIMIT;i++)
                if ((n = *ba++))
                *sample++ = getbits(fr, n+1);
 
+
                ba = balloc;
                for(sample=smpb,i=0;i<SBLIMIT;i++)
                {
@@ -153,6 +205,7 @@ static void I_step_two(real fraction[2][SBLIMIT],unsigned int balloc[2*SBLIMIT],
                for(i=fr->down_sample_sblimit;i<32;i++)
                fraction[0][i] = DOUBLE_TO_REAL(0.0);
        }
+       return 0;
 }
 
 int do_layer1(mpg123_handle *fr)
@@ -171,13 +224,19 @@ int do_layer1(mpg123_handle *fr)
 
        if(I_step_one(balloc,scale_index,fr))
        {
-               if(NOQUIET) error("Aborting layer I decoding after step one.\n");
+               if(NOQUIET)
+                       error("Aborting layer I decoding after step one.");
                return clip;
        }
 
        for(i=0;i<SCALE_BLOCK;i++)
        {
-               I_step_two(fraction,balloc,scale_index,fr);
+               if(I_step_two(fraction,balloc,scale_index,fr))
+               {
+                       if(NOQUIET)
+                               error("Aborting layer I decoding after step two.");
+                       return clip;
+               }
 
                if(single != SINGLE_STEREO)
                clip += (fr->synth_mono)(fraction[single], fr);
index 056e8f4..ba8573f 100644 (file)
@@ -114,7 +114,7 @@ real* init_layer12_table_mmx(mpg123_handle *fr, real *table, int m)
 
 #ifndef NO_LAYER2
 
-static void II_step_one(unsigned int *bit_alloc,int *scale,mpg123_handle *fr)
+static int II_step_one(unsigned int *bit_alloc,int *scale,mpg123_handle *fr)
 {
        int stereo = fr->stereo-1;
        int sblimit = fr->II_sblimit;
@@ -125,6 +125,9 @@ static void II_step_one(unsigned int *bit_alloc,int *scale,mpg123_handle *fr)
        unsigned int scfsi_buf[64];
        unsigned int *scfsi,*bita;
        int sc,step;
+       /* Count the bits needed for getbits_fast(). */
+       unsigned int needbits = 0;
+       unsigned int scale_bits[4] = { 18, 12, 6, 12 };
 
        bita = bit_alloc;
        if(stereo)
@@ -132,19 +135,28 @@ static void II_step_one(unsigned int *bit_alloc,int *scale,mpg123_handle *fr)
                for(i=jsbound;i;i--,alloc1+=(1<<step))
                {
                        step=alloc1->bits;
-                       *bita++ = (char) getbits(fr, step);
-                       *bita++ = (char) getbits(fr, step);
+                       bita[0] = (char) getbits(fr, step);
+                       bita[1] = (char) getbits(fr, step);
+                       needbits += ((bita[0]?1:0)+(bita[1]?1:0))*2;
+                       bita+=2;
                }
                for(i=sblimit-jsbound;i;i--,alloc1+=(1<<step))
                {
                        step=alloc1->bits;
                        bita[0] = (char) getbits(fr, step);
                        bita[1] = bita[0];
+                       needbits += (bita[0]?1:0)*2*2;
                        bita+=2;
                }
                bita = bit_alloc;
                scfsi=scfsi_buf;
 
+               if(fr->bits_avail < needbits)
+               {
+                       if(NOQUIET)
+                               error2("need %u bits, have %li", needbits, fr->bits_avail);
+                       return -1;
+               }
                for(i=sblimit2;i;i--)
                if(*bita++) *scfsi++ = (char) getbits_fast(fr, 2);
        }
@@ -153,17 +165,39 @@ static void II_step_one(unsigned int *bit_alloc,int *scale,mpg123_handle *fr)
                for(i=sblimit;i;i--,alloc1+=(1<<step))
                {
                        step=alloc1->bits;
-                       *bita++ = (char) getbits(fr, step);
+                       *bita = (char) getbits(fr, step);
+                       if(*bita)
+                               needbits += 2;
+                       ++bita;
                }
                bita = bit_alloc;
                scfsi=scfsi_buf;
+               if(fr->bits_avail < needbits)
+               {
+                       if(NOQUIET)
+                               error2("need %u bits, have %li", needbits, fr->bits_avail);
+                       return -1;
+               }
                for(i=sblimit;i;i--)
                if(*bita++) *scfsi++ = (char) getbits_fast(fr, 2);
        }
 
+       needbits = 0;
+       bita = bit_alloc;
+       scfsi=scfsi_buf;
+       for(i=sblimit2;i;--i)
+               if(*bita++)
+                       needbits += scale_bits[*scfsi++];
+       if(fr->bits_avail < needbits)
+       {
+               if(NOQUIET)
+                       error2("need %u bits, have %li", needbits, fr->bits_avail);
+               return -1;
+       }
+
        bita = bit_alloc;
        scfsi=scfsi_buf;
-       for(i=sblimit2;i;i--)
+       for(i=sblimit2;i;--i)
        if(*bita++)
        switch(*scfsi++)
        {
@@ -188,6 +222,8 @@ static void II_step_one(unsigned int *bit_alloc,int *scale,mpg123_handle *fr)
                        *scale++ = sc;
                break;
        }
+
+       return 0;
 }
 
 
@@ -230,6 +266,8 @@ static void II_step_two(unsigned int *bit_alloc,real fraction[2][4][SBLIMIT],int
                        }
                        else
                        fraction[j][0][i] = fraction[j][1][i] = fraction[j][2][i] = DOUBLE_TO_REAL(0.0);
+                       if(fr->bits_avail < 0)
+                               return; /* Caller checks that again. */
                }
        }
 
@@ -267,6 +305,8 @@ static void II_step_two(unsigned int *bit_alloc,real fraction[2][4][SBLIMIT],int
                                fraction[0][2][i] = REAL_SCALE_LAYER12(fr->muls[*tab][m1]); fraction[1][2][i] = REAL_SCALE_LAYER12(fr->muls[*tab][m2]);
                        }
                        scale+=6;
+                       if(fr->bits_avail < 0)
+                               return; /* Caller checks that again. */
                }
                else
                {
@@ -351,11 +391,22 @@ int do_layer2(mpg123_handle *fr)
        if(stereo == 1 || single == SINGLE_MIX) /* also, mix not really handled */
        single = SINGLE_LEFT;
 
-       II_step_one(bit_alloc, scale, fr);
+       if(II_step_one(bit_alloc, scale, fr))
+       {
+               if(NOQUIET)
+                       error("first step of layer I decoding failed");
+               return clip;
+       }
 
        for(i=0;i<SCALE_BLOCK;i++)
        {
                II_step_two(bit_alloc,fraction,scale,fr,i>>2);
+               if(fr->bits_avail < 0)
+               {
+                       if(NOQUIET)
+                               error("missing bits in layer II step two");
+                       return clip;
+               }
                for(j=0;j<3;j++) 
                {
                        if(single != SINGLE_STEREO)
index f17e477..eb41fe6 100644 (file)
@@ -410,6 +410,23 @@ static int III_get_side_info(mpg123_handle *fr, struct III_sideinfo *si,int ster
        const int tabs[2][5] = { { 2,9,5,3,4 } , { 1,8,1,2,9 } };
        const int *tab = tabs[fr->lsf];
 
+       { /* First ensure we got enough bits available. */
+               unsigned int needbits = 0;
+               needbits += tab[1]; /* main_data_begin */
+               needbits += stereo == 1 ? tab[2] : tab[3]; /* private */
+               if(!fr->lsf)
+                       needbits += stereo*4; /* scfsi */
+               /* For each granule for each channel ... */
+               needbits += tab[0]*stereo*(29+tab[4]+1+22+(!fr->lsf?1:0)+2);
+               if(fr->bits_avail < needbits) \
+               {
+                       if(NOQUIET)
+                               error2( "%u bits for side info needed, only %li available"
+                               ,       needbits, fr->bits_avail );
+                       return 1;
+               }
+       }
+
        si->main_data_begin = getbits(fr, tab[1]);
 
        if(si->main_data_begin > fr->bitreservoir)
@@ -434,8 +451,9 @@ static int III_get_side_info(mpg123_handle *fr, struct III_sideinfo *si,int ster
        }
 
        /* Keep track of the available data bytes for the bit reservoir.
-       Think: Substract the 2 crc bytes in parser already? */
-       fr->bitreservoir = fr->bitreservoir + fr->framesize - fr->ssize - (fr->error_protection ? 2 : 0);
+          CRC is included in ssize already. */
+       fr->bitreservoir = fr->bitreservoir + fr->framesize - fr->ssize;
+
        /* Limit the reservoir to the max for MPEG 1.0 or 2.x . */
        if(fr->bitreservoir > (unsigned int) (fr->lsf == 0 ? 511 : 255))
        fr->bitreservoir = (fr->lsf == 0 ? 511 : 255);
@@ -443,21 +461,21 @@ static int III_get_side_info(mpg123_handle *fr, struct III_sideinfo *si,int ster
        /* Now back into less commented territory. It's code. It works. */
 
        if (stereo == 1)
-       si->private_bits = getbits_fast(fr, tab[2]);
+       si->private_bits = getbits(fr, tab[2]);
        else 
-       si->private_bits = getbits_fast(fr, tab[3]);
+       si->private_bits = getbits(fr, tab[3]);
 
        if(!fr->lsf) for(ch=0; ch<stereo; ch++)
        {
                si->ch[ch].gr[0].scfsi = -1;
-               si->ch[ch].gr[1].scfsi = getbits_fast(fr, 4);
+               si->ch[ch].gr[1].scfsi = getbits(fr, 4);
        }
 
        for (gr=0; gr<tab[0]; gr++)
        for (ch=0; ch<stereo; ch++)
        {
                register struct gr_info_s *gr_info = &(si->ch[ch].gr[gr]);
-
+               unsigned int qss;
                gr_info->part2_3_length = getbits(fr, 12);
                gr_info->big_values = getbits(fr, 9);
                if(gr_info->big_values > 288)
@@ -465,18 +483,25 @@ static int III_get_side_info(mpg123_handle *fr, struct III_sideinfo *si,int ster
                        if(NOQUIET) error("big_values too large!");
                        gr_info->big_values = 288;
                }
-               gr_info->pow2gain = fr->gainpow2+256 - getbits_fast(fr, 8) + powdiff;
-               if(ms_stereo) gr_info->pow2gain += 2;
+               qss = getbits_fast(fr, 8);
+               gr_info->pow2gain = fr->gainpow2+256 - qss + powdiff;
+               if(ms_stereo)
+                       gr_info->pow2gain += 2;
+#ifndef NO_MOREINFO
+               if(fr->pinfo)
+                       fr->pinfo->qss[gr][ch] = qss;
+#endif
                gr_info->scalefac_compress = getbits(fr, tab[4]);
                if(gr_info->part2_3_length == 0)
                {
-                       if(gr_info->scalefac_compress > 0)
-                               debug1( "scalefac_compress _should_ be zero instead of %i"
+                       if(gr_info->scalefac_compress > 0 && VERBOSE2)
+                               error1( "scalefac_compress should be zero instead of %i"
                                ,       gr_info->scalefac_compress );
                        gr_info->scalefac_compress = 0;
                }
 
-               if(get1bit(fr))
+               /* 22 bits for if/else block */
+               if(getbits(fr,1))
                { /* window switch flag  */
                        int i;
                        gr_info->block_type       = getbits_fast(fr, 2);
@@ -489,7 +514,14 @@ static int III_get_side_info(mpg123_handle *fr, struct III_sideinfo *si,int ster
                        */
                        gr_info->table_select[2] = 0;
                        for(i=0;i<3;i++)
-                       gr_info->full_gain[i] = gr_info->pow2gain + (getbits_fast(fr, 3)<<3);
+                       {
+                               unsigned int sbg = (getbits_fast(fr, 3)<<3);
+                               gr_info->full_gain[i] = gr_info->pow2gain + sbg;
+#ifndef NO_MOREINFO
+                               if(fr->pinfo)
+                                       fr->pinfo->sub_gain[gr][ch][i] = sbg / 8;
+#endif
+                       }
 
                        if(gr_info->block_type == 0)
                        {
@@ -572,7 +604,10 @@ static int III_get_scale_factors_1(mpg123_handle *fr, int *scf,struct gr_info_s
        if(gr_info->block_type == 2)
        {
                int i=18;
-               numbits = (num0 + num1) * 18;
+               numbits = (num0 + num1) * 18 /* num0 * (17+1?) + num1 * 18 */
+                       - (gr_info->mixed_block_flag ? num0 : 0);
+               if(numbits > gr_info->part2_3_length)
+                       return -1;
 
                if(gr_info->mixed_block_flag)
                {
@@ -580,7 +615,6 @@ static int III_get_scale_factors_1(mpg123_handle *fr, int *scf,struct gr_info_s
                        *scf++ = getbits_fast(fr, num0);
 
                        i = 9;
-                       numbits -= num0; /* num0 * 17 + num1 * 18 */
                }
 
                for(;i;i--) *scf++ = getbits_fast(fr, num0);
@@ -596,51 +630,53 @@ static int III_get_scale_factors_1(mpg123_handle *fr, int *scf,struct gr_info_s
 
                if(scfsi < 0)
                { /* scfsi < 0 => granule == 0 */
+                       numbits = (num0 + num1) * 10 + num0;
+                       if(numbits > gr_info->part2_3_length)
+                               return -1;
+
                        for(i=11;i;i--) *scf++ = getbits_fast(fr, num0);
 
                        for(i=10;i;i--) *scf++ = getbits_fast(fr, num1);
 
-                       numbits = (num0 + num1) * 10 + num0;
                        *scf++ = 0;
                }
                else
                {
-                       numbits = 0;
+                       numbits = !(scfsi & 0x8) * num0 * 6
+                               + !(scfsi & 0x4) * num0 * 5
+                               + !(scfsi & 0x2) * num1 * 5
+                               + !(scfsi & 0x1) * num1 * 5;
+                       if(numbits > gr_info->part2_3_length)
+                               return -1;
+
                        if(!(scfsi & 0x8))
                        {
                                for (i=0;i<6;i++) *scf++ = getbits_fast(fr, num0);
-
-                               numbits += num0 * 6;
                        }
                        else scf += 6; 
 
                        if(!(scfsi & 0x4))
                        {
                                for (i=0;i<5;i++) *scf++ = getbits_fast(fr, num0);
-
-                               numbits += num0 * 5;
                        }
                        else scf += 5;
 
                        if(!(scfsi & 0x2))
                        {
                                for(i=0;i<5;i++) *scf++ = getbits_fast(fr, num1);
-
-                               numbits += num1 * 5;
                        }
                        else scf += 5;
 
                        if(!(scfsi & 0x1))
                        {
                                for (i=0;i<5;i++) *scf++ = getbits_fast(fr, num1);
-
-                               numbits += num1 * 5;
                        }
                        else scf += 5;
 
                        *scf++ = 0;  /* no l[21] in original sources */
                }
        }
+
        return numbits;
 }
 
@@ -649,7 +685,7 @@ static int III_get_scale_factors_2(mpg123_handle *fr, int *scf,struct gr_info_s
 {
        const unsigned char *pnt;
        int i,j,n=0,numbits=0;
-       unsigned int slen;
+       unsigned int slen, slen2;
 
        const unsigned char stab[3][6][4] =
        {
@@ -685,12 +721,22 @@ static int III_get_scale_factors_2(mpg123_handle *fr, int *scf,struct gr_info_s
 
        if(gr_info->part2_3_length == 0)
        {
-               int i;
                for(i=0;i<39;i++)
                        *scf++ = 0;
                return 0;
        }
 
+       slen2 = slen;
+       for(i=0;i<4;i++)
+       {
+               int num = slen2 & 0x7;
+               slen2 >>= 3;
+               if(num)
+                       numbits += pnt[i] * num;
+       }
+       if(numbits > gr_info->part2_3_length)
+               return -1;
+
        for(i=0;i<4;i++)
        {
                int num = slen & 0x7;
@@ -698,8 +744,6 @@ static int III_get_scale_factors_2(mpg123_handle *fr, int *scf,struct gr_info_s
                if(num)
                {
                        for(j=0;j<(int)(pnt[i]);j++) *scf++ = getbits_fast(fr, num);
-
-                       numbits += pnt[i] * num;
                }
                else
                for(j=0;j<(int)(pnt[i]);j++) *scf++ = 0;
@@ -773,6 +817,8 @@ static int III_dequantize_sample(mpg123_handle *fr, real xr[SBLIMIT][SSLIMIT],in
        mask <<= 8-num;
        part2remain -= num;
 
+       /* Bitindex is zero now, we are allowed to use getbyte(). */
+
        {
                int bv       = gr_info->big_values;
                int region1  = gr_info->region1start;
@@ -843,6 +889,7 @@ static int III_dequantize_sample(mpg123_handle *fr, real xr[SBLIMIT][SSLIMIT],in
                                if( (!mc) )
                                {
                                        mc    = *m++;
+//fprintf(stderr, "%i setting xrpnt = xr + %i (%ld)\n", __LINE__, *m, xrpnt-(real*)xr);
                                        xrpnt = ((real *) xr) + (*m++);
                                        lwin  = *m++;
                                        cb    = *m++;
@@ -972,6 +1019,7 @@ static int III_dequantize_sample(mpg123_handle *fr, real xr[SBLIMIT][SSLIMIT],in
                                        if(!mc)
                                        {
                                                mc = *m++;
+//fprintf(stderr, "%i setting xrpnt = xr + %i (%ld)\n", __LINE__, *m, xrpnt-(real*)xr);
                                                xrpnt = ((real *) xr) + (*m++);
                                                lwin = *m++;
                                                cb = *m++;
@@ -1226,6 +1274,7 @@ static int III_dequantize_sample(mpg123_handle *fr, real xr[SBLIMIT][SSLIMIT],in
        part2remain += num;
        backbits(fr, num);
        num = 0;
+
        }
        else
        {
@@ -1249,7 +1298,8 @@ static int III_dequantize_sample(mpg123_handle *fr, real xr[SBLIMIT][SSLIMIT],in
        if(part2remain > 0) skipbits(fr, part2remain);
        else if(part2remain < 0)
        {
-               debug1("Can't rewind stream by %d bits!",-part2remain);
+               if(VERBOSE2)
+                       error1("Can't rewind stream by %d bits!",-part2remain);
                return 1; /* -> error */
        }
        return 0;
@@ -1977,6 +2027,73 @@ static void III_hybrid(real fsIn[SBLIMIT][SSLIMIT], real tsOut[SSLIMIT][SBLIMIT]
        }
 }
 
+#ifndef NO_MOREINFO
+static void fill_pinfo_side(mpg123_handle *fr, struct III_sideinfo *si, int gr, int stereo1)
+{
+       int   i, sb;
+       float ifqstep; /* Why not double? */
+       int ch, ss;;
+
+       for(ch = 0; ch < stereo1; ++ch)
+       {
+               struct gr_info_s *gr_infos = &(si->ch[ch].gr[gr]);
+               fr->pinfo->big_values[gr][ch] = gr_infos->big_values;
+               fr->pinfo->scalefac_scale[gr][ch] = gr_infos->scalefac_scale;
+               fr->pinfo->mixed[gr][ch] = gr_infos->mixed_block_flag;
+               fr->pinfo->blocktype[gr][ch] = gr_infos->block_type;
+               fr->pinfo->mainbits[gr][ch] = gr_infos->part2_3_length;
+               fr->pinfo->preflag[gr][ch] = gr_infos->preflag;
+               if(gr == 1)
+                       fr->pinfo->scfsi[ch] = gr_infos->scfsi;
+       }
+
+       for(ch = 0; ch < stereo1; ++ch)
+       {
+               struct gr_info_s *gr_infos = &(si->ch[ch].gr[gr]);
+               ifqstep = (fr->pinfo->scalefac_scale[gr][ch] == 0) ? .5 : 1.0;
+               if(2 == gr_infos->block_type)
+               {
+                       for(i = 0; i < 3; ++i)
+                       {
+                               for(sb = 0; sb < 12; ++sb)
+                               {
+                                       int       j = 3 * sb + i;
+                                       /*
+                                                is_p = scalefac[sfb*3+lwin-gr_infos->mixed_block_flag]; 
+                                       */
+                                       /* scalefac was copied into pinfo->sfb_s[] before */
+                                       fr->pinfo->sfb_s[gr][ch][j] = -ifqstep *
+                                               fr->pinfo->sfb_s[gr][ch][j - gr_infos->mixed_block_flag];
+                                       fr->pinfo->sfb_s[gr][ch][j] -= 2 *
+                                               (fr->pinfo->sub_gain[gr][ch][i]);
+                               }
+                               fr->pinfo->sfb_s[gr][ch][3 * sb + i] =
+                                       -2 * (fr->pinfo->sub_gain[gr][ch][i]);
+                       }
+               } else
+               {
+                       for(sb = 0; sb < 21; ++sb)
+                       {
+                               /* scalefac was copied into pinfo->sfb[] before */
+                               fr->pinfo->sfb[gr][ch][sb] = fr->pinfo->sfb_s[gr][ch][sb];
+                               if (gr_infos->preflag)
+                                       fr->pinfo->sfb[gr][ch][sb] += pretab_choice[1][sb];
+                               fr->pinfo->sfb[gr][ch][sb] *= -ifqstep;
+                       }
+                       fr->pinfo->sfb[gr][ch][21] = 0;
+               }
+       }
+
+
+       for(ch = 0; ch < stereo1; ++ch)
+       {
+               int j = 0;
+               for(sb = 0; sb < SBLIMIT; ++sb)
+                       for (ss = 0; ss < SSLIMIT; ++ss, ++j)
+                               fr->pinfo->xr[gr][ch][j] = fr->layer3.hybrid_in[ch][sb][ss];
+       }
+}
+#endif
 
 /* And at the end... the main layer3 handler */
 int do_layer3(mpg123_handle *fr)
@@ -2017,8 +2134,14 @@ int do_layer3(mpg123_handle *fr)
                return clip;
        }
 
-       set_pointer(fr,sideinfo.main_data_begin);
-
+       set_pointer(fr, 1, sideinfo.main_data_begin);
+#ifndef NO_MOREINFO
+       if(fr->pinfo)
+       {
+               fr->pinfo->maindata = sideinfo.main_data_begin;
+               fr->pinfo->padding  = fr->padding;
+       }
+#endif
        for(gr=0;gr<granules;gr++)
        {
                /*  hybridIn[2][SBLIMIT][SSLIMIT] */
@@ -2029,14 +2152,46 @@ int do_layer3(mpg123_handle *fr)
                {
                        struct gr_info_s *gr_info = &(sideinfo.ch[0].gr[gr]);
                        long part2bits;
+                       if(gr_info->part2_3_length > fr->bits_avail)
+                       {
+                               if(NOQUIET)
+                                       error2(
+                                               "part2_3_length (%u) too large for available bit count (%li)"
+                                       ,       gr_info->part2_3_length, fr->bits_avail );
+                               return clip;
+                       }
                        if(fr->lsf)
                        part2bits = III_get_scale_factors_2(fr, scalefacs[0],gr_info,0);
                        else
                        part2bits = III_get_scale_factors_1(fr, scalefacs[0],gr_info,0,gr);
 
+                       if(part2bits < 0)
+                       {
+                               if(VERBOSE2)
+                                       error("not enough bits for scale factors");
+                               return clip;
+                       }
+
+#ifndef NO_MOREINFO
+                       if(fr->pinfo)
+                       {
+                               int i;
+                               fr->pinfo->sfbits[gr][0] = part2bits;
+                               for(i=0; i<39; ++i)
+                                       fr->pinfo->sfb_s[gr][0][i] = scalefacs[0][i];
+                       }
+#endif
+
                        if(III_dequantize_sample(fr, hybridIn[0], scalefacs[0],gr_info,sfreq,part2bits))
                        {
-                               if(VERBOSE2) error("dequantization failed!");
+                               if(NOQUIET)
+                                       error("dequantization failed!");
+                               return clip;
+                       }
+                       if(fr->bits_avail < 0)
+                       {
+                               if(NOQUIET)
+                                       error("bit deficit after dequant");
                                return clip;
                        }
                }
@@ -2050,9 +2205,33 @@ int do_layer3(mpg123_handle *fr)
                        else
                        part2bits = III_get_scale_factors_1(fr, scalefacs[1],gr_info,1,gr);
 
+                       if(part2bits < 0)
+                       {
+                               if(VERBOSE2)
+                                       error("not enough bits for scale factors");
+                               return clip;
+                       }
+
+#ifndef NO_MOREINFO
+                       if(fr->pinfo)
+                       {
+                               int i;
+                               fr->pinfo->sfbits[gr][1] = part2bits;
+                               for(i=0; i<39; ++i)
+                                       fr->pinfo->sfb_s[gr][1][i] = scalefacs[1][i];
+                       }
+#endif
+
                        if(III_dequantize_sample(fr, hybridIn[1],scalefacs[1],gr_info,sfreq,part2bits))
                        {
-                               if(VERBOSE2) error("dequantization failed!");
+                               if(NOQUIET)
+                                       error("dequantization failed!");
+                               return clip;
+                       }
+                       if(fr->bits_avail < 0)
+                       {
+                               if(NOQUIET)
+                                       error("bit deficit after dequant");
                                return clip;
                        }
 
@@ -2102,6 +2281,11 @@ int do_layer3(mpg123_handle *fr)
                        }
                }
 
+#ifndef NO_MOREINFO
+               if(fr->pinfo)
+                       fill_pinfo_side(fr, &sideinfo, gr, stereo1);
+#endif
+
                for(ch=0;ch<stereo1;ch++)
                {
                        struct gr_info_s *gr_info = &(sideinfo.ch[ch].gr[gr]);
index 45cb53d..982d7ca 100644 (file)
@@ -1,7 +1,7 @@
 /*
        lfs_alias: Aliases to the small/native API functions with the size of long int as suffix.
 
-       copyright 2010-2013 by the mpg123 project - free software under the terms of the LGPL 2.1
+       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
 
@@ -100,6 +100,14 @@ 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)
 {
index 7545b77..a01f302 100644 (file)
@@ -1,7 +1,7 @@
 /*
        lfs_wrap: Crappy wrapper code for supporting crappy ambiguous large file support.
 
-       copyright 2010 by the mpg123 project - free software under the terms of the LGPL 2.1
+       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, thanks to Guido Draheim for consulting
@@ -552,7 +552,6 @@ off_t wrap_lseek(void *handle, off_t offset, int whence)
                        case IO_FD: return ioh->r_lseek(ioh->fd, smalloff, whence);
                        case IO_HANDLE: return ioh->r_h_lseek(ioh->handle, smalloff, whence);
                }
-               error("Serious breakage - bad IO type in LFS wrapper!");
                return -1;
        }
        else
@@ -571,6 +570,7 @@ off_t wrap_lseek(void *handle, off_t offset, int whence)
 #undef mpg123_replace_reader
 #undef mpg123_replace_reader_handle
 #undef mpg123_open
+#undef mpg123_open_fixed
 #undef mpg123_open_fd
 #undef mpg123_open_handle
 
@@ -699,6 +699,19 @@ int attribute_align_arg mpg123_open(mpg123_handle *mh, const char *path)
        else return MPG123_LARGENAME(mpg123_open)(mh, path);
 }
 
+// This one needs to follow the logic of the original, and wrap the actual
+// mpg123_open() here.
+int attribute_align_arg mpg123_open_fixed( mpg123_handle *mh, const char *path
+,      int channels, int encoding )
+{
+       int err = open_fixed_pre(mh, channels, encoding);
+       if(err == MPG123_OK)
+               err = mpg123_open(mh, path);
+       if(err == MPG123_OK)
+               err = open_fixed_post(mh, channels, encoding);
+       return err;
+}
+
 /*
        This is in fact very similar to the above:
        The open routines always need to watch out for a prepared wrapper handle to use replaced normal I/O.
index cc77905..e2a64f8 100644 (file)
@@ -1,7 +1,7 @@
 /*
        libmpg123: MPEG Audio Decoder library
 
-       copyright 1995-2014 by the mpg123 project - free software under the terms of the LGPL 2.1
+       copyright 1995-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
 
 */
@@ -14,6 +14,7 @@
 /* Want accurate rounding function regardless of decoder setup. */
 #define FORCE_ACCURATE
 #include "sample.h"
+#include "parse.h"
 
 #define SEEKFRAME(mh) ((mh)->ignoreframe < 0 ? 0 : (mh)->ignoreframe)
 
@@ -49,6 +50,7 @@ int attribute_align_arg mpg123_init(void)
 void attribute_align_arg mpg123_exit(void)
 {
        /* nothing yet, but something later perhaps */
+       /* Nope. This is dead space. */
 }
 
 /* create a new handle with specified decoder, decoder can be "", "auto" or NULL for auto-detection */
@@ -230,7 +232,8 @@ int attribute_align_arg mpg123_par(mpg123_pars *mp, enum mpg123_parms key, long
 #ifdef FRAME_INDEX
                        mp->index_size = val;
 #else
-                       ret = MPG123_NO_INDEX;
+                       if(val) // It is only an eror if you want to enable the index.
+                               ret = MPG123_NO_INDEX;
 #endif
                break;
                case MPG123_PREFRAMES:
@@ -253,6 +256,9 @@ int attribute_align_arg mpg123_par(mpg123_pars *mp, enum mpg123_parms key, long
                        ret = MPG123_MISSING_FEATURE;
 #endif
                break;
+               case MPG123_FREEFORMAT_SIZE:
+                       mp->freeformat_framesize = val;
+               break; 
                default:
                        ret = MPG123_BAD_PARAM;
        }
@@ -342,6 +348,9 @@ int attribute_align_arg mpg123_getpar(mpg123_pars *mp, enum mpg123_parms key, lo
                        ret = MPG123_MISSING_FEATURE;
 #endif
                break;
+               case MPG123_FREEFORMAT_SIZE:
+                       *val = mp->freeformat_framesize;
+               break; 
                default:
                        ret = MPG123_BAD_PARAM;
        }
@@ -384,6 +393,15 @@ int attribute_align_arg mpg123_getstate(mpg123_handle *mh, enum mpg123_state key
                        theval = mh->state_flags & FRAME_FRESH_DECODER;
                        mh->state_flags &= ~FRAME_FRESH_DECODER;
                break;
+               case MPG123_ENC_DELAY:
+                       theval = mh->enc_delay;
+               break;
+               case MPG123_ENC_PADDING:
+                       theval = mh->enc_padding;
+               break;
+               case MPG123_DEC_DELAY:
+                       theval = mh->lay == 3 ? GAPLESS_DELAY : -1;
+               break;
                default:
                        mh->err = MPG123_BAD_KEY;
                        ret = MPG123_ERR;
@@ -394,6 +412,7 @@ int attribute_align_arg mpg123_getstate(mpg123_handle *mh, enum mpg123_state key
 
        return ret;
 }
+
 int attribute_align_arg mpg123_eq(mpg123_handle *mh, enum mpg123_channels channel, int band, double val)
 {
 #ifndef NO_EQUALIZER
@@ -444,6 +463,54 @@ int attribute_align_arg mpg123_open(mpg123_handle *mh, const char *path)
        return open_stream(mh, path, -1);
 }
 
+// The convenience function mpg123_open_fixed() wraps over acual mpg123_open
+// and hence needs to have the exact same code in lfs_wrap.c. The flesh is
+// in open_fixed_pre() and open_fixed_post(), wich are only defined here.
+int open_fixed_pre(mpg123_handle *mh, int channels, int encoding)
+{
+       if(!mh)
+               return MPG123_BAD_HANDLE;
+       mh->p.flags |= MPG123_NO_FRANKENSTEIN;
+       int err = mpg123_format_none(mh);
+       if(err == MPG123_OK)
+               err = mpg123_format2(mh, 0, channels, encoding);
+       return err;
+}
+
+int open_fixed_post(mpg123_handle *mh, int channels, int encoding)
+{
+       if(!mh)
+               return MPG123_BAD_HANDLE;
+       long rate;
+       int err = mpg123_getformat(mh, &rate, &channels, &encoding);
+       if(err == MPG123_OK)
+               err = mpg123_format_none(mh);
+       if(err == MPG123_OK)
+               err = mpg123_format(mh, rate, channels, encoding);
+       if(err == MPG123_OK)
+       {
+               if(mh->track_frames < 1 && (mh->rdat.flags & READER_SEEKABLE))
+               {
+                       debug("open_fixed_post: scan because we can seek and do not know track_frames");
+                       err = mpg123_scan(mh);
+               }
+       }
+       if(err != MPG123_OK)
+               mpg123_close(mh);
+       return err;
+}
+
+int attribute_align_arg mpg123_open_fixed( mpg123_handle *mh, const char *path
+,      int channels, int encoding )
+{
+       int err = open_fixed_pre(mh, channels, encoding);
+       if(err == MPG123_OK)
+               err = mpg123_open(mh, path);
+       if(err == MPG123_OK)
+               err = open_fixed_post(mh, channels, encoding);
+       return err;
+}
+
 int attribute_align_arg mpg123_open_fd(mpg123_handle *mh, int fd)
 {
        if(mh == NULL) return MPG123_BAD_HANDLE;
@@ -546,6 +613,8 @@ int decode_update(mpg123_handle *mh)
                        {
                                mh->down_sample_sblimit = SBLIMIT * mh->af.rate;
                                mh->down_sample_sblimit /= frame_freq(mh);
+                               if(mh->down_sample_sblimit < 1)
+                                       mh->down_sample_sblimit = 1;
                        }
                        else mh->down_sample_sblimit = SBLIMIT;
                        mh->outblock = outblock_bytes(mh,
@@ -571,6 +640,7 @@ int decode_update(mpg123_handle *mh)
        do_rva(mh);
        debug3("done updating decoder structure with native rate %li and af.rate %li and down_sample %i", frame_freq(mh), mh->af.rate, mh->down_sample);
 
+       mh->decoder_change = 0;
        return 0;
 }
 
@@ -637,9 +707,9 @@ static int get_next_frame(mpg123_handle *mh)
                        else return MPG123_ERR; /* Some real error. */
                }
                /* Now, there should be new data to decode ... and also possibly new stream properties */
-               if(mh->header_change > 1)
+               if(mh->header_change > 1 || mh->decoder_change)
                {
-                       debug("big header change");
+                       debug("big header or decoder change");
                        change = 1;
                        mh->header_change = 0;
                        /* Need to update decoder structure right away since frame might need to
@@ -667,7 +737,6 @@ static int get_next_frame(mpg123_handle *mh)
           All other situations resulted in returns from the loop. */
        if(change)
        {
-               mh->decoder_change = 0;
                if(mh->fresh)
                {
 #ifdef GAPLESS
@@ -832,20 +901,25 @@ int attribute_align_arg mpg123_decode_frame(mpg123_handle *mh, off_t *num, unsig
        if(mh == NULL) return MPG123_BAD_HANDLE;
        if(mh->buffer.size < mh->outblock) return MPG123_NO_SPACE;
        mh->buffer.fill = 0; /* always start fresh */
+       /* Be nice: Set these also for sensible values in case of error. */
+       if(audio) *audio = NULL;
+       if(bytes) *bytes = 0;
        while(TRUE)
        {
                /* decode if possible */
                if(mh->to_decode)
                {
+                       if(num != NULL) *num = mh->num;
                        if(mh->new_format)
                        {
                                debug("notifiying new format");
                                mh->new_format = 0;
                                return MPG123_NEW_FORMAT;
                        }
-                       if(num != NULL) *num = mh->num;
                        debug("decoding");
 
+                       if(mh->decoder_change && decode_update(mh) < 0)
+                               return MPG123_ERR;
                        decode_the_frame(mh);
 
                        mh->to_decode = mh->to_ignore = FALSE;
@@ -865,7 +939,7 @@ int attribute_align_arg mpg123_decode_frame(mpg123_handle *mh, off_t *num, unsig
        }
 }
 
-int attribute_align_arg mpg123_read(mpg123_handle *mh, unsigned char *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);
 }
@@ -915,14 +989,14 @@ int attribute_align_arg mpg123_feed(mpg123_handle *mh, const unsigned char *in,
        }
 */
 
-int attribute_align_arg mpg123_decode(mpg123_handle *mh, const unsigned char *inmemory, size_t inmemsize, unsigned char *outmemory, size_t outmemsize, size_t *done)
+int attribute_align_arg mpg123_decode(mpg123_handle *mh, const unsigned char *inmemory, size_t inmemsize, void *outmem, size_t outmemsize, size_t *done)
 {
        int ret = MPG123_OK;
        size_t mdone = 0;
+       unsigned char *outmemory = outmem;
 
        if(done != NULL) *done = 0;
        if(mh == NULL) return MPG123_BAD_HANDLE;
-#ifndef NO_FEEDER
        if(inmemsize > 0 && mpg123_feed(mh, inmemory, inmemsize) != MPG123_OK)
        {
                ret = MPG123_ERR;
@@ -949,6 +1023,11 @@ int attribute_align_arg mpg123_decode(mpg123_handle *mh, const unsigned char *in
                                ret = MPG123_NO_SPACE;
                                goto decodeend;
                        }
+                       if(mh->decoder_change && decode_update(mh) < 0)
+                       {
+                               ret = MPG123_ERR;
+                               goto decodeend;
+                       }
                        decode_the_frame(mh);
                        mh->to_decode = mh->to_ignore = FALSE;
                        mh->buffer.p = mh->buffer.data;
@@ -977,10 +1056,6 @@ int attribute_align_arg mpg123_decode(mpg123_handle *mh, const unsigned char *in
 decodeend:
        if(done != NULL) *done = mdone;
        return ret;
-#else
-       mh->err = MPG123_MISSING_FEATURE;
-       return MPG123_ERR;
-#endif
 }
 
 long attribute_align_arg mpg123_clip(mpg123_handle *mh)
@@ -1031,7 +1106,7 @@ int attribute_align_arg mpg123_info(mpg123_handle *mh, struct mpg123_frameinfo *
                case 1: mi->mode = MPG123_M_JOINT;  break;
                case 2: mi->mode = MPG123_M_DUAL;   break;
                case 3: mi->mode = MPG123_M_MONO;   break;
-               default: error("That mode cannot be!");
+               default: mi->mode = 0; // Nothing good to do here.
        }
        mi->mode_ext = mh->mode_ext;
        mi->framesize = mh->framesize+4; /* Include header. */
@@ -1462,6 +1537,23 @@ int attribute_align_arg mpg123_id3(mpg123_handle *mh, mpg123_id3v1 **v1, mpg123_
        return MPG123_OK;
 }
 
+int attribute_align_arg mpg123_id3_raw( mpg123_handle *mh
+,      unsigned char **v1, size_t *v1_size
+,      unsigned char **v2, size_t *v2_size )
+{
+       if(!mh)
+               return MPG123_ERR;
+       if(v1 != NULL)
+               *v1 = mh->id3buf[0] ? mh->id3buf : NULL;
+       if(v1_size != NULL)
+               *v1_size = mh->id3buf[0] ? 128 : 0;
+       if(v2 != NULL)
+               *v2 = mh->id3v2_raw;
+       if(v2_size != NULL)
+               *v2_size = mh->id3v2_size;
+       return MPG123_OK;
+}
+
 int attribute_align_arg mpg123_icy(mpg123_handle *mh, char **icy_meta)
 {
        if(mh == NULL) return MPG123_BAD_HANDLE;
@@ -1627,6 +1719,11 @@ void attribute_align_arg mpg123_delete(mpg123_handle *mh)
        }
 }
 
+void attribute_align_arg mpg123_free(void *ptr)
+{
+       free(ptr);
+}
+
 static const char *mpg123_error[] =
 {
        "No error... (code 0)",
index 794689e..5ba3adc 100644 (file)
@@ -9,7 +9,7 @@
 #ifndef MPG123_LIB_H
 #define MPG123_LIB_H
 
-#include "../src/libmpg123/fmt123.h"
+#include <fmt123.h>
 
 /** \file mpg123.h The header file for the libmpg123 MPEG Audio decoder */
 
@@ -83,6 +83,7 @@ typedef ptrdiff_t ssize_t;
 #endif
 #define MPG123_LARGENAME(func) MPG123_MACROCAT(func, MPG123_LARGESUFFIX)
 
+#define mpg123_open_fixed   MPG123_LARGENAME(mpg123_open_fixed)
 #define mpg123_open         MPG123_LARGENAME(mpg123_open)
 #define mpg123_open_fd      MPG123_LARGENAME(mpg123_open_fd)
 #define mpg123_open_handle  MPG123_LARGENAME(mpg123_open_handle)
@@ -131,14 +132,19 @@ struct mpg123_handle_struct;
 typedef struct mpg123_handle_struct mpg123_handle;
 
 /** Function to initialise the mpg123 library. 
- *     This function is not thread-safe. Call it exactly once per process, before any other (possibly threaded) work with the library.
+ * This should be called once in a non-parallel context. It is not explicitly
+ * thread-safe, but repeated/concurrent calls still _should_ be safe as static
+ * tables are filled with the same values anyway.
  *
  *     \return MPG123_OK if successful, otherwise an error number.
  */
 MPG123_EXPORT int mpg123_init(void);
 
-/** Function to close down the mpg123 library. 
- *     This function is not thread-safe. Call it exactly once per process, before any other (possibly threaded) work with the library. */
+/** Superfluous Function to close down the mpg123 library.
+ * This was created with the thought that there sometime will be cleanup code
+ * to be run after library use. This never materialized. You can forget about
+ * this function and it is only here for old programs that do call it.
+ */
 MPG123_EXPORT void mpg123_exit(void);
 
 /** Create a handle with optional choice of decoder (named by a string, see mpg123_decoders() or mpg123_supported_decoders()).
@@ -156,6 +162,13 @@ MPG123_EXPORT mpg123_handle *mpg123_new(const char* decoder, int *error);
  */
 MPG123_EXPORT void mpg123_delete(mpg123_handle *mh);
 
+/** Free plain memory allocated within libmpg123.
+ *  This is for library users that are not sure to use the same underlying
+ *  memory allocator as libmpg123. It is just a wrapper over free() in
+ *  the underlying C library.
+ */
+MPG123_EXPORT void mpg123_free(void *ptr);
+
 /** Enumeration of the parameters types that it is possible to set/get. */
 enum mpg123_parms
 {
@@ -169,7 +182,8 @@ enum mpg123_parms
        MPG123_UPSPEED,        /**< play every Nth frame (integer) */
        MPG123_START_FRAME,    /**< start with this frame (skip frames before that, integer) */ 
        MPG123_DECODE_FRAMES,  /**< decode only this number of frames (integer) */
-       MPG123_ICY_INTERVAL,   /**< stream contains ICY metadata with this interval (integer) */
+       MPG123_ICY_INTERVAL,   /**< Stream contains ICY metadata with this interval (integer).
+                                   Make sure to set this _before_ opening a stream.*/
        MPG123_OUTSCALE,       /**< the scale for output samples (amplitude - integer or float according to mpg123 output format, normally integer) */
        MPG123_TIMEOUT,        /**< timeout for reading from a stream (not supported on win32, integer) */
        MPG123_REMOVE_FLAGS,   /**< remove some flags (inverse of MPG123_ADD_FLAGS, integer) */
@@ -178,6 +192,11 @@ enum mpg123_parms
        ,MPG123_PREFRAMES /**< Decode/ignore that many frames in advance for layer 3. This is needed to fill bit reservoir after seeking, for example (but also at least one frame in advance is needed to have all "normal" data for layer 3). Give a positive integer value, please.*/
        ,MPG123_FEEDPOOL  /**< For feeder mode, keep that many buffers in a pool to avoid frequent malloc/free. The pool is allocated on mpg123_open_feed(). If you change this parameter afterwards, you can trigger growth and shrinkage during decoding. The default value could change any time. If you care about this, then set it. (integer) */
        ,MPG123_FEEDBUFFER /**< Minimal size of one internal feeder buffer, again, the default value is subject to change. (integer) */
+       ,MPG123_FREEFORMAT_SIZE /**< Tell the parser a free-format frame size to
+        * avoid read-ahead to get it. A value of -1 (default) means that the parser
+        * will determine it. The parameter value is applied during decoder setup
+        * for a freshly opened stream only.
+        */
 };
 
 /** Flag bits for MPG123_FLAGS, use the usual binary or to combine. */
@@ -208,6 +227,37 @@ enum mpg123_param_flags
         *  the stream is assumed as non-seekable unless overridden.
         */
        ,MPG123_FORCE_SEEKABLE = 0x40000 /**< 19th bit: Force the stream to be seekable. */
+       ,MPG123_STORE_RAW_ID3  = 0x80000 /**< store raw ID3 data (even if skipping) */
+       ,MPG123_FORCE_ENDIAN   = 0x100000 /**< Enforce endianess of output samples.
+        *  This is not reflected in the format codes. If this flag is set along with
+        *  MPG123_BIG_ENDIAN, MPG123_ENC_SIGNED16 means s16be, without
+        *  MPG123_BIG_ENDIAN, it means s16le. Normal operation without
+        *  MPG123_FORCE_ENDIAN produces output in native byte order.
+        */
+       ,MPG123_BIG_ENDIAN     = 0x200000 /**< Choose big endian instead of little. */
+       ,MPG123_NO_READAHEAD   = 0x400000 /**< Disable read-ahead in parser. If
+        * you know you provide full frames to the feeder API, this enables
+        * decoder output from the first one on, instead of having to wait for
+        * the next frame to confirm that the stream is healthy. It also disables
+        * free format support unless you provide a frame size using
+        * MPG123_FREEFORMAT_SIZE.
+        */
+       ,MPG123_FLOAT_FALLBACK = 0x800000 /**< Consider floating point output encoding only after
+        * trying other (possibly downsampled) rates and encodings first. This is to
+        * support efficient playback where floating point output is only configured for
+        * an external resampler, bypassing that resampler when the desired rate can
+        * be produced directly. This is enabled by default to be closer to older versions
+        * of libmpg123 which did not enable float automatically at all. If disabled,
+        * float is considered after the 16 bit default and higher-bit integer encodings
+        * for any rate. */
+       ,MPG123_NO_FRANKENSTEIN = 0x1000000 /**< Disable support for Frankenstein streams
+        * (different MPEG streams stiched together). Do not accept serious change of MPEG
+        * header inside a single stream. With this flag, the audio output format cannot
+        * change during decoding unless you open a new stream. This also stops decoding
+        * after an announced end of stream (Info header contained a number of frames
+        * and this number has been reached). This makes your MP3 files behave more like
+        * ordinary media files with defined structure, rather than stream dumps with
+        * some sugar. */
 };
 
 /** choices for MPG123_RVA */
@@ -259,6 +309,9 @@ enum mpg123_feature_set
        ,MPG123_FEATURE_PARSE_ICY            /**< ICY support                  */
        ,MPG123_FEATURE_TIMEOUT_READ         /**< Reader with timeout (network). */
        ,MPG123_FEATURE_EQUALIZER            /**< tunable equalizer */
+       ,MPG123_FEATURE_MOREINFO             /**< more info extraction (for frame analyzer) */
+       ,MPG123_FEATURE_OUTPUT_FLOAT32      /**< 32 bit float output */
+       ,MPG123_FEATURE_OUTPUT_FLOAT64      /**< 64 bit float output (usually never) */
 };
 
 /** Query libmpg123 features.
@@ -267,6 +320,17 @@ enum mpg123_feature_set
  */
 MPG123_EXPORT int mpg123_feature(const enum mpg123_feature_set key);
 
+/** Query libmpg123 features with better ABI compatibility
+ *
+ *  This is the same as mpg123_feature(), but this time not using
+ *  the enum as argument. Compilers don't have to agree on the size of
+ *  enums and hence they are not safe in public API.
+ *
+ *  \param key feature selection
+ *  \return 1 for success, 0 for unimplemented functions
+ */
+MPG123_EXPORT int mpg123_feature2(int key);
+
 /* @} */
 
 
@@ -421,7 +485,12 @@ MPG123_EXPORT const char* mpg123_current_decoder(mpg123_handle *mh);
  *
  * Functions to get and select the format of the decoded audio.
  *
- * Before you dive in, please be warned that you might get confused by this. This seems to happen a lot, therefore I am trying to explain in advance.
+ * Before you dive in, please be warned that you might get confused by this.
+ * This seems to happen a lot, therefore I am trying to explain in advance.
+ * If you do feel confused and just want to decode your normal MPEG audio files that
+ * don't alter properties in the middle, just use mpg123_open_fixed() with a fixed encoding
+ * and channel count and forget about a matrix of audio formats. If you want to get funky,
+ * read ahead ...
  *
  * The mpg123 library decides what output format to use when encountering the first frame in a stream, or actually any frame that is still valid but differs from the frames before in the prompted output format. At such a deciding point, an internal table of allowed encodings, sampling rates and channel setups is consulted. According to this table, an output format is chosen and the decoding engine set up accordingly (including optimized routines for different output formats). This might seem unusual but it just follows from the non-existence of "MPEG audio files" with defined overall properties. There are streams, streams are concatenations of (semi) independent frames. We store streams on disk and call them "MPEG audio files", but that does not change their nature as the decoder is concerned (the LAME/Xing header for gapless decoding makes things interesting again).
  *
@@ -443,7 +512,9 @@ enum mpg123_channelcount
 
 /** An array of supported standard sample rates
  *  These are possible native sample rates of MPEG audio files.
- *  You can still force mpg123 to resample to a different one, but by default you will only get audio in one of these samplings.
+ *  You can still force mpg123 to resample to a different one, but by
+ *  default you will only get audio in one of these samplings.
+ *  This list is in ascending order.
  *  \param list Store a pointer to the sample rates array there.
  *  \param number Store the number of sample rates there. */
 MPG123_EXPORT void mpg123_rates(const long **list, size_t *number);
@@ -482,6 +553,19 @@ MPG123_EXPORT int mpg123_format_all(mpg123_handle *mh);
 MPG123_EXPORT int mpg123_format( mpg123_handle *mh
 ,      long rate, int channels, int encodings );
 
+/** Set the audio format support of a mpg123_handle in detail:
+ *  \param mh handle
+ *  \param rate The sample rate value (in Hertz). Special value 0 means
+ *     all rates (the reason for this variant of mpg123_format()).
+ *  \param channels A combination of MPG123_STEREO and MPG123_MONO.
+ *  \param encodings A combination of accepted encodings for rate and channels,
+ *     p.ex MPG123_ENC_SIGNED16 | MPG123_ENC_ULAW_8 (or 0 for no support).
+ *     Please note that some encodings may not be supported in the library build
+ *     and thus will be ignored here.
+ *  \return MPG123_OK on success, MPG123_ERR if there was an error. */
+MPG123_EXPORT int mpg123_format2( mpg123_handle *mh
+,      long rate, int channels, int encodings );
+
 /** Check to see if a specific format at a specific rate is supported 
  *  by mpg123_handle.
  *  \param mh handle
@@ -530,8 +614,51 @@ MPG123_EXPORT int mpg123_getformat2( mpg123_handle *mh
  * @{
  */
 
-/* reading samples / triggering decoding, possible return values: */
-/** Enumeration of the error codes returned by libmpg123 functions. */
+/** Open a simple MPEG file with fixed properties.
+ *
+ *  This function shall simplify the common use case of a plain MPEG
+ *  file on disk that you want to decode, with one fixed sample
+ *  rate and channel count, and usually a length defined by a Lame/Info/Xing
+ *  tag. It will:
+ *
+ *  - set the MPG123_NO_FRANKENSTEIN flag
+ *  - set up format support according to given parameters,
+ *  - open the file,
+ *  - query audio format,
+ *  - fix the audio format support table to ensure the format stays the same,
+ *  - call mpg123_scan() if there is no header frame to tell the track length.
+ *
+ *  From that on, you can call mpg123_getformat() for querying the sample
+ *  rate (and channel count in case you allowed both) and mpg123_length()
+ *  to get a pretty safe number for the duration.
+ *  Only the sample rate is left open as that indeed is a fixed property of
+ *  MPEG files. You could set MPG123_FORCE_RATE beforehand, but that may trigger
+ *  low-quality resampling in the decoder, only do so if in dire need.
+ *  The library will convert mono files to stereo for you, and vice versa.
+ *  If any constraint cannot be satisified (most likely because of a non-default
+ *  build of libmpg123), you get MPG123_ERR returned and can query the detailed
+ *  cause from the handle. Only on MPG123_OK there will an open file that you
+ *  then close using mpg123_close(), or implicitly on mpg123_delete() or the next
+ *  call to open another file.
+ *
+ *  So, for your usual CD rip collection, you could use
+ *
+ *    mpg123_open_fixed(mh, path, MPG123_STEREO, MPG123_ENC_SIGNED_16)
+ *
+ *  and be happy calling mpg123_getformat() to verify 44100 Hz rate, then just
+ *  playing away with mpg123_read(). The occasional mono file, or MP2 file,
+ *  will also be decoded without you really noticing. Just the speed could be
+ *  wrong if you do not care about sample rate at all.
+ *  \param mh handle
+ *  \param path filesystem path
+ *  \param channels allowed channel count, either 1 (MPG123_MONO) or
+ *    2 (MPG123_STEREO), or bitwise or of them, but then you're halfway back to
+ *    calling mpg123_format() again;-)
+ *  \param encoding a definite encoding from enum mpg123_enc_enum
+ *    or a bitmask like for mpg123_format(), defeating the purpose somewhat
+ */
+MPG123_EXPORT int mpg123_open_fixed(mpg123_handle *mh, const char *path
+,      int channels, int encoding);
 
 /** Open and prepare to decode the specified file by filesystem path.
  *  This does not open HTTP urls; libmpg123 contains no networking code.
@@ -561,6 +688,8 @@ MPG123_EXPORT int mpg123_open_handle(mpg123_handle *mh, void *iohandle);
 
 /** Open a new bitstream and prepare for direct feeding
  *  This works together with mpg123_decode(); you are responsible for reading and feeding the input bitstream.
+ *  Also, you are expected to handle ICY metadata extraction yourself. This
+ *  input method does not handle MPG123_ICY_INTERVAL. It does parse ID3 frames, though.
  *  \param mh handle
  *  \return MPG123_OK on success
  */
@@ -573,6 +702,10 @@ MPG123_EXPORT int mpg123_open_feed(mpg123_handle *mh);
 MPG123_EXPORT int mpg123_close(mpg123_handle *mh);
 
 /** Read from stream and decode up to outmemsize bytes.
+ *
+ *  Note: The type of outmemory changed to a void pointer in mpg123 1.26.0
+ *  (API version 45).
+ *
  *  \param mh handle
  *  \param outmemory address of output buffer to write to
  *  \param outmemsize maximum number of bytes to write
@@ -580,7 +713,7 @@ MPG123_EXPORT int mpg123_close(mpg123_handle *mh);
  *  \return MPG123_OK or error/message code
  */
 MPG123_EXPORT int mpg123_read(mpg123_handle *mh
-,      unsigned char *outmemory, size_t outmemsize, size_t *done );
+,      void *outmemory, size_t outmemsize, size_t *done );
 
 /** Feed data for a stream that has been opened with mpg123_open_feed().
  *  It's give and take: You provide the bytestream, mpg123 gives you the decoded samples.
@@ -599,6 +732,10 @@ MPG123_EXPORT int mpg123_feed( mpg123_handle *mh
  *  without taking decoded data.
  *  Think of this function being the union of mpg123_read() and mpg123_feed() (which it actually is, sort of;-).
  *  You can actually always decide if you want those specialized functions in separate steps or one call this one here.
+ *
+ *  Note: The type of outmemory changed to a void pointer in mpg123 1.26.0
+ *  (API version 45).
+ *
  *  \param mh handle
  *  \param inmemory input buffer
  *  \param inmemsize number of input bytes
@@ -609,7 +746,7 @@ MPG123_EXPORT int mpg123_feed( mpg123_handle *mh
  */
 MPG123_EXPORT int mpg123_decode( mpg123_handle *mh
 ,      const unsigned char *inmemory, size_t inmemsize
-,      unsigned char *outmemory, size_t outmemsize, size_t *done );
+,      void *outmemory, size_t outmemsize, size_t *done );
 
 /** Decode next MPEG frame to internal buffer
  *  or read a frame and return after setting a new format.
@@ -905,6 +1042,30 @@ struct mpg123_frameinfo
        enum mpg123_vbr vbr;                    /**< The VBR mode. */
 };
 
+/** Data structure for even more detailed information out of the decoder,
+  * for MPEG layer III only.
+  * This was added to support the frame analyzer by the Lame project and
+  * just follows what was used there before. You know what the fields mean
+  * if you want use this structure. */
+struct mpg123_moreinfo
+{
+       double xr[2][2][576];
+       double sfb[2][2][22];  /* [2][2][SBMAX_l] */
+       double sfb_s[2][2][3*13]; /* [2][2][3*SBMAX_s] */
+       int qss[2][2];
+       int big_values[2][2];
+       int sub_gain[2][2][3];
+       int scalefac_scale[2][2];
+       int preflag[2][2];
+       int blocktype[2][2];
+       int mixed[2][2];
+       int mainbits[2][2];
+       int sfbits[2][2];
+       int scfsi[2];
+       int maindata;
+       int padding;
+};
+
 /** Get frame information about the MPEG audio bitstream and store it in a mpg123_frameinfo structure.
  *  \param mh handle
  *  \param mi address of existing frameinfo structure to write to
@@ -912,6 +1073,15 @@ struct mpg123_frameinfo
  */
 MPG123_EXPORT int mpg123_info(mpg123_handle *mh, struct mpg123_frameinfo *mi);
 
+/** Trigger collection of additional decoder information while decoding.
+ *  \param mh handle
+ *  \param mi pointer to data storage (NULL to disable collection)
+ *  \return MPG123_OK if the collection was enabled/disabled as desired, MPG123_ERR
+ *    otherwise (e.g. if the feature is disabled)
+ */
+MPG123_EXPORT int mpg123_set_moreinfo( mpg123_handle *mh
+,      struct mpg123_moreinfo *mi );
+
 /** Get the safe output buffer size for all cases
  *  (when you want to replace the internal buffer)
  *  \return safe buffer size
@@ -927,13 +1097,22 @@ MPG123_EXPORT size_t mpg123_safe_buffer(void);
  */
 MPG123_EXPORT int mpg123_scan(mpg123_handle *mh);
 
-/** Return, if possible, the full (expected) length of current track in frames.
+/** Return, if possible, the full (expected) length of current track in
+ *  MPEG frames.
  * \param mh handle
  * \return length >= 0 or MPG123_ERR if there is no length guess possible.
  */
 MPG123_EXPORT off_t mpg123_framelength(mpg123_handle *mh);
 
-/** Return, if possible, the full (expected) length of current track in samples.
+/** Return, if possible, the full (expected) length of current
+ *  track in samples (PCM frames).
+ *
+ *  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.
  */
@@ -973,6 +1152,9 @@ enum mpg123_state
        ,MPG123_BUFFERFILL   /**< Get fill of internal (feed) input buffer as integer byte count returned as long and as double. An error is returned on integer overflow while converting to (signed) long, but the returned floating point value shold still be fine. */
        ,MPG123_FRANKENSTEIN /**< Stream consists of carelessly stitched together files. Seeking may yield unexpected results (also with MPG123_ACCURATE, it may be confused). */
        ,MPG123_FRESH_DECODER /**< Decoder structure has been updated, possibly indicating changed stream (integer value, 0 if false, 1 if true). Flag is cleared after retrieval. */
+       ,MPG123_ENC_DELAY /** Encoder delay read from Info tag (layer III, -1 if unknown). */
+       ,MPG123_ENC_PADDING /** Encoder padding read from Info tag (layer III, -1 if unknown). */
+       ,MPG123_DEC_DELAY /** Decoder delay (for layer III only, -1 otherwise). */
 };
 
 /** Get various current decoder/stream state information.
@@ -1005,12 +1187,26 @@ typedef struct
        size_t fill; /**< number of used bytes (including closing zero byte) */
 } mpg123_string;
 
-/** Create and allocate memory for a new mpg123_string
+/** Allocate and intialize a new string.
+ *  \param val optional initial string value (can be NULL)
+ */
+MPG123_EXPORT mpg123_string* mpg123_new_string(const char* val);
+
+/** Free memory of contents and the string structure itself.
+ *  \param sb string handle
+ */
+MPG123_EXPORT void mpg123_delete_string(mpg123_string* sb);
+
+/** Initialize an existing mpg123_string structure to {NULL, 0, 0}.
+ *  If you hand in a NULL pointer here, your program should crash. The other
+ *  string functions are more forgiving, but this one here is too basic.
  *  \param sb string handle (address of existing structure on your side)
  */
 MPG123_EXPORT void mpg123_init_string(mpg123_string* sb);
 
-/** Free-up mempory for an existing mpg123_string
+/** Free-up memory of the contents of an mpg123_string (not the struct itself).
+ *  This also calls mpg123_init_string() and hence is safe to be called
+ *  repeatedly.
  *  \param sb string handle
  */
 MPG123_EXPORT void mpg123_free_string(mpg123_string* sb);
@@ -1041,6 +1237,20 @@ MPG123_EXPORT int mpg123_grow_string(mpg123_string* sb, size_t news);
  */
 MPG123_EXPORT int mpg123_copy_string(mpg123_string* from, mpg123_string* to);
 
+/** Move the contents of one mpg123_string string to another.
+ *  This frees any memory associated with the target and moves over the
+ *  pointers from the source, leaving the source without content after
+ *  that. The only possible error is that you hand in NULL pointers.
+ *  If you handed in a valid source, its contents will be gone, even if
+ *  there was no target to move to. If you hand in a valid target, its
+ *  original contents will also always be gone, to be replaced with the
+ *  source's contents if there was some.
+ *  \param from source string handle
+ *  \param to   target string handle
+ *  \return 0 on error, 1 on success
+ */
+MPG123_EXPORT int mpg123_move_string(mpg123_string* from, mpg123_string* to);
+
 /** Append a C-String to an mpg123_string
  *  \param sb string handle
  *  \param stuff to append
@@ -1075,8 +1285,10 @@ MPG123_EXPORT int mpg123_set_string(mpg123_string* sb, const char* stuff);
 MPG123_EXPORT int mpg123_set_substring( mpg123_string *sb
 ,      const char *stuff, size_t from, size_t count );
 
-/** Count characters in a mpg123 string (non-null bytes or UTF-8 characters).
- *  Even with the fill property, the character count is not obvious as there could be multiple trailing null bytes.
+/** Count characters in a mpg123 string (non-null bytes or Unicode points).
+ *  This function is of limited use, as it does just count code points
+ *  encoded in an UTF-8 string, only loosely related to the count of visible
+ *  characters. Get your full Unicode handling support elsewhere.
  *  \param sb string handle
  *  \param utf8 a flag to tell if the string is in utf8 encoding
  *  \return character count
@@ -1089,6 +1301,15 @@ MPG123_EXPORT size_t mpg123_strlen(mpg123_string *sb, int utf8);
  */
 MPG123_EXPORT int mpg123_chomp_string(mpg123_string *sb);
 
+/** Determine if two strings contain the same data.
+ *  This only returns 1 if both given handles are non-NULL and
+ *  if they are filled with the same bytes.
+ *  \param a first string handle
+ *  \param b second string handle
+ *  \return 0 for different strings, 1 for identical
+ */
+MPG123_EXPORT int mpg123_same_string(mpg123_string *a, mpg123_string *b);
+
 /** The mpg123 text encodings. This contains encodings we encounter in ID3 tags or ICY meta info. */
 enum mpg123_text_encoding
 {
@@ -1139,8 +1360,10 @@ MPG123_EXPORT int mpg123_store_utf8(mpg123_string *sb, enum mpg123_text_encoding
 
 /** Sub data structure for ID3v2, for storing various text fields (including comments).
  *  This is for ID3v2 COMM, TXXX and all the other text fields.
- *  Only COMM and TXXX have a description, only COMM and USLT have a language.
- *  You should consult the ID3v2 specification for the use of the various text fields ("frames" in ID3v2 documentation, I use "fields" here to separate from MPEG frames). */
+ *  Only COMM, TXXX and USLT may have a description, only COMM and USLT
+ *  have a language.
+ *  You should consult the ID3v2 specification for the use of the various text fields
+ * ("frames" in ID3v2 documentation, I use "fields" here to separate from MPEG frames). */
 typedef struct
 {
        char lang[3]; /**< Three-letter language code (not terminated). */
@@ -1210,7 +1433,8 @@ typedef struct
        size_t          texts;        /**< Numer of text fields. */
        mpg123_text    *extra;        /**< The array of extra (TXXX) fields. */
        size_t          extras;       /**< Number of extra text (TXXX) fields. */
-       mpg123_picture  *picture;     /**< Array of ID3v2 pictures fields (APIC). */
+       mpg123_picture  *picture;     /**< Array of ID3v2 pictures fields (APIC).
+               Only populated if MPG123_PICTURE flag is set! */
        size_t           pictures;    /**< Number of picture (APIC) fields. */
 } mpg123_id3v2;
 
@@ -1252,6 +1476,21 @@ MPG123_EXPORT void mpg123_meta_free(mpg123_handle *mh);
 MPG123_EXPORT int mpg123_id3( mpg123_handle *mh
 ,      mpg123_id3v1 **v1, mpg123_id3v2 **v2 );
 
+/** Return pointers to and size of stored raw ID3 data if storage has
+ *  been configured with MPG123_RAW_ID3 and stream parsing passed the
+ *  metadata already. Null value with zero size is a possibility!
+ *  The storage can change at any next API call.
+ *  \param v1 address to store pointer to v1 tag
+ *  \param v1_size size of v1 data in bytes
+ *  \param v2 address to store pointer to v2 tag
+ *  \param v2_size size of v2 data in bytes
+ *  \return MPG123_OK or MPG123_ERR. Only on MPG123_OK the output
+ *          values are set.
+ */
+MPG123_EXPORT int mpg123_id3_raw( mpg123_handle *mh
+,      unsigned char **v1, size_t *v1_size
+,      unsigned char **v2, size_t *v2_size );
+
 /** Point icy_meta to existing data structure wich may change on any next read/decode function call.
  *  \param mh handle
  *  \param icy_meta return address for ICY meta string (set to NULL if nothing there)
@@ -1336,6 +1575,19 @@ MPG123_EXPORT int mpg123_fmt_all(mpg123_pars *mp);
 MPG123_EXPORT int mpg123_fmt(mpg123_pars *mp
 ,      long rate, int channels, int encodings);
 
+/** Set the audio format support of a mpg123_pars in detail:
+ * \param mp parameter handle
+ * \param rate The sample rate value (in Hertz). Special value 0 means
+ *             all rates (reason for this variant of mpg123_fmt).
+ * \param channels A combination of MPG123_STEREO and MPG123_MONO.
+ * \param encodings A combination of accepted encodings for rate and channels,
+ *                  p.ex MPG123_ENC_SIGNED16|MPG123_ENC_ULAW_8 (or 0 for no
+ *                  support).
+ * \return MPG123_OK on success
+*/
+MPG123_EXPORT int mpg123_fmt2(mpg123_pars *mp
+,      long rate, int channels, int encodings);
+
 /** Check to see if a specific format at a specific rate is supported
  *  by mpg123_pars.
  *  \param mp parameter handle
@@ -1380,13 +1632,17 @@ MPG123_EXPORT int mpg123_getpar( mpg123_pars *mp
   * Note that the required buffer size could be bigger than expected from output
   * encoding if libmpg123 has to convert from primary decoder output (p.ex. 32 bit
   * storage for 24 bit output).
+  *
+  *  Note: The type of data changed to a void pointer in mpg123 1.26.0
+  *  (API version 45).
+  *
   * \param mh handle
   * \param data pointer to user buffer
   * \param size of buffer in bytes
   * \return MPG123_OK on success
   */
 MPG123_EXPORT int mpg123_replace_buffer(mpg123_handle *mh
-,      unsigned char *data, size_t size);
+,      void *data, size_t size);
 
 /** The max size of one frame's decoded output with current settings.
  *  Use that to determine an appropriate minimum buffer size for decoding one frame.
index 57efbd9..fcbd541 100644 (file)
@@ -303,6 +303,9 @@ off_t outblock_bytes(mpg123_handle *fr, off_t s);
 /* Postprocessing format conversion of freshly decoded buffer. */
 void postprocess_buffer(mpg123_handle *fr);
 
+int open_fixed_pre(mpg123_handle *mh, int channels, int encoding);
+int open_fixed_post(mpg123_handle *mh, int channels, int encoding);
+
 /* If networking is enabled and we really mean internal networking, the timeout_read function is available. */
 #if defined (NETWORK) && !defined (WANT_WIN32_SOCKETS)
 /* Does not work with win32 */
index 1049a09..c2efd3d 100644 (file)
@@ -1,7 +1,7 @@
 /*
        parse: spawned from common; clustering around stream/frame parsing
 
-       copyright ?-2014 by the mpg123 project - free software under the terms of the LGPL 2.1
+       copyright ?-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 Michael Hipp & Thomas Orgis
 */
@@ -408,6 +408,9 @@ static int check_lame_tag(mpg123_handle *fr)
                lame_offset += 3; /* 24 in */
                if(VERBOSE3) fprintf(stderr, "Note: Encoder delay = %i; padding = %i\n"
                ,       (int)pad_in, (int)pad_out);
+               /* Store even if libmpg123 does not do gapless decoding itself. */
+               fr->enc_delay   = (int)pad_in;
+               fr->enc_padding = (int)pad_out;
                #ifdef GAPLESS
                if(fr->p.flags & MPG123_GAPLESS)
                frame_gapless_init(fr, fr->track_frames, pad_in, pad_out);
@@ -458,8 +461,7 @@ static int halfspeed_do(mpg123_handle *fr)
                        debug("repeat!");
                        fr->to_decode = fr->to_ignore = TRUE;
                        --fr->halfphase;
-                       fr->bitindex = 0;
-                       fr->wordpointer = (unsigned char *) fr->bsbuf;
+                       set_pointer(fr, 0, 0);
                        if(fr->lay == 3) memcpy (fr->bsbuf, fr->ssave, fr->ssize);
                        if(fr->error_protection) fr->crc = getbits(fr, 16); /* skip crc */
                        return 1;
@@ -511,6 +513,20 @@ int read_frame(mpg123_handle *fr)
 
        /* From now on, old frame data is tainted by parsing attempts. */
        fr->to_decode = fr->to_ignore = FALSE;
+
+       if( fr->p.flags & MPG123_NO_FRANKENSTEIN &&
+               ( (fr->track_frames > 0 && fr->num >= fr->track_frames-1)
+#ifdef GAPLESS
+               || (fr->gapless_frames > 0 && fr->num >= fr->gapless_frames-1)
+#endif
+               ) )
+       {
+               mdebug( "stopping parsing at %"OFF_P
+                       " frames as indicated fixed track length"
+               ,       (off_p)fr->num+1 );
+               return 0;
+       }
+
 read_again:
        /* In case we are looping to find a valid frame, discard any buffered data before the current position.
           This is essential to prevent endless looping, always going back to the beginning when feeder buffer is exhausted. */
@@ -543,7 +559,9 @@ init_resync:
 
        if(!fr->firsthead)
        {
-               ret = do_readahead(fr, newhead);
+               ret = fr->p.flags & MPG123_NO_READAHEAD
+               ?       PARSE_GOOD
+               :       do_readahead(fr, newhead);
                /* readahead can fail mit NEED_MORE, in which case we must also make the just read header available again for next go */
                if(ret < 0) fr->rd->back_bytes(fr, 4);
                JUMP_CONCLUSION(ret);
@@ -551,16 +569,27 @@ init_resync:
 
        /* Now we should have our valid header and proceed to reading the frame. */
 
+       if(fr->p.flags & MPG123_NO_FRANKENSTEIN)
+       {
+               if(fr->firsthead && !head_compatible(fr->firsthead, newhead))
+               {
+                       mdebug( "stopping before reading frame %"OFF_P
+                               " as its header indicates Frankenstein coming for you", (off_p)fr->num );
+                       return 0;
+               }
+       }
+
        /* if filepos is invalid, so is framepos */
        framepos = fr->rd->tell(fr) - 4;
        /* flip/init buffer for Layer 3 */
        {
                unsigned char *newbuf = fr->bsspace[fr->bsnum]+512;
                /* read main data into memory */
+               debug2("read frame body of %i at %"OFF_P, fr->framesize, framepos+4);
                if((ret=fr->rd->read_frame_body(fr,newbuf,fr->framesize))<0)
                {
                        /* if failed: flip back */
-                       debug("need more?");
+                       debug1("%s", ret == MPG123_NEED_MORE ? "need more" : "read error");
                        goto read_frame_bad;
                }
                fr->bsbufold = fr->bsbuf;
@@ -593,8 +622,8 @@ init_resync:
                debug2("fr->firsthead: %08lx, audio_start: %li", fr->firsthead, (long int)fr->audio_start);
        }
 
-  fr->bitindex = 0;
-  fr->wordpointer = (unsigned char *) fr->bsbuf;
+       set_pointer(fr, 0, 0);
+
        /* Question: How bad does the floating point value get with repeated recomputation?
           Also, considering that we can play the file or parts of many times. */
        if(++fr->mean_frames != 0)
@@ -787,6 +816,12 @@ static int decode_header(mpg123_handle *fr,unsigned long newhead, int *freeforma
                if(fr->freeformat_framesize < 0)
                {
                        int ret;
+                       if(fr->p.flags & MPG123_NO_READAHEAD)
+                       {
+                               if(VERBOSE3)
+                                       error("Got no free-format frame size and am not allowed to read ahead.");
+                               return PARSE_BAD;
+                       }
                        *freeformat_count += 1;
                        if(*freeformat_count > 5)
                        {
@@ -825,9 +860,10 @@ static int decode_header(mpg123_handle *fr,unsigned long newhead, int *freeforma
                        fr->do_layer = do_layer1;
                        if(!fr->freeformat)
                        {
-                               fr->framesize  = (long) tabsel_123[fr->lsf][0][fr->bitrate_index] * 12000;
-                               fr->framesize /= freqs[fr->sampling_frequency];
-                               fr->framesize  = ((fr->framesize+fr->padding)<<2)-4;
+                               long fs = (long) tabsel_123[fr->lsf][0][fr->bitrate_index] * 12000;
+                               fs /= freqs[fr->sampling_frequency];
+                               fs = ((fs+fr->padding)<<2)-4;
+                               fr->framesize = (int)fs;
                        }
                break;
 #endif
@@ -838,9 +874,10 @@ static int decode_header(mpg123_handle *fr,unsigned long newhead, int *freeforma
                        if(!fr->freeformat)
                        {
                                debug2("bitrate index: %i (%i)", fr->bitrate_index, tabsel_123[fr->lsf][1][fr->bitrate_index] );
-                               fr->framesize = (long) tabsel_123[fr->lsf][1][fr->bitrate_index] * 144000;
-                               fr->framesize /= freqs[fr->sampling_frequency];
-                               fr->framesize += fr->padding - 4;
+                               long fs = (long) tabsel_123[fr->lsf][1][fr->bitrate_index] * 144000;
+                               fs /= freqs[fr->sampling_frequency];
+                               fs += fr->padding - 4;
+                               fr->framesize = (int)fs;
                        }
                break;
 #endif
@@ -858,9 +895,17 @@ static int decode_header(mpg123_handle *fr,unsigned long newhead, int *freeforma
 
                        if(!fr->freeformat)
                        {
-                               fr->framesize  = (long) tabsel_123[fr->lsf][2][fr->bitrate_index] * 144000;
-                               fr->framesize /= freqs[fr->sampling_frequency]<<(fr->lsf);
-                               fr->framesize = fr->framesize + fr->padding - 4;
+                               long fs = (long) tabsel_123[fr->lsf][2][fr->bitrate_index] * 144000;
+                               fs /= freqs[fr->sampling_frequency]<<(fr->lsf);
+                               fs += fr->padding - 4;
+                               fr->framesize = fs;
+                       }
+                       if(fr->framesize < fr->ssize)
+                       {
+                               if(NOQUIET)
+                                       error2( "Frame smaller than mandatory side info (%i < %i)!"
+                                       ,       fr->framesize, fr->ssize );
+                               return PARSE_BAD;
                        }
                break;
 #endif 
@@ -878,13 +923,38 @@ static int decode_header(mpg123_handle *fr,unsigned long newhead, int *freeforma
        return PARSE_GOOD;
 }
 
-void set_pointer(mpg123_handle *fr, long backstep)
-{
-       fr->wordpointer = fr->bsbuf + fr->ssize - backstep;
-       if (backstep)
-       memcpy(fr->wordpointer,fr->bsbufold+fr->fsizeold-backstep,backstep);
+/* Prepare for bit reading. Two stages:
+  0. Layers 1 and 2, side info for layer 3
+  1. Second call for possible bit reservoir for layer 3 part 2,3.
+     This overwrites side info needed for stage 0.
 
-       fr->bitindex = 0; 
+  Continuing to read bits after layer 3 side info shall fail unless
+  set_pointer() is called to refresh things. 
+*/
+void set_pointer(mpg123_handle *fr, int part2, long backstep)
+{
+       fr->bitindex = 0;
+       if(fr->lay == 3)
+       {
+               if(part2)
+               {
+                       fr->wordpointer = fr->bsbuf + fr->ssize - backstep;
+                       if(backstep)
+                               memcpy( fr->wordpointer, fr->bsbufold+fr->fsizeold-backstep
+                               ,       backstep );
+                       fr->bits_avail = (long)(fr->framesize - fr->ssize + backstep)*8;
+               }
+               else
+               {
+                       fr->wordpointer = fr->bsbuf;
+                       fr->bits_avail  = fr->ssize*8;
+               }
+       }
+       else
+       {
+               fr->wordpointer = fr->bsbuf;
+               fr->bits_avail  = fr->framesize*8;
+       }
 }
 
 /********************************/
@@ -1204,7 +1274,8 @@ static int skip_junk(mpg123_handle *fr, unsigned long *newheadp, long *headcount
        if(limit >= 0 && *headcount >= limit)
        {
                if(NOQUIET) error1("Giving up searching valid MPEG header after %li bytes of junk.", *headcount);
-               return PARSE_END;
+               fr->err = MPG123_RESYNC_FAIL;
+               return PARSE_ERR;
        }
        else debug1("hopefully found one at %"OFF_P, (off_p)fr->rd->tell(fr));
 
index 91f9f7d..33eeccd 100644 (file)
@@ -16,7 +16,7 @@ int frame_bitrate(mpg123_handle *fr);
 long frame_freq(mpg123_handle *fr);
 int read_frame_recover(mpg123_handle* fr); /* dead? */
 int read_frame(mpg123_handle *fr);
-void set_pointer(mpg123_handle *fr, long backstep);
+void set_pointer(mpg123_handle *fr, int part2, long backstep);
 int position_info(mpg123_handle* fr, unsigned long no, long buffsize, unsigned long* frames_left, double* current_seconds, double* seconds_left);
 double compute_bpf(mpg123_handle *fr);
 long time_to_frame(mpg123_handle *fr, double seconds);
index 58dad6d..a360c0d 100644 (file)
@@ -1,9 +1,10 @@
 /* TODO: Check all read calls (in loops, especially!) for return value 0 (EOF)! */
-
+/* Check if get_fileinfo should read ID3 info or not, seems a bit out of place here. */
+/* #define EXTRA_DEBUG */
 /*
        readers.c: reading input data
 
-       copyright ?-2008 by the mpg123 project - free software under the terms of the LGPL 2.1
+       copyright ?-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 Michael Hipp
 */
@@ -383,18 +384,12 @@ static int stream_back_bytes(mpg123_handle *fr, off_t bytes)
 }
 
 
-/* returns size on success... */
+/* returns size on success... otherwise an error code < 0 */
 static int generic_read_frame_body(mpg123_handle *fr,unsigned char *buf, int size)
 {
        long l;
-
-       if((l=fr->rd->fullread(fr,buf,size)) != size)
-       {
-               long ll = l;
-               if(ll <= 0) ll = 0;
-               return READER_MORE;
-       }
-       return l;
+       l=fr->rd->fullread(fr,buf,size);
+       return (l >= 0 && l<size) ? READER_ERROR : l;
 }
 
 static off_t generic_tell(mpg123_handle *fr)
@@ -436,18 +431,35 @@ static off_t get_fileinfo(mpg123_handle *fr)
 {
        off_t len;
 
-       if((len=io_seek(&fr->rdat,0,SEEK_END)) < 0)     return -1;
-
-       if(io_seek(&fr->rdat,-128,SEEK_END) < 0) return -1;
-
-       if(fr->rd->fullread(fr,(unsigned char *)fr->id3buf,128) != 128) return -1;
-
-       if(!strncmp((char*)fr->id3buf,"TAG",3)) len -= 128;
-
-       if(io_seek(&fr->rdat,0,SEEK_SET) < 0)   return -1;
+       if((len=io_seek(&fr->rdat,0,SEEK_END)) < 0)
+       {
+               debug("cannot seek to end");
+               return -1;
+       } else if(len >= 128)
+       {
+               if(io_seek(&fr->rdat,-128,SEEK_END) < 0)
+               {
+                       debug("cannot seek to END-128");
+                       return -1;
+               }
+               if(fr->rd->fullread(fr,(unsigned char *)fr->id3buf,128) != 128)
+               {
+                       debug("cannot read ID3v1?!");
+                       return -1;
+               }
+               if(!strncmp((char*)fr->id3buf,"TAG",3)) len -= 128;
+       } else
+       {
+               debug("stream too short for ID3");
+       }
 
-       if(len <= 0)    return -1;
+       if(io_seek(&fr->rdat,0,SEEK_SET) < 0)
+       {
+               debug("cannot seek back");
+               return -1;
+       }
 
+       debug1("returning length: %"OFF_P, (off_p)len);
        return len;
 }
 
@@ -831,6 +843,8 @@ static ssize_t buffered_fullread(mpg123_handle *fr, unsigned char *out, ssize_t
 {
        struct bufferchain *bc = &fr->rdat.buffer;
        ssize_t gotcount;
+       if(VERBOSE3)
+               mdebug("buffered_fullread: want %zd", count);
        if(bc->size - bc->pos < count)
        { /* Add more stuff to buffer. If hitting end of file, adjust count. */
                unsigned char readbuf[4096];
@@ -863,9 +877,8 @@ static ssize_t buffered_fullread(mpg123_handle *fr, unsigned char *out, ssize_t
                count = bc->size - bc->pos; /* We want only what we got. */
        }
        gotcount = bc_give(bc, out, count);
-
-       if(VERBOSE3) debug2("wanted %li, got %li", (long)count, (long)gotcount);
-
+       if(VERBOSE3)
+               mdebug("buffered_fullread: got %zd", gotcount);
        if(gotcount != count){ if(NOQUIET) error("gotcount != count"); return READER_ERROR; }
        else return gotcount;
 }
@@ -1028,7 +1041,9 @@ static int default_init(mpg123_handle *fr)
                int flags;
                if(fr->rdat.r_read != NULL)
                {
-                       error("Timeout reading does not work with user-provided read function. Implement it yourself!");
+                       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);
@@ -1060,6 +1075,7 @@ static int default_init(mpg123_handle *fr)
        */
        if(fr->rdat.filelen >= 0)
        {
+               debug("seekable stream");
                fr->rdat.flags |= READER_SEEKABLE;
                if(!strncmp((char*)fr->id3buf,"TAG",3))
                {
@@ -1071,18 +1087,21 @@ static int default_init(mpg123_handle *fr)
        else if(fr->p.flags & MPG123_SEEKBUFFER)
        {
 #ifdef NO_FEEDER
-               error("Buffered readers not supported in this build.");
+               if(NOQUIET)
+                       error("Buffered readers not supported in this build.");
                fr->err = MPG123_MISSING_FEATURE;
                return -1;
 #else
                if     (fr->rd == &readers[READER_STREAM])
                {
+                       debug("switching to buffered stream reader");
                        fr->rd = &readers[READER_BUF_STREAM];
                        fr->rdat.fullread = plain_fullread;
                }
 #ifndef NO_ICY
                else if(fr->rd == &readers[READER_ICY_STREAM])
                {
+                       debug("switching to buffered ICY stream reader");
                        fr->rd = &readers[READER_BUF_ICY_STREAM];
                        fr->rdat.fullread = icy_fullread;
                }
@@ -1095,7 +1114,7 @@ static int default_init(mpg123_handle *fr)
                bc_init(&fr->rdat.buffer);
                fr->rdat.filelen = 0; /* We carry the offset, but never know how big the stream is. */
                fr->rdat.flags |= READER_BUFFERED;
-#endif /* NO_FEEDER */
+#endif /* NO_ICY */
        }
        return 0;
 }
@@ -1119,7 +1138,8 @@ int open_feed(mpg123_handle *fr)
 {
        debug("feed reader");
 #ifdef NO_FEEDER
-       error("Buffered readers not supported in this build.");
+       if(NOQUIET)
+               error("Buffered readers not supported in this build.");
        fr->err = MPG123_MISSING_FEATURE;
        return -1;
 #else
index 2e6cbff..5a98fe0 100644 (file)
@@ -151,4 +151,45 @@ static inline int16_t ftoi16(float x)
 #define WRITE_REAL_SAMPLE(samples,sum,clip) *(samples) = ((real)1./SHORT_SCALE)*(sum)
 #endif
 
+/* Finished 32 bit sample to unsigned 32 bit sample. */
+#define CONV_SU32(s) \
+( (s >= 0) \
+       ?       ((uint32_t)s + (uint32_t)2147483648UL) \
+       :       (s == -2147483647-1 /* Work around to prevent a non-conformant MSVC warning/error */ \
+               ?       0 /* Separate because negation would overflow. */  \
+               :       (uint32_t)2147483648UL - (uint32_t)(-s) ) \
+)
+
+/* Finished 16 bit sample to unsigned 16 bit sample. */
+#define CONV_SU16(s) (uint16_t)((int32_t)(s)+32768)
+
+/* Same style for syn123 generic conversion. */
+#define CONV_SU8(s) (uint8_t)((int16_t)s+128)
+
+/* Unsigned 32 bit sample to signed 32 bit sample. */
+#define CONV_US32(u) \
+( (u >= 2147483648UL) \
+       ?       (int32_t)((uint32_t)u - (uint32_t)2147483648UL) \
+       :       ((u == 0) \
+               ?       (int32_t)-2147483648UL \
+               :       -(int32_t)((uint32_t)2147483648UL - u) ) \
+)
+
+/* Unsigned 16 bit sample to signed 16 bit sample. */
+#define CONV_US16(s) (int16_t)((int32_t)s-32768)
+
+/* Same style for syn123 generic conversion. */
+#define CONV_US8(s) (int8_t)((int16_t)s-128)
+
+/* 24 bit conversion: drop or add a least significant byte. */
+#ifdef WORDS_BIGENDIAN
+/* Highest byte first. Drop last. */
+#define DROP4BYTE(w,r) {(w)[0]=(r)[0]; (w)[1]=(r)[1]; (w)[2]=(r)[2];}
+#define ADD4BYTE(w,r)  {(w)[0]=(r)[0]; (w)[1]=(r)[1]; (w)[2]=(r)[2]; (w)[3]=0}
+#else
+/* Lowest byte first, drop that. */
+#define DROP4BYTE(w,r) {(w)[0]=(r)[1]; (w)[1]=(r)[2]; (w)[2]=(r)[3];}
+#define ADD4BYTE(w,r)  {(w)[0]=0; (w)[1]=(r)[0]; (w)[2]=(r)[1]; (w)[3]=(r)[2];}
+#endif
+
 #endif
index b1cecc9..fb3b830 100644 (file)
@@ -1,7 +1,7 @@
 /*
        stringbuf: mimicking a bit of C++ to more safely handle strings
 
-       copyright 2006-17 by the mpg123 project
+       copyright 2006-20 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
 #include <string.h>
 #include "debug.h"
 
+mpg123_string* attribute_align_arg mpg123_new_string(const char *val)
+{
+       mpg123_string *sb = malloc(sizeof(mpg123_string));
+       if(!sb)
+               return NULL;
+       mpg123_init_string(sb);
+       mpg123_set_string(sb, val);
+       return sb;
+}
+
+void attribute_align_arg mpg123_delete_string(mpg123_string* sb)
+{
+       if(!sb)
+               return;
+       mpg123_free_string(sb);
+       free(sb);
+}
+
 void attribute_align_arg mpg123_init_string(mpg123_string* sb)
 {
        /* Handing in NULL here is a fatal mistake and rightfully so. */
@@ -59,6 +77,12 @@ int attribute_align_arg mpg123_resize_string(mpg123_string* sb, size_t new)
                {
                        sb->p = t;
                        sb->size = new;
+                       if(sb->size < sb->fill)
+                       {
+                               // Cut short the existing data, properly.
+                               sb->fill = sb->size;
+                               sb->p[sb->fill-1] = 0;
+                       }
                        return 1;
                }
                else return 0;
@@ -95,6 +119,19 @@ int attribute_align_arg mpg123_copy_string(mpg123_string* from, mpg123_string* t
        else return 0;
 }
 
+int attribute_align_arg mpg123_move_string(mpg123_string *from, mpg123_string *to)
+{
+       if(to)
+               mpg123_free_string(to);
+       else
+               mpg123_free_string(from);
+       if(from && to)
+               *to = *from;
+       if(from)
+               mpg123_init_string(from);
+       return (from && to) ? 1 : 0;
+}
+
 int attribute_align_arg mpg123_add_string(mpg123_string* sb, const char* stuff)
 {
        debug1("adding %s", stuff);
@@ -200,3 +237,14 @@ int attribute_align_arg mpg123_chomp_string(mpg123_string *sb)
 
        return 1;
 }
+
+int attribute_align_arg mpg123_same_string(mpg123_string *a, mpg123_string *b)
+{
+       if(!a || !b)
+               return 0;
+       if(a->fill != b->fill)
+               return 0;
+       if(memcmp(a->p, b->p, a->fill))
+               return 0;
+       return 1;
+}
diff --git a/libmpg123/src/libmpg123/swap_bytes_impl.h b/libmpg123/src/libmpg123/swap_bytes_impl.h
new file mode 100644 (file)
index 0000000..28e7ff4
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+       swap_bytes: Swap byte order of samples in a buffer.
+
+       copyright 2018 by the mpg123 project
+       licensed under the terms of the LGPL 2.1
+       see COPYING and AUTHORS files in distribution or http://mpg123.org
+
+       initially written by Thomas Orgis
+
+       This is C source to include in your code to get the function named
+       swap_bytes. It is serves intentional duplication in libmpg123 and
+       libsyn123 to avoid introducing a dependency between them. This function
+       is too small for that.
+*/
+
+/* Other headers are already included! */
+
+/* Optionally use platform-specific byteswap macros. */
+#ifdef HAVE_BYTESWAP_H
+#include <byteswap.h>
+#endif
+
+/* Plain stupid swapping of elements in a byte array. */
+/* This is the fallback when there is no native bswap macro. */
+#define SWAP(a,b) tmp = p[a]; p[a] = p[b]; p[b] = tmp;
+
+/* Convert samplecount elements of samplesize bytes each in buffer buf. */
+static void swap_bytes(void *buf, size_t samplesize, size_t samplecount)
+{
+       unsigned char *p = buf;
+       unsigned char *pend = (unsigned char*)buf+samplesize*samplecount;
+       unsigned char tmp;
+
+       if(samplesize < 2)
+               return;
+       switch(samplesize)
+       {
+               case 2: /* AB -> BA */
+#ifdef HAVE_BYTESWAP_H
+               {
+                       uint16_t* pp = (uint16_t*)p;
+                       for(; pp<(uint16_t*)pend; ++pp)
+                               *pp = bswap_16(*pp);
+               }
+#else
+                       for(; p<pend; p+=2)
+                       {
+                               SWAP(0,1)
+                       }
+#endif
+               break;
+               case 3: /* ABC -> CBA */
+                       for(; p<pend; p+=3)
+                       {
+                               SWAP(0,2)
+                       }
+               break;
+               case 4: /* ABCD -> DCBA */
+#ifdef HAVE_BYTESWAP_H
+               {
+                       uint32_t* pp = (uint32_t*)p;
+                       for(; pp<(uint32_t*)pend; ++pp)
+                               *pp = bswap_32(*pp);
+               }
+#else
+                       for(; p<pend; p+=4)
+                       {
+                               SWAP(0,3)
+                               SWAP(1,2)
+                       }
+#endif
+               break;
+               case 8: /* ABCDEFGH -> HGFEDCBA */
+#ifdef HAVE_BYTESWAP_H
+               {
+                       uint64_t* pp = (uint64_t*)p;
+                       for(; pp<(uint64_t*)pend; ++pp)
+                               *pp = bswap_64(*pp);
+               }
+#else
+                       for(; p<pend; p+=8)
+                       {
+                               SWAP(0,7)
+                               SWAP(1,6)
+                               SWAP(2,5)
+                               SWAP(3,4)
+                       }
+#endif
+               break;
+               /* All the weird choices with the full nested loop. */
+               default:
+                       for(; p<pend; p+=samplesize)
+                       {
+                               size_t j;
+                               for(j=0; j<samplesize/2; ++j)
+                               {
+                                       SWAP(j, samplesize-j-1)
+                               }
+                       }
+       }
+}
+
+#undef SWAP