From abd85adc5d760ed3206539a6bb1ef1883ea025dc Mon Sep 17 00:00:00 2001 From: Ozkan Sezer Date: Tue, 10 Dec 2019 17:55:03 +0300 Subject: [PATCH] move tag skip and SDL_RW with bookkeeping code into separate mp3utils.c it is currently used by music_mad.c. if it gets used in music_mpg123.c, remember to adjust the ifdef guard. --- Makefile.in | 2 +- .../UWP_VS2015/SDL_mixer-UWP.vcxproj | 1 + .../UWP_VS2015/SDL_mixer-UWP.vcxproj.filters | 1 + .../SDL_mixer-WinPhone80.vcxproj | 2 + .../SDL_mixer-WinPhone80.vcxproj.filters | 2 + .../SDL_mixer-WinPhone81.vcxproj | 2 + .../SDL_mixer-WinPhone81.vcxproj.filters | 2 + .../WinRT80_VS2012/SDL_mixer-WinRT80.vcxproj | 2 + .../SDL_mixer-WinRT80.vcxproj.filters | 2 + .../WinRT81_VS2013/SDL_mixer-WinRT81.vcxproj | 2 + .../SDL_mixer-WinRT81.vcxproj.filters | 2 + VisualC/SDL_mixer.vcxproj | 2 + VisualC/SDL_mixer.vcxproj.filters | 6 + Xcode-iOS/SDL_mixer.xcodeproj/project.pbxproj | 12 + Xcode/SDL_mixer.xcodeproj/project.pbxproj | 8 + src/codecs/mp3utils.c | 255 ++++++++++++++++++ src/codecs/mp3utils.h | 36 +++ src/codecs/music_mad.c | 240 +---------------- 18 files changed, 347 insertions(+), 232 deletions(-) create mode 100644 src/codecs/mp3utils.c create mode 100644 src/codecs/mp3utils.h diff --git a/Makefile.in b/Makefile.in index 6c4c82f5..8a0e5ccf 100644 --- a/Makefile.in +++ b/Makefile.in @@ -38,7 +38,7 @@ VERSION_OBJECTS = @VERSION_OBJECTS@ PLAYWAVE_OBJECTS = @PLAYWAVE_OBJECTS@ PLAYMUS_OBJECTS = @PLAYMUS_OBJECTS@ -DIST = *.txt Android.mk Makefile.in SDL2_mixer.pc.in SDL2_mixer.spec.in include/SDL_mixer.h VisualC VisualC-WinRT Xcode Xcode-iOS acinclude aclocal.m4 autogen.sh build-scripts configure configure.in debian external gcc-fat.sh src/compat.c src/compat.h src/effect_position.c src/effect_stereoreverse.c src/effects_internal.c src/effects_internal.h src/codecs/load_aiff.c src/codecs/load_aiff.h src/codecs/load_voc.c src/codecs/load_voc.h src/mixer.c src/mixer.h src/music.c src/music.h src/codecs/music_cmd.c src/codecs/music_cmd.h src/codecs/music_flac.c src/codecs/music_flac.h src/codecs/music_fluidsynth.c src/codecs/music_fluidsynth.h src/codecs/music_mad.c src/codecs/music_mad.h src/codecs/music_mikmod.c src/codecs/music_mikmod.h src/codecs/music_modplug.c src/codecs/music_modplug.h src/codecs/music_mpg123.c src/codecs/music_mpg123.h src/codecs/music_nativemidi.c src/codecs/music_nativemidi.h src/codecs/music_ogg.c src/codecs/music_ogg.h src/codecs/music_opus.c src/codecs/music_opus.h src/codecs/music_timidity.c src/codecs/music_timidity.h src/codecs/music_wav.c src/codecs/music_wav.h src/codecs/native_midi playmus.c playwave.c src/codecs/timidity version.rc +DIST = *.txt Android.mk Makefile.in SDL2_mixer.pc.in SDL2_mixer.spec.in include/SDL_mixer.h VisualC VisualC-WinRT Xcode Xcode-iOS acinclude aclocal.m4 autogen.sh build-scripts configure configure.in debian external gcc-fat.sh src/compat.c src/compat.h src/effect_position.c src/effect_stereoreverse.c src/effects_internal.c src/effects_internal.h src/codecs/load_aiff.c src/codecs/load_aiff.h src/codecs/load_voc.c src/codecs/load_voc.h src/codecs/mp3utils.c src/codecs/mp3utils.h src/mixer.c src/mixer.h src/music.c src/music.h src/codecs/music_cmd.c src/codecs/music_cmd.h src/codecs/music_flac.c src/codecs/music_flac.h src/codecs/music_fluidsynth.c src/codecs/music_fluidsynth.h src/codecs/music_mad.c src/codecs/music_mad.h src/codecs/music_mikmod.c src/codecs/music_mikmod.h src/codecs/music_modplug.c src/codecs/music_modplug.h src/codecs/music_mpg123.c src/codecs/music_mpg123.h src/codecs/music_nativemidi.c src/codecs/music_nativemidi.h src/codecs/music_ogg.c src/codecs/music_ogg.h src/codecs/music_opus.c src/codecs/music_opus.h src/codecs/music_timidity.c src/codecs/music_timidity.h src/codecs/music_wav.c src/codecs/music_wav.h src/codecs/native_midi playmus.c playwave.c src/codecs/timidity version.rc LT_AGE = @LT_AGE@ LT_CURRENT = @LT_CURRENT@ diff --git a/VisualC-WinRT/UWP_VS2015/SDL_mixer-UWP.vcxproj b/VisualC-WinRT/UWP_VS2015/SDL_mixer-UWP.vcxproj index bdc31f82..685f7aff 100644 --- a/VisualC-WinRT/UWP_VS2015/SDL_mixer-UWP.vcxproj +++ b/VisualC-WinRT/UWP_VS2015/SDL_mixer-UWP.vcxproj @@ -35,6 +35,7 @@ + diff --git a/VisualC-WinRT/UWP_VS2015/SDL_mixer-UWP.vcxproj.filters b/VisualC-WinRT/UWP_VS2015/SDL_mixer-UWP.vcxproj.filters index d7109be2..0730304e 100644 --- a/VisualC-WinRT/UWP_VS2015/SDL_mixer-UWP.vcxproj.filters +++ b/VisualC-WinRT/UWP_VS2015/SDL_mixer-UWP.vcxproj.filters @@ -9,6 +9,7 @@ + diff --git a/VisualC-WinRT/WinPhone80_VS2012/SDL_mixer-WinPhone80.vcxproj b/VisualC-WinRT/WinPhone80_VS2012/SDL_mixer-WinPhone80.vcxproj index c12146d1..d85ecbf1 100644 --- a/VisualC-WinRT/WinPhone80_VS2012/SDL_mixer-WinPhone80.vcxproj +++ b/VisualC-WinRT/WinPhone80_VS2012/SDL_mixer-WinPhone80.vcxproj @@ -172,6 +172,7 @@ + @@ -202,6 +203,7 @@ + diff --git a/VisualC-WinRT/WinPhone80_VS2012/SDL_mixer-WinPhone80.vcxproj.filters b/VisualC-WinRT/WinPhone80_VS2012/SDL_mixer-WinPhone80.vcxproj.filters index 3baf83b1..a68cbf9d 100644 --- a/VisualC-WinRT/WinPhone80_VS2012/SDL_mixer-WinPhone80.vcxproj.filters +++ b/VisualC-WinRT/WinPhone80_VS2012/SDL_mixer-WinPhone80.vcxproj.filters @@ -9,6 +9,7 @@ + @@ -57,6 +58,7 @@ + diff --git a/VisualC-WinRT/WinPhone81_VS2013/SDL_mixer-WinPhone81.vcxproj b/VisualC-WinRT/WinPhone81_VS2013/SDL_mixer-WinPhone81.vcxproj index 8cce307b..1fb76dfd 100644 --- a/VisualC-WinRT/WinPhone81_VS2013/SDL_mixer-WinPhone81.vcxproj +++ b/VisualC-WinRT/WinPhone81_VS2013/SDL_mixer-WinPhone81.vcxproj @@ -41,6 +41,7 @@ + @@ -71,6 +72,7 @@ + diff --git a/VisualC-WinRT/WinPhone81_VS2013/SDL_mixer-WinPhone81.vcxproj.filters b/VisualC-WinRT/WinPhone81_VS2013/SDL_mixer-WinPhone81.vcxproj.filters index 5b2273ff..3b76a661 100644 --- a/VisualC-WinRT/WinPhone81_VS2013/SDL_mixer-WinPhone81.vcxproj.filters +++ b/VisualC-WinRT/WinPhone81_VS2013/SDL_mixer-WinPhone81.vcxproj.filters @@ -9,6 +9,7 @@ + @@ -57,6 +58,7 @@ + diff --git a/VisualC-WinRT/WinRT80_VS2012/SDL_mixer-WinRT80.vcxproj b/VisualC-WinRT/WinRT80_VS2012/SDL_mixer-WinRT80.vcxproj index 7bd8f1d3..4e319468 100644 --- a/VisualC-WinRT/WinRT80_VS2012/SDL_mixer-WinRT80.vcxproj +++ b/VisualC-WinRT/WinRT80_VS2012/SDL_mixer-WinRT80.vcxproj @@ -49,6 +49,7 @@ + @@ -79,6 +80,7 @@ + diff --git a/VisualC-WinRT/WinRT80_VS2012/SDL_mixer-WinRT80.vcxproj.filters b/VisualC-WinRT/WinRT80_VS2012/SDL_mixer-WinRT80.vcxproj.filters index a4132621..73808f65 100644 --- a/VisualC-WinRT/WinRT80_VS2012/SDL_mixer-WinRT80.vcxproj.filters +++ b/VisualC-WinRT/WinRT80_VS2012/SDL_mixer-WinRT80.vcxproj.filters @@ -8,6 +8,7 @@ + @@ -55,6 +56,7 @@ + diff --git a/VisualC-WinRT/WinRT81_VS2013/SDL_mixer-WinRT81.vcxproj b/VisualC-WinRT/WinRT81_VS2013/SDL_mixer-WinRT81.vcxproj index 43df8e71..9bfcc0a6 100644 --- a/VisualC-WinRT/WinRT81_VS2013/SDL_mixer-WinRT81.vcxproj +++ b/VisualC-WinRT/WinRT81_VS2013/SDL_mixer-WinRT81.vcxproj @@ -49,6 +49,7 @@ + @@ -79,6 +80,7 @@ + diff --git a/VisualC-WinRT/WinRT81_VS2013/SDL_mixer-WinRT81.vcxproj.filters b/VisualC-WinRT/WinRT81_VS2013/SDL_mixer-WinRT81.vcxproj.filters index 4c100a44..a65033a3 100644 --- a/VisualC-WinRT/WinRT81_VS2013/SDL_mixer-WinRT81.vcxproj.filters +++ b/VisualC-WinRT/WinRT81_VS2013/SDL_mixer-WinRT81.vcxproj.filters @@ -8,6 +8,7 @@ + @@ -55,6 +56,7 @@ + diff --git a/VisualC/SDL_mixer.vcxproj b/VisualC/SDL_mixer.vcxproj index 44f859d4..3ad07f47 100644 --- a/VisualC/SDL_mixer.vcxproj +++ b/VisualC/SDL_mixer.vcxproj @@ -201,6 +201,7 @@ + @@ -457,6 +458,7 @@ + diff --git a/VisualC/SDL_mixer.vcxproj.filters b/VisualC/SDL_mixer.vcxproj.filters index 820bda48..ab47644a 100644 --- a/VisualC/SDL_mixer.vcxproj.filters +++ b/VisualC/SDL_mixer.vcxproj.filters @@ -22,6 +22,9 @@ Sources + + Sources + Sources @@ -194,6 +197,9 @@ Sources + + Sources + Sources diff --git a/Xcode-iOS/SDL_mixer.xcodeproj/project.pbxproj b/Xcode-iOS/SDL_mixer.xcodeproj/project.pbxproj index 7798452c..cc6b2eab 100644 --- a/Xcode-iOS/SDL_mixer.xcodeproj/project.pbxproj +++ b/Xcode-iOS/SDL_mixer.xcodeproj/project.pbxproj @@ -36,6 +36,10 @@ 639008DF2385A84C009019FA /* compat.h in Headers */ = {isa = PBXBuildFile; fileRef = 639008DD2385A84C009019FA /* compat.h */; }; 639008E02385A84C009019FA /* compat.c in Sources */ = {isa = PBXBuildFile; fileRef = 639008DC2385A84C009019FA /* compat.c */; }; 639008E12385A84C009019FA /* compat.h in Headers */ = {isa = PBXBuildFile; fileRef = 639008DD2385A84C009019FA /* compat.h */; }; + 6391980C239FE6AE00F1D8F8 /* mp3utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 6391980A239FE6AE00F1D8F8 /* mp3utils.c */; }; + 6391980D239FE6AE00F1D8F8 /* mp3utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 6391980B239FE6AE00F1D8F8 /* mp3utils.h */; }; + 6391980E239FE6AE00F1D8F8 /* mp3utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 6391980A239FE6AE00F1D8F8 /* mp3utils.c */; }; + 6391980F239FE6AE00F1D8F8 /* mp3utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 6391980B239FE6AE00F1D8F8 /* mp3utils.h */; }; AA1C71151F9BC66000A6BC31 /* effect_position.c in Sources */ = {isa = PBXBuildFile; fileRef = AA1C71131F9BC66000A6BC31 /* effect_position.c */; }; AA1C71161F9BC66000A6BC31 /* effect_stereoreverse.c in Sources */ = {isa = PBXBuildFile; fileRef = AA1C71141F9BC66000A6BC31 /* effect_stereoreverse.c */; }; AA1C71191F9BC67200A6BC31 /* effects_internal.h in Headers */ = {isa = PBXBuildFile; fileRef = AA1C71171F9BC67100A6BC31 /* effects_internal.h */; }; @@ -344,6 +348,8 @@ 1014BAEA010A4B677F000001 /* SDL_mixer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SDL_mixer.h; sourceTree = ""; }; 639008DC2385A84C009019FA /* compat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = compat.c; sourceTree = ""; }; 639008DD2385A84C009019FA /* compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = compat.h; sourceTree = ""; }; + 6391980A239FE6AE00F1D8F8 /* mp3utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mp3utils.c; sourceTree = ""; }; + 6391980B239FE6AE00F1D8F8 /* mp3utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mp3utils.h; sourceTree = ""; }; AA1C71131F9BC66000A6BC31 /* effect_position.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = effect_position.c; sourceTree = ""; }; AA1C71141F9BC66000A6BC31 /* effect_stereoreverse.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = effect_stereoreverse.c; sourceTree = ""; }; AA1C71171F9BC67100A6BC31 /* effects_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = effects_internal.h; sourceTree = ""; }; @@ -596,6 +602,8 @@ 63FD69EC23853AB000C3C961 /* codecs */ = { isa = PBXGroup; children = ( + 6391980A239FE6AE00F1D8F8 /* mp3utils.c */, + 6391980B239FE6AE00F1D8F8 /* mp3utils.h */, AAE406061F9609B900EDAF53 /* load_aiff.c */, AAE406181F9609BA00EDAF53 /* load_aiff.h */, AAE406141F9609BA00EDAF53 /* load_voc.c */, @@ -820,6 +828,7 @@ AA53147E1FE0FE2E0025C9BE /* tables.h in Headers */, AA53147F1FE0FE2E0025C9BE /* music_wav.h in Headers */, 639008E12385A84C009019FA /* compat.h in Headers */, + 6391980F239FE6AE00F1D8F8 /* mp3utils.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -873,6 +882,7 @@ AA60219617653A9800662B9C /* tables.h in Headers */, AAE406301F9609BD00EDAF53 /* music_wav.h in Headers */, 639008DF2385A84C009019FA /* compat.h in Headers */, + 6391980D239FE6AE00F1D8F8 /* mp3utils.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1120,6 +1130,7 @@ AA5314EA1FE0FE2E0025C9BE /* sndfile.cpp in Sources */, AA5314EB1FE0FE2E0025C9BE /* sndmix.cpp in Sources */, 639008E02385A84C009019FA /* compat.c in Sources */, + 6391980E239FE6AE00F1D8F8 /* mp3utils.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1234,6 +1245,7 @@ AA60219417653A9800662B9C /* sndfile.cpp in Sources */, AA60219517653A9800662B9C /* sndmix.cpp in Sources */, 639008DE2385A84C009019FA /* compat.c in Sources */, + 6391980C239FE6AE00F1D8F8 /* mp3utils.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Xcode/SDL_mixer.xcodeproj/project.pbxproj b/Xcode/SDL_mixer.xcodeproj/project.pbxproj index 9549c752..17fef862 100644 --- a/Xcode/SDL_mixer.xcodeproj/project.pbxproj +++ b/Xcode/SDL_mixer.xcodeproj/project.pbxproj @@ -13,6 +13,8 @@ 630FBD8520D5211F009867AB /* music_opus.h in Headers */ = {isa = PBXBuildFile; fileRef = 630FBD8420D5211F009867AB /* music_opus.h */; }; 639008C82385A822009019FA /* compat.c in Sources */ = {isa = PBXBuildFile; fileRef = 639008C62385A822009019FA /* compat.c */; }; 639008C92385A822009019FA /* compat.h in Headers */ = {isa = PBXBuildFile; fileRef = 639008C72385A822009019FA /* compat.h */; }; + 639197F1239FE66700F1D8F8 /* mp3utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 639197EF239FE66700F1D8F8 /* mp3utils.c */; }; + 639197F2239FE66700F1D8F8 /* mp3utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 639197F0239FE66700F1D8F8 /* mp3utils.h */; }; 63CD6ADC20D52DE20096FB34 /* Opus.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 630FBD7620D52063009867AB /* Opus.framework */; }; 63CD6ADD20D52DE90096FB34 /* OpusFile.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 630FBD7C20D5206E009867AB /* OpusFile.framework */; }; AA6021301765383B00662B9C /* modplug.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = AA60212F1765382200662B9C /* modplug.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; @@ -119,6 +121,8 @@ 630FBD8420D5211F009867AB /* music_opus.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = music_opus.h; sourceTree = ""; }; 639008C62385A822009019FA /* compat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = compat.c; sourceTree = ""; }; 639008C72385A822009019FA /* compat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = compat.h; sourceTree = ""; }; + 639197EF239FE66700F1D8F8 /* mp3utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mp3utils.c; sourceTree = ""; }; + 639197F0239FE66700F1D8F8 /* mp3utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mp3utils.h; sourceTree = ""; }; AA60212F1765382200662B9C /* modplug.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = modplug.framework; path = Frameworks/modplug.framework; sourceTree = ""; }; AA64428E175AA7A500A2125A /* mpg123.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = mpg123.framework; path = Frameworks/mpg123.framework; sourceTree = ""; }; AA6442D0175B181300A2125A /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; @@ -294,6 +298,8 @@ 6398B0BB238528360024EEA1 /* codecs */ = { isa = PBXGroup; children = ( + 639197EF239FE66700F1D8F8 /* mp3utils.c */, + 639197F0239FE66700F1D8F8 /* mp3utils.h */, AAE405DE1F9607C300EDAF53 /* music_cmd.c */, AAE405DB1F9607C200EDAF53 /* music_cmd.h */, AAE405D41F9607C100EDAF53 /* music_flac.c */, @@ -435,6 +441,7 @@ AAE405F51F9607C300EDAF53 /* music_ogg.h in Headers */, 630FBD8520D5211F009867AB /* music_opus.h in Headers */, 639008C92385A822009019FA /* compat.h in Headers */, + 639197F2239FE66700F1D8F8 /* mp3utils.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -638,6 +645,7 @@ 0448E8AE108B937A00C9D3EA /* native_midi_macosx.c in Sources */, 630FBD8320D52105009867AB /* music_opus.c in Sources */, 639008C82385A822009019FA /* compat.c in Sources */, + 639197F1239FE66700F1D8F8 /* mp3utils.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/src/codecs/mp3utils.c b/src/codecs/mp3utils.c new file mode 100644 index 00000000..a850d143 --- /dev/null +++ b/src/codecs/mp3utils.c @@ -0,0 +1,255 @@ +/* + SDL_mixer: An audio mixer library based on the SDL library + Copyright (C) 1997-2019 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#include "SDL_stdinc.h" +#include "SDL_rwops.h" + +#include "mp3utils.h" + +#if defined(MUSIC_MP3_MAD) /*|| defined(MUSIC_MP3_MPG123)*/ + +/*********************** SDL_RW WITH BOOKKEEPING ************************/ + +size_t MP3_RWread(struct mp3file_t *fil, void *ptr, size_t size, size_t maxnum) { + size_t remaining = (size_t)(fil->length - fil->pos); + size_t ret; + maxnum *= size; + if (maxnum > remaining) maxnum = remaining; + ret = SDL_RWread(fil->src, ptr, 1, maxnum); + fil->pos += (Sint64)ret; + return ret; +} + +Sint64 MP3_RWseek(struct mp3file_t *fil, Sint64 offset, int whence) { + Sint64 ret; + switch (whence) { /* assumes a legal whence value */ + case RW_SEEK_CUR: + offset += fil->pos; + break; + case RW_SEEK_END: + offset = fil->length + offset; + break; + } + if (offset < 0) return -1; + if (offset > fil->length) + offset = fil->length; + ret = SDL_RWseek(fil->src, fil->start + offset, RW_SEEK_SET); + if (ret < 0) return ret; + fil->pos = offset; + return (fil->pos - fil->start); +} + + +/*************************** TAG HANDLING: ******************************/ + +static SDL_INLINE SDL_bool is_id3v1(const unsigned char *data, size_t length) +{ + /* http://id3.org/ID3v1 : 3 bytes "TAG" identifier and 125 bytes tag data */ + if (length < 3 || SDL_memcmp(data,"TAG",3) != 0) { + return SDL_FALSE; + } + return SDL_TRUE; +} +static SDL_INLINE SDL_bool is_id3v2(const unsigned char *data, size_t length) +{ + /* ID3v2 header is 10 bytes: http://id3.org/id3v2.4.0-structure */ + /* bytes 0-2: "ID3" identifier */ + if (length < 10 || SDL_memcmp(data,"ID3",3) != 0) { + return SDL_FALSE; + } + /* bytes 3-4: version num (major,revision), each byte always less than 0xff. */ + if (data[3] == 0xff || data[4] == 0xff) { + return SDL_FALSE; + } + /* bytes 6-9 are the ID3v2 tag size: a 32 bit 'synchsafe' integer, i.e. the + * highest bit 7 in each byte zeroed. i.e.: 7 bit information in each byte -> + * effectively a 28 bit value. */ + if (data[6] >= 0x80 || data[7] >= 0x80 || data[8] >= 0x80 || data[9] >= 0x80) { + return SDL_FALSE; + } + return SDL_TRUE; +} +static SDL_INLINE long get_id3v2_len(const unsigned char *data, long length) +{ + /* size is a 'synchsafe' integer (see above) */ + long size = (long)((data[6]<<21) + (data[7]<<14) + (data[8]<<7) + data[9]); + size += 10; /* header size */ + /* ID3v2 header[5] is flags (bits 4-7 only, 0-3 are zero). + * bit 4 set: footer is present (a copy of the header but + * with "3DI" as ident.) */ + if (data[5] & 0x10) { + size += 10; /* footer size */ + } + /* optional padding (always zeroes) */ + while (size < length && data[size] == 0) { + ++size; + } + return size; +} +static SDL_INLINE SDL_bool is_apetag(const unsigned char *data, size_t length) +{ + /* http://wiki.hydrogenaud.io/index.php?title=APEv2_specification + * Header/footer is 32 bytes: bytes 0-7 ident, bytes 8-11 version, + * bytes 12-17 size. bytes 24-31 are reserved: must be all zeroes. */ + Uint32 v; + + if (length < 32 || SDL_memcmp(data,"APETAGEX",8) != 0) { + return SDL_FALSE; + } + v = (Uint32)((data[11]<<24) | (data[10]<<16) | (data[9]<<8) | data[8]); /* version */ + if (v != 2000U && v != 1000U) { + return SDL_FALSE; + } + v = 0; /* reserved bits : */ + if (SDL_memcmp(&data[24],&v,4) != 0 || SDL_memcmp(&data[28],&v,4) != 0) { + return SDL_FALSE; + } + return SDL_TRUE; +} +static SDL_INLINE long get_ape_len(const unsigned char *data) +{ + Uint32 flags, version; + long size = (long)((data[15]<<24) | (data[14]<<16) | (data[13]<<8) | data[12]); + version = (Uint32)((data[11]<<24) | (data[10]<<16) | (data[9]<<8) | data[8]); + flags = (Uint32)((data[23]<<24) | (data[22]<<16) | (data[21]<<8) | data[20]); + if (version == 2000U && (flags & (1U<<31))) size += 32; /* header present. */ + return size; +} +static SDL_INLINE int is_lyrics3tag(const unsigned char *data, long length) { + /* http://id3.org/Lyrics3 + * http://id3.org/Lyrics3v2 */ + if (length < 15) return 0; + if (SDL_memcmp(data+6,"LYRICS200",9) == 0) return 2; /* v2 */ + if (SDL_memcmp(data+6,"LYRICSEND",9) == 0) return 1; /* v1 */ + return 0; +} +static SDL_INLINE long get_lyrics3v1_len(struct mp3file_t *m) { + const char *p; long i, len; + char buf[5104]; + /* needs manual search: http://id3.org/Lyrics3 */ + if (m->length < 20) return -1; + len = (m->length > 5109)? 5109 : (long)m->length; + MP3_RWseek(m, -len, RW_SEEK_END); + MP3_RWread(m, buf, 1, (len -= 9)); /* exclude footer */ + MP3_RWseek(m, 0, RW_SEEK_SET); + /* strstr() won't work here. */ + for (i = len - 11, p = buf; i >= 0; --i, ++p) { + if (SDL_memcmp(p, "LYRICSBEGIN", 11) == 0) + break; + } + if (i < 0) return -1; + return len - (long)(p - buf) + 9 /* footer */; +} +static SDL_INLINE long get_lyrics3v2_len(const unsigned char *data, long length) { + /* 6 bytes before the end marker is size in decimal format - + * does not include the 9 bytes end marker and size field. */ + if (length != 6) return 0; + return SDL_strtol((const char *)data, NULL, 10) + 15; +} +static SDL_INLINE SDL_bool verify_lyrics3v2(const unsigned char *data, long length) { + if (length < 11) return SDL_FALSE; + if (SDL_memcmp(data,"LYRICSBEGIN",11) == 0) return SDL_TRUE; + return SDL_FALSE; +} + +int mp3_skiptags(struct mp3file_t *fil) +{ + unsigned char buf[128]; + long len; size_t readsize; + + readsize = MP3_RWread(fil, buf, 1, 128); + if (!readsize) return -1; + + /* ID3v2 tag is at the start */ + if (is_id3v2(buf, readsize)) { + len = get_id3v2_len(buf, (long)readsize); + if (len >= fil->length) return -1; + fil->start += len; + fil->length -= len; + MP3_RWseek(fil, 0, RW_SEEK_SET); + } + /* APE tag _might_ be at the start (discouraged + * but not forbidden, either.) read the header. */ + else if (is_apetag(buf, readsize)) { + len = get_ape_len(buf); + if (len >= fil->length) return -1; + fil->start += len; + fil->length -= len; + MP3_RWseek(fil, 0, RW_SEEK_SET); + } + + /* ID3v1 tag is at the end */ + if (fil->length < 128) goto ape; + MP3_RWseek(fil, -128, RW_SEEK_END); + readsize = MP3_RWread(fil, buf, 1, 128); + MP3_RWseek(fil, 0, RW_SEEK_SET); + if (readsize != 128) return -1; + if (is_id3v1(buf, 128)) { + fil->length -= 128; + + /* FIXME: handle possible double-ID3v1 tags?? */ + } + + /* do we know whether ape or lyrics3 is the first? + * well, we don't: we need to handle that later... */ + + ape: /* APE tag may be at the end: read the footer */ + if (fil->length >= 32) { + MP3_RWseek(fil, -32, RW_SEEK_END); + readsize = MP3_RWread(fil, buf, 1, 32); + MP3_RWseek(fil, 0, RW_SEEK_SET); + if (readsize != 32) return -1; + if (is_apetag(buf, 32)) { + len = get_ape_len(buf); + if (len >= fil->length) return -1; + fil->length -= len; + } + } + + if (fil->length >= 15) { + MP3_RWseek(fil, -15, RW_SEEK_END); + readsize = MP3_RWread(fil, buf, 1, 15); + MP3_RWseek(fil, 0, RW_SEEK_SET); + if (readsize != 15) return -1; + len = is_lyrics3tag(buf, 15); + if (len == 2) { + len = get_lyrics3v2_len(buf, 6); + if (len >= fil->length) return -1; + if (len < 15) return -1; + MP3_RWseek(fil, -len, RW_SEEK_END); + readsize = MP3_RWread(fil, buf, 1, 11); + MP3_RWseek(fil, 0, RW_SEEK_SET); + if (readsize != 11) return -1; + if (!verify_lyrics3v2(buf, 11)) return -1; + fil->length -= len; + } + else if (len == 1) { + len = get_lyrics3v1_len(fil); + if (len < 0) return -1; + fil->length -= len; + } + } + + return (fil->length > 0)? 0: -1; +} +#endif /* MUSIC_MP3_????? */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/codecs/mp3utils.h b/src/codecs/mp3utils.h new file mode 100644 index 00000000..0f8d7d7f --- /dev/null +++ b/src/codecs/mp3utils.h @@ -0,0 +1,36 @@ +/* + SDL_mixer: An audio mixer library based on the SDL library + Copyright (C) 1997-2019 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef MIX_MP3UTILS_H +#define MIX_MP3UTILS_H + +struct mp3file_t { + SDL_RWops *src; + Sint64 start, length, pos; +}; + +extern int mp3_skiptags(struct mp3file_t *fil); +extern size_t MP3_RWread(struct mp3file_t *fil, void *ptr, size_t size, size_t maxnum); +extern Sint64 MP3_RWseek(struct mp3file_t *fil, Sint64 offset, int whence); + +#endif /* MIX_MP3UTILS_H */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/codecs/music_mad.c b/src/codecs/music_mad.c index 69c25d14..e5c3cbea 100644 --- a/src/codecs/music_mad.c +++ b/src/codecs/music_mad.c @@ -22,6 +22,7 @@ #ifdef MUSIC_MP3_MAD #include "music_mad.h" +#include "mp3utils.h" #include "mad.h" @@ -136,9 +137,8 @@ enum { }; typedef struct { + struct mp3file_t mp3file; int play_count; - SDL_RWops *src; - Sint64 start, length, pos; int freesrc; struct mad_stream stream; struct mad_frame frame; @@ -152,38 +152,7 @@ typedef struct { } MAD_Music; -static size_t MAD_RWread(MAD_Music *music, void *ptr, size_t size, size_t maxnum) { - size_t remaining = (size_t)(music->length - music->pos); - size_t ret; - maxnum *= size; - if (maxnum > remaining) maxnum = remaining; - ret = SDL_RWread(music->src, ptr, 1, maxnum); - music->pos += (Sint64)ret; - return ret; -} - -static Sint64 MAD_RWseek(MAD_Music *music, Sint64 offset, int whence) { - Sint64 ret; - switch (whence) { /* assumes a legal whence value */ - case RW_SEEK_CUR: - offset += music->pos; - break; - case RW_SEEK_END: - offset = music->length + offset; - break; - } - if (offset < 0) return -1; - if (offset > music->length) - offset = music->length; - ret = SDL_RWseek(music->src, music->start + offset, RW_SEEK_SET); - if (ret < 0) return ret; - music->pos = offset; - return (music->pos - music->start); -} - - static int MAD_Seek(void *context, double position); -static int skip_tags(MAD_Music *music); static void *MAD_CreateFromRW(SDL_RWops *src, int freesrc) { @@ -194,11 +163,11 @@ static void *MAD_CreateFromRW(SDL_RWops *src, int freesrc) SDL_OutOfMemory(); return NULL; } - music->src = src; + music->mp3file.src = src; music->volume = MIX_MAX_VOLUME; - music->length = SDL_RWsize(src); - if (skip_tags(music) < 0) { + music->mp3file.length = SDL_RWsize(src); + if (mp3_skiptags(&music->mp3file) < 0) { SDL_free(music); Mix_SetError("music_mad: corrupt mp3 file."); return NULL; @@ -228,198 +197,6 @@ static int MAD_Play(void *context, int play_count) } -/*************************** TAG HANDLING: ******************************/ - -static SDL_INLINE SDL_bool is_id3v1(const unsigned char *data, size_t length) -{ - /* http://id3.org/ID3v1 : 3 bytes "TAG" identifier and 125 bytes tag data */ - if (length < 3 || SDL_memcmp(data,"TAG",3) != 0) { - return SDL_FALSE; - } - return SDL_TRUE; -} -static SDL_INLINE SDL_bool is_id3v2(const unsigned char *data, size_t length) -{ - /* ID3v2 header is 10 bytes: http://id3.org/id3v2.4.0-structure */ - /* bytes 0-2: "ID3" identifier */ - if (length < 10 || SDL_memcmp(data,"ID3",3) != 0) { - return SDL_FALSE; - } - /* bytes 3-4: version num (major,revision), each byte always less than 0xff. */ - if (data[3] == 0xff || data[4] == 0xff) { - return SDL_FALSE; - } - /* bytes 6-9 are the ID3v2 tag size: a 32 bit 'synchsafe' integer, i.e. the - * highest bit 7 in each byte zeroed. i.e.: 7 bit information in each byte -> - * effectively a 28 bit value. */ - if (data[6] >= 0x80 || data[7] >= 0x80 || data[8] >= 0x80 || data[9] >= 0x80) { - return SDL_FALSE; - } - return SDL_TRUE; -} -static SDL_INLINE long get_id3v2_len(const unsigned char *data, long length) -{ - /* size is a 'synchsafe' integer (see above) */ - long size = (long)((data[6]<<21) + (data[7]<<14) + (data[8]<<7) + data[9]); - size += 10; /* header size */ - /* ID3v2 header[5] is flags (bits 4-7 only, 0-3 are zero). - * bit 4 set: footer is present (a copy of the header but - * with "3DI" as ident.) */ - if (data[5] & 0x10) { - size += 10; /* footer size */ - } - /* optional padding (always zeroes) */ - while (size < length && data[size] == 0) { - ++size; - } - return size; -} -static SDL_INLINE SDL_bool is_apetag(const unsigned char *data, size_t length) -{ - /* http://wiki.hydrogenaud.io/index.php?title=APEv2_specification - * Header/footer is 32 bytes: bytes 0-7 ident, bytes 8-11 version, - * bytes 12-17 size. bytes 24-31 are reserved: must be all zeroes. */ - Uint32 v; - - if (length < 32 || SDL_memcmp(data,"APETAGEX",8) != 0) { - return SDL_FALSE; - } - v = (Uint32)((data[11]<<24) | (data[10]<<16) | (data[9]<<8) | data[8]); /* version */ - if (v != 2000U && v != 1000U) { - return SDL_FALSE; - } - v = 0; /* reserved bits : */ - if (SDL_memcmp(&data[24],&v,4) != 0 || SDL_memcmp(&data[28],&v,4) != 0) { - return SDL_FALSE; - } - return SDL_TRUE; -} -static SDL_INLINE long get_ape_len(const unsigned char *data) -{ - Uint32 flags, version; - long size = (long)((data[15]<<24) | (data[14]<<16) | (data[13]<<8) | data[12]); - version = (Uint32)((data[11]<<24) | (data[10]<<16) | (data[9]<<8) | data[8]); - flags = (Uint32)((data[23]<<24) | (data[22]<<16) | (data[21]<<8) | data[20]); - if (version == 2000U && (flags & (1U<<31))) size += 32; /* header present. */ - return size; -} -static SDL_INLINE int is_lyrics3tag(const unsigned char *data, long length) { - /* http://id3.org/Lyrics3 - * http://id3.org/Lyrics3v2 */ - if (length < 15) return 0; - if (SDL_memcmp(data+6,"LYRICS200",9) == 0) return 2; /* v2 */ - if (SDL_memcmp(data+6,"LYRICSEND",9) == 0) return 1; /* v1 */ - return 0; -} -static SDL_INLINE long get_lyrics3v1_len(MAD_Music *m) { - const char *p; long i, len; - /* needs manual search: http://id3.org/Lyrics3 */ - /* this relies on the input_buffer size >= 5100 */ - if (m->length < 20) return -1; - len = (m->length > 5109)? 5109 : (long)m->length; - MAD_RWseek(m, -len, RW_SEEK_END); - MAD_RWread(m, m->input_buffer, 1, (len -= 9)); /* exclude footer */ - MAD_RWseek(m, 0, RW_SEEK_SET); - /* strstr() won't work here. */ - for (i = len - 11, p = (const char*)m->input_buffer; i >= 0; --i, ++p) { - if (SDL_memcmp(p, "LYRICSBEGIN", 11) == 0) - break; - } - if (i < 0) return -1; - return len - (long)(p - (const char*)m->input_buffer) + 9 /* footer */; -} -static SDL_INLINE long get_lyrics3v2_len(const unsigned char *data, long length) { - /* 6 bytes before the end marker is size in decimal format - - * does not include the 9 bytes end marker and size field. */ - if (length != 6) return 0; - return SDL_strtol((const char *)data, NULL, 10) + 15; -} -static SDL_INLINE SDL_bool verify_lyrics3v2(const unsigned char *data, long length) { - if (length < 11) return SDL_FALSE; - if (SDL_memcmp(data,"LYRICSBEGIN",11) == 0) return SDL_TRUE; - return SDL_FALSE; -} - -static int skip_tags(MAD_Music *music) -{ - long len; size_t readsize; - - readsize = MAD_RWread(music, music->input_buffer, 1, MAD_INPUT_BUFFER_SIZE); - if (!readsize) return -1; - - /* ID3v2 tag is at the start */ - if (is_id3v2(music->input_buffer, readsize)) { - len = get_id3v2_len(music->input_buffer, (long)readsize); - if (len >= music->length) return -1; - music->start += len; - music->length -= len; - MAD_RWseek(music, 0, RW_SEEK_SET); - } - /* APE tag _might_ be at the start (discouraged - * but not forbidden, either.) read the header. */ - else if (is_apetag(music->input_buffer, readsize)) { - len = get_ape_len(music->input_buffer); - if (len >= music->length) return -1; - music->start += len; - music->length -= len; - MAD_RWseek(music, 0, RW_SEEK_SET); - } - - /* ID3v1 tag is at the end */ - if (music->length < 128) goto ape; - MAD_RWseek(music, -128, RW_SEEK_END); - readsize = MAD_RWread(music, music->input_buffer, 1, 128); - MAD_RWseek(music, 0, RW_SEEK_SET); - if (readsize != 128) return -1; - if (is_id3v1(music->input_buffer, 128)) { - music->length -= 128; - - /* FIXME: handle possible double-ID3v1 tags?? */ - } - - /* do we know whether ape or lyrics3 is the first? - * well, we don't: we need to handle that later... */ - - ape: /* APE tag may be at the end: read the footer */ - if (music->length >= 32) { - MAD_RWseek(music, -32, RW_SEEK_END); - readsize = MAD_RWread(music, music->input_buffer, 1, 32); - MAD_RWseek(music, 0, RW_SEEK_SET); - if (readsize != 32) return -1; - if (is_apetag(music->input_buffer, 32)) { - len = get_ape_len(music->input_buffer); - if (len >= music->length) return -1; - music->length -= len; - } - } - - if (music->length >= 15) { - MAD_RWseek(music, -15, RW_SEEK_END); - readsize = MAD_RWread(music, music->input_buffer, 1, 15); - MAD_RWseek(music, 0, RW_SEEK_SET); - if (readsize != 15) return -1; - len = is_lyrics3tag(music->input_buffer, 15); - if (len == 2) { - len = get_lyrics3v2_len(music->input_buffer, 6); - if (len >= music->length) return -1; - if (len < 15) return -1; - MAD_RWseek(music, -len, RW_SEEK_END); - readsize = MAD_RWread(music, music->input_buffer, 1, 11); - MAD_RWseek(music, 0, RW_SEEK_SET); - if (readsize != 11) return -1; - if (!verify_lyrics3v2(music->input_buffer, 11)) return -1; - music->length -= len; - } - else if (len == 1) { - len = get_lyrics3v1_len(music); - if (len < 0) return -1; - music->length -= len; - } - } - - return (music->length > 0)? 0: -1; -} - /* Reads the next frame from the file. Returns true on success or false on failure. */ @@ -447,7 +224,7 @@ static SDL_bool read_next_frame(MAD_Music *music) } /* Now read additional bytes from the input file. */ - read_size = MAD_RWread(music, read_start, 1, read_size); + read_size = MP3_RWread(&music->mp3file, read_start, 1, read_size); if (read_size == 0) { if ((music->status & (MS_input_eof | MS_input_error)) == 0) { @@ -596,6 +373,7 @@ static int MAD_GetSome(void *context, void *data, int bytes, SDL_bool *done) } return 0; } + static int MAD_GetAudio(void *context, void *data, int bytes) { MAD_Music *music = (MAD_Music *)context; @@ -621,7 +399,7 @@ static int MAD_Seek(void *context, double position) mad_timer_reset(&music->next_frame_start); music->status &= ~MS_error_flags; - MAD_RWseek(music, 0, RW_SEEK_SET); + MP3_RWseek(&music->mp3file, 0, RW_SEEK_SET); } /* Now we have to skip frames until we come to the right one. @@ -655,7 +433,7 @@ static void MAD_Delete(void *context) SDL_FreeAudioStream(music->audiostream); } if (music->freesrc) { - SDL_RWclose(music->src); + SDL_RWclose(music->mp3file.src); } SDL_free(music); }