Update libopenmpt to version 0.5.7
parent
9a427cf03c
commit
7139f5aa08
|
@ -1,4 +1,4 @@
|
|||
|
||||
MPT_SVNVERSION=14311
|
||||
MPT_SVNURL=https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.6
|
||||
MPT_SVNDATE=2021-03-14T15:27:41.476009Z
|
||||
MPT_SVNVERSION=14391
|
||||
MPT_SVNURL=https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.7
|
||||
MPT_SVNDATE=2021-03-20T17:06:12.434258Z
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
CC = contrib/fuzzing/afl/afl-clang-fast
|
||||
CXX = contrib/fuzzing/afl/afl-clang-fast++
|
||||
LD = contrib/fuzzing/afl/afl-clang-fast++
|
||||
CC = contrib/fuzzing/afl/afl-clang-lto
|
||||
CXX = contrib/fuzzing/afl/afl-clang-lto++
|
||||
LD = contrib/fuzzing/afl/afl-clang-lto++
|
||||
AR = ar
|
||||
|
||||
ifneq ($(STDCXX),)
|
||||
|
@ -15,6 +15,10 @@ CFLAGS_STDC = -std=c99
|
|||
CXXFLAGS += $(CXXFLAGS_STDCXX)
|
||||
CFLAGS += $(CFLAGS_STDC)
|
||||
|
||||
DYNLINK=0
|
||||
SHARED_LIB=0
|
||||
STATIC_LIB=1
|
||||
|
||||
CPPFLAGS +=
|
||||
CXXFLAGS += -fPIC -fno-strict-aliasing
|
||||
CFLAGS += -fPIC -fno-strict-aliasing
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
|
||||
#pragma once
|
||||
#define OPENMPT_VERSION_SVNVERSION "14311"
|
||||
#define OPENMPT_VERSION_REVISION 14311
|
||||
#define OPENMPT_VERSION_SVNVERSION "14391"
|
||||
#define OPENMPT_VERSION_REVISION 14391
|
||||
#define OPENMPT_VERSION_DIRTY 0
|
||||
#define OPENMPT_VERSION_MIXEDREVISIONS 0
|
||||
#define OPENMPT_VERSION_URL "https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.6"
|
||||
#define OPENMPT_VERSION_DATE "2021-03-14T15:27:41.476009Z"
|
||||
#define OPENMPT_VERSION_URL "https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.7"
|
||||
#define OPENMPT_VERSION_DATE "2021-03-20T17:06:12.434258Z"
|
||||
#define OPENMPT_VERSION_IS_PACKAGE 1
|
||||
|
||||
|
|
|
@ -18,6 +18,6 @@ OPENMPT_NAMESPACE_BEGIN
|
|||
#define VER_MAJORMAJOR 1
|
||||
#define VER_MAJOR 29
|
||||
#define VER_MINOR 08
|
||||
#define VER_MINORMINOR 00
|
||||
#define VER_MINORMINOR 03
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
cd "${0%/*}"
|
||||
cd ../..
|
||||
AFL_HARDEN=1 CONFIG=afl make clean all EXAMPLES=0 TEST=0 OPENMPT123=0 NO_VORBIS=1 NO_VORBISFILE=1 NO_MPG123=1
|
||||
AFL_HARDEN=1 CONFIG=afl make clean all EXAMPLES=0 TEST=0 OPENMPT123=0 NO_VORBIS=1 NO_VORBISFILE=1 NO_MPG123=1 CHECKED_ADDRESS=1
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
#!/usr/bin/env bash
|
||||
cd "${0%/*}"
|
||||
. ./fuzz-settings.sh
|
||||
|
||||
# Create tmpfs for storing temporary fuzzing data
|
||||
mkdir $FUZZING_TEMPDIR
|
||||
sudo mount -t tmpfs -o size=300M none $FUZZING_TEMPDIR
|
||||
rm -rf $FUZZING_TEMPDIR/bin
|
||||
mkdir $FUZZING_TEMPDIR/bin
|
||||
cp -d ../../bin/* $FUZZING_TEMPDIR/bin/
|
||||
|
||||
#export AFL_PRELOAD=$AFL_DIR/libdislocator.so
|
||||
LD_LIBRARY_PATH=$FUZZING_TEMPDIR/bin $AFL_DIR/afl-fuzz -p exploit -f $FUZZING_TEMPDIR/infile01 -x all_formats.dict -t $FUZZING_TIMEOUT $FUZZING_INPUT -o $FUZZING_FINDINGS_DIR -M fuzzer01 $FUZZING_TEMPDIR/bin/fuzz $FUZZING_TEMPDIR/infile01
|
|
@ -1,12 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
cd "${0%/*}"
|
||||
. ./fuzz-settings.sh
|
||||
|
||||
# Create tmpfs for storing temporary fuzzing data
|
||||
mkdir $FUZZING_TEMPDIR
|
||||
sudo mount -t tmpfs -o size=200M none $FUZZING_TEMPDIR
|
||||
rm -rf $FUZZING_TEMPDIR/bin
|
||||
mkdir $FUZZING_TEMPDIR/bin
|
||||
cp -d ../../bin/* $FUZZING_TEMPDIR/bin/
|
||||
|
||||
LD_LIBRARY_PATH=$FUZZING_TEMPDIR/bin $AFL_BIN -f $FUZZING_TEMPDIR/infile01 -x all_formats.dict -t $FUZZING_TIMEOUT $FUZZING_INPUT -o $FUZZING_FINDINGS_DIR -M fuzzer01 $FUZZING_TEMPDIR/bin/fuzz $FUZZING_TEMPDIR/infile01
|
|
@ -0,0 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
cd "${0%/*}"
|
||||
. ./fuzz-settings.sh
|
||||
|
||||
#export AFL_PRELOAD=$AFL_DIR/libdislocator.so
|
||||
LD_LIBRARY_PATH=$FUZZING_TEMPDIR/bin $AFL_DIR/afl-fuzz -p coe -f $FUZZING_TEMPDIR/infile02 -x all_formats.dict -t $FUZZING_TIMEOUT $FUZZING_INPUT -o $FUZZING_FINDINGS_DIR -S fuzzer02 $FUZZING_TEMPDIR/bin/fuzz $FUZZING_TEMPDIR/infile02
|
|
@ -0,0 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
cd "${0%/*}"
|
||||
. ./fuzz-settings.sh
|
||||
|
||||
#export AFL_PRELOAD=$AFL_DIR/libdislocator.so
|
||||
LD_LIBRARY_PATH=$FUZZING_TEMPDIR/bin $AFL_DIR/afl-fuzz -p explore -f $FUZZING_TEMPDIR/infile03 -x all_formats.dict -t $FUZZING_TIMEOUT $FUZZING_INPUT -o $FUZZING_FINDINGS_DIR -S fuzzer03 $FUZZING_TEMPDIR/bin/fuzz $FUZZING_TEMPDIR/infile03
|
|
@ -15,4 +15,4 @@ FUZZING_FINDINGS_DIR=~/libopenmpt-fuzzing
|
|||
# Fuzzer timeout in ms, + = don't abort on timeout
|
||||
FUZZING_TIMEOUT=5000+
|
||||
# Path to afl-fuzz binary
|
||||
AFL_BIN=afl/afl-fuzz
|
||||
AFL_DIR=afl
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
cd "${0%/*}"
|
||||
. ./fuzz-settings.sh
|
||||
|
||||
LD_LIBRARY_PATH=$FUZZING_TEMPDIR/bin $AFL_BIN -f $FUZZING_TEMPDIR/infile02 -x all_formats.dict -t $FUZZING_TIMEOUT $FUZZING_INPUT -o $FUZZING_FINDINGS_DIR -S fuzzer02 $FUZZING_TEMPDIR/bin/fuzz $FUZZING_TEMPDIR/infile02
|
|
@ -20,7 +20,7 @@
|
|||
#include <libopenmpt/libopenmpt.h>
|
||||
#include <libopenmpt/libopenmpt_stream_callbacks_file.h>
|
||||
|
||||
#define BUFFERSIZE 512
|
||||
#define BUFFERSIZE 450 // shouldn't match OpenMPT's internal mix buffer size (512)
|
||||
#define SAMPLERATE 22050
|
||||
|
||||
static int16_t buffer[BUFFERSIZE];
|
||||
|
@ -46,6 +46,11 @@ int main( int argc, char * argv[] ) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
openmpt_module_set_position_seconds( mod, 1.0 );
|
||||
openmpt_module_read_mono( mod, SAMPLERATE, BUFFERSIZE, buffer );
|
||||
openmpt_module_set_position_order_row( mod, 3, 16 );
|
||||
openmpt_module_read_mono( mod, SAMPLERATE, BUFFERSIZE, buffer );
|
||||
|
||||
/* fuzz string-related stuff */
|
||||
openmpt_free_string ( openmpt_module_get_metadata( mod, "date" ) );
|
||||
openmpt_free_string ( openmpt_module_get_metadata( mod, "message" ) );
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#!/usr/bin/env bash
|
||||
cd "${0%/*}"
|
||||
|
||||
AFL_VERSION="$(wget --quiet -O - "https://api.github.com/repos/AFLplusplus/AFLplusplus/releases/latest" | grep -Po '"tag_name": "\K.*?(?=")')"
|
||||
AFL_FILENAME="$AFL_VERSION.tar.gz"
|
||||
GET_AFL_VERSION?="$(wget --quiet -O - "https://api.github.com/repos/AFLplusplus/AFLplusplus/releases/latest" | grep -Po '"tag_name": "\K.*?(?=")')"
|
||||
AFL_FILENAME="$GET_AFL_VERSION.tar.gz"
|
||||
AFL_URL="https://github.com/AFLplusplus/AFLplusplus/archive/$AFL_FILENAME"
|
||||
|
||||
rm $AFL_FILENAME
|
||||
|
|
|
@ -2,45 +2,50 @@ libopenmpt fuzz suite
|
|||
=====================
|
||||
|
||||
In this directory, you can find the necessary tools for fuzzing libopenmpt with
|
||||
the American Fuzzy Lop fuzzer (afl-fuzz).
|
||||
the American Fuzzy Lop fuzzer (afl++).
|
||||
|
||||
Contents:
|
||||
|
||||
* `all_formats.dict`: A dictionary containing magic bytes from all supported
|
||||
module formats to make the life of the fuzzer a bit easier.
|
||||
* `fuzz-master.sh`: Script to launch the main fuzzing process. If you want to
|
||||
* `fuzz-main.sh`: Script to launch the main fuzzing process. If you want to
|
||||
use just one fuzzer instance, run this one.
|
||||
* `fuzz-slave.sh`: Script to launch the secondary fuzzing process. It is
|
||||
recommended to run at least two fuzzer instances, as the deterministic and
|
||||
random fuzz mode have been found to complement each other really well.
|
||||
* `fuzz-secondary[1|2].sh`: Scripts to launch the secondary fuzzing process. It
|
||||
is recommended to run at least two fuzzer instances, as the deterministic and
|
||||
random fuzz mode have been found to complement each other really well. The two
|
||||
scripts are set up to use different exploration strategies
|
||||
* `fuzz-settings.sh`: Set up your preferences and afl settings here before the
|
||||
first run.
|
||||
* `fuzz.c`: A tiny C program that is used by the fuzzer to test libopenmpt.
|
||||
* `get-afl.sh`: A simple script to obtain the latest version of the fuzzer.
|
||||
* `get-afl.sh`: A simple script to obtain the latest version of afl++.
|
||||
You can also make it download from a specific branch or tag, e.g.
|
||||
`GET_AFL_VERSION=stable ./get-afl.sh` to download the latest stable but
|
||||
unreleased code.
|
||||
|
||||
Prerequisites
|
||||
=============
|
||||
* afl from http://lcamtuf.coredump.cx/afl/ - the makefile expects this to be
|
||||
installed in `contrib/fuzzing/afl`, as it is automatically done by the
|
||||
`get-afl.sh` install script.
|
||||
* [afl++](https://github.com/AFLplusplus/AFLplusplus) - the makefile expects
|
||||
this to be installed in `contrib/fuzzing/afl`, as it is automatically done by
|
||||
the `get-afl.sh` install script.
|
||||
* Clang with LLVM dev headers (llvm-config needs to be installed).
|
||||
afl also works with gcc, but our makefile has been set up to make use of afl's
|
||||
faster LLVM mode.
|
||||
faster LLVM-LTO mode.
|
||||
|
||||
How to use
|
||||
==========
|
||||
* Run `get-afl.sh`, or manually extract afl to `contrib/fuzzing/afl`, use `make`
|
||||
to build afl-fuzz, `cd llvm_mode`, `make` to build afl-clang-fast.
|
||||
If building with either option fails because `llvm-config` cannot be found,
|
||||
try prepending `LLVM_CONFIG=/usr/bin/llvm-config-3.8` or similar, and read the
|
||||
afl manual.
|
||||
* Run `get-afl.sh`, or manually extract afl to `contrib/fuzzing/afl`, use
|
||||
`make source-only` to build. If building fails because `llvm-config` cannot be
|
||||
found, try prepending `LLVM_CONFIG=/usr/bin/llvm-config-12` or similar, and
|
||||
read the afl manual.
|
||||
* Build libopenmpt with the `build.sh` script in this directory.
|
||||
* Set up `fuzz-settings.sh` to your taste. Most importantly, you will have to
|
||||
specify the input directory for first use.
|
||||
The default setup mounts a tmpfs folder for all temporary files. You may
|
||||
change this behaviour if you do not have root privileges.
|
||||
* Run `fuzz-master.sh` for the first (deterministic) instance of afl-fuzz.
|
||||
* For a "slave" instance to run on another core, run `fuzz-slave.sh`.
|
||||
* If you want to make use of even more cores, make a copy of `fuzz-slave.sh`
|
||||
and adjust "infile02" / "fuzzer02" to "infile03" / "fuzzer03" (they need to be
|
||||
unique)
|
||||
* Run `fuzz-main.sh` for the first (deterministic) instance of afl-fuzz.
|
||||
* For a "secondary" instance to run on another core, run `fuzz-secondary1.sh`
|
||||
and/or `fuzz-secondary2.sh`.
|
||||
* If you want to make use of even more cores, create more copies
|
||||
`fuzz-secondary2.sh` and adjust "infile03" / "fuzzer03" to
|
||||
"infile04" / "fuzzer04" and so o (they need to be unique). Try variying the
|
||||
fuzzing strategey (the -p parameter) to get results more quickly.
|
||||
|
|
|
@ -5,6 +5,17 @@ Changelog {#changelog}
|
|||
For fully detailed change log, please see the source repository directly. This
|
||||
is just a high-level summary.
|
||||
|
||||
### libopenmpt 0.5.7 (2021-03-20)
|
||||
|
||||
* [**Sec**] Possible null-pointer dereference read caused by a sequence of
|
||||
`openmpt::module::read`, `openmpt::module::set_position_seconds` with a
|
||||
position past the song end, and another `openmpt::module::read` call.
|
||||
(r14363)
|
||||
|
||||
* IT: Instrument / sample panning was reset on note-off / fade commands.
|
||||
* IMF: Set Finetune is now implemented correctly.
|
||||
* Fixed excessive memory consumption with malformed files in various formats.
|
||||
|
||||
### libopenmpt 0.5.6 (2021-03-14)
|
||||
|
||||
* AMS: Avoid allocating excessive amount of memory for compressed song message
|
||||
|
|
|
@ -24,7 +24,6 @@ Dependencies
|
|||
used for building:
|
||||
* `std::numeric_limits<unsigned char>::digits == 8` (enforced by
|
||||
static_assert)
|
||||
* `sizeof(char) == 1` (enforced by static_assert)
|
||||
* existence of `std::uintptr_t` (enforced by static_assert)
|
||||
* in C++20 mode, `std::endian::little != std::endian::big` (enforced
|
||||
by static_assert)
|
||||
|
@ -33,8 +32,6 @@ Dependencies
|
|||
assumed)
|
||||
* representation of basic source character set is identical in char
|
||||
and `wchar_t` (implicitly assumed)
|
||||
* libopenmpt also has experimental support for platforms without
|
||||
`wchar_t` support like DJGPP
|
||||
|
||||
libopenmpt does not rely on any specific implementation defined or
|
||||
undefined behaviour (if it does, that's a bug in libopenmpt). In
|
||||
|
@ -43,23 +40,26 @@ Dependencies
|
|||
* shifting signed values is implementation defined
|
||||
* `signed` integer overflow is undefined
|
||||
* `float` and `double` can be non-IEEE754
|
||||
|
||||
libopenmpt can optionally support for certain incomplete C++
|
||||
implementations:
|
||||
* platforms without `wchar_t` support (like DJGPP)
|
||||
* platforms without working `std::random_device` (like Emscripten when
|
||||
running in `AudioWorkletProcessor` context)
|
||||
* platforms without working `std::high_resolution_clock` (like
|
||||
Emscripten when running in `AudioWorkletProcessor` context)
|
||||
|
||||
* Required compilers to use libopenmpt:
|
||||
* Any **C89** / **C99** / **C11** compatible compiler should work with
|
||||
the C API as long as a **C99** compatible **stdint.h** is available.
|
||||
* Any **C++17** compatible compiler should work with the C++ API.
|
||||
* **J2B** support requires an inflate (deflate decompression) implementation:
|
||||
* **zlib**
|
||||
* **miniz** can be used internally if no zlib is available.
|
||||
* Built-in **MO3** support requires:
|
||||
* **libmpg123 >= 1.14.0**
|
||||
* **libogg**
|
||||
* **libvorbis**
|
||||
* **libvorbisfile**
|
||||
* Instead of libmpg123, **minimp3 by Lion (github.com/lieff)** can be used
|
||||
internally to decode MP3 samples.
|
||||
* Instead of libogg, libvorbis and libvorbisfile, **stb_vorbis** can be
|
||||
used internally to decode Vorbis samples.
|
||||
* **zlib** (or **miniz** can be used internally)
|
||||
* **MO3** support requires:
|
||||
* **libmpg123 >= 1.14.0** (or **minimp3 by Lion (github.com/lieff)** can
|
||||
be used internally)
|
||||
* **libogg**, **libvorbis**, and **libvorbisfile** (or **stb_vorbis** can
|
||||
be used internally)
|
||||
* Building on Unix-like systems requires:
|
||||
* **GNU make**
|
||||
* **pkg-config**
|
||||
|
|
|
@ -1108,8 +1108,9 @@ double module_impl::set_position_seconds( double seconds ) {
|
|||
}
|
||||
m_sndFile->SetCurrentOrder( static_cast<ORDERINDEX>( subsong->start_order ) );
|
||||
GetLengthType t = m_sndFile->GetLength( m_ctl_seek_sync_samples ? eAdjustSamplePositions : eAdjust, GetLengthTarget( seconds ).StartPos( static_cast<SEQUENCEINDEX>( subsong->sequence ), static_cast<ORDERINDEX>( subsong->start_order ), static_cast<ROWINDEX>( subsong->start_row ) ) ).back();
|
||||
m_sndFile->m_PlayState.m_nNextOrder = m_sndFile->m_PlayState.m_nCurrentOrder = t.lastOrder;
|
||||
m_sndFile->m_PlayState.m_nNextRow = t.lastRow;
|
||||
m_sndFile->m_PlayState.m_nNextOrder = m_sndFile->m_PlayState.m_nCurrentOrder = t.targetReached ? t.lastOrder : t.endOrder;
|
||||
m_sndFile->m_PlayState.m_nNextRow = t.targetReached ? t.lastRow : t.endRow;
|
||||
m_sndFile->m_PlayState.m_nTickCount = Util::MaxValueOfType(m_sndFile->m_PlayState.m_nTickCount) - 1;
|
||||
m_currentPositionSeconds = base_seconds + t.duration;
|
||||
return m_currentPositionSeconds;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
/*! \brief libopenmpt minor version number */
|
||||
#define OPENMPT_API_VERSION_MINOR 5
|
||||
/*! \brief libopenmpt patch version number */
|
||||
#define OPENMPT_API_VERSION_PATCH 6
|
||||
#define OPENMPT_API_VERSION_PATCH 7
|
||||
/*! \brief libopenmpt pre-release tag */
|
||||
#define OPENMPT_API_VERSION_PREREL ""
|
||||
/*! \brief libopenmpt pre-release flag */
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
LIBOPENMPT_VERSION_MAJOR=0
|
||||
LIBOPENMPT_VERSION_MINOR=5
|
||||
LIBOPENMPT_VERSION_PATCH=6
|
||||
LIBOPENMPT_VERSION_PATCH=7
|
||||
LIBOPENMPT_VERSION_PREREL=
|
||||
|
||||
LIBOPENMPT_LTVER_CURRENT=2
|
||||
LIBOPENMPT_LTVER_REVISION=6
|
||||
LIBOPENMPT_LTVER_REVISION=7
|
||||
LIBOPENMPT_LTVER_AGE=2
|
||||
|
|
|
@ -77,8 +77,9 @@ bool UnpackUMX(std::vector<ContainerItem> &containerItems, FileReader &file, Con
|
|||
}
|
||||
|
||||
std::vector<int32> classes;
|
||||
classes.reserve(fileHeader.importCount);
|
||||
for(uint32 i = 0; i < fileHeader.importCount && file.CanRead(4); i++)
|
||||
const uint32 importCount = std::min(fileHeader.importCount.get(), mpt::saturate_cast<uint32>(file.BytesLeft() / 4u));
|
||||
classes.reserve(importCount);
|
||||
for(uint32 i = 0; i < importCount && file.CanRead(4); i++)
|
||||
{
|
||||
int32 objName = ReadUMXImportTableEntry(file, fileHeader.packageVersion);
|
||||
if(static_cast<size_t>(objName) < names.size())
|
||||
|
|
|
@ -168,6 +168,7 @@ bool CSoundFile::ReadC67(FileReader &file, ModLoadingFlags loadFlags)
|
|||
m_nSamples = 64;
|
||||
m_nChannels = 4 + 9;
|
||||
m_playBehaviour.set(kOPLBeatingOscillators);
|
||||
m_SongFlags.set(SONG_IMPORTED);
|
||||
|
||||
// Pan PCM channels only
|
||||
for(CHANNELINDEX chn = 0; chn < 4; chn++)
|
||||
|
|
|
@ -934,10 +934,10 @@ bool CSoundFile::ReadDMF(FileReader &file, ModLoadingFlags loadFlags)
|
|||
file.Read(chunkHeader);
|
||||
uint32 chunkLength = chunkHeader.length, chunkSkip = 0;
|
||||
// When loop start was added to version 3, the chunk size was not updated...
|
||||
if(fileHeader.version == 3 && chunkHeader.GetID() == DMFChunk::idSEQU && chunkLength < uint32_max - 2)
|
||||
if(fileHeader.version == 3 && chunkHeader.GetID() == DMFChunk::idSEQU)
|
||||
chunkSkip = 2;
|
||||
// ...and when the loop end was added to version 4, it was also note updated! Luckily they fixed it in version 5.
|
||||
else if(fileHeader.version == 4 && chunkHeader.GetID() == DMFChunk::idSEQU && chunkLength < uint32_max - 4)
|
||||
else if(fileHeader.version == 4 && chunkHeader.GetID() == DMFChunk::idSEQU)
|
||||
chunkSkip = 4;
|
||||
// Earlier X-Tracker versions also write a garbage length for the SMPD chunk if samples are compressed.
|
||||
// I don't know when exactly this stopped, but I have no version 5-7 files to check (and no X-Tracker version that writes those versions).
|
||||
|
|
|
@ -163,6 +163,7 @@ bool CSoundFile::ReadGDM(FileReader &file, ModLoadingFlags loadFlags)
|
|||
}
|
||||
|
||||
InitializeGlobals(gdmFormatOrigin[fileHeader.originalFormat]);
|
||||
m_SongFlags.set(SONG_IMPORTED);
|
||||
|
||||
m_modFormat.formatName = U_("General Digital Music");
|
||||
m_modFormat.type = U_("gdm");
|
||||
|
|
|
@ -2086,19 +2086,11 @@ void CSoundFile::ReadMixPluginChunk(FileReader &file, SNDMIXPLUGIN &plugin)
|
|||
plugin.editorX = plugin.editorY = int32_min;
|
||||
|
||||
// Plugin user data
|
||||
const uint32 pluginDataChunkSize = file.ReadUint32LE();
|
||||
FileReader pluginDataChunk = file.ReadChunk(pluginDataChunkSize);
|
||||
FileReader pluginDataChunk = file.ReadChunk(file.ReadUint32LE());
|
||||
plugin.pluginData.resize(mpt::saturate_cast<size_t>(pluginDataChunk.BytesLeft()));
|
||||
pluginDataChunk.ReadRaw(mpt::as_span(plugin.pluginData));
|
||||
|
||||
if(pluginDataChunk.IsValid())
|
||||
{
|
||||
plugin.pluginData.resize(pluginDataChunkSize);
|
||||
pluginDataChunk.ReadRaw(plugin.pluginData.data(), pluginDataChunkSize);
|
||||
}
|
||||
|
||||
FileReader modularData = file.ReadChunk(file.ReadUint32LE());
|
||||
|
||||
//if dwMPTExtra is positive and there are dwMPTExtra bytes left in nPluginSize, we have some more data!
|
||||
if(modularData.IsValid())
|
||||
if(FileReader modularData = file.ReadChunk(file.ReadUint32LE()); modularData.IsValid())
|
||||
{
|
||||
while(modularData.CanRead(5))
|
||||
{
|
||||
|
|
|
@ -160,6 +160,7 @@ bool CSoundFile::ReadITP(FileReader &file, ModLoadingFlags loadFlags)
|
|||
{
|
||||
return false;
|
||||
}
|
||||
m_SongFlags.set(SONG_IMPORTED);
|
||||
if(songFlags & ITP_ITOLDEFFECTS)
|
||||
m_SongFlags.set(SONG_ITOLDEFFECTS);
|
||||
if(songFlags & ITP_ITCOMPATGXX)
|
||||
|
|
|
@ -399,40 +399,38 @@ struct MO3SampleChunk
|
|||
} while(carry); \
|
||||
}
|
||||
|
||||
static bool UnpackMO3Data(FileReader &file, uint8 *dst, uint32 size)
|
||||
|
||||
static bool UnpackMO3Data(FileReader &file, std::vector<uint8> &uncompressed, const uint32 size)
|
||||
{
|
||||
if(!size)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16 data = 0;
|
||||
int8 carry = 0; // x86 carry (used to propagate the most significant bit from one byte to another)
|
||||
int32 strLen = 0; // length of previous string
|
||||
int32 strOffset; // string offset
|
||||
uint8 *initDst = dst;
|
||||
uint32 ebp, previousPtr = 0;
|
||||
uint32 initSize = size;
|
||||
uint32 previousPtr = 0;
|
||||
|
||||
// Read first uncompressed byte
|
||||
*dst++ = file.ReadUint8();
|
||||
size--;
|
||||
uncompressed.push_back(file.ReadUint8());
|
||||
uint32 remain = size - 1;
|
||||
|
||||
while(size > 0)
|
||||
while(remain > 0)
|
||||
{
|
||||
READ_CTRL_BIT;
|
||||
if(!carry)
|
||||
{
|
||||
// a 0 ctrl bit means 'copy', not compressed byte
|
||||
if(!file.Read(*dst))
|
||||
if(uint8 b; file.Read(b))
|
||||
uncompressed.push_back(b);
|
||||
else
|
||||
break;
|
||||
dst++;
|
||||
size--;
|
||||
remain--;
|
||||
} else
|
||||
{
|
||||
// a 1 ctrl bit means compressed bytes are following
|
||||
ebp = 0; // length adjustment
|
||||
DECODE_CTRL_BITS; // read length, and if strLen > 3 (coded using more than 1 bits pair) also part of the offset value
|
||||
uint8 lengthAdjust = 0; // length adjustment
|
||||
DECODE_CTRL_BITS; // read length, and if strLen > 3 (coded using more than 1 bits pair) also part of the offset value
|
||||
strLen -= 3;
|
||||
if(strLen < 0)
|
||||
{
|
||||
|
@ -442,17 +440,17 @@ static bool UnpackMO3Data(FileReader &file, uint8 *dst, uint32 size)
|
|||
} else
|
||||
{
|
||||
// LZ ptr in ctrl stream
|
||||
uint8 b;
|
||||
if(!file.Read(b))
|
||||
if(uint8 b; file.Read(b))
|
||||
strOffset = (strLen << 8) | b; // read less significant offset byte from stream
|
||||
else
|
||||
break;
|
||||
strOffset = (strLen << 8) | b; // read less significant offset byte from stream
|
||||
strLen = 0;
|
||||
strOffset = ~strOffset;
|
||||
if(strOffset < -1280)
|
||||
ebp++;
|
||||
ebp++; // length is always at least 1
|
||||
lengthAdjust++;
|
||||
lengthAdjust++; // length is always at least 1
|
||||
if(strOffset < -32000)
|
||||
ebp++;
|
||||
lengthAdjust++;
|
||||
previousPtr = strOffset; // save current Ptr
|
||||
}
|
||||
|
||||
|
@ -467,36 +465,33 @@ static bool UnpackMO3Data(FileReader &file, uint8 *dst, uint32 size)
|
|||
DECODE_CTRL_BITS; // decode length: 1 is the most significant bit,
|
||||
strLen += 2; // then first bit of each bits pairs (noted n1), until n0.
|
||||
}
|
||||
strLen += ebp; // length adjustment
|
||||
if(size >= static_cast<uint32>(strLen) && strLen > 0)
|
||||
{
|
||||
// Copy previous string
|
||||
if(strOffset >= 0 || static_cast<std::ptrdiff_t>(dst - initDst) + strOffset < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
size -= strLen;
|
||||
const uint8 *string = dst + strOffset;
|
||||
while(strLen > 0)
|
||||
{
|
||||
*dst++ = *string++;
|
||||
strLen--;
|
||||
}
|
||||
} else
|
||||
{
|
||||
strLen += lengthAdjust; // length adjustment
|
||||
|
||||
if(remain < static_cast<uint32>(strLen) || strLen <= 0)
|
||||
break;
|
||||
}
|
||||
if(strOffset >= 0 || -static_cast<ptrdiff_t>(uncompressed.size()) > strOffset)
|
||||
break;
|
||||
|
||||
// Copy previous string
|
||||
// Need to do this in two steps as source and destination may overlap (e.g. strOffset = -1, strLen = 2 repeats last character twice)
|
||||
uncompressed.insert(uncompressed.end(), strLen, 0);
|
||||
remain -= strLen;
|
||||
auto src = uncompressed.cend() - strLen + strOffset;
|
||||
auto dst = uncompressed.end() - strLen;
|
||||
do
|
||||
{
|
||||
strLen--;
|
||||
*dst++ = *src++;
|
||||
} while(strLen > 0);
|
||||
}
|
||||
}
|
||||
#ifdef MPT_BUILD_FUZZER
|
||||
// When using a fuzzer, we should not care if the decompressed buffer has the correct size.
|
||||
// This makes finding new interesting test cases much easier.
|
||||
while(size-- > 0)
|
||||
{
|
||||
*dst++ = 0;
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
return remain == 0;
|
||||
#endif // MPT_BUILD_FUZZER
|
||||
return (dst - initDst) == static_cast<std::ptrdiff_t>(initSize);
|
||||
}
|
||||
|
||||
|
||||
|
@ -742,7 +737,7 @@ static bool ValidateHeader(const MO3ContainerHeader &containerHeader)
|
|||
{
|
||||
return false;
|
||||
}
|
||||
if(containerHeader.musicSize <= sizeof(MO3FileHeader))
|
||||
if(containerHeader.musicSize <= sizeof(MO3FileHeader) || containerHeader.musicSize >= uint32_max / 2u)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -789,24 +784,25 @@ bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags)
|
|||
}
|
||||
|
||||
const uint8 version = containerHeader.version;
|
||||
const uint32 musicSize = containerHeader.musicSize;
|
||||
|
||||
uint32 compressedSize = uint32_max;
|
||||
uint32 compressedSize = uint32_max, reserveSize = 1024 * 1024; // Generous estimate based on biggest pre-v5 MO3s found in the wild (~350K music data)
|
||||
if(version >= 5)
|
||||
{
|
||||
// Size of compressed music chunk
|
||||
compressedSize = file.ReadUint32LE();
|
||||
#ifndef MPT_BUILD_FUZZER
|
||||
if(!file.CanRead(compressedSize))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif // !MPT_BUILD_FUZZER
|
||||
// Generous estimate based on highest real-world compression ratio I found in a module (~20:1)
|
||||
reserveSize = std::min(Util::MaxValueOfType(reserveSize) / 32u, compressedSize) * 32u;
|
||||
}
|
||||
|
||||
std::vector<uint8> musicData(musicSize);
|
||||
|
||||
if(!UnpackMO3Data(file, musicData.data(), musicSize))
|
||||
std::vector<uint8> musicData;
|
||||
// We don't always reserve the whole uncompressed size as claimed by the module to guard against broken files
|
||||
// that e.g. claim that the uncompressed size is 1GB while the MO3 file itself is only 100 bytes.
|
||||
// As the LZ compression used in MO3 doesn't allow for establishing a clear upper bound for the maximum size,
|
||||
// this is probably the only sensible way we can prevent DoS due to huge allocations.
|
||||
musicData.reserve(std::min(reserveSize, containerHeader.musicSize.get()));
|
||||
if(!UnpackMO3Data(file, musicData, containerHeader.musicSize))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -849,6 +845,7 @@ bool CSoundFile::ReadMO3(FileReader &file, ModLoadingFlags loadFlags)
|
|||
else
|
||||
SetType(MOD_TYPE_XM);
|
||||
|
||||
m_SongFlags.set(SONG_IMPORTED);
|
||||
if(fileHeader.flags & MO3FileHeader::linearSlides)
|
||||
m_SongFlags.set(SONG_LINEARSLIDES);
|
||||
if((fileHeader.flags & MO3FileHeader::s3mAmigaLimits) && m_nType == MOD_TYPE_S3M)
|
||||
|
|
|
@ -1951,7 +1951,7 @@ bool CSoundFile::ReadICE(FileReader &file, ModLoadingFlags loadFlags)
|
|||
m_nMinPeriod = 14 * 4;
|
||||
m_nMaxPeriod = 3424 * 4;
|
||||
m_nSamplePreAmp = 64;
|
||||
m_SongFlags.set(SONG_PT_MODE);
|
||||
m_SongFlags.set(SONG_PT_MODE | SONG_IMPORTED);
|
||||
|
||||
// Setup channel pan positions and volume
|
||||
SetupMODPanning();
|
||||
|
|
|
@ -333,7 +333,9 @@ bool CSoundFile::ReadSTP(FileReader &file, ModLoadingFlags loadFlags)
|
|||
STPLoopList &loopList = loopInfo[actualSmp - 1];
|
||||
loopList.clear();
|
||||
|
||||
uint16 numLoops = file.ReadUint16BE();
|
||||
const uint16 numLoops = file.ReadUint16BE();
|
||||
if(!file.CanRead(numLoops * 8u))
|
||||
return false;
|
||||
loopList.reserve(numLoops);
|
||||
|
||||
STPLoopInfo loop;
|
||||
|
|
|
@ -70,8 +70,9 @@ bool CSoundFile::ReadUAX(FileReader &file, ModLoadingFlags loadFlags)
|
|||
}
|
||||
|
||||
std::vector<int32> classes;
|
||||
classes.reserve(fileHeader.importCount);
|
||||
for(uint32 i = 0; i < fileHeader.importCount && file.CanRead(4); i++)
|
||||
const uint32 importCount = std::min(fileHeader.importCount.get(), mpt::saturate_cast<uint32>(file.BytesLeft() / 4u));
|
||||
classes.reserve(importCount);
|
||||
for(uint32 i = 0; i < importCount && file.CanRead(4); i++)
|
||||
{
|
||||
int32 objName = ReadUMXImportTableEntry(file, fileHeader.packageVersion);
|
||||
if(static_cast<size_t>(objName) < names.size())
|
||||
|
|
|
@ -244,26 +244,27 @@ enum DuplicateNoteAction : uint8
|
|||
// Module flags - contains both song configuration and playback state... Use SONG_FILE_FLAGS and SONG_PLAY_FLAGS distinguish between the two.
|
||||
enum SongFlags
|
||||
{
|
||||
SONG_FASTVOLSLIDES = 0x0002, // Old Scream Tracker 3.0 volume slides
|
||||
SONG_ITOLDEFFECTS = 0x0004, // Old Impulse Tracker effect implementations
|
||||
SONG_ITCOMPATGXX = 0x0008, // IT "Compatible Gxx" (IT's flag to behave more like other trackers w/r/t portamento effects)
|
||||
SONG_LINEARSLIDES = 0x0010, // Linear slides vs. Amiga slides
|
||||
SONG_PATTERNLOOP = 0x0020, // Loop current pattern (pattern editor)
|
||||
SONG_STEP = 0x0040, // Song is in "step" mode (pattern editor)
|
||||
SONG_PAUSED = 0x0080, // Song is paused (no tick processing, just rendering audio)
|
||||
SONG_FADINGSONG = 0x0100, // Song is fading out
|
||||
SONG_ENDREACHED = 0x0200, // Song is finished
|
||||
SONG_FIRSTTICK = 0x1000, // Is set when the current tick is the first tick of the row
|
||||
SONG_MPTFILTERMODE = 0x2000, // Local filter mode (reset filter on each note)
|
||||
SONG_SURROUNDPAN = 0x4000, // Pan in the rear channels
|
||||
SONG_EXFILTERRANGE = 0x8000, // Cutoff Filter has double frequency range (up to ~10Khz)
|
||||
SONG_AMIGALIMITS = 0x10000, // Enforce amiga frequency limits
|
||||
SONG_S3MOLDVIBRATO = 0x20000, // ScreamTracker 2 vibrato in S3M files
|
||||
SONG_BREAKTOROW = 0x80000, // Break to row command encountered (internal flag, do not touch)
|
||||
SONG_POSJUMP = 0x100000, // Position jump encountered (internal flag, do not touch)
|
||||
SONG_PT_MODE = 0x200000, // ProTracker 1/2 playback mode
|
||||
SONG_PLAYALLSONGS = 0x400000, // Play all subsongs consecutively (libopenmpt)
|
||||
SONG_ISAMIGA = 0x800000, // Is an Amiga module and thus qualifies to be played using the Paula BLEP resampler
|
||||
SONG_FASTVOLSLIDES = 0x02, // Old Scream Tracker 3.0 volume slides
|
||||
SONG_ITOLDEFFECTS = 0x04, // Old Impulse Tracker effect implementations
|
||||
SONG_ITCOMPATGXX = 0x08, // IT "Compatible Gxx" (IT's flag to behave more like other trackers w/r/t portamento effects)
|
||||
SONG_LINEARSLIDES = 0x10, // Linear slides vs. Amiga slides
|
||||
SONG_PATTERNLOOP = 0x20, // Loop current pattern (pattern editor)
|
||||
SONG_STEP = 0x40, // Song is in "step" mode (pattern editor)
|
||||
SONG_PAUSED = 0x80, // Song is paused (no tick processing, just rendering audio)
|
||||
SONG_FADINGSONG = 0x0100, // Song is fading out
|
||||
SONG_ENDREACHED = 0x0200, // Song is finished
|
||||
SONG_FIRSTTICK = 0x1000, // Is set when the current tick is the first tick of the row
|
||||
SONG_MPTFILTERMODE = 0x2000, // Local filter mode (reset filter on each note)
|
||||
SONG_SURROUNDPAN = 0x4000, // Pan in the rear channels
|
||||
SONG_EXFILTERRANGE = 0x8000, // Cutoff Filter has double frequency range (up to ~10Khz)
|
||||
SONG_AMIGALIMITS = 0x1'0000, // Enforce amiga frequency limits
|
||||
SONG_S3MOLDVIBRATO = 0x2'0000, // ScreamTracker 2 vibrato in S3M files
|
||||
SONG_BREAKTOROW = 0x8'0000, // Break to row command encountered (internal flag, do not touch)
|
||||
SONG_POSJUMP = 0x10'0000, // Position jump encountered (internal flag, do not touch)
|
||||
SONG_PT_MODE = 0x20'0000, // ProTracker 1/2 playback mode
|
||||
SONG_PLAYALLSONGS = 0x40'0000, // Play all subsongs consecutively (libopenmpt)
|
||||
SONG_ISAMIGA = 0x80'0000, // Is an Amiga module and thus qualifies to be played using the Paula BLEP resampler
|
||||
SONG_IMPORTED = 0x100'0000, // Song type does not represent actual module format / was imported from a different format (OpenMPT)
|
||||
};
|
||||
DECLARE_FLAGSET(SongFlags)
|
||||
|
||||
|
|
|
@ -243,8 +243,6 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
|
|||
{
|
||||
std::vector<GetLengthType> results;
|
||||
GetLengthType retval;
|
||||
retval.startOrder = target.startOrder;
|
||||
retval.startRow = target.startRow;
|
||||
|
||||
// Are we trying to reach a certain pattern position?
|
||||
const bool hasSearchTarget = target.mode != GetLengthTarget::NoTarget && target.mode != GetLengthTarget::GetAllSubsongs;
|
||||
|
@ -259,8 +257,18 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
|
|||
// Temporary visited rows vector (so that GetLength() won't interfere with the player code if the module is playing at the same time)
|
||||
RowVisitor visitedRows(*this, sequence);
|
||||
|
||||
playState.m_nNextRow = playState.m_nRow = target.startRow;
|
||||
playState.m_nNextOrder = playState.m_nCurrentOrder = target.startOrder;
|
||||
// If sequence starts with some non-existent patterns, find a better start
|
||||
{
|
||||
ORDERINDEX startOrder = target.startOrder;
|
||||
ROWINDEX startRow = target.startRow;
|
||||
if(visitedRows.GetFirstUnvisitedRow(startOrder, startRow, true))
|
||||
{
|
||||
target.startOrder = startOrder;
|
||||
target.startRow = startRow;
|
||||
}
|
||||
}
|
||||
retval.startRow = playState.m_nNextRow = playState.m_nRow = target.startRow;
|
||||
retval.startOrder = playState.m_nNextOrder = playState.m_nCurrentOrder = target.startOrder;
|
||||
|
||||
// Fast LUTs for commands that are too weird / complicated / whatever to emulate in sample position adjust mode.
|
||||
std::bitset<MAX_EFFECTS> forbiddenCommands;
|
||||
|
@ -1317,6 +1325,7 @@ std::vector<GetLengthType> CSoundFile::GetLength(enmGetLengthResetMode adjustMod
|
|||
m_opl->Patch(n, chn.pModSample->adlib);
|
||||
m_opl->NoteCut(n);
|
||||
}
|
||||
chn.pCurrentSample = nullptr;
|
||||
}
|
||||
|
||||
#ifndef NO_PLUGINS
|
||||
|
@ -2928,10 +2937,7 @@ bool CSoundFile::ProcessEffects()
|
|||
{
|
||||
CheckNNA(nChn, instr, note, false);
|
||||
}
|
||||
}
|
||||
|
||||
if(note)
|
||||
{
|
||||
if(chn.nRestorePanOnNewNote > 0)
|
||||
{
|
||||
chn.nPan = (chn.nRestorePanOnNewNote & 0x7FFF) - 1;
|
||||
|
@ -4699,7 +4705,14 @@ void CSoundFile::ExtendedS3MCommands(CHANNELINDEX nChn, ModCommand::PARAM param)
|
|||
// S2x: Set FineTune
|
||||
case 0x20: if(!m_SongFlags[SONG_FIRSTTICK])
|
||||
break;
|
||||
if(GetType() != MOD_TYPE_669)
|
||||
if(GetType() == MOD_TYPE_IMF)
|
||||
{
|
||||
if(chn.nPeriod && chn.pModSample)
|
||||
{
|
||||
chn.nC5Speed = Util::muldivr(chn.pModSample->nC5Speed, 1712, ProTrackerTunedPeriods[param * 12]);
|
||||
chn.nPeriod = GetPeriodFromNote(chn.nNote, 0, chn.nC5Speed);
|
||||
}
|
||||
} else if(GetType() != MOD_TYPE_669)
|
||||
{
|
||||
chn.nC5Speed = S3MFineTuneTable[param];
|
||||
chn.nFineTune = MOD2XMFineTune(param);
|
||||
|
|
|
@ -455,15 +455,20 @@ bool CSoundFile::Create(FileReader file, ModLoadingFlags loadFlags)
|
|||
m_songMessage.assign(mpt::ToCharset(mpt::Charset::Locale, unarchiver.GetComment()));
|
||||
}
|
||||
#endif
|
||||
#ifdef MODPLUG_TRACKER
|
||||
} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
|
||||
{
|
||||
MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e);
|
||||
return false;
|
||||
#endif // MODPLUG_TRACKER
|
||||
} catch(const std::exception &)
|
||||
{
|
||||
#ifdef MODPLUG_TRACKER
|
||||
return false;
|
||||
#else
|
||||
// libopenmpt already handles this.
|
||||
throw;
|
||||
#endif // MODPLUG_TRACKER
|
||||
#endif // MODPLUG_TRACKER
|
||||
}
|
||||
} else
|
||||
{
|
||||
|
@ -961,10 +966,10 @@ void CSoundFile::LoopPattern(PATTERNINDEX nPat, ROWINDEX nRow)
|
|||
m_PlayState.m_nTickCount = m_PlayState.m_nMusicSpeed;
|
||||
m_PlayState.m_nPatternDelay = 0;
|
||||
m_PlayState.m_nFrameDelay = 0;
|
||||
m_PlayState.m_nBufferCount = 0;
|
||||
m_PlayState.m_nNextPatStartRow = 0;
|
||||
m_SongFlags.set(SONG_PATTERNLOOP);
|
||||
}
|
||||
m_PlayState.m_nBufferCount = 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -146,7 +146,7 @@ std::string ReadUMXNameTableEntry(FileReader &chunk, uint16 packageVersion)
|
|||
{
|
||||
return "";
|
||||
}
|
||||
name.reserve(length);
|
||||
name.reserve(std::min(length, mpt::saturate_cast<int32>(chunk.BytesLeft())));
|
||||
}
|
||||
|
||||
// Simple zero-terminated string
|
||||
|
@ -174,8 +174,9 @@ std::vector<std::string> ReadUMXNameTable(FileReader &file, const UMXFileHeader
|
|||
{
|
||||
return names;
|
||||
}
|
||||
names.reserve(fileHeader.nameCount);
|
||||
for(uint32 i = 0; i < fileHeader.nameCount && file.CanRead(4); i++)
|
||||
const uint32 nameCount = std::min(fileHeader.nameCount.get(), mpt::saturate_cast<uint32>(file.BytesLeft() / 5u));
|
||||
names.reserve(nameCount);
|
||||
for(uint32 i = 0; i < nameCount && file.CanRead(5); i++)
|
||||
{
|
||||
names.push_back(ReadUMXNameTableEntry(file, fileHeader.packageVersion));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue