Skip to content

Commit

Permalink
music_ogg.c: revise parsing loop info
Browse files Browse the repository at this point in the history
According to Vitaly Novichkov [1], there are broken vorbis files in the
wild which has bad looping info with leading and/or trailing non-digits
that fool strtoull() [2] [3].  Therefore, strip those non-digits before
feeding to SDL_strtoull.  Based on code from SDL_mixer-X fork by Vitaly
Novichkov [1].

[1] WohlSoft/SDL-Mixer-X@a67d8fd#comments
[2] https://github.com/WohlSoft/SDL-Mixer-X/files/3808096/Not.So.Heavenly.Boss.Battle.ogg.zip
[3] https://github.com/WohlSoft/SDL-Mixer-X/files/3808099/Not.So.Heavenly.Preparation.Room.ogg.zip
  • Loading branch information
sezero committed Nov 10, 2019
1 parent 50432fd commit c5df1d5
Showing 1 changed file with 27 additions and 12 deletions.
39 changes: 27 additions & 12 deletions music_ogg.c
Expand Up @@ -223,6 +223,25 @@ static int OGG_UpdateSection(OGG_music *music)
return 0;
}

/* Convert string into integer with clean-up from junk and leading zeroes */
static ogg_int64_t str_to_int64(char *param)
{
char *front = param;
char *back;

/* Find digit between of 1 and 9 at begin */
while (*front != '\0' && (*front < '1' || *front > '9')) {
front++;
}
/* Find any non-digit character or NULL */
back = front;
while (*back != '\0' && (*back >= '0' && *back <= '9')) {
back++;
}
*back = '\0';
return (ogg_int64_t)SDL_strtoull(front, NULL, 0);
}

/* Parse time string of the form HH:MM:SS.mmm and return equivalent sample
* position */
static ogg_int64_t parse_time(char *time, long samplerate_hz)
Expand All @@ -231,29 +250,25 @@ static ogg_int64_t parse_time(char *time, long samplerate_hz)
ogg_int64_t result = 0;
char c;

// Time is directly expressed as a sample position
if (SDL_strchr(time, ':') == NULL)
{
return SDL_strtoull(time, NULL, 0);
/* Time is directly expressed as a sample position */
if (SDL_strchr(time, ':') == NULL) {
return str_to_int64(time);
}

result = 0;
num_start = time;

for (p = time; *p != '\0'; ++p)
{
if (*p == '.' || *p == ':')
{
for (p = time; *p != '\0'; ++p) {
if (*p == '.' || *p == ':') {
c = *p; *p = '\0';
result = result * 60 + SDL_atoi(num_start);
num_start = p + 1;
*p = c;
}

if (*p == '.')
{
if (*p == '.') {
return result * samplerate_hz
+ (ogg_int64_t) (SDL_atof(p) * samplerate_hz);
+ (ogg_int64_t) (SDL_atof(p) * samplerate_hz);
}
}

Expand Down Expand Up @@ -321,7 +336,7 @@ static void *OGG_CreateFromRW(SDL_RWops *src, int freesrc)
if (SDL_strcasecmp(argument, "LOOPSTART") == 0)
music->loop_start = parse_time(value, rate);
else if (SDL_strcasecmp(argument, "LOOPLENGTH") == 0) {
music->loop_len = SDL_strtoull(value, NULL, 0);
music->loop_len = str_to_int64(value);
isLoopLength = 1;
} else if (SDL_strcasecmp(argument, "LOOPEND") == 0) {
isLoopLength = 0;
Expand Down

0 comments on commit c5df1d5

Please sign in to comment.