From bdadaa0371ed8f7c4b4783cb67e3925310882acb Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Tue, 19 May 2026 10:32:38 -0400
Subject: [PATCH] vorbis: Explicitly reject .XM files.
Otherwise .oxm files (XM mod files with Ogg Vorbis-compressed samples) might
get incorrectly claimed by the Vorbis decoder. Since libvorbis reads into the
file a little looking for the "OggS" magic--in case we came in mid-stream and
it can find a starting point to anchor to--it might catch the first Vorbis
sample's magic and think the whole file is Ogg Vorbis.
Our stb_vorbis decoder is more aggressive, and will reject anything that
doesn't start with a valid Ogg Vorbis header, but letting the actual libvorbis
decoder be more "robust" seems reasonable for now, so we're checking for this
special case where it's _too_ eager to make things work.
Fixes #834.
---
src/decoder_vorbis.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/src/decoder_vorbis.c b/src/decoder_vorbis.c
index 9f764a89..b622c38f 100644
--- a/src/decoder_vorbis.c
+++ b/src/decoder_vorbis.c
@@ -159,8 +159,20 @@ static const ov_callbacks VORBIS_IoCallbacks = { VORBIS_IoRead, VORBIS_IoSeek, V
static bool SDLCALL VORBIS_init_audio(SDL_IOStream *io, SDL_AudioSpec *spec, SDL_PropertiesID props, Sint64 *duration_frames, void **audio_userdata)
{
+ Uint8 buffer[17];
+ if (SDL_ReadIO(io, buffer, sizeof (buffer)) != sizeof (buffer)) {
+ return false;
+ } else if (SDL_memcmp(buffer, "Extended Module: ", 17) == 0) { // this is an XM file that _might_ be OXM and we would incorrectly claim it. Drop out now.
+ return SDL_SetError("Not an Ogg Vorbis audio stream");
+ }
+
+ // Go back and let ov_test_callbacks() take a run at it, too.
+ if (SDL_SeekIO(io, 0, SDL_IO_SEEK_SET) < 0) {
+ return false;
+ }
+
// just load the bare minimum from the IOStream to verify it's an Ogg Vorbis file.
- // !!! FIXME: is ov_open_callbacks going to return more slowly if this isn't an Opus file? It's probably better to just do the full open.
+ // !!! FIXME: is ov_open_callbacks going to return more slowly if this isn't a Vorbis file? It's probably better to just do the full open.
OggVorbis_File vf;
if (vorbis.ov_test_callbacks(io, &vf, NULL, 0, VORBIS_IoCallbacks) < 0) {
return SDL_SetError("Not an Ogg Vorbis audio stream");