wav gsm playback and encoding is broken because the wav.c patch to avoid
division by 0 introduced a regression. Debian has a fix for an older
version of sox from Helmut Grohne <helmut () subdivi ! de>. This patch
is from Steffen Nurpmeso <steffen () sdaoden ! eu> who applied it
against git. I added a tweak to not recalculate wave->numSamples for wav
gsm files, which is where division by 0 happens. Apparently, gsm has
variable bits_per_sample, so 0 is an acceptable value.

Steffen's diff: https://marc.info/?l=oss-security&m=167882517702862&w=2
tweak: https://marc.info/?l=oss-security&m=168026419507884&w=2

Test cases
----------
With this diff these two test cases pass.

Test case 1: convert /dev/null to bug.wav (wav gsm) and then convert
bug.wav to fail.wav.

This test case is expected to pass.

incorrect output:
--8<---------------cut here---------------start------------->8---
$ sox -t raw -r 44100 -e signed-integer -b 8 /dev/null -t wav -e gsm-full-rate \
bug.wav $ sox bug.wav fail.wav
sox FAIL formats: can't open input file `bug.wav': WAV file bits per sample is 
zero
--8<---------------cut here---------------end--------------->8---

correct output (which this provides):
--8<---------------cut here---------------start------------->8---
$ sox -t raw -r 44100 -e signed-integer -b 8 /dev/null -t wav -e gsm-full-rate \
bug.wav $ sox bug.wav fail.wav
$ file fail.wav
fail.wav: RIFF (little-endian) data, WAVE audio, GSM 6.10, mono 44100 Hz
--8<---------------cut here---------------end--------------->8---

Test case 2: convert flac to wav gsm. then, convert wav gsm to wav gsm.

This test case is expected to pass.
--8<---------------cut here---------------start------------->8---
$ sox -t flac -r 44100 -e signed-integer -b 16 song.flac -t wav -e 
gsm-full-rate \
ok.wav $ sox ok.wav ok2.wav
--8<---------------cut here---------------end--------------->8---

Feedback is welcome. OK?

Index: Makefile
===================================================================
RCS file: /cvs/ports/audio/sox/Makefile,v
retrieving revision 1.76
diff -u -p -u -p -r1.76 Makefile
--- Makefile    22 Feb 2023 16:27:38 -0000      1.76
+++ Makefile    3 Apr 2023 22:51:32 -0000
@@ -5,7 +5,7 @@ V=              14.4.2pl20210509
 GIT_V=         14.4.3git
 DISTNAME=      sox-${V}
 SHARED_LIBS += sox 4.1 # 3.0
-REVISION=      0
+REVISION=      1
 
 CATEGORIES=    audio
 HOMEPAGE=      http://sox.sourceforge.net/
Index: patches/patch-src_wav_c
===================================================================
RCS file: /cvs/ports/audio/sox/patches/patch-src_wav_c,v
retrieving revision 1.3
diff -u -p -u -p -r1.3 patch-src_wav_c
--- patches/patch-src_wav_c     22 Feb 2023 15:03:03 -0000      1.3
+++ patches/patch-src_wav_c     3 Apr 2023 22:51:32 -0000
@@ -1,14 +1,22 @@
 https://marc.info/?l=oss-security&m=167571683504082&w=2
 
+unbreak wav gsm
+see:
+https://marc.info/?l=oss-security&m=167882517702862&w=2
+https://marc.info/?l=oss-security&m=168026419507884&w=2
+
 Index: src/wav.c
 --- src/wav.c.orig
 +++ src/wav.c
-@@ -654,6 +654,12 @@ static int wav_read_fmt(sox_format_t *ft, uint32_t len
+@@ -654,6 +654,15 @@ static int wav_read_fmt(sox_format_t *ft, uint32_t len
      if (err)
          return SOX_EOF;
  
-+    if (wav->bitsPerSample == 0)
-+    {
++    if (wav->bitsPerSample == 0
++#ifdef HAVE_LIBGSM
++            && wav->formatTag != WAVE_FORMAT_GSM610
++#endif
++    ){
 +        lsx_fail_errno(ft, SOX_EHDR, "WAV file bits per sample is zero");
 +        return SOX_EOF;
 +    }
@@ -16,3 +24,68 @@ Index: src/wav.c
      /* non-PCM formats except alaw and mulaw formats have extended fmt chunk.
       * Check for those cases.
       */
+@@ -963,7 +972,11 @@ static int startread(sox_format_t *ft)
+ #endif
+     }
+ 
+-    if (!wav->numSamples)
++    if (!wav->numSamples
++#ifdef HAVE_LIBGSM
++            && wav->formatTag != WAVE_FORMAT_GSM610
++#endif
++    )
+         wav->numSamples = div_bits(qwDataLength, ft->encoding.bits_per_sample)
+             / ft->signal.channels;
+ 
+@@ -1348,8 +1361,10 @@ static int wavwritehdr(sox_format_t * ft, int second_h
+         (dwSamplesWritten + wSamplesPerBlock - 1) / wSamplesPerBlock;
+     dwDataLength = blocksWritten * wBlockAlign;
+ 
++#ifdef HAVE_LIBGSM
+     if (wFormatTag == WAVE_FORMAT_GSM610)
+         dwDataLength = (dwDataLength+1) & ~1u; /* round up to even */
++#endif
+ 
+     if (wFormatTag == WAVE_FORMAT_PCM && (wBitsPerSample > 16 || wChannels > 
2)
+         && strcmp(ft->filetype, "wavpcm")) {
+@@ -1444,9 +1459,11 @@ static int wavwritehdr(sox_format_t * ft, int second_h
+             lsx_writew(ft, (uint16_t)(lsx_ms_adpcm_i_coef[i][1]));
+         }
+         break;
++#ifdef HAVE_LIBGSM
+         case WAVE_FORMAT_GSM610:
+         lsx_writew(ft, wSamplesPerBlock);
+         break;
++#endif
+         default:
+         break;
+     }
+@@ -1554,7 +1571,9 @@ static int stopwrite(sox_format_t * ft)
+ 
+         /* Add a pad byte if the number of data bytes is odd.
+            See wavwritehdr() above for the calculation. */
++#ifdef HAVE_LIBGSM
+         if (wav->formatTag != WAVE_FORMAT_GSM610)
++#endif
+           lsx_padbytes(ft, (size_t)((wav->numSamples + wav->samplesPerBlock - 
1)/wav->samplesPerBlock*wav->blockAlign) % 2);
+ 
+         free(wav->packet);
+@@ -1594,6 +1613,7 @@ static int seek(sox_format_t * ft, uint64_t offset)
+ 
+   if (ft->encoding.bits_per_sample & 7)
+     lsx_fail_errno(ft, SOX_ENOTSUP, "seeking not supported with this 
encoding");
++#ifdef HAVE_LIBGSM
+   else if (wav->formatTag == WAVE_FORMAT_GSM610) {
+     int alignment;
+     size_t gsmoff;
+@@ -1613,7 +1633,9 @@ static int seek(sox_format_t * ft, uint64_t offset)
+           new_offset += (wav->samplesPerBlock - alignment);
+       wav->numSamples = ft->signal.length - (new_offset / 
ft->signal.channels);
+     }
+-  } else {
++  }
++#endif /* HAVE_LIBGSM */
++  else {
+     double wide_sample = offset - (offset % ft->signal.channels);
+     double to_d = wide_sample * ft->encoding.bits_per_sample / 8;
+     off_t to = to_d;

Reply via email to