Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package chromaprint for openSUSE:Factory 
checked in at 2026-10-16 20:07:06
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/chromaprint (Old)
 and      /work/SRC/openSUSE:Factory/.chromaprint.new.3698736 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "chromaprint"

Fri Oct 16 20:07:06 2026 rev:30 rq:1385138 version:1.6.2

Changes:
--------
--- /work/SRC/openSUSE:Factory/chromaprint/chromaprint.changes  2026-10-15 
18:20:22.366014150 +0200
+++ /work/SRC/openSUSE:Factory/.chromaprint.new.3698736/chromaprint.changes     
2026-10-16 20:07:23.464380668 +0200
@@ -1,0 +2,13 @@
+Fri Oct 16 06:30:22 UTC 2026 - Bjørn Lie <[email protected]>
+
+- Update to version 1.6.2:
+  * Fixed a crash in fpcalc when the channel layout changes mid-stream
+    (e.g. AC-3 files switching between 5.1 and stereo)
+  * Fixed decoding of audio with more than 8 planar channels in fpcalc
+  * Fingerprint decoding now rejects invalid input that previously caused
+    undefined behaviour (shifting past 32 bits)
+  * The C API encoding/decoding functions now return an error for a negative
+    size, a NULL buffer with a nonzero size, and, when encoding, more items
+    than the fingerprint header can hold (previously silently truncated)
+
+-------------------------------------------------------------------

Old:
----
  chromaprint-1.6.1.tar.gz

New:
----
  chromaprint-1.6.2.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ chromaprint.spec ++++++
--- /var/tmp/diff_new_pack.u2r3rR/_old  2026-10-16 20:07:24.279414724 +0200
+++ /var/tmp/diff_new_pack.u2r3rR/_new  2026-10-16 20:07:24.282414849 +0200
@@ -20,7 +20,7 @@
 %define rev aa67c95b9e486884a6d3ee8b0c91207d8c2b0551
 %define sover      1
 Name:           chromaprint
-Version:        1.6.1
+Version:        1.6.2
 Release:        0
 Summary:        Audio Fingerprinting Library
 License:        LGPL-2.1-only AND MIT

++++++ chromaprint-1.6.1.tar.gz -> chromaprint-1.6.2.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/chromaprint-1.6.1/CMakeLists.txt 
new/chromaprint-1.6.2/CMakeLists.txt
--- old/chromaprint-1.6.1/CMakeLists.txt        2026-07-28 08:12:40.000000000 
+0200
+++ new/chromaprint-1.6.2/CMakeLists.txt        2026-10-15 11:56:52.000000000 
+0200
@@ -2,7 +2,7 @@
 
 set(chromaprint_VERSION_MAJOR 1)
 set(chromaprint_VERSION_MINOR 6)
-set(chromaprint_VERSION_PATCH 1)
+set(chromaprint_VERSION_PATCH 2)
 set(chromaprint_VERSION 
"${chromaprint_VERSION_MAJOR}.${chromaprint_VERSION_MINOR}.${chromaprint_VERSION_PATCH}")
 
 project(chromaprint LANGUAGES C CXX VERSION "${chromaprint_VERSION}")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/chromaprint-1.6.1/NEWS.txt 
new/chromaprint-1.6.2/NEWS.txt
--- old/chromaprint-1.6.1/NEWS.txt      2026-07-28 08:12:40.000000000 +0200
+++ new/chromaprint-1.6.2/NEWS.txt      2026-10-15 11:56:52.000000000 +0200
@@ -1,3 +1,15 @@
+Version 1.6.2 -- October 15, 2026
+=================================
+
+ - Fixed a crash in fpcalc when the channel layout changes mid-stream
+   (e.g. AC-3 files switching between 5.1 and stereo)
+ - Fixed decoding of audio with more than 8 planar channels in fpcalc
+ - Fingerprint decoding now rejects invalid input that previously caused
+   undefined behaviour (shifting past 32 bits)
+ - The C API encoding/decoding functions now return an error for a negative
+   size, a NULL buffer with a nonzero size, and, when encoding, more items
+   than the fingerprint header can hold (previously silently truncated)
+
 Version 1.6.1 -- July 28, 2026
 ==============================
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/chromaprint-1.6.1/src/audio/ffmpeg_audio_reader.h 
new/chromaprint-1.6.2/src/audio/ffmpeg_audio_reader.h
--- old/chromaprint-1.6.1/src/audio/ffmpeg_audio_reader.h       2026-07-28 
08:12:40.000000000 +0200
+++ new/chromaprint-1.6.2/src/audio/ffmpeg_audio_reader.h       2026-10-15 
11:56:52.000000000 +0200
@@ -70,8 +70,18 @@
 
 private:
        inline void SetError(const char *format, int errnum = 0);
+       inline bool ConverterMatchesFrame(const AVFrame *frame) const;
+       inline int ResetConverter(const AVFrame *frame);
+       inline bool EnsureConvertBuffer(int nb_samples);
 
        std::unique_ptr<FFmpegAudioProcessor> m_converter;
+#if CHROMAPRINT_HAVE_AV_CHANNEL_LAYOUT
+       AVChannelLayout m_converter_channel_layout = {};
+#else
+       uint64_t m_converter_channel_layout = 0;
+#endif
+       int m_converter_sample_format = AV_SAMPLE_FMT_NONE;
+       int m_converter_sample_rate = 0;
        uint8_t *m_convert_buffer[1] = { nullptr };
        int m_convert_buffer_nb_samples = 0;
 
@@ -104,6 +114,9 @@
        Close();
        av_dict_free(&m_input_opts);
        av_freep(&m_convert_buffer[0]);
+#if CHROMAPRINT_HAVE_AV_CHANNEL_LAYOUT
+       av_channel_layout_uninit(&m_converter_channel_layout);
+#endif
 }
 
 inline bool FFmpegAudioReader::SetInputFormat(const char *name) {
@@ -191,48 +204,13 @@
                m_output_sample_rate = m_codec_ctx->sample_rate;
        }
 
-#if CHROMAPRINT_HAVE_AV_CHANNEL_LAYOUT
-       AVChannelLayout output_channel_layout;
        if (!m_output_channels) {
                m_output_channels = CHROMAPRINT_CODEC_CHANNELS(m_codec_ctx);
        }
-       av_channel_layout_default(&output_channel_layout, m_output_channels);
-#else
-       if (!m_output_channels) {
-               m_output_channels = CHROMAPRINT_CODEC_CHANNELS(m_codec_ctx);
-       }
-       uint64_t output_channel_layout = 
av_get_default_channel_layout(m_output_channels);
-#endif
 
-       if (m_codec_ctx->sample_fmt != AV_SAMPLE_FMT_S16 || 
CHROMAPRINT_CODEC_CHANNELS(m_codec_ctx) != m_output_channels || 
m_codec_ctx->sample_rate != m_output_sample_rate) {
-               m_converter.reset(new FFmpegAudioProcessor());
-               m_converter->SetCompatibleMode();
-               m_converter->SetInputSampleFormat(m_codec_ctx->sample_fmt);
-               m_converter->SetInputSampleRate(m_codec_ctx->sample_rate);
-#if CHROMAPRINT_HAVE_AV_CHANNEL_LAYOUT
-               m_converter->SetInputChannelLayout(&(m_codec_ctx->ch_layout));
-#else
-               m_converter->SetInputChannelLayout(m_codec_ctx->channel_layout
-                       ? m_codec_ctx->channel_layout
-                       : av_get_default_channel_layout(m_codec_ctx->channels));
-#endif
-               m_converter->SetOutputSampleFormat(AV_SAMPLE_FMT_S16);
-               m_converter->SetOutputSampleRate(m_output_sample_rate);
-#if CHROMAPRINT_HAVE_AV_CHANNEL_LAYOUT
-               m_converter->SetOutputChannelLayout(&output_channel_layout);
-#else
-               m_converter->SetOutputChannelLayout(output_channel_layout);
-#endif
-               auto ret = m_converter->Init();
-               if (ret != 0) {
-                       SetError("Could not create an audio converter 
instance", ret);
-                       return false;
-               }
-       }
-
-#if CHROMAPRINT_HAVE_AV_CHANNEL_LAYOUT
-       av_channel_layout_uninit(&output_channel_layout);
-#endif
+       // The converter is set up in Read() from the decoded frames, because
+       // some decoders (e.g. AC-3) change the channel layout mid-stream.
+       m_converter.reset();
 
        m_opened = true;
        m_has_more_packets = true;
@@ -334,24 +312,38 @@
                }
 
                if (m_frame->nb_samples > 0) {
-                       if (m_converter) {
-                               if (m_frame->nb_samples > 
m_convert_buffer_nb_samples) {
-                                       int linsize;
-                                       av_freep(&m_convert_buffer[0]);
-                                       m_convert_buffer_nb_samples = 
std::max(1024 * 8, m_frame->nb_samples);
-                                       ret = 
av_samples_alloc(m_convert_buffer, &linsize, 
CHROMAPRINT_CODEC_CHANNELS(m_codec_ctx), m_convert_buffer_nb_samples, 
AV_SAMPLE_FMT_S16, 1);
-                                       if (ret < 0) {
-                                               SetError("Couldn't allocate 
audio converter buffer", ret);
+                       int nb_flushed = 0;
+                       if (!ConverterMatchesFrame(m_frame)) {
+                               if (!EnsureConvertBuffer(m_frame->nb_samples)) {
+                                       return false;
+                               }
+                               // The input format changed, drain what the old 
converter still
+                               // holds before replacing it.
+                               if (m_converter) {
+                                       nb_flushed = 
m_converter->Flush(m_convert_buffer, m_convert_buffer_nb_samples);
+                                       if (nb_flushed < 0) {
+                                               SetError("Couldn't convert 
audio", nb_flushed);
                                                return false;
                                        }
                                }
-                               auto nb_samples = 
m_converter->Convert(m_convert_buffer, m_convert_buffer_nb_samples, (const 
uint8_t **) m_frame->data, m_frame->nb_samples);
+                               ret = ResetConverter(m_frame);
+                               if (ret < 0) {
+                                       SetError("Could not create an audio 
converter instance", ret);
+                                       return false;
+                               }
+                       }
+                       if (m_converter) {
+                               if (!EnsureConvertBuffer(m_frame->nb_samples)) {
+                                       return false;
+                               }
+                               uint8_t *out[1] = { m_convert_buffer[0] + 
nb_flushed * m_output_channels * sizeof(int16_t) };
+                               auto nb_samples = m_converter->Convert(out, 
m_convert_buffer_nb_samples - nb_flushed, (const uint8_t **) 
m_frame->extended_data, m_frame->nb_samples);
                                if (nb_samples < 0) {
-                                       SetError("Couldn't convert audio", ret);
+                                       SetError("Couldn't convert audio", 
nb_samples);
                                        return false;
                                }
                                *data = (const int16_t *) m_convert_buffer[0];
-                               *size = nb_samples;
+                               *size = nb_flushed + nb_samples;
                        } else {
                                *data = (const int16_t *) m_frame->data[0];
                                *size = m_frame->nb_samples;
@@ -375,6 +367,84 @@
        }
 }
 
+inline bool FFmpegAudioReader::EnsureConvertBuffer(int nb_samples) {
+       // Leave room for samples flushed from a previous converter and for 
upsampling.
+       nb_samples = std::max(1024 * 8, nb_samples * 4);
+       if (nb_samples > m_convert_buffer_nb_samples) {
+               int linesize;
+               av_freep(&m_convert_buffer[0]);
+               m_convert_buffer_nb_samples = 0;
+               int ret = av_samples_alloc(m_convert_buffer, &linesize, 
m_output_channels, nb_samples, AV_SAMPLE_FMT_S16, 1);
+               if (ret < 0) {
+                       SetError("Couldn't allocate audio converter buffer", 
ret);
+                       return false;
+               }
+               m_convert_buffer_nb_samples = nb_samples;
+       }
+       return true;
+}
+
+inline bool FFmpegAudioReader::ConverterMatchesFrame(const AVFrame *frame) 
const {
+       if (!m_converter) {
+               return frame->format == AV_SAMPLE_FMT_S16 &&
+                       frame->sample_rate == m_output_sample_rate &&
+                       CHROMAPRINT_FRAME_CHANNELS(frame) == m_output_channels;
+       }
+       if (frame->format != m_converter_sample_format || frame->sample_rate != 
m_converter_sample_rate) {
+               return false;
+       }
+#if CHROMAPRINT_HAVE_AV_CHANNEL_LAYOUT
+       return av_channel_layout_compare(&frame->ch_layout, 
&m_converter_channel_layout) == 0;
+#else
+       return (frame->channel_layout ? frame->channel_layout : 
av_get_default_channel_layout(frame->channels)) == m_converter_channel_layout;
+#endif
+}
+
+inline int FFmpegAudioReader::ResetConverter(const AVFrame *frame) {
+       int ret;
+
+       m_converter.reset();
+       m_converter_sample_format = frame->format;
+       m_converter_sample_rate = frame->sample_rate;
+#if CHROMAPRINT_HAVE_AV_CHANNEL_LAYOUT
+       ret = av_channel_layout_copy(&m_converter_channel_layout, 
&frame->ch_layout);
+       if (ret < 0) {
+               return ret;
+       }
+       AVChannelLayout output_channel_layout;
+       av_channel_layout_default(&output_channel_layout, m_output_channels);
+#else
+       m_converter_channel_layout = frame->channel_layout
+               ? frame->channel_layout
+               : av_get_default_channel_layout(frame->channels);
+       uint64_t output_channel_layout = 
av_get_default_channel_layout(m_output_channels);
+#endif
+
+       m_converter.reset(new FFmpegAudioProcessor());
+       m_converter->SetCompatibleMode();
+       m_converter->SetInputSampleFormat((AVSampleFormat) frame->format);
+       m_converter->SetInputSampleRate(frame->sample_rate);
+#if CHROMAPRINT_HAVE_AV_CHANNEL_LAYOUT
+       m_converter->SetInputChannelLayout(&m_converter_channel_layout);
+       m_converter->SetOutputChannelLayout(&output_channel_layout);
+#else
+       m_converter->SetInputChannelLayout(m_converter_channel_layout);
+       m_converter->SetOutputChannelLayout(output_channel_layout);
+#endif
+       m_converter->SetOutputSampleFormat(AV_SAMPLE_FMT_S16);
+       m_converter->SetOutputSampleRate(m_output_sample_rate);
+
+#if CHROMAPRINT_HAVE_AV_CHANNEL_LAYOUT
+       av_channel_layout_uninit(&output_channel_layout);
+#endif
+
+       ret = m_converter->Init();
+       if (ret < 0) {
+               m_converter.reset();
+       }
+       return ret;
+}
+
 inline void FFmpegAudioReader::SetError(const char *message, int errnum) {
        m_error = message;
        if (errnum < 0) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/chromaprint-1.6.1/src/audio/ffmpeg_audio_reader_test.cpp 
new/chromaprint-1.6.2/src/audio/ffmpeg_audio_reader_test.cpp
--- old/chromaprint-1.6.1/src/audio/ffmpeg_audio_reader_test.cpp        
2026-07-28 08:12:40.000000000 +0200
+++ new/chromaprint-1.6.2/src/audio/ffmpeg_audio_reader_test.cpp        
2026-10-15 11:56:52.000000000 +0200
@@ -25,8 +25,33 @@
        }
 
 /*     ASSERT_TRUE(reader.ReadAll([&](const int16_t *data, size_t size) {
-               
+
        }));*/
 }
 
+TEST(FFmpegAudioReaderTest, ReadChannelLayoutChange) {
+       FFmpegAudioReader reader;
+
+       reader.SetOutputChannels(2);
+       reader.SetOutputSampleRate(11025);
+
+       // 5.1 AC-3 stream with a few stereo frames in the middle
+       ASSERT_TRUE(reader.Open(TESTS_DIR "/data/test_51_stereo_switch.ac3")) 
<< reader.GetError();
+       ASSERT_TRUE(reader.IsOpen());
+
+       ASSERT_EQ(2, reader.GetChannels());
+       ASSERT_EQ(11025, reader.GetSampleRate());
+
+       const int16_t *data;
+       size_t size;
+       size_t total_size = 0;
+       while (reader.Read(&data, &size)) {
+               total_size += size;
+       }
+       ASSERT_TRUE(reader.IsFinished()) << reader.GetError();
+
+       // 15 frames of 1536 samples at 44100 Hz
+       ASSERT_NEAR(15 * 1536 * 11025 / 44100, total_size, 100);
+}
+
 }; // namespace chromaprint
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/chromaprint-1.6.1/src/audio/ffmpeg_compat.h 
new/chromaprint-1.6.2/src/audio/ffmpeg_compat.h
--- old/chromaprint-1.6.1/src/audio/ffmpeg_compat.h     2026-07-28 
08:12:40.000000000 +0200
+++ new/chromaprint-1.6.2/src/audio/ffmpeg_compat.h     2026-10-15 
11:56:52.000000000 +0200
@@ -21,8 +21,10 @@
 
 #if CHROMAPRINT_HAVE_AV_CHANNEL_LAYOUT
 #define CHROMAPRINT_CODEC_CHANNELS(ctx) ((ctx)->ch_layout.nb_channels)
+#define CHROMAPRINT_FRAME_CHANNELS(frame) ((frame)->ch_layout.nb_channels)
 #else
 #define CHROMAPRINT_CODEC_CHANNELS(ctx) ((ctx)->channels)
+#define CHROMAPRINT_FRAME_CHANNELS(frame) ((frame)->channels)
 #endif
 
 // avformat_open_input() and av_find_best_stream() took non-const AVInputFormat
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/chromaprint-1.6.1/src/chromaprint.cpp 
new/chromaprint-1.6.2/src/chromaprint.cpp
--- old/chromaprint-1.6.1/src/chromaprint.cpp   2026-07-28 08:12:40.000000000 
+0200
+++ new/chromaprint-1.6.2/src/chromaprint.cpp   2026-10-15 11:56:52.000000000 
+0200
@@ -172,6 +172,10 @@
 
 int chromaprint_encode_fingerprint(const uint32_t *fp, int size, int 
algorithm, char **encoded_fp, int *encoded_size, int base64)
 {
+       // The encoded header stores the size in 24 bits.
+       if ((fp == NULL && size != 0) || size < 0 || size > 0xFFFFFF || 
encoded_fp == NULL || encoded_size == NULL) {
+               return 0;
+       }
        std::vector<uint32_t> uncompressed(fp, fp + size);
        std::string encoded = CompressFingerprint(uncompressed, algorithm);
        if (base64) {
@@ -185,13 +189,19 @@
 
 int chromaprint_decode_fingerprint(const char *encoded_fp, int encoded_size, 
uint32_t **fp, int *size, int *algorithm, int base64)
 {
-       std::string encoded(encoded_fp, encoded_size);
-       if (base64) {
-               encoded = Base64Decode(encoded);
+       if (fp == NULL || size == NULL) {
+               return 0;
        }
        std::vector<uint32_t> uncompressed;
        int algo;
-       auto ok = DecompressFingerprint(encoded, uncompressed, algo);
+       bool ok = false;
+       if (encoded_size >= 0 && (encoded_fp != NULL || encoded_size == 0)) {
+               std::string encoded(encoded_fp, encoded_size);
+               if (base64) {
+                       encoded = Base64Decode(encoded);
+               }
+               ok = DecompressFingerprint(encoded, uncompressed, algo);
+       }
        if (!ok) {
                *fp = nullptr;
                *size = 0;
@@ -211,13 +221,16 @@
 
 int chromaprint_decode_fingerprint_header(const char *encoded_fp, int 
encoded_size, int *size, int *algorithm, int base64)
 {
-       std::string encoded(encoded_fp, std::min(6, encoded_size));
-       if (base64) {
-               encoded = Base64Decode(encoded);
-       }
        size_t size_out;
        int algorithm_out;
-       auto ok = DecompressFingerprintHeader(encoded, size_out, algorithm_out);
+       bool ok = false;
+       if (encoded_size >= 0 && (encoded_fp != NULL || encoded_size == 0)) {
+               std::string encoded(encoded_fp, std::min(6, encoded_size));
+               if (base64) {
+                       encoded = Base64Decode(encoded);
+               }
+               ok = DecompressFingerprintHeader(encoded, size_out, 
algorithm_out);
+       }
        if (!ok) {
                if (size) {
                        *size = 0;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/chromaprint-1.6.1/src/chromaprint.h 
new/chromaprint-1.6.2/src/chromaprint.h
--- old/chromaprint-1.6.1/src/chromaprint.h     2026-07-28 08:12:40.000000000 
+0200
+++ new/chromaprint-1.6.2/src/chromaprint.h     2026-10-15 11:56:52.000000000 
+0200
@@ -84,7 +84,7 @@
 
 #define CHROMAPRINT_VERSION_MAJOR 1
 #define CHROMAPRINT_VERSION_MINOR 6
-#define CHROMAPRINT_VERSION_PATCH 1
+#define CHROMAPRINT_VERSION_PATCH 2
 
 enum ChromaprintAlgorithm {
        CHROMAPRINT_ALGORITHM_TEST1 = 0,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/chromaprint-1.6.1/src/fingerprint_decompressor.cpp 
new/chromaprint-1.6.2/src/fingerprint_decompressor.cpp
--- old/chromaprint-1.6.1/src/fingerprint_decompressor.cpp      2026-07-28 
08:12:40.000000000 +0200
+++ new/chromaprint-1.6.2/src/fingerprint_decompressor.cpp      2026-10-15 
11:56:52.000000000 +0200
@@ -19,7 +19,7 @@
 {
 }
 
-void FingerprintDecompressor::UnpackBits()
+bool FingerprintDecompressor::UnpackBits()
 {
        int i = 0, last_bit = 0;
     uint32_t value = 0;
@@ -31,9 +31,14 @@
                        i++;
                } else {
                        last_bit += bit;
-                       value ^= 1 << (last_bit - 1);
+                       if (last_bit > 32) {
+                               DEBUG("FingerprintDecompressor::Decompress() -- 
Invalid fingerprint (bit position past 32)");
+                               return false;
+                       }
+                       value ^= uint32_t(1) << (last_bit - 1);
                }
        }
+       return true;
 }
 
 bool FingerprintDecompressor::DecompressHeader(const std::string &input)
@@ -60,6 +65,13 @@
                return false;
        }
 
+       if (m_size == 0) {
+               // An empty fingerprint has no body, so anything after the 
header is
+               // trailing data, ignored like trailing data after any 
fingerprint.
+               m_output.clear();
+               return true;
+       }
+
        size_t offset = 4;
        m_bits.resize(GetUnpackedInt3ArraySize(input.size() - offset));
        UnpackInt3Array(input.begin() + offset, input.end(), m_bits.begin());
@@ -102,8 +114,7 @@
 
        m_output.assign(m_size, -1);
 
-       UnpackBits();
-       return true;
+       return UnpackBits();
 }
 
 }; // namespace chromaprint
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/chromaprint-1.6.1/src/fingerprint_decompressor.h 
new/chromaprint-1.6.2/src/fingerprint_decompressor.h
--- old/chromaprint-1.6.1/src/fingerprint_decompressor.h        2026-07-28 
08:12:40.000000000 +0200
+++ new/chromaprint-1.6.2/src/fingerprint_decompressor.h        2026-10-15 
11:56:52.000000000 +0200
@@ -22,7 +22,7 @@
        int GetAlgorithm() const { return m_algorithm; }
 
 private:
-       void UnpackBits();
+       bool UnpackBits();
        std::vector<uint32_t> m_output;
        size_t m_size { 0 };
        int m_algorithm { -1 };
Binary files old/chromaprint-1.6.1/tests/data/test_51_stereo_switch.ac3 and 
new/chromaprint-1.6.2/tests/data/test_51_stereo_switch.ac3 differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/chromaprint-1.6.1/tests/test_api.cpp 
new/chromaprint-1.6.2/tests/test_api.cpp
--- old/chromaprint-1.6.1/tests/test_api.cpp    2026-07-28 08:12:40.000000000 
+0200
+++ new/chromaprint-1.6.2/tests/test_api.cpp    2026-10-15 11:56:52.000000000 
+0200
@@ -237,4 +237,45 @@
        ASSERT_EQ(0, algorithm);
 }
 
+TEST(API, TestEncodeFingerprintInvalidSize)
+{
+       uint32_t fingerprint[] = { 1, 0 };
+       char *encoded;
+       int encoded_size;
+
+       ASSERT_EQ(0, chromaprint_encode_fingerprint(fingerprint, -1, 1, 
&encoded, &encoded_size, 0));
+       // The header has room for a 24-bit size only.
+       ASSERT_EQ(0, chromaprint_encode_fingerprint(fingerprint, 0x1000000, 1, 
&encoded, &encoded_size, 0));
+       ASSERT_EQ(0, chromaprint_encode_fingerprint(NULL, 2, 1, &encoded, 
&encoded_size, 0));
+}
+
+TEST(API, TestDecodeFingerprintInvalidSize)
+{
+       uint32_t *fp;
+       int length, algorithm;
+       char data[] = { 0, 0, 0, 2, 65, 0 };
+
+       ASSERT_EQ(0, chromaprint_decode_fingerprint(data, -1, &fp, &length, 
&algorithm, 0));
+       ASSERT_EQ(0, length);
+       ASSERT_EQ(0, chromaprint_decode_fingerprint(NULL, 6, &fp, &length, 
&algorithm, 0));
+       ASSERT_EQ(0, length);
+
+       ASSERT_EQ(0, chromaprint_decode_fingerprint_header(data, -1, &length, 
&algorithm, 0));
+       ASSERT_EQ(0, length);
+       ASSERT_EQ(0, chromaprint_decode_fingerprint_header(NULL, 6, &length, 
&algorithm, 0));
+       ASSERT_EQ(0, length);
+}
+
+TEST(API, TestDecodeFingerprintBitPastPosition32)
+{
+       uint32_t *fp;
+       int length, algorithm;
+       // Six distances of 6 reach bit 36.
+       char data[] = { 0, 0, 0, 1, char(182), 109, 3 };
+
+       ASSERT_EQ(0, chromaprint_decode_fingerprint(data, NELEMS(data), &fp, 
&length, &algorithm, 0));
+       ASSERT_EQ(nullptr, fp);
+       ASSERT_EQ(0, length);
+}
+
 }; // namespace chromaprint
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/chromaprint-1.6.1/tests/test_fingerprint_decompressor.cpp 
new/chromaprint-1.6.2/tests/test_fingerprint_decompressor.cpp
--- old/chromaprint-1.6.1/tests/test_fingerprint_decompressor.cpp       
2026-07-28 08:12:40.000000000 +0200
+++ new/chromaprint-1.6.2/tests/test_fingerprint_decompressor.cpp       
2026-10-15 11:56:52.000000000 +0200
@@ -127,3 +127,98 @@
        CheckFingerprints(value, (uint32_t *) expected, NELEMS(expected));
        ASSERT_EQ(1, algorithm);
 }
+
+TEST(FingerprintDecompressor, BitAtPosition32)
+{
+       // Five distances of 6 and one of 2 reach bit 32 exactly.
+       uint32_t expected[] = { 0xA0820820 };
+       char data[] = { 0, 0, 0, 1, char(182), 109, 1 };
+
+       int algorithm = 1;
+       std::vector<uint32_t> value;
+       ASSERT_EQ(true, DecompressFingerprint(std::string(data, NELEMS(data)), 
value, algorithm));
+       CheckFingerprints(value, expected, NELEMS(expected));
+}
+
+TEST(FingerprintDecompressor, BitPastPosition32)
+{
+       // Six distances of 6 reach bit 36.
+       char data[] = { 0, 0, 0, 1, char(182), 109, 3 };
+
+       int algorithm = 1;
+       std::vector<uint32_t> value;
+       ASSERT_EQ(false, DecompressFingerprint(std::string(data, NELEMS(data)), 
value, algorithm));
+}
+
+TEST(FingerprintDecompressor, ExceptionPastPosition32)
+{
+       // A distance of 7 + 26 reaches bit 33.
+       char data[] = { 0, 0, 0, 1, 7, 26 };
+
+       int algorithm = 1;
+       std::vector<uint32_t> value;
+       ASSERT_EQ(false, DecompressFingerprint(std::string(data, NELEMS(data)), 
value, algorithm));
+}
+
+TEST(FingerprintDecompressor, SecondItemPastPosition32)
+{
+       // The first item is valid, the second reaches bit 36.
+       char data[] = { 0, 0, 0, 2, char(129), 109, char(219), 0 };
+
+       int algorithm = 1;
+       std::vector<uint32_t> value;
+       ASSERT_EQ(false, DecompressFingerprint(std::string(data, NELEMS(data)), 
value, algorithm));
+}
+
+TEST(FingerprintDecompressor, SecondItemExceptionPastPosition32)
+{
+       // The first item takes an exception of 3, the second 7 + 26.
+       char data[] = { 0, 0, 0, 2, char(199), 1, 67, 3 };
+
+       int algorithm = 1;
+       std::vector<uint32_t> value;
+       ASSERT_EQ(false, DecompressFingerprint(std::string(data, NELEMS(data)), 
value, algorithm));
+}
+
+TEST(FingerprintDecompressor, ZeroItemsWithTrailingData)
+{
+       char data[][8] = {
+               { 1, 0, 0, 0, 0, 0, 0, 0 },
+               { 1, 0, 0, 0, char(255), char(255), char(255), char(255) },
+               { 1, 0, 0, 0, char(182), 109, 3, 0 },
+       };
+
+       for (size_t i = 0; i < NELEMS(data); i++) {
+               int algorithm = 0;
+               std::vector<uint32_t> value;
+               ASSERT_EQ(true, DecompressFingerprint(std::string(data[i], 
NELEMS(data[i])), value, algorithm));
+               ASSERT_EQ(0, value.size());
+               ASSERT_EQ(1, algorithm);
+       }
+}
+
+TEST(FingerprintDecompressor, Corrupted)
+{
+       // Every truncation and every single-bit flip of a valid fingerprint
+       // either fails or decodes to as many items as the header says.
+       const std::string data = 
Base64Decode("AQAAEwkjrUmSJQpUHflR9mjSJMdZpcO_Imdw9dCO9Clu4_wQPvhCB01w6xAtXNcAp5RASgDBhDSCGGIAcwA");
+
+       auto check = [](const std::string &input) {
+               size_t size = 0;
+               int algorithm = 0;
+               std::vector<uint32_t> value;
+               if (DecompressFingerprint(input, value, algorithm)) {
+                       ASSERT_EQ(true, DecompressFingerprintHeader(input, 
size, algorithm));
+                       ASSERT_EQ(size, value.size());
+               }
+       };
+
+       for (size_t len = 0; len < data.size(); len++) {
+               check(data.substr(0, len));
+       }
+       for (size_t bit = 0; bit < data.size() * 8; bit++) {
+               std::string corrupted = data;
+               corrupted[bit / 8] ^= char(1 << (bit % 8));
+               check(corrupted);
+       }
+}

Reply via email to