Updated libopenmpt to version 0.4.2
This commit is contained in:
parent
9431a11028
commit
d1e4abf78c
301 changed files with 22527 additions and 17376 deletions
|
@ -1,6 +1,4 @@
|
|||
The OpenMPT code is licensed under the BSD license.
|
||||
|
||||
Copyright (c) 2004-2018, OpenMPT contributors
|
||||
Copyright (c) 2004-2019, OpenMPT contributors
|
||||
Copyright (c) 1997-2003, Olivier Lapicque
|
||||
All rights reserved.
|
||||
|
||||
|
@ -25,3 +23,4 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
# TEST=1 Include test suite in default target.
|
||||
# ONLY_TEST=0 Only build the test suite.
|
||||
# STRICT=0 Treat warnings as errors.
|
||||
# MODERN=0 Pass more modern compiler options.
|
||||
# STDCXX=c++11 C++ standard version (only for GCC and clang)
|
||||
# CHECKED=0 Enable run-time assertions.
|
||||
# CHECKED_ADDRESS=0 Enable address sanitizer
|
||||
|
@ -68,10 +69,11 @@
|
|||
# NO_VORBIS=1 Avoid using libvorbis, even if found
|
||||
# NO_VORBISFILE=1 Avoid using libvorbisfile, even if found
|
||||
#
|
||||
# NO_MINIMP3=1 Do not fallback to minimp3
|
||||
# NO_STBVORBIS=1 Do not fallback to stb_vorbis
|
||||
#
|
||||
# USE_MINIMP3=1 Use minimp3.
|
||||
# Beware that minimp3 is LGPL 2.1 licensed.
|
||||
# USE_ALLEGRO42=1 Use liballegro 4.2 (DJGPP only)
|
||||
# BUNDLED_ALLEGRO42=1 Use liballegro 4.2 in libopenmpt source tree (DJGPP only)
|
||||
#
|
||||
# Build flags for libopenmpt examples and openmpt123
|
||||
# (provide on each `make` invocation)
|
||||
|
@ -157,6 +159,7 @@ ONLY_TEST=0
|
|||
SOSUFFIX=.so
|
||||
SOSUFFIXWINDOWS=0
|
||||
OPENMPT123=1
|
||||
MODERN=0
|
||||
STRICT=0
|
||||
|
||||
CHECKED=0
|
||||
|
@ -201,6 +204,11 @@ ifeq ($(OS),Windows_NT)
|
|||
HOST=windows
|
||||
HOST_FLAVOUR=
|
||||
|
||||
TOOLCHAIN_SUFFIX=
|
||||
|
||||
CPPCHECK = cppcheck
|
||||
|
||||
MKDIR_P = mkdir
|
||||
RM = del /q /f
|
||||
RMTREE = del /q /f /s
|
||||
INSTALL = echo install
|
||||
|
@ -208,11 +216,18 @@ INSTALL_MAKE_DIR = echo install
|
|||
INSTALL_DIR = echo install
|
||||
FIXPATH = $(subst /,\,$1)
|
||||
|
||||
NUMTHREADS:=$(NUMBER_OF_PROCESSORS)
|
||||
|
||||
else
|
||||
|
||||
HOST=unix
|
||||
HOST_FLAVOUR=
|
||||
|
||||
TOOLCHAIN_SUFFIX=
|
||||
|
||||
CPPCHECK = cppcheck
|
||||
|
||||
MKDIR_P = mkdir -p
|
||||
RM = rm -f
|
||||
RMTREE = rm -rf
|
||||
INSTALL = install
|
||||
|
@ -230,10 +245,24 @@ endif
|
|||
ifeq ($(UNAME_S),FreeBSD)
|
||||
HOST_FLAVOUR=FREEBSD
|
||||
endif
|
||||
ifeq ($(UNAME_S),Haiku)
|
||||
HOST_FLAVOUR=HAIKU
|
||||
endif
|
||||
|
||||
ifeq ($(HOST_FLAVOUR),LINUX)
|
||||
NUMTHREADS:=$(shell nproc)
|
||||
else
|
||||
NUMTHREADS:=1
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
|
||||
# early build setup
|
||||
|
||||
BINDIR_MADE:=$(shell $(MKDIR_P) bin)
|
||||
|
||||
|
||||
# compiler setup
|
||||
|
||||
ifeq ($(CONFIG)x,x)
|
||||
|
@ -249,8 +278,6 @@ endif
|
|||
|
||||
# build setup
|
||||
|
||||
BINDIR_MADE:=$(shell mkdir -p bin)
|
||||
|
||||
ifeq ($(SOSUFFIXWINDOWS),1)
|
||||
LIBOPENMPT_SONAME=libopenmpt-$(LIBOPENMPT_SO_VERSION)$(SOSUFFIX)
|
||||
else
|
||||
|
@ -295,8 +322,13 @@ CFLAGS += -Wall
|
|||
|
||||
else
|
||||
|
||||
ifeq ($(MPT_COMPILER_NOVISIBILITY),1)
|
||||
CXXFLAGS +=
|
||||
CFLAGS +=
|
||||
else
|
||||
CXXFLAGS += -fvisibility=hidden
|
||||
CFLAGS += -fvisibility=hidden
|
||||
endif
|
||||
LDFLAGS +=
|
||||
LDLIBS +=
|
||||
ARFLAGS +=
|
||||
|
@ -307,9 +339,15 @@ CXXFLAGS += -O0 -g -fno-omit-frame-pointer
|
|||
CFLAGS += -O0 -g -fno-omit-frame-pointer
|
||||
else
|
||||
ifeq ($(OPTIMIZE_SIZE),1)
|
||||
CXXFLAGS += -ffunction-sections -fdata-sections -Os -ffast-math
|
||||
CFLAGS += -ffunction-sections -fdata-sections -Os -ffast-math -fno-strict-aliasing
|
||||
CXXFLAGS += -Os -ffast-math
|
||||
CFLAGS += -Os -ffast-math -fno-strict-aliasing
|
||||
LDFLAGS +=
|
||||
ifeq ($(MPT_COMPILER_NOGCSECTIONS),1)
|
||||
else
|
||||
CXXFLAGS += -ffunction-sections -fdata-sections
|
||||
CFLAGS += -ffunction-sections -fdata-sections
|
||||
LDFLAGS += -Wl,--gc-sections
|
||||
endif
|
||||
else
|
||||
ifeq ($(OPTIMIZE),1)
|
||||
CXXFLAGS += -O3 -ffast-math
|
||||
|
@ -332,6 +370,7 @@ endif
|
|||
|
||||
CXXFLAGS += -Wall -Wextra -Wundef -Wcast-qual -Wcast-align $(CXXFLAGS_WARNINGS)
|
||||
CFLAGS += -Wall -Wextra -Wundef -Wcast-qual -Wcast-align $(CFLAGS_WARNINGS)
|
||||
LDFLAGS += $(LDFLAGS_WARNINGS)
|
||||
|
||||
endif
|
||||
|
||||
|
@ -371,10 +410,10 @@ endif
|
|||
ifeq ($(NO_ZLIB),1)
|
||||
else
|
||||
#LDLIBS += -lz
|
||||
ifeq ($(shell pkg-config --exists zlib && echo yes),yes)
|
||||
CPPFLAGS_ZLIB := $(shell pkg-config --cflags-only-I zlib ) -DMPT_WITH_ZLIB
|
||||
LDFLAGS_ZLIB := $(shell pkg-config --libs-only-L zlib ) $(shell pkg-config --libs-only-other zlib )
|
||||
LDLIBS_ZLIB := $(shell pkg-config --libs-only-l zlib )
|
||||
ifeq ($(shell pkg-config$(TOOLCHAIN_SUFFIX) --exists zlib && echo yes),yes)
|
||||
CPPFLAGS_ZLIB := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --cflags-only-I zlib ) -DMPT_WITH_ZLIB
|
||||
LDFLAGS_ZLIB := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-L zlib ) $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-other zlib )
|
||||
LDLIBS_ZLIB := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-l zlib )
|
||||
PC_REQUIRES_ZLIB := zlib
|
||||
else
|
||||
ifeq ($(FORCE_DEPS),1)
|
||||
|
@ -389,10 +428,10 @@ endif
|
|||
ifeq ($(NO_MPG123),1)
|
||||
else
|
||||
#LDLIBS += -lmpg123
|
||||
ifeq ($(shell pkg-config --exists 'libmpg123 >= 1.13.0' && echo yes),yes)
|
||||
CPPFLAGS_MPG123 := $(shell pkg-config --cflags-only-I 'libmpg123 >= 1.13.0' ) -DMPT_WITH_MPG123
|
||||
LDFLAGS_MPG123 := $(shell pkg-config --libs-only-L 'libmpg123 >= 1.13.0' ) $(shell pkg-config --libs-only-other 'libmpg123 >= 1.13.0' )
|
||||
LDLIBS_MPG123 := $(shell pkg-config --libs-only-l 'libmpg123 >= 1.13.0' )
|
||||
ifeq ($(shell pkg-config$(TOOLCHAIN_SUFFIX) --exists 'libmpg123 >= 1.14.0' && echo yes),yes)
|
||||
CPPFLAGS_MPG123 := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --cflags-only-I 'libmpg123 >= 1.14.0' ) -DMPT_WITH_MPG123
|
||||
LDFLAGS_MPG123 := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-L 'libmpg123 >= 1.14.0' ) $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-other 'libmpg123 >= 1.14.0' )
|
||||
LDLIBS_MPG123 := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-l 'libmpg123 >= 1.14.0' )
|
||||
PC_REQUIRES_MPG123 := libmpg123
|
||||
else
|
||||
ifeq ($(FORCE_DEPS),1)
|
||||
|
@ -407,10 +446,10 @@ endif
|
|||
ifeq ($(NO_OGG),1)
|
||||
else
|
||||
#LDLIBS += -logg
|
||||
ifeq ($(shell pkg-config --exists ogg && echo yes),yes)
|
||||
CPPFLAGS_OGG := $(shell pkg-config --cflags-only-I ogg ) -DMPT_WITH_OGG
|
||||
LDFLAGS_OGG := $(shell pkg-config --libs-only-L ogg ) $(shell pkg-config --libs-only-other ogg )
|
||||
LDLIBS_OGG := $(shell pkg-config --libs-only-l ogg )
|
||||
ifeq ($(shell pkg-config$(TOOLCHAIN_SUFFIX) --exists ogg && echo yes),yes)
|
||||
CPPFLAGS_OGG := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --cflags-only-I ogg ) -DMPT_WITH_OGG
|
||||
LDFLAGS_OGG := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-L ogg ) $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-other ogg )
|
||||
LDLIBS_OGG := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-l ogg )
|
||||
PC_REQUIRES_OGG := ogg
|
||||
else
|
||||
ifeq ($(FORCE_DEPS),1)
|
||||
|
@ -425,10 +464,10 @@ endif
|
|||
ifeq ($(NO_VORBIS),1)
|
||||
else
|
||||
#LDLIBS += -lvorbis
|
||||
ifeq ($(shell pkg-config --exists vorbis && echo yes),yes)
|
||||
CPPFLAGS_VORBIS := $(shell pkg-config --cflags-only-I vorbis ) -DMPT_WITH_VORBIS
|
||||
LDFLAGS_VORBIS := $(shell pkg-config --libs-only-L vorbis ) $(shell pkg-config --libs-only-other vorbis )
|
||||
LDLIBS_VORBIS := $(shell pkg-config --libs-only-l vorbis )
|
||||
ifeq ($(shell pkg-config$(TOOLCHAIN_SUFFIX) --exists vorbis && echo yes),yes)
|
||||
CPPFLAGS_VORBIS := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --cflags-only-I vorbis ) -DMPT_WITH_VORBIS
|
||||
LDFLAGS_VORBIS := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-L vorbis ) $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-other vorbis )
|
||||
LDLIBS_VORBIS := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-l vorbis )
|
||||
PC_REQUIRES_VORBIS := vorbis
|
||||
else
|
||||
ifeq ($(FORCE_DEPS),1)
|
||||
|
@ -443,10 +482,10 @@ endif
|
|||
ifeq ($(NO_VORBISFILE),1)
|
||||
else
|
||||
#LDLIBS += -lvorbisfile
|
||||
ifeq ($(shell pkg-config --exists vorbisfile && echo yes),yes)
|
||||
CPPFLAGS_VORBISFILE := $(shell pkg-config --cflags-only-I vorbisfile ) -DMPT_WITH_VORBISFILE
|
||||
LDFLAGS_VORBISFILE := $(shell pkg-config --libs-only-L vorbisfile ) $(shell pkg-config --libs-only-other vorbisfile )
|
||||
LDLIBS_VORBISFILE := $(shell pkg-config --libs-only-l vorbisfile )
|
||||
ifeq ($(shell pkg-config$(TOOLCHAIN_SUFFIX) --exists vorbisfile && echo yes),yes)
|
||||
CPPFLAGS_VORBISFILE := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --cflags-only-I vorbisfile ) -DMPT_WITH_VORBISFILE
|
||||
LDFLAGS_VORBISFILE := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-L vorbisfile ) $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-other vorbisfile )
|
||||
LDLIBS_VORBISFILE := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-l vorbisfile )
|
||||
PC_REQUIRES_VORBISFILE := vorbisfile
|
||||
else
|
||||
ifeq ($(FORCE_DEPS),1)
|
||||
|
@ -461,10 +500,10 @@ endif
|
|||
ifeq ($(NO_SDL2),1)
|
||||
else
|
||||
#LDLIBS += -lsdl2
|
||||
ifeq ($(shell pkg-config --exists sdl2 && echo yes),yes)
|
||||
CPPFLAGS_SDL := $(shell pkg-config --cflags-only-I sdl2 ) -DMPT_WITH_SDL2
|
||||
LDFLAGS_SDL := $(shell pkg-config --libs-only-L sdl2 ) $(shell pkg-config --libs-only-other sdl2 )
|
||||
LDLIBS_SDL := $(shell pkg-config --libs-only-l sdl2 )
|
||||
ifeq ($(shell pkg-config$(TOOLCHAIN_SUFFIX) --exists sdl2 && echo yes),yes)
|
||||
CPPFLAGS_SDL := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --cflags-only-I sdl2 ) -DMPT_WITH_SDL2
|
||||
LDFLAGS_SDL := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-L sdl2 ) $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-other sdl2 )
|
||||
LDLIBS_SDL := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-l sdl2 )
|
||||
NO_SDL:=1
|
||||
else
|
||||
ifeq ($(FORCE_DEPS),1)
|
||||
|
@ -479,10 +518,10 @@ endif
|
|||
ifeq ($(NO_SDL),1)
|
||||
else
|
||||
#LDLIBS += -lsdl
|
||||
ifeq ($(shell pkg-config --exists sdl && echo yes),yes)
|
||||
CPPFLAGS_SDL := $(shell pkg-config --cflags-only-I sdl ) -DMPT_WITH_SDL
|
||||
LDFLAGS_SDL := $(shell pkg-config --libs-only-L sdl ) $(shell pkg-config --libs-only-other sdl )
|
||||
LDLIBS_SDL := $(shell pkg-config --libs-only-l sdl )
|
||||
ifeq ($(shell pkg-config$(TOOLCHAIN_SUFFIX) --exists sdl && echo yes),yes)
|
||||
CPPFLAGS_SDL := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --cflags-only-I sdl ) -DMPT_WITH_SDL
|
||||
LDFLAGS_SDL := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-L sdl ) $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-other sdl )
|
||||
LDLIBS_SDL := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-l sdl )
|
||||
else
|
||||
ifeq ($(FORCE_DEPS),1)
|
||||
$(error sdl not found)
|
||||
|
@ -496,10 +535,10 @@ endif
|
|||
ifeq ($(NO_PORTAUDIO),1)
|
||||
else
|
||||
#LDLIBS += -lportaudio
|
||||
ifeq ($(shell pkg-config --exists portaudio-2.0 && echo yes),yes)
|
||||
CPPFLAGS_PORTAUDIO := $(shell pkg-config --cflags-only-I portaudio-2.0 ) -DMPT_WITH_PORTAUDIO
|
||||
LDFLAGS_PORTAUDIO := $(shell pkg-config --libs-only-L portaudio-2.0 ) $(shell pkg-config --libs-only-other portaudio-2.0 )
|
||||
LDLIBS_PORTAUDIO := $(shell pkg-config --libs-only-l portaudio-2.0 )
|
||||
ifeq ($(shell pkg-config$(TOOLCHAIN_SUFFIX) --exists portaudio-2.0 && echo yes),yes)
|
||||
CPPFLAGS_PORTAUDIO := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --cflags-only-I portaudio-2.0 ) -DMPT_WITH_PORTAUDIO
|
||||
LDFLAGS_PORTAUDIO := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-L portaudio-2.0 ) $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-other portaudio-2.0 )
|
||||
LDLIBS_PORTAUDIO := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-l portaudio-2.0 )
|
||||
else
|
||||
ifeq ($(FORCE_DEPS),1)
|
||||
$(error portaudio not found)
|
||||
|
@ -513,10 +552,10 @@ endif
|
|||
ifeq ($(NO_PORTAUDIOCPP),1)
|
||||
else
|
||||
#LDLIBS += -lportaudiocpp
|
||||
ifeq ($(shell pkg-config --exists portaudiocpp && echo yes),yes)
|
||||
CPPFLAGS_PORTAUDIOCPP := $(shell pkg-config --cflags-only-I portaudiocpp ) -DMPT_WITH_PORTAUDIOCPP
|
||||
LDFLAGS_PORTAUDIOCPP := $(shell pkg-config --libs-only-L portaudiocpp ) $(shell pkg-config --libs-only-other portaudiocpp )
|
||||
LDLIBS_PORTAUDIOCPP := $(shell pkg-config --libs-only-l portaudiocpp )
|
||||
ifeq ($(shell pkg-config$(TOOLCHAIN_SUFFIX) --exists portaudiocpp && echo yes),yes)
|
||||
CPPFLAGS_PORTAUDIOCPP := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --cflags-only-I portaudiocpp ) -DMPT_WITH_PORTAUDIOCPP
|
||||
LDFLAGS_PORTAUDIOCPP := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-L portaudiocpp ) $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-other portaudiocpp )
|
||||
LDLIBS_PORTAUDIOCPP := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-l portaudiocpp )
|
||||
else
|
||||
ifeq ($(FORCE_DEPS),1)
|
||||
$(error portaudiocpp not found)
|
||||
|
@ -530,10 +569,10 @@ endif
|
|||
ifeq ($(NO_PULSEAUDIO),1)
|
||||
else
|
||||
#LDLIBS += -lpulse-simple
|
||||
ifeq ($(shell pkg-config --exists libpulse libpulse-simple && echo yes),yes)
|
||||
CPPFLAGS_PULSEAUDIO := $(shell pkg-config --cflags-only-I libpulse libpulse-simple ) -DMPT_WITH_PULSEAUDIO
|
||||
LDFLAGS_PULSEAUDIO := $(shell pkg-config --libs-only-L libpulse libpulse-simple ) $(shell pkg-config --libs-only-other libpulse libpulse-simple )
|
||||
LDLIBS_PULSEAUDIO := $(shell pkg-config --libs-only-l libpulse libpulse-simple )
|
||||
ifeq ($(shell pkg-config$(TOOLCHAIN_SUFFIX) --exists libpulse libpulse-simple && echo yes),yes)
|
||||
CPPFLAGS_PULSEAUDIO := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --cflags-only-I libpulse libpulse-simple ) -DMPT_WITH_PULSEAUDIO
|
||||
LDFLAGS_PULSEAUDIO := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-L libpulse libpulse-simple ) $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-other libpulse libpulse-simple )
|
||||
LDLIBS_PULSEAUDIO := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-l libpulse libpulse-simple )
|
||||
else
|
||||
ifeq ($(FORCE_DEPS),1)
|
||||
$(error pulseaudio not found)
|
||||
|
@ -547,10 +586,10 @@ endif
|
|||
ifeq ($(NO_FLAC),1)
|
||||
else
|
||||
#LDLIBS += -lFLAC
|
||||
ifeq ($(shell pkg-config --exists 'flac >= 1.3.0' && echo yes),yes)
|
||||
CPPFLAGS_FLAC := $(shell pkg-config --cflags-only-I 'flac >= 1.3.0' ) -DMPT_WITH_FLAC
|
||||
LDFLAGS_FLAC := $(shell pkg-config --libs-only-L 'flac >= 1.3.0' ) $(shell pkg-config --libs-only-other 'flac >= 1.3.0' )
|
||||
LDLIBS_FLAC := $(shell pkg-config --libs-only-l 'flac >= 1.3.0' )
|
||||
ifeq ($(shell pkg-config$(TOOLCHAIN_SUFFIX) --exists 'flac >= 1.3.0' && echo yes),yes)
|
||||
CPPFLAGS_FLAC := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --cflags-only-I 'flac >= 1.3.0' ) -DMPT_WITH_FLAC
|
||||
LDFLAGS_FLAC := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-L 'flac >= 1.3.0' ) $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-other 'flac >= 1.3.0' )
|
||||
LDLIBS_FLAC := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-l 'flac >= 1.3.0' )
|
||||
else
|
||||
ifeq ($(FORCE_DEPS),1)
|
||||
$(error flac not found)
|
||||
|
@ -564,10 +603,10 @@ endif
|
|||
ifeq ($(NO_SNDFILE),1)
|
||||
else
|
||||
#LDLIBS += -lsndfile
|
||||
ifeq ($(shell pkg-config --exists sndfile && echo yes),yes)
|
||||
CPPFLAGS_SNDFILE := $(shell pkg-config --cflags-only-I sndfile ) -DMPT_WITH_SNDFILE
|
||||
LDFLAGS_SNDFILE := $(shell pkg-config --libs-only-L sndfile ) $(shell pkg-config --libs-only-other sndfile )
|
||||
LDLIBS_SNDFILE := $(shell pkg-config --libs-only-l sndfile )
|
||||
ifeq ($(shell pkg-config$(TOOLCHAIN_SUFFIX) --exists sndfile && echo yes),yes)
|
||||
CPPFLAGS_SNDFILE := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --cflags-only-I sndfile ) -DMPT_WITH_SNDFILE
|
||||
LDFLAGS_SNDFILE := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-L sndfile ) $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-other sndfile )
|
||||
LDLIBS_SNDFILE := $(shell pkg-config$(TOOLCHAIN_SUFFIX) --libs-only-l sndfile )
|
||||
else
|
||||
ifeq ($(FORCE_DEPS),1)
|
||||
$(error sndfile not found)
|
||||
|
@ -578,17 +617,31 @@ NO_SNDFILE:=1
|
|||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(USE_ALLEGRO42),1)
|
||||
CPPFLAGS_ALLEGRO42 ?=
|
||||
LDFLAGS_ALLEGRO42 ?=
|
||||
LDLIBS_ALLEGRO42 ?= liballeg.a
|
||||
CPPFLAGS_ALLEGRO42 += -DMPT_WITH_ALLEGRO42
|
||||
endif
|
||||
|
||||
ifeq ($(HACK_ARCHIVE_SUPPORT),1)
|
||||
CPPFLAGS += -DMPT_BUILD_HACK_ARCHIVE_SUPPORT
|
||||
endif
|
||||
|
||||
CPPCHECK_FLAGS += -j $(NUMTHREADS)
|
||||
CPPCHECK_FLAGS += --std=c99 --std=c++11
|
||||
CPPCHECK_FLAGS += --quiet
|
||||
CPPCHECK_FLAGS += --enable=warning --inline-suppr --template='{file}:{line}: warning: {severity}: {message} [{id}]'
|
||||
CPPCHECK_FLAGS += --suppress=missingIncludeSystem
|
||||
|
||||
CPPCHECK_FLAGS += $(CPPFLAGS)
|
||||
CPPFLAGS += $(CPPFLAGS_ZLIB) $(CPPFLAGS_MPG123) $(CPPFLAGS_OGG) $(CPPFLAGS_VORBIS) $(CPPFLAGS_VORBISFILE)
|
||||
LDFLAGS += $(LDFLAGS_ZLIB) $(LDFLAGS_MPG123) $(LDFLAGS_OGG) $(LDFLAGS_VORBIS) $(LDFLAGS_VORBISFILE)
|
||||
LDLIBS += $(LDLIBS_ZLIB) $(LDLIBS_MPG123) $(LDLIBS_OGG) $(LDLIBS_VORBIS) $(LDLIBS_VORBISFILE)
|
||||
|
||||
CPPFLAGS_OPENMPT123 += $(CPPFLAGS_SDL2) $(CPPFLAGS_SDL) $(CPPFLAGS_PORTAUDIO) $(CPPFLAGS_PULSEAUDIO) $(CPPFLAGS_FLAC) $(CPPFLAGS_SNDFILE)
|
||||
LDFLAGS_OPENMPT123 += $(LDFLAGS_SDL2) $(LDFLAGS_SDL) $(LDFLAGS_PORTAUDIO) $(LDFLAGS_PULSEAUDIO) $(LDFLAGS_FLAC) $(LDFLAGS_SNDFILE)
|
||||
LDLIBS_OPENMPT123 += $(LDLIBS_SDL2) $(LDLIBS_SDL) $(LDLIBS_PORTAUDIO) $(LDLIBS_PULSEAUDIO) $(LDLIBS_FLAC) $(LDLIBS_SNDFILE)
|
||||
CPPFLAGS_OPENMPT123 += $(CPPFLAGS_SDL2) $(CPPFLAGS_SDL) $(CPPFLAGS_PORTAUDIO) $(CPPFLAGS_PULSEAUDIO) $(CPPFLAGS_FLAC) $(CPPFLAGS_SNDFILE) $(CPPFLAGS_ALLEGRO42)
|
||||
LDFLAGS_OPENMPT123 += $(LDFLAGS_SDL2) $(LDFLAGS_SDL) $(LDFLAGS_PORTAUDIO) $(LDFLAGS_PULSEAUDIO) $(LDFLAGS_FLAC) $(LDFLAGS_SNDFILE) $(LDFLAGS_ALLEGRO42)
|
||||
LDLIBS_OPENMPT123 += $(LDLIBS_SDL2) $(LDLIBS_SDL) $(LDLIBS_PORTAUDIO) $(LDLIBS_PULSEAUDIO) $(LDLIBS_FLAC) $(LDLIBS_SNDFILE) $(LDLIBS_ALLEGRO42)
|
||||
|
||||
|
||||
%: %.o
|
||||
|
@ -717,7 +770,8 @@ endif
|
|||
include/minimp3/minimp3.o : CFLAGS+=$(CFLAGS_SILENT)
|
||||
include/minimp3/minimp3.test.o : CFLAGS+=$(CFLAGS_SILENT)
|
||||
ifeq ($(NO_MPG123),1)
|
||||
ifeq ($(USE_MINIMP3),1)
|
||||
ifeq ($(NO_MINIMP3),1)
|
||||
else
|
||||
LIBOPENMPT_C_SOURCES += include/minimp3/minimp3.c
|
||||
LIBOPENMPTTEST_C_SOURCES += include/minimp3/minimp3.c
|
||||
CPPFLAGS += -DMPT_WITH_MINIMP3
|
||||
|
@ -869,6 +923,8 @@ ifeq ($(SHARED_SONAME),1)
|
|||
LIBOPENMPT_LDFLAGS += -Wl,-soname,$(LIBOPENMPT_SONAME)
|
||||
endif
|
||||
|
||||
MISC_OUTPUTS += bin/empty.cpp
|
||||
MISC_OUTPUTS += bin/empty.out
|
||||
MISC_OUTPUTS += bin/openmpt123$(EXESUFFIX).norpath
|
||||
MISC_OUTPUTS += bin/libopenmpt_example_c$(EXESUFFIX).norpath
|
||||
MISC_OUTPUTS += bin/libopenmpt_example_c_mem$(EXESUFFIX).norpath
|
||||
|
@ -880,15 +936,23 @@ MISC_OUTPUTS += bin/libopenmpt_example_c_stdout$(EXESUFFIX).norpath
|
|||
MISC_OUTPUTS += libopenmpt$(SOSUFFIX)
|
||||
MISC_OUTPUTS += bin/.docs
|
||||
MISC_OUTPUTS += bin/libopenmpt_test$(EXESUFFIX)
|
||||
MISC_OUTPUTS += bin/libopenmpt_test.wasm
|
||||
MISC_OUTPUTS += bin/libopenmpt_test.js.mem
|
||||
MISC_OUTPUTS += bin/made.docs
|
||||
MISC_OUTPUTS += bin/$(LIBOPENMPT_SONAME)
|
||||
MISC_OUTPUTS += bin/libopenmpt.wasm
|
||||
MISC_OUTPUTS += bin/libopenmpt.js.mem
|
||||
MISC_OUTPUTS += bin/libopenmpt_example_c.wasm
|
||||
MISC_OUTPUTS += bin/libopenmpt_example_c.js.mem
|
||||
MISC_OUTPUTS += bin/libopenmpt_example_c_mem.wasm
|
||||
MISC_OUTPUTS += bin/libopenmpt_example_c_mem.js.mem
|
||||
MISC_OUTPUTS += bin/libopenmpt_example_c_pipe.wasm
|
||||
MISC_OUTPUTS += bin/libopenmpt_example_c_pipe.js.mem
|
||||
MISC_OUTPUTS += bin/libopenmpt_example_c_probe.wasm
|
||||
MISC_OUTPUTS += bin/libopenmpt_example_c_probe.js.mem
|
||||
MISC_OUTPUTS += bin/libopenmpt_example_c_stdout.wasm
|
||||
MISC_OUTPUTS += bin/libopenmpt_example_c_stdout.js.mem
|
||||
MISC_OUTPUTS += bin/libopenmpt_example_c_unsafe.wasm
|
||||
MISC_OUTPUTS += bin/libopenmpt_example_c_unsafe.js.mem
|
||||
MISC_OUTPUTS += bin/openmpt.a
|
||||
#old
|
||||
|
@ -906,6 +970,7 @@ DIST_OUTPUTS += bin/dist-zip.tar
|
|||
DIST_OUTPUTS += bin/dist-doc.tar
|
||||
DIST_OUTPUTS += bin/dist-autotools.tar
|
||||
DIST_OUTPUTS += bin/dist-js.tar
|
||||
DIST_OUTPUTS += bin/dist-dos.tar
|
||||
DIST_OUTPUTS += bin/made.docs
|
||||
|
||||
DIST_OUTPUTDIRS += bin/dist
|
||||
|
@ -914,6 +979,7 @@ DIST_OUTPUTDIRS += bin/dist-tar
|
|||
DIST_OUTPUTDIRS += bin/dist-zip
|
||||
DIST_OUTPUTDIRS += bin/dist-autotools
|
||||
DIST_OUTPUTDIRS += bin/dist-js
|
||||
DIST_OUTPUTDIRS += bin/dist-dos
|
||||
DIST_OUTPUTDIRS += bin/docs
|
||||
|
||||
|
||||
|
@ -1090,6 +1156,16 @@ bin/dist-js.tar: bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION).dev.js.tar.gz
|
|||
cd bin/dist-js/ && cp libopenmpt-$(DIST_LIBOPENMPT_VERSION).dev.js.tar.gz libopenmpt/dev.js/$(DIST_LIBOPENMPT_TARBALL_VERSION)/
|
||||
cd bin/dist-js/ && tar cvf ../dist-js.tar libopenmpt
|
||||
|
||||
.PHONY: dist-dos
|
||||
dist-dos: bin/dist-dos.tar
|
||||
|
||||
bin/dist-dos.tar: bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION).bin.dos.zip
|
||||
rm -rf bin/dist-dos.tar
|
||||
cd bin/dist-dos/ && rm -rf libopenmpt
|
||||
cd bin/dist-dos/ && mkdir -p libopenmpt/bin.dos/$(DIST_LIBOPENMPT_TARBALL_VERSION)/
|
||||
cd bin/dist-dos/ && cp libopenmpt-$(DIST_LIBOPENMPT_VERSION).bin.dos.zip libopenmpt/bin.dos/$(DIST_LIBOPENMPT_TARBALL_VERSION)/
|
||||
cd bin/dist-dos/ && tar cvf ../dist-dos.tar libopenmpt
|
||||
|
||||
.PHONY: bin/dist.mk
|
||||
bin/dist.mk:
|
||||
rm -rf $@
|
||||
|
@ -1145,6 +1221,8 @@ bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION).makefile.tar: bin/dist.mk bin
|
|||
svn export ./examples bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/examples
|
||||
svn export ./openmpt123 bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/openmpt123
|
||||
svn export ./contrib bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/contrib
|
||||
svn export ./include/allegro42 bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/allegro42
|
||||
svn export ./include/cwsdpmi bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/cwsdpmi
|
||||
svn export ./include/minimp3 bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/minimp3
|
||||
svn export ./include/miniz bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/miniz
|
||||
svn export ./include/modplug bin/dist-tar/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include/modplug
|
||||
|
@ -1159,17 +1237,24 @@ bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION).msvc.zip: bin/dist.mk bin/svn
|
|||
rm -rf bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)
|
||||
mkdir -p bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)
|
||||
mkdir -p bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build
|
||||
mkdir -p bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/genie
|
||||
mkdir -p bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/premake
|
||||
mkdir -p bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/include
|
||||
svn export ./LICENSE bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSE --native-eol CRLF
|
||||
svn export ./README.md bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/README.md --native-eol CRLF
|
||||
svn export ./Makefile bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/Makefile --native-eol CRLF
|
||||
svn export ./bin bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin --native-eol CRLF
|
||||
svn export ./build/genie/def bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/genie/def --native-eol CRLF
|
||||
svn export ./build/premake/def bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/premake/def --native-eol CRLF
|
||||
svn export ./build/premake/inc bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/premake/inc --native-eol CRLF
|
||||
svn export ./build/premake/lnk bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/premake/lnk --native-eol CRLF
|
||||
svn export ./build/svn_version bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/svn_version --native-eol CRLF
|
||||
svn export ./build/vcpkg bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vcpkg --native-eol CRLF
|
||||
svn export ./build/vs bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs --native-eol CRLF
|
||||
svn export ./build/vs2015 bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs2015 --native-eol CRLF
|
||||
svn export ./build/vs2015xp bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs2015xp --native-eol CRLF
|
||||
svn export ./build/vs2017 bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs2017 --native-eol CRLF
|
||||
svn export ./build/vs2017win10 bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs2017win10
|
||||
svn export ./build/vs2017xp bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/vs2017xp --native-eol CRLF
|
||||
svn export ./build/windesktop81 bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/windesktop81 --native-eol CRLF
|
||||
svn export ./build/winstore82 bin/dist-zip/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/build/winstore82 --native-eol CRLF
|
||||
|
@ -1210,25 +1295,64 @@ bin/dist-zip/OpenMPT-src-$(DIST_OPENMPT_VERSION).zip: bin/svn_version_dist.h
|
|||
cd bin/dist-zip/OpenMPT-src-$(DIST_OPENMPT_VERSION)/ && zip -r ../OpenMPT-src-$(DIST_OPENMPT_VERSION).zip --compression-method deflate -9 *
|
||||
|
||||
.PHONY: bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION).dev.js.tar
|
||||
bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION).dev.js.tar: bin/libopenmpt.js
|
||||
bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION).dev.js.tar:
|
||||
mkdir -p bin/dist-js
|
||||
rm -rf bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)
|
||||
mkdir -p bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)
|
||||
mkdir -p bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/licenses
|
||||
svn export ./LICENSE bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/license.txt
|
||||
svn export ./include/minimp3/LICENSE bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/licenses/license.minimp3.txt
|
||||
svn export ./include/miniz/miniz.c bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/licenses/license.miniz.txt
|
||||
svn export ./include/stb_vorbis/stb_vorbis.c bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/licenses/license.stb_vorbis.txt
|
||||
cp bin/libopenmpt.js bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/libopenmpt.js
|
||||
cp bin/libopenmpt.js.mem bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/libopenmpt.js.mem
|
||||
mkdir -p bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin
|
||||
mkdir -p bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin/wasm
|
||||
cp bin/stage/wasm/libopenmpt.js bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin/wasm/libopenmpt.js
|
||||
cp bin/stage/wasm/libopenmpt.wasm bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin/wasm/libopenmpt.wasm
|
||||
mkdir -p bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin/asmjs128m
|
||||
cp bin/stage/asmjs128m/libopenmpt.js bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin/asmjs128m/libopenmpt.js
|
||||
cp bin/stage/asmjs128m/libopenmpt.js.mem bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin/asmjs128m/libopenmpt.js.mem
|
||||
mkdir -p bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin/asmjs
|
||||
cp bin/stage/asmjs/libopenmpt.js bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin/asmjs/libopenmpt.js
|
||||
cp bin/stage/asmjs/libopenmpt.js.mem bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin/asmjs/libopenmpt.js.mem
|
||||
mkdir -p bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin/js
|
||||
cp bin/stage/js/libopenmpt.js bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin/js/libopenmpt.js
|
||||
cp bin/stage/js/libopenmpt.js.mem bin/dist-js/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/bin/js/libopenmpt.js.mem
|
||||
cd bin/dist-js/ && tar cv libopenmpt-$(DIST_LIBOPENMPT_VERSION) > libopenmpt-$(DIST_LIBOPENMPT_VERSION).dev.js.tar
|
||||
|
||||
.PHONY: bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION).bin.dos.zip
|
||||
bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION).bin.dos.zip:
|
||||
mkdir -p bin/dist-dos
|
||||
rm -rf bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)
|
||||
mkdir -p bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)
|
||||
mkdir -p bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES
|
||||
svn export ./LICENSE bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSE.TXT --native-eol CRLF
|
||||
cd bin/dist-dos && unzip ../../build/externals/all422s.zip allegro/readme.txt
|
||||
mv bin/dist-dos/allegro/readme.txt bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES/ALLEGRO.TXT
|
||||
rmdir bin/dist-dos/allegro
|
||||
cp include/cwsdpmi/bin/cwsdpmi.doc bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES/CWSDPMI.TXT
|
||||
svn export ./include/minimp3/LICENSE bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES/MINIMP3.TXT --native-eol CRLF
|
||||
svn export ./include/miniz/miniz.c bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES/MINIZ.TXT --native-eol CRLF
|
||||
svn export ./include/stb_vorbis/stb_vorbis.c bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/LICENSES/STBVORB.TXT --native-eol CRLF
|
||||
mkdir -p bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/SRC
|
||||
cp build/externals/csdpmi7s.zip bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/SRC/CSDPMI7S.ZIP
|
||||
mkdir -p bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/BIN
|
||||
cp bin/openmpt123.exe bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/BIN/OMPT123.EXE
|
||||
cp include/cwsdpmi/bin/cwsdpmi.doc bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/BIN/CWSDPMI.DOC
|
||||
cp include/cwsdpmi/bin/CWSDPMI.EXE bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/BIN/CWSDPMI.EXE
|
||||
cp include/cwsdpmi/bin/CWSDPR0.EXE bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/BIN/CWSDPR0.EXE
|
||||
cp include/cwsdpmi/bin/cwsparam.doc bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/BIN/CWSPARAM.DOC
|
||||
cp include/cwsdpmi/bin/CWSPARAM.EXE bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/BIN/CWSPARAM.EXE
|
||||
cp include/cwsdpmi/bin/CWSDSTUB.EXE bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/BIN/CWSDSTUB.EXE
|
||||
cp include/cwsdpmi/bin/CWSDSTR0.EXE bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/BIN/CWSDSTR0.EXE
|
||||
cd bin/dist-dos/libopenmpt-$(DIST_LIBOPENMPT_VERSION)/ && zip -r ../libopenmpt-$(DIST_LIBOPENMPT_VERSION).bin.dos.zip --compression-method deflate -9 *
|
||||
|
||||
bin/libopenmpt.a: $(LIBOPENMPT_OBJECTS)
|
||||
$(INFO) [AR] $@
|
||||
$(SILENT)$(AR) $(ARFLAGS) $@ $^
|
||||
|
||||
bin/libopenmpt$(SOSUFFIX): $(LIBOPENMPT_OBJECTS)
|
||||
$(INFO) [LD] $@
|
||||
$(SILENT)$(LINK.cc) -shared $(LIBOPENMPT_LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@
|
||||
$(SILENT)$(LINK.cc) -shared $(LIBOPENMPT_LDFLAGS) $(SO_LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@
|
||||
ifeq ($(SHARED_SONAME),1)
|
||||
$(SILENT)mv bin/libopenmpt$(SOSUFFIX) bin/$(LIBOPENMPT_SONAME)
|
||||
$(SILENT)ln -sf $(LIBOPENMPT_SONAME) bin/libopenmpt$(SOSUFFIX)
|
||||
|
@ -1236,7 +1360,7 @@ endif
|
|||
|
||||
bin/libopenmpt_modplug$(SOSUFFIX): $(LIBOPENMPT_MODPLUG_OBJECTS) $(OUTPUT_LIBOPENMPT)
|
||||
$(INFO) [LD] $@
|
||||
$(SILENT)$(LINK.cc) -shared $(LDFLAGS_LIBOPENMPT) $(LIBOPENMPT_MODPLUG_OBJECTS) $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) -o $@
|
||||
$(SILENT)$(LINK.cc) -shared $(SO_LDFLAGS) $(LDFLAGS_LIBOPENMPT) $(LIBOPENMPT_MODPLUG_OBJECTS) $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) -o $@
|
||||
|
||||
bin/openmpt123.1: bin/openmpt123$(EXESUFFIX) openmpt123/openmpt123.h2m
|
||||
$(INFO) [HELP2MAN] $@
|
||||
|
@ -1248,11 +1372,11 @@ openmpt123/openmpt123.o: openmpt123/openmpt123.cpp
|
|||
$(SILENT)$(COMPILE.cc) $(CXXFLAGS_OPENMPT123) $(CPPFLAGS_OPENMPT123) $(OUTPUT_OPTION) $<
|
||||
bin/openmpt123$(EXESUFFIX): $(OPENMPT123_OBJECTS) $(OBJECTS_LIBOPENMPT) $(OUTPUT_LIBOPENMPT)
|
||||
$(INFO) [LD] $@
|
||||
$(SILENT)$(LINK.cc) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_OPENMPT123) $(OPENMPT123_OBJECTS) $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_OPENMPT123) -o $@
|
||||
$(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_OPENMPT123) $(OPENMPT123_OBJECTS) $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_OPENMPT123) -o $@
|
||||
ifeq ($(HOST),unix)
|
||||
$(SILENT)mv $@ $@.norpath
|
||||
$(INFO) [LD] $@
|
||||
$(SILENT)$(LINK.cc) $(LDFLAGS_RPATH) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_OPENMPT123) $(OPENMPT123_OBJECTS) $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_OPENMPT123) -o $@
|
||||
$(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_RPATH) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_OPENMPT123) $(OPENMPT123_OBJECTS) $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_OPENMPT123) -o $@
|
||||
endif
|
||||
|
||||
contrib/fuzzing/fuzz.o: contrib/fuzzing/fuzz.c
|
||||
|
@ -1298,61 +1422,82 @@ examples/libopenmpt_example_cxx.o: examples/libopenmpt_example_cxx.cpp
|
|||
$(SILENT)$(COMPILE.cc) $(CXXFLAGS_PORTAUDIOCPP) $(CPPFLAGS_PORTAUDIOCPP) $(OUTPUT_OPTION) $<
|
||||
bin/libopenmpt_example_c$(EXESUFFIX): examples/libopenmpt_example_c.o $(OBJECTS_LIBOPENMPT) $(OUTPUT_LIBOPENMPT)
|
||||
$(INFO) [LD] $@
|
||||
$(SILENT)$(LINK.cc) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_PORTAUDIO) examples/libopenmpt_example_c.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_PORTAUDIO) -o $@
|
||||
$(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_PORTAUDIO) examples/libopenmpt_example_c.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_PORTAUDIO) -o $@
|
||||
ifeq ($(HOST),unix)
|
||||
$(SILENT)mv $@ $@.norpath
|
||||
$(INFO) [LD] $@
|
||||
$(SILENT)$(LINK.cc) $(LDFLAGS_RPATH) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_PORTAUDIO) examples/libopenmpt_example_c.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_PORTAUDIO) -o $@
|
||||
$(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(BIN_LDFLAGS)$(LDFLAGS_RPATH) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_PORTAUDIO) examples/libopenmpt_example_c.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_PORTAUDIO) -o $@
|
||||
endif
|
||||
bin/libopenmpt_example_c_mem$(EXESUFFIX): examples/libopenmpt_example_c_mem.o $(OBJECTS_LIBOPENMPT) $(OUTPUT_LIBOPENMPT)
|
||||
$(INFO) [LD] $@
|
||||
$(SILENT)$(LINK.cc) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_PORTAUDIO) examples/libopenmpt_example_c_mem.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_PORTAUDIO) -o $@
|
||||
$(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_PORTAUDIO) examples/libopenmpt_example_c_mem.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_PORTAUDIO) -o $@
|
||||
ifeq ($(HOST),unix)
|
||||
$(SILENT)mv $@ $@.norpath
|
||||
$(INFO) [LD] $@
|
||||
$(SILENT)$(LINK.cc) $(LDFLAGS_RPATH) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_PORTAUDIO) examples/libopenmpt_example_c_mem.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_PORTAUDIO) -o $@
|
||||
$(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_RPATH) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_PORTAUDIO) examples/libopenmpt_example_c_mem.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_PORTAUDIO) -o $@
|
||||
endif
|
||||
bin/libopenmpt_example_c_unsafe$(EXESUFFIX): examples/libopenmpt_example_c_unsafe.o $(OBJECTS_LIBOPENMPT) $(OUTPUT_LIBOPENMPT)
|
||||
$(INFO) [LD] $@
|
||||
$(SILENT)$(LINK.cc) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_PORTAUDIO) examples/libopenmpt_example_c_unsafe.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_PORTAUDIO) -o $@
|
||||
$(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_PORTAUDIO) examples/libopenmpt_example_c_unsafe.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_PORTAUDIO) -o $@
|
||||
ifeq ($(HOST),unix)
|
||||
$(SILENT)mv $@ $@.norpath
|
||||
$(INFO) [LD] $@
|
||||
$(SILENT)$(LINK.cc) $(LDFLAGS_RPATH) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_PORTAUDIO) examples/libopenmpt_example_c_unsafe.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_PORTAUDIO) -o $@
|
||||
$(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_RPATH) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_PORTAUDIO) examples/libopenmpt_example_c_unsafe.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_PORTAUDIO) -o $@
|
||||
endif
|
||||
bin/libopenmpt_example_c_pipe$(EXESUFFIX): examples/libopenmpt_example_c_pipe.o $(OBJECTS_LIBOPENMPT) $(OUTPUT_LIBOPENMPT)
|
||||
$(INFO) [LD] $@
|
||||
$(SILENT)$(LINK.cc) $(LDFLAGS_LIBOPENMPT) examples/libopenmpt_example_c_pipe.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) -o $@
|
||||
$(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_LIBOPENMPT) examples/libopenmpt_example_c_pipe.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) -o $@
|
||||
ifeq ($(HOST),unix)
|
||||
$(SILENT)mv $@ $@.norpath
|
||||
$(INFO) [LD] $@
|
||||
$(SILENT)$(LINK.cc) $(LDFLAGS_RPATH) $(LDFLAGS_LIBOPENMPT) examples/libopenmpt_example_c_pipe.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) -o $@
|
||||
$(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_RPATH) $(LDFLAGS_LIBOPENMPT) examples/libopenmpt_example_c_pipe.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) -o $@
|
||||
endif
|
||||
bin/libopenmpt_example_c_stdout$(EXESUFFIX): examples/libopenmpt_example_c_stdout.o $(OBJECTS_LIBOPENMPT) $(OUTPUT_LIBOPENMPT)
|
||||
$(INFO) [LD] $@
|
||||
$(SILENT)$(LINK.cc) $(LDFLAGS_LIBOPENMPT) examples/libopenmpt_example_c_stdout.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) -o $@
|
||||
$(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_LIBOPENMPT) examples/libopenmpt_example_c_stdout.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) -o $@
|
||||
ifeq ($(HOST),unix)
|
||||
$(SILENT)mv $@ $@.norpath
|
||||
$(INFO) [LD] $@
|
||||
$(SILENT)$(LINK.cc) $(LDFLAGS_RPATH) $(LDFLAGS_LIBOPENMPT) examples/libopenmpt_example_c_stdout.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) -o $@
|
||||
$(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_RPATH) $(LDFLAGS_LIBOPENMPT) examples/libopenmpt_example_c_stdout.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) -o $@
|
||||
endif
|
||||
bin/libopenmpt_example_c_probe$(EXESUFFIX): examples/libopenmpt_example_c_probe.o $(OBJECTS_LIBOPENMPT) $(OUTPUT_LIBOPENMPT)
|
||||
$(INFO) [LD] $@
|
||||
$(SILENT)$(LINK.cc) $(LDFLAGS_LIBOPENMPT) examples/libopenmpt_example_c_probe.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) -o $@
|
||||
$(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_LIBOPENMPT) examples/libopenmpt_example_c_probe.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) -o $@
|
||||
ifeq ($(HOST),unix)
|
||||
$(SILENT)mv $@ $@.norpath
|
||||
$(INFO) [LD] $@
|
||||
$(SILENT)$(LINK.cc) $(LDFLAGS_RPATH) $(LDFLAGS_LIBOPENMPT) examples/libopenmpt_example_c_probe.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) -o $@
|
||||
$(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_RPATH) $(LDFLAGS_LIBOPENMPT) examples/libopenmpt_example_c_probe.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) -o $@
|
||||
endif
|
||||
bin/libopenmpt_example_cxx$(EXESUFFIX): examples/libopenmpt_example_cxx.o $(OBJECTS_LIBOPENMPT) $(OUTPUT_LIBOPENMPT)
|
||||
$(INFO) [LD] $@
|
||||
$(SILENT)$(LINK.cc) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_PORTAUDIOCPP) examples/libopenmpt_example_cxx.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_PORTAUDIOCPP) -o $@
|
||||
$(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_PORTAUDIOCPP) examples/libopenmpt_example_cxx.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_PORTAUDIOCPP) -o $@
|
||||
ifeq ($(HOST),unix)
|
||||
$(SILENT)mv $@ $@.norpath
|
||||
$(INFO) [LD] $@
|
||||
$(SILENT)$(LINK.cc) $(LDFLAGS_RPATH) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_PORTAUDIOCPP) examples/libopenmpt_example_cxx.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_PORTAUDIOCPP) -o $@
|
||||
$(SILENT)$(LINK.cc) $(BIN_LDFLAGS) $(LDFLAGS_RPATH) $(LDFLAGS_LIBOPENMPT) $(LDFLAGS_PORTAUDIOCPP) examples/libopenmpt_example_cxx.o $(OBJECTS_LIBOPENMPT) $(LOADLIBES) $(LDLIBS) $(LDLIBS_LIBOPENMPT) $(LDLIBS_PORTAUDIOCPP) -o $@
|
||||
endif
|
||||
|
||||
.PHONY: cppcheck-libopenmpt
|
||||
cppcheck-libopenmpt:
|
||||
$(INFO) [CPPCHECK] libopenmpt
|
||||
$(SILENT)$(CPPCHECK) -DCPPCHECK -DMPT_CPPCHECK_CUSTOM $(CPPCHECK_FLAGS) $(CPPCHECK_PLATFORM) --check-config --suppress=unmatchedSuppression $(LIBOPENMPT_CXX_SOURCES) $(LIBOPENMPT_C_SOURCES)
|
||||
$(SILENT)$(CPPCHECK) -DCPPCHECK -DMPT_CPPCHECK_CUSTOM $(CPPCHECK_FLAGS) $(CPPCHECK_PLATFORM) $(LIBOPENMPT_CXX_SOURCES) $(LIBOPENMPT_C_SOURCES)
|
||||
|
||||
.PHONY: cppcheck-libopenmpt-test
|
||||
cppcheck-libopenmpt-test:
|
||||
$(INFO) [CPPCHECK] libopenmpt-test
|
||||
$(SILENT)$(CPPCHECK) -DCPPCHECK -DMPT_CPPCHECK_CUSTOM $(CPPCHECK_FLAGS) $(CPPCHECK_PLATFORM) -DLIBOPENMPT_BUILD_TEST --check-config --suppress=unmatchedSuppression $(LIBOPENMPTTEST_CXX_SOURCES) $(LIBOPENMPTTEST_C_SOURCES)
|
||||
$(SILENT)$(CPPCHECK) -DCPPCHECK -DMPT_CPPCHECK_CUSTOM $(CPPCHECK_FLAGS) $(CPPCHECK_PLATFORM) -DLIBOPENMPT_BUILD_TEST $(LIBOPENMPTTEST_CXX_SOURCES) $(LIBOPENMPTTEST_C_SOURCES)
|
||||
|
||||
.PHONY: cppcheck-openmpt123
|
||||
cppcheck-openmpt123:
|
||||
$(INFO) [CPPCHECK] openmpt123
|
||||
$(SILENT)$(CPPCHECK) -DCPPCHECK -DMPT_CPPCHECK_CUSTOM $(CPPCHECK_FLAGS) $(CPPCHECK_PLATFORM) --check-config --suppress=unmatchedSuppression $(OPENMPT123_CXX_SOURCES)
|
||||
$(SILENT)$(CPPCHECK) -DCPPCHECK -DMPT_CPPCHECK_CUSTOM $(CPPCHECK_FLAGS) $(CPPCHECK_PLATFORM) $(OPENMPT123_CXX_SOURCES)
|
||||
|
||||
.PHONY: cppcheck
|
||||
cppcheck: cppcheck-libopenmpt cppcheck-libopenmpt-test cppcheck-openmpt123
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
$(INFO) clean ...
|
||||
|
|
|
@ -1,10 +1,26 @@
|
|||
|
||||
README
|
||||
======
|
||||
|
||||
OpenMPT and libopenmpt
|
||||
======================
|
||||
|
||||
This repository contains OpenMPT, a free Windows/Wine-based
|
||||
[tracker](https://en.wikipedia.org/wiki/Music_tracker) and libopenmpt,
|
||||
a library to render tracker music (MOD, XM, S3M, IT MPTM and dozens of other
|
||||
legacy formats) to a PCM audio stream. libopenmpt is directly based on OpenMPT,
|
||||
offering the same playback quality and format support, and development of the
|
||||
two happens in parallel.
|
||||
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
The OpenMPT/libopenmpt project is distributed under the *BSD-3-Clause* License.
|
||||
See [LICENSE](LICENSE) for the full license text.
|
||||
|
||||
Files below the `include/` (external projects) and `contrib/` (related assets
|
||||
not directly considered integral part of the project) folders may be subject to
|
||||
other licenses. See the respective subfolders for license information. These
|
||||
folders are not distributed in all source packages, and in particular they are
|
||||
not distributed in the Autotools packages.
|
||||
|
||||
|
||||
How to compile
|
||||
--------------
|
||||
|
@ -24,58 +40,35 @@ How to compile
|
|||
To compile the project, open `build/vs2017/OpenMPT.sln` and hit the
|
||||
compile button.
|
||||
|
||||
- OpenMPT requires the compile host system to be 64bit x86-64.
|
||||
|
||||
- The Windows 8.1 SDK and Microsoft Foundation Classes (MFC) are required to
|
||||
build OpenMPT (both are included with Visual Studio, however may need to be
|
||||
selected explicitly during setup). In order to build OpenMPT for Windows XP,
|
||||
the XP targetting toolset also needs to be installed.
|
||||
|
||||
- The VST and ASIO SDKs are needed for compiling with VST and ASIO support.
|
||||
- The ASIO SDK is needed for compiling with ASIO support.
|
||||
|
||||
If you don't want this, uncomment `#define NO_VST` and comment out
|
||||
`#define MPT_WITH_ASIO` in the file `common/BuildSettings.h`.
|
||||
If you don't want this, comment out `#define MPT_WITH_ASIO` in the file
|
||||
`common/BuildSettings.h`.
|
||||
|
||||
The ASIO and VST SDKs can be downloaded automatically on Windows 7 or later
|
||||
with 7-Zip installed by just running the `build/download_externals.cmd`
|
||||
script.
|
||||
The ASIO SDK can be downloaded automatically on Windows 7 or later by just
|
||||
running the `build/download_externals.cmd` script.
|
||||
|
||||
If you do not want to or cannot use this script, you may follow these manual
|
||||
steps instead:
|
||||
|
||||
- ASIO:
|
||||
|
||||
If you use `#define MPT_WITH_ASIO`, you will need to put the ASIO SDK in
|
||||
the `include/ASIOSDK2` folder. The top level directory of the SDK is
|
||||
already named `ASIOSDK2`, so simply move that directory in the include
|
||||
folder.
|
||||
|
||||
Please visit
|
||||
[steinberg.net](http://www.steinberg.net/en/company/developers.html) to
|
||||
- Visit
|
||||
[steinberg.net](https://www.steinberg.net/en/company/developers.html) to
|
||||
download the SDK.
|
||||
|
||||
- VST:
|
||||
- Put the ASIO SDK in the `include/ASIOSDK2` folder. The top level
|
||||
directory of the SDK is already named `ASIOSDK2`, so simply move that
|
||||
directory in the include folder.
|
||||
|
||||
If you don't use `#define NO_VST`, you will need to put the VST SDK in
|
||||
the `include/vstsdk2.4` folder.
|
||||
|
||||
Simply copy all files from the `VST3 SDK` folder in the SDK .zip file to
|
||||
`include/vstsdk2.4/`.
|
||||
|
||||
Note: OpenMPT makes use of the VST 2.4 specification only. The VST3 SDK
|
||||
still contains all necessary files in the right locations. If you still
|
||||
have the old VST 2.4 SDK laying around, this should also work fine.
|
||||
|
||||
Please visit
|
||||
[steinberg.net](http://www.steinberg.net/en/company/developers.html) to
|
||||
download the SDK.
|
||||
|
||||
If you need further help with the VST and ASIO SDKs, get in touch with the
|
||||
If you need further help with the ASIO SDK, get in touch with the
|
||||
main OpenMPT developers.
|
||||
|
||||
- 7-Zip is required to be installed in the default path in order to build the
|
||||
required files for OpenMPT Wine integration.
|
||||
|
||||
Please visit [7-zip.org](http://www.7-zip.org/) to download 7-Zip.
|
||||
|
||||
|
||||
### libopenmpt and openmpt123
|
||||
|
||||
|
@ -90,12 +83,31 @@ For detailed requirements, see `libopenmpt/dox/quickstart.md`.
|
|||
make check
|
||||
sudo make install
|
||||
|
||||
Cross-compilation is generally supported (although only tested for
|
||||
targetting MinGW-w64).
|
||||
|
||||
Note that some MinGW-w64 distributions come with the `win32` threading model
|
||||
enabled by default instead of the `posix` threading model. The `win32`
|
||||
threading model lacks proper support for C++11 `<thread>` and `<mutex>` as
|
||||
well as thread-safe magic statics. It is recommended to use the `posix`
|
||||
threading model for libopenmpt for this reason. On Debian, the appropriate
|
||||
configure command is
|
||||
`./configure --host=x86_64-w64-mingw32 CC=x86_64-w64-mingw32-gcc-posix CXX=x86_64-w64-mingw32-g++-posix`
|
||||
for 64bit, or
|
||||
`./configure --host=i686-w64-mingw32 CC=i686-w64-mingw32-gcc-posix CXX=i686-w64-mingw32-g++-posix`
|
||||
for 32bit. Other MinGW-w64 distributions may differ.
|
||||
|
||||
- Visual Studio:
|
||||
|
||||
- You will find solutions for Visual Studio 2015 to 2017 in the
|
||||
corresponding `build/vsVERSION/` folder.
|
||||
Projects that target Windows versions before Windows 7 are available in
|
||||
`build/vsVERSIONxp/`
|
||||
`build/vsVERSIONxp/`.
|
||||
Projects that target Windows 10 1709 Desktop (10.0.16299.0, including
|
||||
ARM and ARM64) or later versions are available in
|
||||
`build/vsVERSIONwin10/`.
|
||||
Minimal projects that target Windows 10 UWP are available in
|
||||
`build/winstore82/`.
|
||||
Most projects are supported with any of the mentioned Visual Studio
|
||||
verions, with the following exceptions:
|
||||
|
||||
|
@ -103,10 +115,13 @@ For detailed requirements, see `libopenmpt/dox/quickstart.md`.
|
|||
|
||||
- xmp-openmpt: Requires Visual Studio with MFC.
|
||||
|
||||
- libopenmpt requires the compile host system to be 64bit x86-64 when
|
||||
building with Visual Studio.
|
||||
|
||||
- You will need the Winamp 5 SDK and the XMPlay SDK if you want to
|
||||
compile the plugins for these 2 players. They can be downloaded
|
||||
automatically on Windows 7 or later with 7-Zip installed by just running
|
||||
the `build/download_externals.cmd` script.
|
||||
automatically on Windows 7 or later by just running the
|
||||
`build/download_externals.cmd` script.
|
||||
|
||||
If you do not want to or cannot use this script, you may follow these
|
||||
manual steps instead:
|
||||
|
@ -126,7 +141,7 @@ For detailed requirements, see `libopenmpt/dox/quickstart.md`.
|
|||
To build libopenmpt with XMPlay input plugin support, copy the
|
||||
contents of xmp-sdk.zip into include/xmplay/.
|
||||
|
||||
Please visit [un4seen.com](http://www.un4seen.com/xmplay.html) to
|
||||
Please visit [un4seen.com](https://www.un4seen.com/xmplay.html) to
|
||||
download the SDK.
|
||||
You can disable xmp-openmpt in the solution configuration.
|
||||
|
||||
|
@ -147,13 +162,14 @@ For detailed requirements, see `libopenmpt/dox/quickstart.md`.
|
|||
|
||||
make CONFIG=mingw64-win64 # for win64
|
||||
|
||||
- gcc or clang (on Unix-like systems, including Mac OS X with MacPorts):
|
||||
- gcc or clang (on Unix-like systems, including Mac OS X with MacPorts,
|
||||
and Haiku (32-bit Hybrid and 64-bit)):
|
||||
|
||||
The minimum required compiler versions are:
|
||||
|
||||
- gcc 4.8
|
||||
|
||||
- clang 3.4
|
||||
- clang 3.6
|
||||
|
||||
The Makefile requires pkg-config for native builds.
|
||||
For sound output in openmpt123, PortAudio or SDL is required.
|
||||
|
@ -176,27 +192,54 @@ For detailed requirements, see `libopenmpt/dox/quickstart.md`.
|
|||
|
||||
- emscripten (on Unix-like systems):
|
||||
|
||||
libopenmpt has been tested and verified to work with emscripten 1.31 or
|
||||
later (earlier versions might or might not work).
|
||||
libopenmpt has been tested and verified to work with emscripten 1.38.5
|
||||
or later. Earlier versions are not supported.
|
||||
|
||||
Run:
|
||||
|
||||
make CONFIG=emscripten # for emscripten >= 1.38.1
|
||||
# generates WebAssembly with dynamic heap growth
|
||||
make CONFIG=emscripten EMSCRIPTEN_TARGET=wasm
|
||||
|
||||
make CONFIG=emscripten-old # for emscripten < 1.38.0
|
||||
or
|
||||
|
||||
# generates asm.js with a fixed size 128MB heap
|
||||
make CONFIG=emscripten EMSCRIPTEN_TARGET=asmjs128m
|
||||
|
||||
or
|
||||
|
||||
# generates asm.js with a fixed default size heap (as of Emscripten
|
||||
# 1.38.11, this amounts to 16MB)
|
||||
make CONFIG=emscripten EMSCRIPTEN_TARGET=asmjs
|
||||
|
||||
or
|
||||
|
||||
# generates JavaScript with dynamic heap growth and with
|
||||
# compatibility for older VMs
|
||||
make CONFIG=emscripten EMSCRIPTEN_TARGET=js
|
||||
|
||||
Running the test suite on the command line is also supported by using
|
||||
node.js. Version 0.10.25 or greater has been tested. Earlier versions
|
||||
node.js. Version 8.9.1 or greater has been tested. Earlier versions
|
||||
might or might not work. Depending on how your distribution calls the
|
||||
`node.js` binary, you might have to edit
|
||||
`build/make/config-emscripten.mk` or
|
||||
`build/make/config-emscripten-old.mk`.
|
||||
`build/make/config-emscripten.mk`.
|
||||
|
||||
- Haiku:
|
||||
- DJGPP / DOS
|
||||
|
||||
To compile libopenmpt on Haiku (using the 32-bit gcc2h), run:
|
||||
Cross-compilation from Linux systems is supported with DJGPP GCC 7.2 or
|
||||
later via
|
||||
|
||||
make CONFIG=haiku
|
||||
make CONFIG=djgpp
|
||||
|
||||
`openmpt123` can use liballegro 4.2 for sound output on DJGPP/DOS.
|
||||
liballegro can either be installed system-wide in the DJGPP environment
|
||||
or downloaded into the `libopenmpt` source tree.
|
||||
|
||||
make CONFIG=djgpp USE_ALLEGRO42=1 # use installed liballegro
|
||||
|
||||
or
|
||||
|
||||
./build/download_externals.sh # download liballegro binaries
|
||||
make CONFIG=djgpp USE_ALLEGRO42=1 BUNDLED_ALLEGRO42=1
|
||||
|
||||
- American Fuzzy Lop:
|
||||
|
||||
|
@ -204,11 +247,11 @@ For detailed requirements, see `libopenmpt/dox/quickstart.md`.
|
|||
|
||||
make CONFIG=afl
|
||||
|
||||
For more detailed instructions, read contrib/fuzzing/readme.md
|
||||
For more detailed instructions, read `contrib/fuzzing/readme.md`.
|
||||
|
||||
- other compilers:
|
||||
|
||||
To compiler libopenmpt with other C++11 compliant compilers, run:
|
||||
To compile libopenmpt with other C++11 compliant compilers, run:
|
||||
|
||||
make CONFIG=generic
|
||||
|
||||
|
@ -243,131 +286,9 @@ For detailed requirements, see `libopenmpt/dox/quickstart.md`.
|
|||
|
||||
|
||||
|
||||
Coding conventions
|
||||
------------------
|
||||
Contributing to OpenMPT/libopenmpt
|
||||
----------------------------------
|
||||
|
||||
|
||||
### OpenMPT
|
||||
See [contributing](doc/contributing.md).
|
||||
|
||||
(see below for an example)
|
||||
|
||||
- Place curly braces at the beginning of the line, not at the end
|
||||
- Generally make use of the custom index types like `SAMPLEINDEX` or
|
||||
`ORDERINDEX` when referring to samples, orders, etc.
|
||||
- When changing playback behaviour, make sure that you use the function
|
||||
`CSoundFile::IsCompatibleMode()` so that modules made with previous versions
|
||||
of MPT still sound correct (if the change is extremely small, this might be
|
||||
unnecessary)
|
||||
- `CamelCase` function and variable names are preferred.
|
||||
|
||||
#### OpenMPT code example
|
||||
|
||||
~~~~{.cpp}
|
||||
void Foo::Bar(int foobar)
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
// some code
|
||||
}
|
||||
}
|
||||
~~~~
|
||||
|
||||
|
||||
### libopenmpt
|
||||
|
||||
**Note:**
|
||||
**This applies to `libopenmpt/` and `openmpt123/` directories only.**
|
||||
**Use OpenMPT style (see above) otherwise.**
|
||||
|
||||
The code generally tries to follow these conventions, but they are not
|
||||
strictly enforced and there are valid reasons to diverge from these
|
||||
conventions. Using common sense is recommended.
|
||||
|
||||
- In general, the most important thing is to keep style consistent with
|
||||
directly surrounding code.
|
||||
- Use C++ std types when possible, prefer `std::size_t` and `std::int32_t`
|
||||
over `long` or `int`. Do not use C99 std types (e.g. no pure `int32_t`)
|
||||
- Qualify namespaces explicitly, do not use `using`.
|
||||
Members of `namespace openmpt` can be named without full namespace
|
||||
qualification.
|
||||
- Prefer the C++ version in `namespace std` if the same functionality is
|
||||
provided by the C standard library as well. Also, include the C++
|
||||
version of C standard library headers (e.g. use `<cstdio>` instead of
|
||||
`<stdio.h>`.
|
||||
- Do not use ANY locale-dependant C functions. For locale-dependant C++
|
||||
functionaly (especially iostream), always imbue the
|
||||
`std::locale::classic()` locale.
|
||||
- Prefer kernel_style_names over CamelCaseNames.
|
||||
- If a folder (or one of its parent folders) contains .clang-format,
|
||||
use clang-format v3.5 for indenting C++ and C files, otherwise:
|
||||
- `{` are placed at the end of the opening line.
|
||||
- Enclose even single statements in curly braces.
|
||||
- Avoid placing single statements on the same line as the `if`.
|
||||
- Opening parentheses are separated from keywords with a space.
|
||||
- Opening parentheses are not separated from function names.
|
||||
- Place spaces around operators and inside parentheses.
|
||||
- Align `:` and `,` when inheriting or initializing members in a
|
||||
constructor.
|
||||
- The pointer `*` is separated from both the type and the variable name.
|
||||
- Use tabs for identation, spaces for formatting.
|
||||
Tabs should only appear at the very beginning of a line.
|
||||
Do not assume any particular width of the TAB character. If width is
|
||||
important for formatting reasons, use spaces.
|
||||
- Use empty lines at will.
|
||||
- API documentation is done with doxygen.
|
||||
Use general C doxygen for the C API.
|
||||
Use QT-style doxygen for the C++ API.
|
||||
|
||||
#### libopenmpt indentation example
|
||||
|
||||
~~~~{.cpp}
|
||||
namespace openmpt {
|
||||
|
||||
// This is totally meaningless code and just illustrates indentation.
|
||||
|
||||
class foo
|
||||
: public base
|
||||
, public otherbase
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
std::int32_t x;
|
||||
std::int16_t y;
|
||||
|
||||
public:
|
||||
|
||||
foo()
|
||||
: x(0)
|
||||
, y(-1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int bar() const;
|
||||
|
||||
}; // class foo
|
||||
|
||||
int foo::bar() const {
|
||||
|
||||
for ( int i = 0; i < 23; ++i ) {
|
||||
switch ( x ) {
|
||||
case 2:
|
||||
something( y );
|
||||
break;
|
||||
default:
|
||||
something( ( y - 1 ) * 2 );
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( x == 12 ) {
|
||||
return -1;
|
||||
} else if ( x == 42 ) {
|
||||
return 1;
|
||||
}
|
||||
return 42;
|
||||
|
||||
}
|
||||
|
||||
} // namespace openmpt
|
||||
~~~~
|
||||
|
|
|
@ -100,16 +100,17 @@
|
|||
|
||||
// OpenMPT-only dependencies
|
||||
#define MPT_WITH_ASIO
|
||||
#define MPT_WITH_DSOUND
|
||||
#define MPT_WITH_LAME
|
||||
#define MPT_WITH_LHASA
|
||||
#define MPT_WITH_MINIZIP
|
||||
#define MPT_WITH_NLOHMANNJSON
|
||||
#define MPT_WITH_OPUS
|
||||
#define MPT_WITH_OPUSENC
|
||||
#define MPT_WITH_OPUSFILE
|
||||
#define MPT_WITH_PICOJSON
|
||||
#define MPT_WITH_PORTAUDIO
|
||||
//#define MPT_WITH_PULSEAUDIO
|
||||
//#define MPT_WITH_PULSEAUDIOSIMPLE
|
||||
#define MPT_WITH_RTAUDIO
|
||||
#define MPT_WITH_SMBPITCHSHIFT
|
||||
#define MPT_WITH_UNRAR
|
||||
#define MPT_WITH_VORBISENC
|
||||
|
@ -142,27 +143,7 @@
|
|||
#error "only one of LIBOPENMPT_BUILD_FULL or LIBOPENMPT_BUILD_SMALL can be defined"
|
||||
#endif // LIBOPENMPT_BUILD_FULL && LIBOPENMPT_BUILD_SMALL
|
||||
|
||||
#if defined(LIBOPENMPT_BUILD_FULL)
|
||||
|
||||
//#define MPT_WITH_DL
|
||||
//#define MPT_WITH_FLAC
|
||||
//#define MPT_WITH_ICONV
|
||||
//#define MPT_WITH_LTDL
|
||||
#if MPT_OS_WINDOWS && !MPT_OS_WINDOWS_WINRT
|
||||
#if (_WIN32_WINNT >= 0x0601)
|
||||
#define MPT_WITH_MEDIAFOUNDATION
|
||||
#endif
|
||||
#endif
|
||||
//#define MPT_WITH_MINIMP3
|
||||
//#define MPT_WITH_MINIZ
|
||||
#define MPT_WITH_MPG123
|
||||
#define MPT_WITH_OGG
|
||||
//#define MPT_WITH_STBVORBIS
|
||||
#define MPT_WITH_VORBIS
|
||||
#define MPT_WITH_VORBISFILE
|
||||
#define MPT_WITH_ZLIB
|
||||
|
||||
#elif defined(LIBOPENMPT_BUILD_SMALL)
|
||||
#if defined(LIBOPENMPT_BUILD_SMALL)
|
||||
|
||||
//#define MPT_WITH_DL
|
||||
//#define MPT_WITH_FLAC
|
||||
|
@ -201,11 +182,40 @@
|
|||
#endif // MPT_BUILD_MSVC
|
||||
|
||||
|
||||
#if defined(MPT_BUILD_XCODE)
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
|
||||
// n/a
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
#if defined(LIBOPENMPT_BUILD)
|
||||
|
||||
//#define MPT_WITH_DL
|
||||
//#define MPT_WITH_FLAC
|
||||
//#define MPT_WITH_ICONV
|
||||
//#define MPT_WITH_LTDL
|
||||
//#define MPT_WITH_MEDIAFOUNDATION
|
||||
//#define MPT_WITH_MINIMP3
|
||||
//#define MPT_WITH_MINIZ
|
||||
#define MPT_WITH_MPG123
|
||||
#define MPT_WITH_OGG
|
||||
//#define MPT_WITH_STBVORBIS
|
||||
#define MPT_WITH_VORBIS
|
||||
#define MPT_WITH_VORBISFILE
|
||||
#define MPT_WITH_ZLIB
|
||||
|
||||
#endif // LIBOPENMPT_BUILD
|
||||
|
||||
#endif // MPT_BUILD_XCODE
|
||||
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
|
||||
// Enable built-in test suite.
|
||||
#ifdef _DEBUG
|
||||
#if defined(MPT_BUILD_DEBUG) || defined(MPT_BUILD_CHECKED)
|
||||
#define ENABLE_TESTS
|
||||
#endif
|
||||
|
||||
|
@ -214,13 +224,13 @@
|
|||
|
||||
// Disable any debug logging
|
||||
//#define NO_LOGGING
|
||||
#if !defined(_DEBUG) && !defined(MPT_BUILD_WINESUPPORT)
|
||||
#if !defined(MPT_BUILD_DEBUG) && !defined(MPT_BUILD_CHECKED) && !defined(MPT_BUILD_WINESUPPORT)
|
||||
#define MPT_LOG_GLOBAL_LEVEL_STATIC
|
||||
#define MPT_LOG_GLOBAL_LEVEL 0
|
||||
#endif
|
||||
|
||||
// Disable all runtime asserts
|
||||
#if !defined(_DEBUG) && !defined(MPT_BUILD_WINESUPPORT)
|
||||
#if !defined(MPT_BUILD_DEBUG) && !defined(MPT_BUILD_CHECKED) && !defined(MPT_BUILD_WINESUPPORT)
|
||||
#define NO_ASSERTS
|
||||
#endif
|
||||
|
||||
|
@ -284,7 +294,7 @@
|
|||
#else
|
||||
#define MODPLUG_NO_FILESAVE
|
||||
#endif
|
||||
#if defined(MPT_BUILD_ANALZYED) || defined(MPT_BUILD_CHECKED) || defined(ENABLE_TESTS)
|
||||
#if defined(MPT_BUILD_ANALZYED) || defined(MPT_BUILD_DEBUG) || defined(MPT_BUILD_CHECKED) || defined(ENABLE_TESTS)
|
||||
// enable asserts
|
||||
#else
|
||||
#define NO_ASSERTS
|
||||
|
@ -324,6 +334,9 @@
|
|||
#if MPT_OS_WINDOWS
|
||||
|
||||
#define MPT_CHARSET_WIN32
|
||||
#ifndef MPT_ENABLE_CHARSET_LOCALE
|
||||
#define MPT_ENABLE_CHARSET_LOCALE
|
||||
#endif
|
||||
|
||||
#elif MPT_OS_LINUX
|
||||
|
||||
|
@ -354,6 +367,13 @@
|
|||
//#define MPT_LOCALE_ASSUME_CHARSET CharsetUTF8
|
||||
//#endif
|
||||
|
||||
#elif MPT_OS_DJGPP
|
||||
|
||||
#define MPT_CHARSET_INTERNAL
|
||||
#ifndef MPT_LOCALE_ASSUME_CHARSET
|
||||
#define MPT_LOCALE_ASSUME_CHARSET CharsetCP437
|
||||
#endif
|
||||
|
||||
#elif defined(MPT_WITH_ICONV)
|
||||
|
||||
#define MPT_CHARSET_ICONV
|
||||
|
@ -362,7 +382,7 @@
|
|||
|
||||
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
#if MPT_COMPILER_MSVC && !defined(MPT_USTRING_MODE_UTF8_FORCE)
|
||||
|
||||
// Use wide strings for MSVC because this is the native encoding on
|
||||
// microsoft platforms.
|
||||
|
@ -418,13 +438,6 @@
|
|||
|
||||
// fixing stuff up
|
||||
|
||||
#if defined(MPT_BUILD_TARGET_XP)
|
||||
// Also support Wine 1.6 in addition to Windows XP
|
||||
#ifndef MPT_QUIRK_NO_CPP_THREAD
|
||||
#define MPT_QUIRK_NO_CPP_THREAD
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(MPT_BUILD_ANALYZED) || defined(MPT_BUILD_CHECKED)
|
||||
#ifdef NO_ASSERTS
|
||||
#undef NO_ASSERTS // static or dynamic analyzers want assertions on
|
||||
|
@ -444,36 +457,45 @@
|
|||
#if defined(ENABLE_ASM)
|
||||
#if MPT_COMPILER_MSVC && defined(_M_IX86)
|
||||
|
||||
// Generate general x86 inline assembly / intrinsics.
|
||||
// Generate general x86 inline assembly and intrinsics.
|
||||
#define ENABLE_X86
|
||||
// Generate inline assembly using MMX instructions (only used when the CPU supports it).
|
||||
// Generate MMX instructions (only used when the CPU supports it).
|
||||
#define ENABLE_MMX
|
||||
// Generate inline assembly using SSE instructions (only used when the CPU supports it).
|
||||
// Generate SSE instructions (only used when the CPU supports it).
|
||||
#define ENABLE_SSE
|
||||
// Generate inline assembly using SSE2 instructions (only used when the CPU supports it).
|
||||
// Generate SSE2 instructions (only used when the CPU supports it).
|
||||
#define ENABLE_SSE2
|
||||
// Generate inline assembly using SSE3 instructions (only used when the CPU supports it).
|
||||
// Generate SSE3 instructions (only used when the CPU supports it).
|
||||
#define ENABLE_SSE3
|
||||
// Generate inline assembly using SSE4 instructions (only used when the CPU supports it).
|
||||
// Generate SSE4 instructions (only used when the CPU supports it).
|
||||
#define ENABLE_SSE4
|
||||
// Generate inline assembly using AMD specific instruction set extensions (only used when the CPU supports it).
|
||||
|
||||
#if defined(MPT_BUILD_TARGET_XP)
|
||||
// Generate AMD specific instruction set extensions (only used when the CPU supports it).
|
||||
#define ENABLE_X86_AMD
|
||||
#endif
|
||||
|
||||
#elif MPT_COMPILER_MSVC && defined(_M_X64)
|
||||
|
||||
// Generate general x64 inline assembly / intrinsics.
|
||||
// Generate general x64 intrinsics.
|
||||
#define ENABLE_X64
|
||||
// Generate inline assembly using SSE2 instructions (only used when the CPU supports it).
|
||||
// Generate SSE instructions (only used when the CPU supports it).
|
||||
#define ENABLE_SSE
|
||||
// Generate SSE2 instructions (only used when the CPU supports it).
|
||||
#define ENABLE_SSE2
|
||||
// Generate inline assembly using SSE3 instructions (only used when the CPU supports it).
|
||||
// Generate SSE3 instructions (only used when the CPU supports it).
|
||||
#define ENABLE_SSE3
|
||||
// Generate inline assembly using SSE4 instructions (only used when the CPU supports it).
|
||||
// Generate SSE4 instructions (only used when the CPU supports it).
|
||||
#define ENABLE_SSE4
|
||||
|
||||
#endif // arch
|
||||
#endif // ENABLE_ASM
|
||||
|
||||
#if defined(MPT_WITH_MPG123) && defined(MPT_BUILD_MSVC) && defined(MPT_BUILD_MSVC_STATIC) && !defined(LIBOPENMPT_NODELAYLOAD) && !MPT_OS_WINDOWS_WINRT
|
||||
#if defined(MPT_WITH_LAME) && defined(MPT_BUILD_MSVC) && defined(MPT_BUILD_MSVC_STATIC) && defined(MODPLUG_TRACKER) && !MPT_OS_WINDOWS_WINRT
|
||||
#define MPT_ENABLE_LAME_DELAYLOAD
|
||||
#endif
|
||||
|
||||
#if defined(MPT_WITH_MPG123) && defined(MPT_BUILD_MSVC) && defined(MPT_BUILD_MSVC_STATIC) && defined(MODPLUG_TRACKER) && !MPT_OS_WINDOWS_WINRT
|
||||
#define MPT_ENABLE_MPG123_DELAYLOAD
|
||||
#endif
|
||||
|
||||
|
@ -490,6 +512,10 @@
|
|||
#undef MPT_WITH_MEDIAFOUNDATION // MediaFoundation requires Windows
|
||||
#endif
|
||||
|
||||
#if !MPT_COMPILER_MSVC && !MPT_COMPILER_CLANG && defined(MPT_WITH_MEDIAFOUNDATION)
|
||||
#undef MPT_WITH_MEDIAFOUNDATION // MediaFoundation requires MSVC or Clang due to ATL (no MinGW support)
|
||||
#endif
|
||||
|
||||
#if defined(MPT_WITH_MEDIAFOUNDATION) && !defined(MPT_ENABLE_TEMPFILE)
|
||||
#define MPT_ENABLE_TEMPFILE
|
||||
#endif
|
||||
|
@ -498,6 +524,10 @@
|
|||
#define MPT_ENABLE_TEMPFILE
|
||||
#endif
|
||||
|
||||
#if MPT_CXX_AT_LEAST(17) && defined(MPT_CHARSET_CODECVTUTF8)
|
||||
#undef MPT_CHARSET_CODECVTUTF8 // std::codecvt_utf8 is deprecated in c++17
|
||||
#endif
|
||||
|
||||
#if !defined(MPT_CHARSET_WIN32) && !defined(MPT_CHARSET_ICONV) && !defined(MPT_CHARSET_CODECVTUTF8) && !defined(MPT_CHARSET_INTERNAL)
|
||||
#define MPT_CHARSET_INTERNAL
|
||||
#endif
|
||||
|
@ -506,6 +536,10 @@
|
|||
#define MPT_ENABLE_DYNBIND // Tracker requires dynamic library loading for export codecs
|
||||
#endif
|
||||
|
||||
#if defined(MPT_ENABLE_LAME_DELAYLOAD) && !defined(MPT_ENABLE_DYNBIND)
|
||||
#define MPT_ENABLE_DYNBIND // static MSVC builds require dynbind to load delay-loaded DLLs
|
||||
#endif
|
||||
|
||||
#if defined(MPT_ENABLE_MPG123_DELAYLOAD) && !defined(MPT_ENABLE_DYNBIND)
|
||||
#define MPT_ENABLE_DYNBIND // static MSVC builds require dynbind to load delay-loaded DLLs
|
||||
#endif
|
||||
|
@ -538,10 +572,6 @@
|
|||
#define MPT_ENABLE_FILEIO // External samples require disk file io
|
||||
#endif
|
||||
|
||||
#if !defined(MODPLUG_NO_FILESAVE) && !defined(MPT_ENABLE_FILEIO_STDIO)
|
||||
#define MPT_ENABLE_FILEIO_STDIO // file saving requires FILE*
|
||||
#endif
|
||||
|
||||
#if defined(NO_PLUGINS)
|
||||
// Any plugin type requires NO_PLUGINS to not be defined.
|
||||
#define NO_VST
|
||||
|
@ -592,6 +622,16 @@
|
|||
|
||||
// platform configuration
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
#if MPT_OS_WINDOWS
|
||||
#if !defined(MPT_BUILD_WINESUPPORT)
|
||||
#ifndef MPT_MFC_FULL
|
||||
#define _AFX_NO_MFC_CONTROLS_IN_DIALOGS // Do not include support for MFC controls in dialogs (reduces binary bloat; remove this #define if you want to use MFC controls)
|
||||
#endif // !MPT_MFC_FULL
|
||||
#endif // !MPT_BUILD_WINESUPPORT
|
||||
#endif // MPT_OS_WINDOWS
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
@ -632,16 +672,23 @@
|
|||
|
||||
// stdlib configuration
|
||||
|
||||
#if MPT_COMPILER_CLANG
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wreserved-id-macro"
|
||||
#endif
|
||||
|
||||
#define __STDC_CONSTANT_MACROS
|
||||
#define __STDC_LIMIT_MACROS
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
|
||||
#if !MPT_OS_ANDROID
|
||||
#ifndef _FILE_OFFSET_BITS
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#endif
|
||||
#endif // !MPT_OS_ANDROID
|
||||
|
||||
#if MPT_COMPILER_CLANG
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
@ -682,30 +729,20 @@
|
|||
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
|
||||
#if MPT_COMPILER_MSVCCLANGC2
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
// As Clang defines __STDC__ 1, Windows headers will use named union fields. The MediaFoundation headers do not support this, though.
|
||||
// Clang supports nameless union fields just fine, and luckily there is a way to override the Windows headers behaviour.
|
||||
#define _FORCENAMELESSUNION
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
#endif // MPT_COMPILER_MSVCCLANGC2
|
||||
|
||||
|
||||
|
||||
// third-party library configuration
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
//#define MPT_MFC_FULL // use full MFC, including MFC controls
|
||||
#endif
|
||||
|
||||
#ifdef MPT_WITH_FLAC
|
||||
#ifdef MPT_BUILD_MSVC_STATIC
|
||||
#define FLAC__NO_DLL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef MPT_WITH_PICOJSON
|
||||
#define PICOJSON_USE_INT64
|
||||
#endif
|
||||
|
||||
#ifdef MPT_WITH_SMBPITCHSHIFT
|
||||
#ifdef MPT_BUILD_MSVC_SHARED
|
||||
#define SMBPITCHSHIFT_USE_DLL
|
||||
|
|
|
@ -25,10 +25,7 @@
|
|||
|
||||
#elif defined(__clang__) && defined(_MSC_VER) && defined(__c2__)
|
||||
|
||||
#define MPT_COMPILER_MSVCCLANGC2 1
|
||||
#define MPT_COMPILER_MSVCCLANGC2_VERSION (__c2_version__)
|
||||
#define MPT_MSVCCLANGC2_AT_LEAST(major,minor,build) (MPT_COMPILER_MSVCCLANGC2_VERSION >= MPT_COMPILER_MAKE_VERSION3_BUILD((major),(minor),(build)))
|
||||
#define MPT_MSVCCLANGC2_BEFORE(major,minor,build) (MPT_COMPILER_MSVCCLANGC2_VERSION < MPT_COMPILER_MAKE_VERSION3_BUILD((major),(minor),(build)))
|
||||
#error "Clang/C2 is not supported. Please use Clang/LLVM for Windows instead."
|
||||
|
||||
#elif defined(__clang__)
|
||||
|
||||
|
@ -37,8 +34,8 @@
|
|||
#define MPT_CLANG_AT_LEAST(major,minor,patch) (MPT_COMPILER_CLANG_VERSION >= MPT_COMPILER_MAKE_VERSION3((major),(minor),(patch)))
|
||||
#define MPT_CLANG_BEFORE(major,minor,patch) (MPT_COMPILER_CLANG_VERSION < MPT_COMPILER_MAKE_VERSION3((major),(minor),(patch)))
|
||||
|
||||
#if MPT_CLANG_BEFORE(3,4,0)
|
||||
#error "clang version 3.4 required"
|
||||
#if MPT_CLANG_BEFORE(3,6,0)
|
||||
#error "clang version 3.6 required"
|
||||
#endif
|
||||
|
||||
#if defined(__clang_analyzer__)
|
||||
|
@ -61,7 +58,9 @@
|
|||
#elif defined(_MSC_VER)
|
||||
|
||||
#define MPT_COMPILER_MSVC 1
|
||||
#if (_MSC_VER >= 1915)
|
||||
#if (_MSC_VER >= 1916)
|
||||
#define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2017,9)
|
||||
#elif (_MSC_VER >= 1915)
|
||||
#define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2017,8)
|
||||
#elif (_MSC_VER >= 1914)
|
||||
#define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2017,7)
|
||||
|
@ -73,6 +72,8 @@
|
|||
#define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2017,3)
|
||||
#elif (_MSC_VER >= 1910)
|
||||
#define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2017,0)
|
||||
#elif (_MSC_VER >= 1900) && defined(_MSVC_LANG)
|
||||
#define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2015,3)
|
||||
#elif (_MSC_VER >= 1900)
|
||||
#define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2015,0)
|
||||
#elif (_MSC_VER >= 1800)
|
||||
|
@ -110,11 +111,6 @@
|
|||
#ifndef MPT_COMPILER_GENERIC
|
||||
#define MPT_COMPILER_GENERIC 0
|
||||
#endif
|
||||
#ifndef MPT_COMPILER_MSVCCLANGC2
|
||||
#define MPT_COMPILER_MSVCCLANGC2 0
|
||||
#define MPT_MSVCCLANGC2_AT_LEAST(major,minor,build) 0
|
||||
#define MPT_MSVCCLANGC2_BEFORE(major,minor,build) 0
|
||||
#endif
|
||||
#ifndef MPT_COMPILER_CLANG
|
||||
#define MPT_COMPILER_CLANG 0
|
||||
#define MPT_CLANG_AT_LEAST(major,minor,patch) 0
|
||||
|
@ -145,8 +141,10 @@
|
|||
|
||||
#elif MPT_COMPILER_MSVC
|
||||
|
||||
#if MPT_MSVC_AT_LEAST(2017,0)
|
||||
#if (_MSVC_LANG >= 201402)
|
||||
#if MPT_MSVC_AT_LEAST(2015,3)
|
||||
#if (_MSVC_LANG >= 201703)
|
||||
#define MPT_CXX 17
|
||||
#elif (_MSVC_LANG >= 201402)
|
||||
#define MPT_CXX 14
|
||||
#else
|
||||
#define MPT_CXX 11
|
||||
|
@ -171,58 +169,6 @@
|
|||
|
||||
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
#define MPT_PLATFORM_LITTLE_ENDIAN
|
||||
#elif MPT_COMPILER_GCC
|
||||
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
#define MPT_PLATFORM_BIG_ENDIAN
|
||||
#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
#define MPT_PLATFORM_LITTLE_ENDIAN
|
||||
#endif
|
||||
#elif MPT_COMPILER_CLANG || MPT_COMPILER_MSVCCLANGC2
|
||||
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
#define MPT_PLATFORM_BIG_ENDIAN
|
||||
#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
#define MPT_PLATFORM_LITTLE_ENDIAN
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// fallback:
|
||||
#if !defined(MPT_PLATFORM_BIG_ENDIAN) && !defined(MPT_PLATFORM_LITTLE_ENDIAN)
|
||||
// taken from boost/detail/endian.hpp
|
||||
#if (defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)) \
|
||||
|| (defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__)) \
|
||||
|| (defined(_STLP_BIG_ENDIAN) && !defined(_STLP_LITTLE_ENDIAN))
|
||||
#define MPT_PLATFORM_BIG_ENDIAN
|
||||
#elif (defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)) \
|
||||
|| (defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)) \
|
||||
|| (defined(_STLP_LITTLE_ENDIAN) && !defined(_STLP_BIG_ENDIAN))
|
||||
#define MPT_PLATFORM_LITTLE_ENDIAN
|
||||
#elif defined(__sparc) || defined(__sparc__) \
|
||||
|| defined(_POWER) || defined(__powerpc__) \
|
||||
|| defined(__ppc__) || defined(__hpux) || defined(__hppa) \
|
||||
|| defined(_MIPSEB) || defined(_POWER) \
|
||||
|| defined(__s390__)
|
||||
#define MPT_PLATFORM_BIG_ENDIAN
|
||||
#elif defined(__i386__) || defined(__alpha__) \
|
||||
|| defined(__ia64) || defined(__ia64__) \
|
||||
|| defined(_M_IX86) || defined(_M_IA64) \
|
||||
|| defined(_M_ALPHA) || defined(__amd64) \
|
||||
|| defined(__amd64__) || defined(_M_AMD64) \
|
||||
|| defined(__x86_64) || defined(__x86_64__) \
|
||||
|| defined(_M_X64) || defined(__bfin__)
|
||||
#define MPT_PLATFORM_LITTLE_ENDIAN
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(MPT_PLATFORM_BIG_ENDIAN) || defined(MPT_PLATFORM_LITTLE_ENDIAN)
|
||||
#define MPT_PLATFORM_ENDIAN_KNOWN 1
|
||||
#else
|
||||
#define MPT_PLATFORM_ENDIAN_KNOWN 0
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// This should really be based on __STDCPP_THREADS__, but that is not defined by
|
||||
// GCC or clang. Stupid.
|
||||
// Just assume multithreaded and disable for platforms we know are
|
||||
|
@ -235,14 +181,6 @@
|
|||
|
||||
|
||||
|
||||
// C++11 constexpr
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
#define MPT_COMPILER_QUIRK_CONSTEXPR_NO_STRING_LITERALS
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
// Compiler has multiplication/division semantics when shifting signed integers.
|
||||
#define MPT_COMPILER_SHIFT_SIGNED 1
|
||||
|
@ -254,37 +192,19 @@
|
|||
|
||||
|
||||
|
||||
#if MPT_COMPILER_GCC || MPT_COMPILER_MSVC
|
||||
// Compiler supports type-punning through unions. This is not stricly standard-conforming.
|
||||
// For GCC, this is documented, for MSVC this is apparently not documented, but we assume it.
|
||||
#define MPT_COMPILER_UNION_TYPE_ALIASES 1
|
||||
#endif
|
||||
|
||||
#ifndef MPT_COMPILER_UNION_TYPE_ALIASES
|
||||
// Compiler does not support type-punning through unions. std::memcpy is used instead.
|
||||
// This is the safe fallback and strictly standard-conforming.
|
||||
// Another standard-compliant alternative would be casting pointers to a character type pointer.
|
||||
// This results in rather unreadable code and,
|
||||
// in most cases, compilers generate better code by just inlining the memcpy anyway.
|
||||
// (see <http://blog.regehr.org/archives/959>).
|
||||
#define MPT_COMPILER_UNION_TYPE_ALIASES 0
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// The order of the checks matters!
|
||||
#if defined(__EMSCRIPTEN__)
|
||||
#if defined(__DJGPP__)
|
||||
#define MPT_OS_DJGPP 1
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
#define MPT_OS_EMSCRIPTEN 1
|
||||
#if defined(__EMSCRIPTEN_major__) && defined(__EMSCRIPTEN_minor__)
|
||||
#if (__EMSCRIPTEN_major__ > 1)
|
||||
#define MPT_OS_EMSCRIPTEN_ANCIENT 0
|
||||
#elif (__EMSCRIPTEN_major__ == 1) && (__EMSCRIPTEN_minor__ >= 36)
|
||||
#define MPT_OS_EMSCRIPTEN_ANCIENT 0
|
||||
// ok
|
||||
#elif (__EMSCRIPTEN_major__ == 1) && (__EMSCRIPTEN_minor__ >= 38)
|
||||
// ok
|
||||
#else
|
||||
#define MPT_OS_EMSCRIPTEN_ANCIENT 1
|
||||
#error "Emscripten >= 1.38 is required."
|
||||
#endif
|
||||
#else
|
||||
#define MPT_OS_EMSCRIPTEN_ANCIENT 1
|
||||
#endif
|
||||
#elif defined(_WIN32)
|
||||
#define MPT_OS_WINDOWS 1
|
||||
|
@ -324,6 +244,9 @@
|
|||
#define MPT_OS_UNKNOWN 1
|
||||
#endif
|
||||
|
||||
#ifndef MPT_OS_DJGPP
|
||||
#define MPT_OS_DJGPP 0
|
||||
#endif
|
||||
#ifndef MPT_OS_EMSCRIPTEN
|
||||
#define MPT_OS_EMSCRIPTEN 0
|
||||
#endif
|
||||
|
@ -367,7 +290,18 @@
|
|||
|
||||
|
||||
|
||||
#if MPT_OS_EMSCRIPTEN
|
||||
#if (MPT_OS_DJGPP || MPT_OS_EMSCRIPTEN)
|
||||
#undef MPT_PLATFORM_MULTITHREADED
|
||||
#define MPT_PLATFORM_MULTITHREADED 0
|
||||
#endif
|
||||
|
||||
#if MPT_OS_DJGPP
|
||||
#define MPT_COMPILER_QUIRK_NO_WCHAR
|
||||
#endif
|
||||
|
||||
#if MPT_MSVC_BEFORE(2017,8)
|
||||
// fixed in VS2017 15.8
|
||||
// see <https://blogs.msdn.microsoft.com/vcblog/2018/09/18/stl-features-and-fixes-in-vs-2017-15-8/>
|
||||
#define MPT_COMPILER_QUIRK_MSVC_STRINGSTREAM
|
||||
#endif
|
||||
|
||||
|
|
|
@ -190,7 +190,7 @@ std::string ComponentFactoryBase::GetSettingsKey() const
|
|||
void ComponentFactoryBase::PreConstruct() const
|
||||
{
|
||||
MPT_LOG(LogInformation, "Components",
|
||||
mpt::format(MPT_USTRING("Constructing Component %1"))
|
||||
mpt::format(U_("Constructing Component %1"))
|
||||
( mpt::ToUnicode(mpt::CharsetASCII, m_ID)
|
||||
)
|
||||
);
|
||||
|
@ -245,7 +245,7 @@ static std::shared_ptr<ComponentManager> g_ComponentManager;
|
|||
|
||||
void ComponentManager::Init(const IComponentManagerSettings &settings)
|
||||
{
|
||||
MPT_LOG(LogInformation, "Components", MPT_USTRING("Init"));
|
||||
MPT_LOG(LogInformation, "Components", U_("Init"));
|
||||
// cannot use make_shared because the constructor is private
|
||||
g_ComponentManager = std::shared_ptr<ComponentManager>(new ComponentManager(settings));
|
||||
}
|
||||
|
@ -253,7 +253,7 @@ void ComponentManager::Init(const IComponentManagerSettings &settings)
|
|||
|
||||
void ComponentManager::Release()
|
||||
{
|
||||
MPT_LOG(LogInformation, "Components", MPT_USTRING("Release"));
|
||||
MPT_LOG(LogInformation, "Components", U_("Release"));
|
||||
g_ComponentManager = nullptr;
|
||||
}
|
||||
|
||||
|
@ -292,7 +292,7 @@ void ComponentManager::Register(const IComponentFactory &componentFactory)
|
|||
|
||||
void ComponentManager::Startup()
|
||||
{
|
||||
MPT_LOG(LogDebug, "Components", MPT_USTRING("Startup"));
|
||||
MPT_LOG(LogDebug, "Components", U_("Startup"));
|
||||
if(m_Settings.LoadOnStartup())
|
||||
{
|
||||
for(auto &it : m_Components)
|
||||
|
@ -313,6 +313,10 @@ void ComponentManager::Startup()
|
|||
|
||||
bool ComponentManager::IsComponentBlocked(const std::string &settingsKey) const
|
||||
{
|
||||
if(settingsKey.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return m_Settings.IsBlocked(settingsKey);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "../common/misc_util.h"
|
||||
|
@ -53,11 +55,11 @@ class IComponent
|
|||
|
||||
protected:
|
||||
|
||||
IComponent() { }
|
||||
IComponent() = default;
|
||||
|
||||
public:
|
||||
|
||||
virtual ~IComponent() { }
|
||||
virtual ~IComponent() = default;
|
||||
|
||||
public:
|
||||
|
||||
|
@ -98,15 +100,15 @@ protected:
|
|||
|
||||
public:
|
||||
|
||||
virtual ComponentType GetType() const;
|
||||
virtual bool IsInitialized() const;
|
||||
virtual bool IsAvailable() const;
|
||||
ComponentType GetType() const override;
|
||||
bool IsInitialized() const override;
|
||||
bool IsAvailable() const override;
|
||||
|
||||
virtual mpt::ustring GetVersion() const;
|
||||
mpt::ustring GetVersion() const override;
|
||||
|
||||
public:
|
||||
|
||||
virtual void Initialize();
|
||||
void Initialize() override;
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -123,7 +125,7 @@ public:
|
|||
{
|
||||
return;
|
||||
}
|
||||
virtual bool DoInitialize()
|
||||
bool DoInitialize() override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -175,7 +177,7 @@ public:
|
|||
|
||||
protected:
|
||||
|
||||
virtual bool DoInitialize() = 0;
|
||||
bool DoInitialize() override = 0;
|
||||
|
||||
};
|
||||
|
||||
|
@ -185,6 +187,18 @@ protected:
|
|||
#define MPT_COMPONENT_BIND_SYMBOL(libName, symbol, func) MPT_DO { if(!Bind( func , libName , symbol )) { SetBindFailed(); } } MPT_WHILE_0
|
||||
#define MPT_COMPONENT_BIND_SYMBOL_OPTIONAL(libName, symbol, func) Bind( func , libName , symbol )
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
#ifdef UNICODE
|
||||
#define MPT_COMPONENT_BINDWIN_SUFFIX "W"
|
||||
#else
|
||||
#define MPT_COMPONENT_BINDWIN_SUFFIX "A"
|
||||
#endif
|
||||
#define MPT_COMPONENT_BINDWIN(libName, func) MPT_DO { if(!Bind( func , libName , #func MPT_COMPONENT_BINDWIN_SUFFIX )) { SetBindFailed(); } } MPT_WHILE_0
|
||||
#define MPT_COMPONENT_BINDWIN_OPTIONAL(libName, func) Bind( func , libName , #func MPT_COMPONENT_BINDWIN_SUFFIX )
|
||||
#define MPT_COMPONENT_BINDWIN_SYMBOL(libName, symbol, func) MPT_DO { if(!Bind( func , libName , symbol MPT_COMPONENT_BINDWIN_SUFFIX )) { SetBindFailed(); } } MPT_WHILE_0
|
||||
#define MPT_COMPONENT_BINDWIN_SYMBOL_OPTIONAL(libName, symbol, func) Bind( func , libName , symbol MPT_COMPONENT_BINDWIN_SUFFIX )
|
||||
#endif
|
||||
|
||||
|
||||
class ComponentSystemDLL : public ComponentLibrary
|
||||
{
|
||||
|
@ -197,7 +211,7 @@ public:
|
|||
{
|
||||
return;
|
||||
}
|
||||
virtual bool DoInitialize()
|
||||
bool DoInitialize() override
|
||||
{
|
||||
AddLibrary(m_BaseName.ToUTF8(), mpt::LibraryPath::System(m_BaseName));
|
||||
return GetLibrary(m_BaseName.ToUTF8()).IsValid();
|
||||
|
@ -216,7 +230,7 @@ public:
|
|||
{
|
||||
return;
|
||||
}
|
||||
virtual bool DoInitialize()
|
||||
bool DoInitialize() override
|
||||
{
|
||||
AddLibrary(m_FullName.ToUTF8(), mpt::LibraryPath::AppFullName(m_FullName));
|
||||
return GetLibrary(m_FullName.ToUTF8()).IsValid();
|
||||
|
@ -238,9 +252,9 @@ typedef std::shared_ptr<IComponent> (*ComponentFactoryMethod)(ComponentManager &
|
|||
class IComponentFactory
|
||||
{
|
||||
protected:
|
||||
IComponentFactory() { }
|
||||
IComponentFactory() = default;
|
||||
public:
|
||||
virtual ~IComponentFactory() { }
|
||||
virtual ~IComponentFactory() = default;
|
||||
public:
|
||||
virtual std::string GetID() const = 0;
|
||||
virtual std::string GetSettingsKey() const = 0;
|
||||
|
@ -261,10 +275,10 @@ protected:
|
|||
void Initialize(ComponentManager &componentManager, std::shared_ptr<IComponent> component) const;
|
||||
public:
|
||||
virtual ~ComponentFactoryBase();
|
||||
virtual std::string GetID() const;
|
||||
virtual std::string GetSettingsKey() const;
|
||||
virtual std::shared_ptr<IComponent> Construct(ComponentManager &componentManager) const = 0;
|
||||
virtual ComponentFactoryMethod GetStaticConstructor() const = 0;
|
||||
std::string GetID() const override;
|
||||
std::string GetSettingsKey() const override;
|
||||
std::shared_ptr<IComponent> Construct(ComponentManager &componentManager) const override = 0;
|
||||
ComponentFactoryMethod GetStaticConstructor() const override = 0;
|
||||
};
|
||||
|
||||
|
||||
|
@ -278,12 +292,8 @@ public:
|
|||
{
|
||||
return;
|
||||
}
|
||||
virtual ~ComponentFactory()
|
||||
{
|
||||
return;
|
||||
}
|
||||
public:
|
||||
virtual std::shared_ptr<IComponent> Construct(ComponentManager &componentManager) const
|
||||
std::shared_ptr<IComponent> Construct(ComponentManager &componentManager) const override
|
||||
{
|
||||
PreConstruct();
|
||||
std::shared_ptr<IComponent> component = std::make_shared<T>();
|
||||
|
@ -294,7 +304,7 @@ public:
|
|||
{
|
||||
return ComponentFactory().Construct(componentManager);
|
||||
}
|
||||
virtual ComponentFactoryMethod GetStaticConstructor() const
|
||||
virtual ComponentFactoryMethod GetStaticConstructor() const override
|
||||
{
|
||||
return &StaticConstruct;
|
||||
}
|
||||
|
@ -315,10 +325,10 @@ class ComponentManagerSettingsDefault
|
|||
: public IComponentManagerSettings
|
||||
{
|
||||
public:
|
||||
virtual bool LoadOnStartup() const { return false; }
|
||||
virtual bool KeepLoaded() const { return true; }
|
||||
virtual bool IsBlocked(const std::string & /*key*/ ) const { return false; }
|
||||
virtual mpt::PathString Path() const { return mpt::PathString(); }
|
||||
bool LoadOnStartup() const override { return false; }
|
||||
bool KeepLoaded() const override { return true; }
|
||||
bool IsBlocked(const std::string & /*key*/ ) const override { return false; }
|
||||
mpt::PathString Path() const override { return mpt::PathString(); }
|
||||
};
|
||||
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -13,6 +13,7 @@
|
|||
|
||||
#if defined(MPT_ENABLE_TEMPFILE) && MPT_OS_WINDOWS
|
||||
#include <windows.h>
|
||||
#include "mptFileIO.h"
|
||||
#endif // MPT_ENABLE_TEMPFILE && MPT_OS_WINDOWS
|
||||
|
||||
|
||||
|
@ -30,7 +31,7 @@ OnDiskFileWrapper::OnDiskFileWrapper(FileReader &file, const mpt::PathString &fi
|
|||
file.Rewind();
|
||||
if(file.GetFileName().empty())
|
||||
{
|
||||
const mpt::PathString tempName = mpt::CreateTempFileName(MPT_PATHSTRING("OpenMPT"), fileNameExtension);
|
||||
const mpt::PathString tempName = mpt::CreateTempFileName(P_("OpenMPT"), fileNameExtension);
|
||||
|
||||
#if MPT_OS_WINDOWS && MPT_OS_WINDOWS_WINRT
|
||||
#if (_WIN32_WINNT < 0x0602)
|
||||
|
@ -40,7 +41,7 @@ OnDiskFileWrapper::OnDiskFileWrapper(FileReader &file, const mpt::PathString &fi
|
|||
|
||||
#ifdef MPT_ONDISKFILEWRAPPER_NO_CREATEFILE
|
||||
|
||||
FILE * f = _wfopen(tempName.AsNative().c_str(), L"wb");
|
||||
mpt::ofstream f(tempName, std::ios::binary);
|
||||
if(!f)
|
||||
{
|
||||
throw std::runtime_error("");
|
||||
|
@ -53,20 +54,17 @@ OnDiskFileWrapper::OnDiskFileWrapper(FileReader &file, const mpt::PathString &fi
|
|||
do
|
||||
{
|
||||
std::size_t chunkSize = mpt::saturate_cast<std::size_t>(towrite);
|
||||
std::size_t chunkDone = 0;
|
||||
chunkDone = fwrite(view.data() + written, 1, chunkSize, f);
|
||||
if(chunkDone != chunkSize)
|
||||
bool chunkOk = false;
|
||||
chunkOk = mpt::IO::WriteRaw(f, mpt::const_byte_span(view.data() + written, chunkSize));
|
||||
if(!chunkOk)
|
||||
{
|
||||
fclose(f);
|
||||
f = NULL;
|
||||
throw std::runtime_error("");
|
||||
}
|
||||
towrite -= chunkDone;
|
||||
written += chunkDone;
|
||||
towrite -= chunkSize;
|
||||
written += chunkSize;
|
||||
} while(towrite > 0);
|
||||
}
|
||||
fclose(f);
|
||||
f = NULL;
|
||||
f.close();
|
||||
|
||||
#else // !MPT_ONDISKFILEWRAPPER_NO_CREATEFILE
|
||||
|
||||
|
@ -74,7 +72,7 @@ OnDiskFileWrapper::OnDiskFileWrapper(FileReader &file, const mpt::PathString &fi
|
|||
#if MPT_OS_WINDOWS_WINRT
|
||||
hFile = CreateFile2(tempName.AsNative().c_str(), GENERIC_WRITE, FILE_SHARE_READ, CREATE_ALWAYS, NULL);
|
||||
#else
|
||||
hFile = CreateFileW(tempName.AsNative().c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL);
|
||||
hFile = CreateFile(tempName.AsNative().c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL);
|
||||
#endif
|
||||
if(hFile == NULL || hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
|
@ -123,7 +121,7 @@ OnDiskFileWrapper::~OnDiskFileWrapper()
|
|||
{
|
||||
if(m_IsTempFile)
|
||||
{
|
||||
DeleteFileW(m_Filename.AsNative().c_str());
|
||||
DeleteFile(m_Filename.AsNative().c_str());
|
||||
m_IsTempFile = false;
|
||||
}
|
||||
m_Filename = mpt::PathString();
|
||||
|
|
|
@ -10,10 +10,10 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
#include "typedefs.h"
|
||||
#include "mptTypeTraits.h"
|
||||
#include "StringFixer.h"
|
||||
|
||||
#include "mptStringBuffer.h"
|
||||
#include "misc_util.h"
|
||||
#include "Endianness.h"
|
||||
#include "mptIO.h"
|
||||
|
@ -141,14 +141,6 @@ public:
|
|||
// Initialize file reader object based on an existing file reader object window.
|
||||
explicit FileReader(value_data_type other, const mpt::PathString *filename = nullptr) : m_data(other), streamPos(0), fileName(filename) { }
|
||||
|
||||
// Initialize file reader object based on an existing file reader object. The other object's stream position is copied.
|
||||
FileReader(const FileReader &) = default;
|
||||
FileReader& operator=(const FileReader &) = default;
|
||||
|
||||
// Move an existing file reader object
|
||||
FileReader(FileReader &&) noexcept = default;
|
||||
FileReader& operator=(FileReader &&) noexcept = default;
|
||||
|
||||
public:
|
||||
|
||||
mpt::PathString GetFileName() const
|
||||
|
@ -343,6 +335,8 @@ public:
|
|||
cache.resize(size_);
|
||||
if(!cache.empty())
|
||||
{
|
||||
// cppcheck false-positive
|
||||
// cppcheck-suppress containerOutOfBounds
|
||||
file.GetRaw(&(cache[0]), size);
|
||||
}
|
||||
}
|
||||
|
@ -440,6 +434,12 @@ public:
|
|||
return mpt::byte_cast<const T*>(DataContainer().GetRawData() + streamPos);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::size_t GetRawWithOffset(std::size_t offset, T *dst, std::size_t count) const
|
||||
{
|
||||
return static_cast<std::size_t>(DataContainer().Read(mpt::byte_cast<mpt::byte*>(dst), streamPos + offset, count));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::size_t GetRaw(T *dst, std::size_t count) const
|
||||
{
|
||||
|
@ -478,22 +478,22 @@ public:
|
|||
std::string GetRawDataAsString() const
|
||||
{
|
||||
PinnedRawDataView view = GetPinnedRawDataView();
|
||||
return std::string(view.span().begin(), view.span().end());
|
||||
return std::string(mpt::byte_cast<const char*>(view.span().begin()), mpt::byte_cast<const char*>(view.span().end()));
|
||||
}
|
||||
std::string ReadRawDataAsString()
|
||||
{
|
||||
PinnedRawDataView view = ReadPinnedRawDataView();
|
||||
return std::string(view.span().begin(), view.span().end());
|
||||
return std::string(mpt::byte_cast<const char*>(view.span().begin()), mpt::byte_cast<const char*>(view.span().end()));
|
||||
}
|
||||
std::string GetRawDataAsString(std::size_t size) const
|
||||
{
|
||||
PinnedRawDataView view = GetPinnedRawDataView(size);
|
||||
return std::string(view.span().begin(), view.span().end());
|
||||
return std::string(mpt::byte_cast<const char*>(view.span().begin()), mpt::byte_cast<const char*>(view.span().end()));
|
||||
}
|
||||
std::string ReadRawDataAsString(std::size_t size)
|
||||
{
|
||||
PinnedRawDataView view = ReadPinnedRawDataView(size);
|
||||
return std::string(view.span().begin(), view.span().end());
|
||||
return std::string(mpt::byte_cast<const char*>(view.span().begin()), mpt::byte_cast<const char*>(view.span().end()));
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -504,11 +504,12 @@ protected:
|
|||
template <typename T>
|
||||
bool Read(T &target)
|
||||
{
|
||||
if(sizeof(T) != DataContainer().Read(reinterpret_cast<mpt::byte*>(&target), streamPos, sizeof(T)))
|
||||
mpt::byte_span dst = mpt::as_raw_memory(target);
|
||||
if(dst.size() != DataContainer().Read(streamPos, dst))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
streamPos += sizeof(T);
|
||||
streamPos += dst.size();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -520,10 +521,10 @@ public:
|
|||
T ReadIntLE()
|
||||
{
|
||||
static_assert(std::numeric_limits<T>::is_integer == true, "Target type is a not an integer");
|
||||
T target;
|
||||
typename mpt::make_le<T>::type target;
|
||||
if(Read(target))
|
||||
{
|
||||
return SwapBytesLE(target);
|
||||
return target;
|
||||
} else
|
||||
{
|
||||
return 0;
|
||||
|
@ -536,10 +537,10 @@ public:
|
|||
T ReadIntBE()
|
||||
{
|
||||
static_assert(std::numeric_limits<T>::is_integer == true, "Target type is a not an integer");
|
||||
T target;
|
||||
typename mpt::make_be<T>::type target;
|
||||
if(Read(target))
|
||||
{
|
||||
return SwapBytesBE(target);
|
||||
return target;
|
||||
} else
|
||||
{
|
||||
return 0;
|
||||
|
@ -577,9 +578,9 @@ public:
|
|||
}
|
||||
buf[i] = byte;
|
||||
}
|
||||
T target;
|
||||
typename mpt::make_le<T>::type target;
|
||||
std::memcpy(&target, buf, sizeof(T));
|
||||
return SwapBytesLE(target);
|
||||
return target;
|
||||
}
|
||||
|
||||
// Read a supplied-size little endian integer to a fixed size variable.
|
||||
|
@ -663,6 +664,20 @@ public:
|
|||
return ReadIntBE<int16>();
|
||||
}
|
||||
|
||||
// Read a single 8bit character.
|
||||
// If successful, the file cursor is advanced by the size of the integer.
|
||||
char ReadChar()
|
||||
{
|
||||
char target;
|
||||
if(Read(target))
|
||||
{
|
||||
return target;
|
||||
} else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Read unsigned 8-Bit integer.
|
||||
// If successful, the file cursor is advanced by the size of the integer.
|
||||
uint8 ReadUint8()
|
||||
|
@ -728,7 +743,7 @@ public:
|
|||
return target;
|
||||
} else
|
||||
{
|
||||
return 0.0f;
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -742,7 +757,7 @@ public:
|
|||
return target;
|
||||
} else
|
||||
{
|
||||
return 0.0f;
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -757,7 +772,7 @@ public:
|
|||
return true;
|
||||
} else
|
||||
{
|
||||
MemsetZero(target);
|
||||
Clear(target);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -773,8 +788,8 @@ public:
|
|||
{
|
||||
copyBytes = BytesLeft();
|
||||
}
|
||||
DataContainer().Read(reinterpret_cast<mpt::byte *>(&target), streamPos, copyBytes);
|
||||
std::memset(reinterpret_cast<mpt::byte *>(&target) + copyBytes, 0, sizeof(target) - copyBytes);
|
||||
GetRaw(mpt::as_raw_memory(target).data(), copyBytes);
|
||||
std::memset(mpt::as_raw_memory(target).data() + copyBytes, 0, sizeof(target) - copyBytes);
|
||||
Skip(partialSize);
|
||||
return true;
|
||||
}
|
||||
|
@ -849,15 +864,15 @@ public:
|
|||
{
|
||||
char buffer[64];
|
||||
off_t avail = 0;
|
||||
while((avail = std::min(DataContainer().Read(reinterpret_cast<mpt::byte*>(buffer), streamPos, sizeof(buffer)), maxLength - dest.length())) != 0)
|
||||
while((avail = std::min(GetRaw(buffer, mpt::size(buffer)), maxLength - dest.length())) != 0)
|
||||
{
|
||||
auto end = std::find(buffer, buffer + avail, '\0');
|
||||
dest.insert(dest.end(), buffer, end);
|
||||
streamPos += (end - buffer);
|
||||
Skip(end - buffer);
|
||||
if(end < buffer + avail)
|
||||
{
|
||||
// Found null char
|
||||
streamPos++;
|
||||
Skip(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -868,9 +883,6 @@ public:
|
|||
return dest.length() != 0;
|
||||
}
|
||||
|
||||
private:
|
||||
static MPT_FORCEINLINE bool IsLineEnding(char c) { return c == '\r' || c == '\n'; }
|
||||
public:
|
||||
// Read a string up to the next line terminator into a std::string
|
||||
bool ReadLine(std::string &dest, const off_t maxLength = std::numeric_limits<off_t>::max())
|
||||
{
|
||||
|
@ -879,17 +891,18 @@ public:
|
|||
return false;
|
||||
try
|
||||
{
|
||||
char buffer[64], c = '\0';
|
||||
char buffer[64];
|
||||
char c = '\0';
|
||||
off_t avail = 0;
|
||||
while((avail = std::min(DataContainer().Read(reinterpret_cast<mpt::byte*>(buffer), streamPos, sizeof(buffer)), maxLength - dest.length())) != 0)
|
||||
while((avail = std::min(GetRaw(buffer, mpt::size(buffer)), maxLength - dest.length())) != 0)
|
||||
{
|
||||
auto end = std::find_if(buffer, buffer + avail, IsLineEnding);
|
||||
auto end = std::find_if(buffer, buffer + avail, mpt::String::Traits<std::string>::IsLineEnding);
|
||||
dest.insert(dest.end(), buffer, end);
|
||||
streamPos += (end - buffer);
|
||||
Skip(end - buffer);
|
||||
if(end < buffer + avail)
|
||||
{
|
||||
// Found line ending
|
||||
streamPos++;
|
||||
Skip(1);
|
||||
// Handle CRLF line ending
|
||||
if(*end == '\r')
|
||||
{
|
||||
|
@ -909,7 +922,7 @@ public:
|
|||
// Read an array of binary-safe T values.
|
||||
// If successful, the file cursor is advanced by the size of the array.
|
||||
// Otherwise, the target is zeroed.
|
||||
template<typename T, off_t destSize>
|
||||
template<typename T, std::size_t destSize>
|
||||
bool ReadArray(T (&destArray)[destSize])
|
||||
{
|
||||
STATIC_ASSERT(mpt::is_binary_safe<T>::value);
|
||||
|
@ -922,7 +935,24 @@ public:
|
|||
return true;
|
||||
} else
|
||||
{
|
||||
MemsetZero(destArray);
|
||||
Clear(destArray);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
template<typename T, std::size_t destSize>
|
||||
bool ReadArray(std::array<T, destSize> &destArray)
|
||||
{
|
||||
STATIC_ASSERT(mpt::is_binary_safe<T>::value);
|
||||
if(CanRead(sizeof(destArray)))
|
||||
{
|
||||
for(auto &element : destArray)
|
||||
{
|
||||
Read(element);
|
||||
}
|
||||
return true;
|
||||
} else
|
||||
{
|
||||
destArray.fill(T());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -963,10 +993,10 @@ public:
|
|||
{
|
||||
mpt::byte bytes[N - 1];
|
||||
STATIC_ASSERT(sizeof(bytes) == sizeof(magic) - 1);
|
||||
DataContainer().Read(bytes, streamPos, N - 1);
|
||||
GetRaw(bytes, N - 1);
|
||||
if(!std::memcmp(bytes, magic, N - 1))
|
||||
{
|
||||
streamPos += (N - 1);
|
||||
Skip(N - 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -980,8 +1010,8 @@ public:
|
|||
bool identical = true;
|
||||
for(std::size_t i = 0; i < magicLength; ++i)
|
||||
{
|
||||
mpt::byte c = 0;
|
||||
DataContainer().Read(&c, streamPos + i, 1);
|
||||
mpt::byte c = mpt::as_byte(0);
|
||||
GetRawWithOffset(i, &c, 1);
|
||||
if(c != mpt::byte_cast<mpt::byte>(magic[i]))
|
||||
{
|
||||
identical = false;
|
||||
|
@ -990,7 +1020,7 @@ public:
|
|||
}
|
||||
if(identical)
|
||||
{
|
||||
streamPos += magicLength;
|
||||
Skip(magicLength);
|
||||
return true;
|
||||
} else
|
||||
{
|
||||
|
@ -1020,10 +1050,11 @@ public:
|
|||
}
|
||||
|
||||
mpt::byte bytes[16]; // More than enough for any valid VarInt
|
||||
off_t avail = DataContainer().Read(bytes, streamPos, sizeof(bytes)), readPos = 1;
|
||||
off_t avail = GetRaw(bytes, sizeof(bytes));
|
||||
off_t readPos = 1;
|
||||
|
||||
size_t writtenBits = 0;
|
||||
uint8 b = bytes[0];
|
||||
uint8 b = mpt::byte_cast<uint8>(bytes[0]);
|
||||
target = (b & 0x7F);
|
||||
|
||||
// Count actual bits used in most significant byte (i.e. this one)
|
||||
|
@ -1037,18 +1068,18 @@ public:
|
|||
|
||||
while(readPos < avail && (b & 0x80) != 0)
|
||||
{
|
||||
b = bytes[readPos++];
|
||||
b = mpt::byte_cast<uint8>(bytes[readPos++]);
|
||||
target <<= 7;
|
||||
target |= (b & 0x7F);
|
||||
writtenBits += 7;
|
||||
if(readPos == avail)
|
||||
{
|
||||
streamPos += readPos;
|
||||
avail = DataContainer().Read(bytes, streamPos, sizeof(bytes));
|
||||
Skip(readPos);
|
||||
avail = GetRaw(bytes, sizeof(bytes));
|
||||
readPos = 0;
|
||||
}
|
||||
}
|
||||
streamPos += readPos;
|
||||
Skip(readPos);
|
||||
|
||||
if(writtenBits > sizeof(target) * 8u)
|
||||
{
|
||||
|
@ -1072,8 +1103,6 @@ typedef detail::FileReader<FileReaderTraitsDefault> FileReader;
|
|||
typedef detail::FileReader<FileReaderTraitsMemory> MemoryFileReader;
|
||||
|
||||
|
||||
#if defined(LIBOPENMPT_BUILD)
|
||||
|
||||
// Initialize file reader object with pointer to data and data length.
|
||||
template <typename Tbyte> static inline FileReader make_FileReader(mpt::span<Tbyte> bytedata, const mpt::PathString *filename = nullptr)
|
||||
{
|
||||
|
@ -1111,8 +1140,6 @@ static inline FileReader make_FileReader(std::istream *s, const mpt::PathString
|
|||
|
||||
#endif // MPT_FILEREADER_STD_ISTREAM
|
||||
|
||||
#endif // LIBOPENMT_BUILD
|
||||
|
||||
|
||||
#if defined(MPT_ENABLE_FILEIO)
|
||||
// templated in order to reduce header inter-dependencies
|
||||
|
@ -1129,10 +1156,10 @@ FileReader GetFileReader(TInputFile &file)
|
|||
{
|
||||
return FileReader();
|
||||
}
|
||||
return FileReader(tmp.first, tmp.second);
|
||||
return make_FileReader(tmp.first, tmp.second);
|
||||
#else
|
||||
typename TInputFile::ContentsRef tmp = file.Get();
|
||||
return FileReader(mpt::as_span(tmp.first.data, tmp.first.size), tmp.second);
|
||||
return make_FileReader(mpt::as_span(tmp.first.data, tmp.first.size), tmp.second);
|
||||
#endif
|
||||
}
|
||||
#endif // MPT_ENABLE_FILEIO
|
||||
|
@ -1150,7 +1177,7 @@ private:
|
|||
|
||||
public:
|
||||
|
||||
OnDiskFileWrapper(FileReader &file, const mpt::PathString &fileNameExtension = MPT_PATHSTRING("tmp"));
|
||||
OnDiskFileWrapper(FileReader &file, const mpt::PathString &fileNameExtension = P_("tmp"));
|
||||
|
||||
~OnDiskFileWrapper();
|
||||
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "typedefs.h"
|
||||
#include "BuildSettings.h"
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
@ -29,6 +31,7 @@ struct enum_traits
|
|||
// Type-safe wrapper around an enum, that can represent all enum values and bitwise compositions thereof.
|
||||
// Conversions to and from plain integers as well as conversions to the base enum are always explicit.
|
||||
template <typename enum_t>
|
||||
// cppcheck-suppress copyCtorAndEqOperator
|
||||
class enum_value_type
|
||||
{
|
||||
public:
|
||||
|
@ -38,50 +41,50 @@ public:
|
|||
private:
|
||||
store_type bits;
|
||||
public:
|
||||
MPT_CONSTEXPR11_FUN enum_value_type() : bits(0) { }
|
||||
MPT_CONSTEXPR11_FUN enum_value_type(const enum_value_type &x) : bits(x.bits) { }
|
||||
MPT_CONSTEXPR11_FUN enum_value_type(enum_type x) : bits(static_cast<store_type>(x)) { }
|
||||
MPT_CONSTEXPR11_FUN enum_value_type() noexcept : bits(0) { }
|
||||
MPT_CONSTEXPR11_FUN enum_value_type(const enum_value_type &x) noexcept : bits(x.bits) { }
|
||||
MPT_CONSTEXPR11_FUN enum_value_type(enum_type x) noexcept : bits(static_cast<store_type>(x)) { }
|
||||
private:
|
||||
explicit MPT_CONSTEXPR11_FUN enum_value_type(store_type x) : bits(x) { } // private in order to prevent accidental conversions. use from_bits.
|
||||
MPT_CONSTEXPR11_FUN operator store_type () const { return bits; } // private in order to prevent accidental conversions. use as_bits.
|
||||
explicit MPT_CONSTEXPR11_FUN enum_value_type(store_type x) noexcept : bits(x) { } // private in order to prevent accidental conversions. use from_bits.
|
||||
MPT_CONSTEXPR11_FUN operator store_type () const noexcept { return bits; } // private in order to prevent accidental conversions. use as_bits.
|
||||
public:
|
||||
static MPT_CONSTEXPR11_FUN enum_value_type from_bits(store_type bits) { return value_type(bits); }
|
||||
MPT_CONSTEXPR11_FUN enum_type as_enum() const { return static_cast<enum_t>(bits); }
|
||||
MPT_CONSTEXPR11_FUN store_type as_bits() const { return bits; }
|
||||
static MPT_CONSTEXPR11_FUN enum_value_type from_bits(store_type bits) noexcept { return value_type(bits); }
|
||||
MPT_CONSTEXPR11_FUN enum_type as_enum() const noexcept { return static_cast<enum_t>(bits); }
|
||||
MPT_CONSTEXPR11_FUN store_type as_bits() const noexcept { return bits; }
|
||||
public:
|
||||
MPT_CONSTEXPR11_FUN operator bool () const { return bits != store_type(); }
|
||||
MPT_CONSTEXPR11_FUN bool operator ! () const { return bits == store_type(); }
|
||||
MPT_CONSTEXPR11_FUN operator bool () const noexcept { return bits != store_type(); }
|
||||
MPT_CONSTEXPR11_FUN bool operator ! () const noexcept { return bits == store_type(); }
|
||||
|
||||
MPT_CONSTEXPR11_FUN const enum_value_type operator ~ () const { return enum_value_type(~bits); }
|
||||
MPT_CONSTEXPR11_FUN const enum_value_type operator ~ () const noexcept { return enum_value_type(~bits); }
|
||||
|
||||
friend MPT_CONSTEXPR11_FUN bool operator == (enum_value_type a, enum_value_type b) { return a.bits == b.bits; }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator != (enum_value_type a, enum_value_type b) { return a.bits != b.bits; }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator == (enum_value_type a, enum_value_type b) noexcept { return a.bits == b.bits; }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator != (enum_value_type a, enum_value_type b) noexcept { return a.bits != b.bits; }
|
||||
|
||||
friend MPT_CONSTEXPR11_FUN bool operator == (enum_value_type a, enum_t b) { return a == enum_value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator != (enum_value_type a, enum_t b) { return a != enum_value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator == (enum_value_type a, enum_t b) noexcept { return a == enum_value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator != (enum_value_type a, enum_t b) noexcept { return a != enum_value_type(b); }
|
||||
|
||||
friend MPT_CONSTEXPR11_FUN bool operator == (enum_t a, enum_value_type b) { return enum_value_type(a) == b; }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator != (enum_t a, enum_value_type b) { return enum_value_type(a) != b; }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator == (enum_t a, enum_value_type b) noexcept { return enum_value_type(a) == b; }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator != (enum_t a, enum_value_type b) noexcept { return enum_value_type(a) != b; }
|
||||
|
||||
friend MPT_CONSTEXPR11_FUN const enum_value_type operator | (enum_value_type a, enum_value_type b) { return enum_value_type(a.bits | b.bits); }
|
||||
friend MPT_CONSTEXPR11_FUN const enum_value_type operator & (enum_value_type a, enum_value_type b) { return enum_value_type(a.bits & b.bits); }
|
||||
friend MPT_CONSTEXPR11_FUN const enum_value_type operator ^ (enum_value_type a, enum_value_type b) { return enum_value_type(a.bits ^ b.bits); }
|
||||
friend MPT_CONSTEXPR11_FUN const enum_value_type operator | (enum_value_type a, enum_value_type b) noexcept { return enum_value_type(a.bits | b.bits); }
|
||||
friend MPT_CONSTEXPR11_FUN const enum_value_type operator & (enum_value_type a, enum_value_type b) noexcept { return enum_value_type(a.bits & b.bits); }
|
||||
friend MPT_CONSTEXPR11_FUN const enum_value_type operator ^ (enum_value_type a, enum_value_type b) noexcept { return enum_value_type(a.bits ^ b.bits); }
|
||||
|
||||
friend MPT_CONSTEXPR11_FUN const enum_value_type operator | (enum_value_type a, enum_t b) { return a | enum_value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const enum_value_type operator & (enum_value_type a, enum_t b) { return a & enum_value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const enum_value_type operator ^ (enum_value_type a, enum_t b) { return a ^ enum_value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const enum_value_type operator | (enum_value_type a, enum_t b) noexcept { return a | enum_value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const enum_value_type operator & (enum_value_type a, enum_t b) noexcept { return a & enum_value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const enum_value_type operator ^ (enum_value_type a, enum_t b) noexcept { return a ^ enum_value_type(b); }
|
||||
|
||||
friend MPT_CONSTEXPR11_FUN const enum_value_type operator | (enum_t a, enum_value_type b) { return enum_value_type(a) | b; }
|
||||
friend MPT_CONSTEXPR11_FUN const enum_value_type operator & (enum_t a, enum_value_type b) { return enum_value_type(a) & b; }
|
||||
friend MPT_CONSTEXPR11_FUN const enum_value_type operator ^ (enum_t a, enum_value_type b) { return enum_value_type(a) ^ b; }
|
||||
friend MPT_CONSTEXPR11_FUN const enum_value_type operator | (enum_t a, enum_value_type b) noexcept { return enum_value_type(a) | b; }
|
||||
friend MPT_CONSTEXPR11_FUN const enum_value_type operator & (enum_t a, enum_value_type b) noexcept { return enum_value_type(a) & b; }
|
||||
friend MPT_CONSTEXPR11_FUN const enum_value_type operator ^ (enum_t a, enum_value_type b) noexcept { return enum_value_type(a) ^ b; }
|
||||
|
||||
MPT_CONSTEXPR14_FUN enum_value_type &operator |= (enum_value_type b) { *this = *this | b; return *this; }
|
||||
MPT_CONSTEXPR14_FUN enum_value_type &operator &= (enum_value_type b) { *this = *this & b; return *this; }
|
||||
MPT_CONSTEXPR14_FUN enum_value_type &operator ^= (enum_value_type b) { *this = *this ^ b; return *this; }
|
||||
MPT_CONSTEXPR14_FUN enum_value_type &operator |= (enum_value_type b) noexcept { *this = *this | b; return *this; }
|
||||
MPT_CONSTEXPR14_FUN enum_value_type &operator &= (enum_value_type b) noexcept { *this = *this & b; return *this; }
|
||||
MPT_CONSTEXPR14_FUN enum_value_type &operator ^= (enum_value_type b) noexcept { *this = *this ^ b; return *this; }
|
||||
|
||||
MPT_CONSTEXPR14_FUN enum_value_type &operator |= (enum_t b) { *this = *this | b; return *this; }
|
||||
MPT_CONSTEXPR14_FUN enum_value_type &operator &= (enum_t b) { *this = *this & b; return *this; }
|
||||
MPT_CONSTEXPR14_FUN enum_value_type &operator ^= (enum_t b) { *this = *this ^ b; return *this; }
|
||||
MPT_CONSTEXPR14_FUN enum_value_type &operator |= (enum_t b) noexcept { *this = *this | b; return *this; }
|
||||
MPT_CONSTEXPR14_FUN enum_value_type &operator &= (enum_t b) noexcept { *this = *this & b; return *this; }
|
||||
MPT_CONSTEXPR14_FUN enum_value_type &operator ^= (enum_t b) noexcept { *this = *this ^ b; return *this; }
|
||||
|
||||
};
|
||||
|
||||
|
@ -98,51 +101,52 @@ public:
|
|||
private:
|
||||
enum_type value;
|
||||
public:
|
||||
explicit MPT_CONSTEXPR11_FUN Enum(enum_type val) : value(val) { }
|
||||
MPT_CONSTEXPR11_FUN operator enum_type () const { return value; }
|
||||
MPT_CONSTEXPR14_FUN Enum &operator = (enum_type val) { value = val; return *this; }
|
||||
explicit MPT_CONSTEXPR11_FUN Enum(enum_type val) noexcept : value(val) { }
|
||||
MPT_CONSTEXPR11_FUN operator enum_type () const noexcept { return value; }
|
||||
MPT_CONSTEXPR14_FUN Enum &operator = (enum_type val) noexcept { value = val; return *this; }
|
||||
public:
|
||||
MPT_CONSTEXPR11_FUN const value_type operator ~ () const { return ~value_type(value); }
|
||||
|
||||
friend MPT_CONSTEXPR11_FUN bool operator == (self_type a, self_type b) { return value_type(a) == value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator != (self_type a, self_type b) { return value_type(a) != value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator == (self_type a, self_type b) noexcept { return value_type(a) == value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator != (self_type a, self_type b) noexcept { return value_type(a) != value_type(b); }
|
||||
|
||||
friend MPT_CONSTEXPR11_FUN bool operator == (self_type a, value_type b) { return value_type(a) == value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator != (self_type a, value_type b) { return value_type(a) != value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator == (self_type a, value_type b) noexcept { return value_type(a) == value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator != (self_type a, value_type b) noexcept { return value_type(a) != value_type(b); }
|
||||
|
||||
friend MPT_CONSTEXPR11_FUN bool operator == (value_type a, self_type b) { return value_type(a) == value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator != (value_type a, self_type b) { return value_type(a) != value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator == (value_type a, self_type b) noexcept { return value_type(a) == value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator != (value_type a, self_type b) noexcept { return value_type(a) != value_type(b); }
|
||||
|
||||
friend MPT_CONSTEXPR11_FUN bool operator == (self_type a, enum_type b) { return value_type(a) == value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator != (self_type a, enum_type b) { return value_type(a) != value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator == (self_type a, enum_type b) noexcept { return value_type(a) == value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator != (self_type a, enum_type b) noexcept { return value_type(a) != value_type(b); }
|
||||
|
||||
friend MPT_CONSTEXPR11_FUN bool operator == (enum_type a, self_type b) { return value_type(a) == value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator != (enum_type a, self_type b) { return value_type(a) != value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator == (enum_type a, self_type b) noexcept { return value_type(a) == value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator != (enum_type a, self_type b) noexcept { return value_type(a) != value_type(b); }
|
||||
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator | (self_type a, self_type b) { return value_type(a) | value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator & (self_type a, self_type b) { return value_type(a) & value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator ^ (self_type a, self_type b) { return value_type(a) ^ value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator | (self_type a, self_type b) noexcept { return value_type(a) | value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator & (self_type a, self_type b) noexcept { return value_type(a) & value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator ^ (self_type a, self_type b) noexcept { return value_type(a) ^ value_type(b); }
|
||||
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator | (self_type a, value_type b) { return value_type(a) | value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator & (self_type a, value_type b) { return value_type(a) & value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator ^ (self_type a, value_type b) { return value_type(a) ^ value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator | (self_type a, value_type b) noexcept { return value_type(a) | value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator & (self_type a, value_type b) noexcept { return value_type(a) & value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator ^ (self_type a, value_type b) noexcept { return value_type(a) ^ value_type(b); }
|
||||
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator | (value_type a, self_type b) { return value_type(a) | value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator & (value_type a, self_type b) { return value_type(a) & value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator ^ (value_type a, self_type b) { return value_type(a) ^ value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator | (value_type a, self_type b) noexcept { return value_type(a) | value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator & (value_type a, self_type b) noexcept { return value_type(a) & value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator ^ (value_type a, self_type b) noexcept { return value_type(a) ^ value_type(b); }
|
||||
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator | (self_type a, enum_type b) { return value_type(a) | value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator & (self_type a, enum_type b) { return value_type(a) & value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator ^ (self_type a, enum_type b) { return value_type(a) ^ value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator | (self_type a, enum_type b) noexcept { return value_type(a) | value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator & (self_type a, enum_type b) noexcept { return value_type(a) & value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator ^ (self_type a, enum_type b) noexcept { return value_type(a) ^ value_type(b); }
|
||||
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator | (enum_type a, self_type b) { return value_type(a) | value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator & (enum_type a, self_type b) { return value_type(a) & value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator ^ (enum_type a, self_type b) { return value_type(a) ^ value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator | (enum_type a, self_type b) noexcept { return value_type(a) | value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator & (enum_type a, self_type b) noexcept { return value_type(a) & value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator ^ (enum_type a, self_type b) noexcept { return value_type(a) ^ value_type(b); }
|
||||
|
||||
};
|
||||
|
||||
|
||||
template <typename enum_t, typename store_t = typename enum_value_type<enum_t>::store_type >
|
||||
// cppcheck-suppress copyCtorAndEqOperator
|
||||
class FlagSet
|
||||
{
|
||||
public:
|
||||
|
@ -155,66 +159,66 @@ private:
|
|||
|
||||
// support truncated store_type ... :
|
||||
store_type bits_;
|
||||
static MPT_CONSTEXPR11_FUN store_type store_from_value(value_type bits) { return static_cast<store_type>(bits.as_bits()); }
|
||||
static MPT_CONSTEXPR11_FUN value_type value_from_store(store_type bits) { return value_type::from_bits(static_cast<typename value_type::store_type>(bits)); }
|
||||
static MPT_CONSTEXPR11_FUN store_type store_from_value(value_type bits) noexcept { return static_cast<store_type>(bits.as_bits()); }
|
||||
static MPT_CONSTEXPR11_FUN value_type value_from_store(store_type bits) noexcept { return value_type::from_bits(static_cast<typename value_type::store_type>(bits)); }
|
||||
|
||||
MPT_CONSTEXPR14_FUN FlagSet & store(value_type bits) { bits_ = store_from_value(bits); return *this; }
|
||||
MPT_CONSTEXPR11_FUN value_type load() const { return value_from_store(bits_); }
|
||||
MPT_CONSTEXPR14_FUN FlagSet & store(value_type bits) noexcept { bits_ = store_from_value(bits); return *this; }
|
||||
MPT_CONSTEXPR11_FUN value_type load() const noexcept { return value_from_store(bits_); }
|
||||
|
||||
public:
|
||||
|
||||
// Default constructor (no flags set)
|
||||
MPT_CONSTEXPR11_FUN FlagSet() : bits_(store_from_value(value_type()))
|
||||
MPT_CONSTEXPR11_FUN FlagSet() noexcept : bits_(store_from_value(value_type()))
|
||||
{
|
||||
}
|
||||
|
||||
// Copy constructor
|
||||
MPT_CONSTEXPR11_FUN FlagSet(const FlagSet &flags) noexcept
|
||||
: bits_(flags.bits_)
|
||||
{
|
||||
}
|
||||
|
||||
// Value constructor
|
||||
MPT_CONSTEXPR11_FUN FlagSet(value_type flags) : bits_(store_from_value(value_type(flags)))
|
||||
MPT_CONSTEXPR11_FUN FlagSet(value_type flags) noexcept : bits_(store_from_value(value_type(flags)))
|
||||
{
|
||||
}
|
||||
|
||||
MPT_CONSTEXPR11_FUN FlagSet(enum_type flag) : bits_(store_from_value(value_type(flag)))
|
||||
MPT_CONSTEXPR11_FUN FlagSet(enum_type flag) noexcept : bits_(store_from_value(value_type(flag)))
|
||||
{
|
||||
}
|
||||
|
||||
explicit MPT_CONSTEXPR11_FUN FlagSet(store_type flags) : bits_(store_from_value(value_type::from_bits(flags)))
|
||||
explicit MPT_CONSTEXPR11_FUN FlagSet(store_type flags) noexcept : bits_(store_from_value(value_type::from_bits(flags)))
|
||||
{
|
||||
}
|
||||
|
||||
MPT_CONSTEXPR11_FUN operator bool () const
|
||||
MPT_CONSTEXPR11_FUN explicit operator bool () const noexcept
|
||||
{
|
||||
return load();
|
||||
}
|
||||
// In order to catch undesired conversions to bool in integer contexts,
|
||||
// add a deprecated conversion operator to store_type.
|
||||
// C++11 explicit conversion cast operators ('explicit operator bool ();')
|
||||
// would solve this in a better way and always fail at compile-time instead of this
|
||||
// solution which just warns in some cases.
|
||||
// The macro-based extended instrument fields writer in InstrumentExtensions.cpp currently needs this conversion,
|
||||
// so it is not marked deprecated (for now).
|
||||
/*MPT_DEPRECATED*/ MPT_CONSTEXPR11_FUN operator store_type () const
|
||||
// The macro-based extended instrument fields writer in InstrumentExtensions.cpp currently needs this conversion.
|
||||
/*MPT_DEPRECATED*/ MPT_CONSTEXPR11_FUN operator store_type () const noexcept
|
||||
{
|
||||
return load().as_bits();
|
||||
}
|
||||
|
||||
MPT_CONSTEXPR11_FUN value_type value() const
|
||||
MPT_CONSTEXPR11_FUN value_type value() const noexcept
|
||||
{
|
||||
return load();
|
||||
}
|
||||
|
||||
MPT_CONSTEXPR11_FUN operator value_type () const
|
||||
MPT_CONSTEXPR11_FUN operator value_type () const noexcept
|
||||
{
|
||||
return load();
|
||||
}
|
||||
|
||||
// Test if one or more flags are set. Returns true if at least one of the given flags is set.
|
||||
MPT_CONSTEXPR11_FUN bool operator[] (value_type flags) const
|
||||
MPT_CONSTEXPR11_FUN bool operator[] (value_type flags) const noexcept
|
||||
{
|
||||
return test(flags);
|
||||
}
|
||||
|
||||
// String representation of flag set
|
||||
std::string to_string() const
|
||||
std::string to_string() const noexcept
|
||||
{
|
||||
std::string str(size_bits(), '0');
|
||||
|
||||
|
@ -227,182 +231,182 @@ public:
|
|||
}
|
||||
|
||||
// Set one or more flags.
|
||||
MPT_CONSTEXPR14_FUN FlagSet &set(value_type flags)
|
||||
MPT_CONSTEXPR14_FUN FlagSet &set(value_type flags) noexcept
|
||||
{
|
||||
return store(load() | flags);
|
||||
}
|
||||
|
||||
// Set or clear one or more flags.
|
||||
MPT_CONSTEXPR14_FUN FlagSet &set(value_type flags, bool val)
|
||||
MPT_CONSTEXPR14_FUN FlagSet &set(value_type flags, bool val) noexcept
|
||||
{
|
||||
return store((val ? (load() | flags) : (load() & ~flags)));
|
||||
}
|
||||
|
||||
// Clear or flags.
|
||||
MPT_CONSTEXPR14_FUN FlagSet &reset()
|
||||
MPT_CONSTEXPR14_FUN FlagSet &reset() noexcept
|
||||
{
|
||||
return store(value_type());
|
||||
}
|
||||
|
||||
// Clear one or more flags.
|
||||
MPT_CONSTEXPR14_FUN FlagSet &reset(value_type flags)
|
||||
MPT_CONSTEXPR14_FUN FlagSet &reset(value_type flags) noexcept
|
||||
{
|
||||
return store(load() & ~flags);
|
||||
}
|
||||
|
||||
// Toggle all flags.
|
||||
MPT_CONSTEXPR14_FUN FlagSet &flip()
|
||||
MPT_CONSTEXPR14_FUN FlagSet &flip() noexcept
|
||||
{
|
||||
return store(~load());
|
||||
}
|
||||
|
||||
// Toggle one or more flags.
|
||||
MPT_CONSTEXPR14_FUN FlagSet &flip(value_type flags)
|
||||
MPT_CONSTEXPR14_FUN FlagSet &flip(value_type flags) noexcept
|
||||
{
|
||||
return store(load() ^ flags);
|
||||
}
|
||||
|
||||
// Returns the size of the flag set in bytes
|
||||
MPT_CONSTEXPR11_FUN std::size_t size() const
|
||||
MPT_CONSTEXPR11_FUN std::size_t size() const noexcept
|
||||
{
|
||||
return sizeof(store_type);
|
||||
}
|
||||
|
||||
// Returns the size of the flag set in bits
|
||||
MPT_CONSTEXPR11_FUN std::size_t size_bits() const
|
||||
MPT_CONSTEXPR11_FUN std::size_t size_bits() const noexcept
|
||||
{
|
||||
return size() * 8;
|
||||
}
|
||||
|
||||
// Test if one or more flags are set. Returns true if at least one of the given flags is set.
|
||||
MPT_CONSTEXPR11_FUN bool test(value_type flags) const
|
||||
MPT_CONSTEXPR11_FUN bool test(value_type flags) const noexcept
|
||||
{
|
||||
return (load() & flags);
|
||||
}
|
||||
|
||||
// Test if all specified flags are set.
|
||||
MPT_CONSTEXPR11_FUN bool test_all(value_type flags) const
|
||||
MPT_CONSTEXPR11_FUN bool test_all(value_type flags) const noexcept
|
||||
{
|
||||
return (load() & flags) == flags;
|
||||
}
|
||||
|
||||
// Test if any but the specified flags are set.
|
||||
MPT_CONSTEXPR11_FUN bool test_any_except(value_type flags) const
|
||||
MPT_CONSTEXPR11_FUN bool test_any_except(value_type flags) const noexcept
|
||||
{
|
||||
return (load() & ~flags);
|
||||
}
|
||||
|
||||
// Test if any flag is set.
|
||||
MPT_CONSTEXPR11_FUN bool any() const
|
||||
MPT_CONSTEXPR11_FUN bool any() const noexcept
|
||||
{
|
||||
return load();
|
||||
}
|
||||
|
||||
// Test if no flags are set.
|
||||
MPT_CONSTEXPR11_FUN bool none() const
|
||||
MPT_CONSTEXPR11_FUN bool none() const noexcept
|
||||
{
|
||||
return !load();
|
||||
}
|
||||
|
||||
MPT_CONSTEXPR11_FUN store_type GetRaw() const
|
||||
MPT_CONSTEXPR11_FUN store_type GetRaw() const noexcept
|
||||
{
|
||||
return bits_;
|
||||
}
|
||||
|
||||
MPT_CONSTEXPR14_FUN FlagSet & SetRaw(store_type flags)
|
||||
MPT_CONSTEXPR14_FUN FlagSet & SetRaw(store_type flags) noexcept
|
||||
{
|
||||
bits_ = flags;
|
||||
return *this;
|
||||
}
|
||||
|
||||
MPT_CONSTEXPR14_FUN FlagSet &operator = (value_type flags)
|
||||
MPT_CONSTEXPR14_FUN FlagSet &operator = (value_type flags) noexcept
|
||||
{
|
||||
return store(flags);
|
||||
}
|
||||
|
||||
MPT_CONSTEXPR14_FUN FlagSet &operator = (enum_type flag)
|
||||
MPT_CONSTEXPR14_FUN FlagSet &operator = (enum_type flag) noexcept
|
||||
{
|
||||
return store(flag);
|
||||
}
|
||||
|
||||
MPT_CONSTEXPR14_FUN FlagSet &operator = (FlagSet flags)
|
||||
MPT_CONSTEXPR14_FUN FlagSet &operator = (FlagSet flags) noexcept
|
||||
{
|
||||
return store(flags.load());
|
||||
}
|
||||
|
||||
MPT_CONSTEXPR14_FUN FlagSet &operator &= (value_type flags)
|
||||
MPT_CONSTEXPR14_FUN FlagSet &operator &= (value_type flags) noexcept
|
||||
{
|
||||
return store(load() & flags);
|
||||
}
|
||||
|
||||
MPT_CONSTEXPR14_FUN FlagSet &operator |= (value_type flags)
|
||||
MPT_CONSTEXPR14_FUN FlagSet &operator |= (value_type flags) noexcept
|
||||
{
|
||||
return store(load() | flags);
|
||||
}
|
||||
|
||||
MPT_CONSTEXPR14_FUN FlagSet &operator ^= (value_type flags)
|
||||
MPT_CONSTEXPR14_FUN FlagSet &operator ^= (value_type flags) noexcept
|
||||
{
|
||||
return store(load() ^ flags);
|
||||
}
|
||||
|
||||
friend MPT_CONSTEXPR11_FUN bool operator == (self_type a, self_type b) { return a.load() == b.load(); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator != (self_type a, self_type b) { return a.load() != b.load(); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator == (self_type a, self_type b) noexcept { return a.load() == b.load(); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator != (self_type a, self_type b) noexcept { return a.load() != b.load(); }
|
||||
|
||||
friend MPT_CONSTEXPR11_FUN bool operator == (self_type a, value_type b) { return a.load() == value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator != (self_type a, value_type b) { return a.load() != value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator == (self_type a, value_type b) noexcept { return a.load() == value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator != (self_type a, value_type b) noexcept { return a.load() != value_type(b); }
|
||||
|
||||
friend MPT_CONSTEXPR11_FUN bool operator == (value_type a, self_type b) { return value_type(a) == b.load(); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator != (value_type a, self_type b) { return value_type(a) != b.load(); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator == (value_type a, self_type b) noexcept { return value_type(a) == b.load(); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator != (value_type a, self_type b) noexcept { return value_type(a) != b.load(); }
|
||||
|
||||
friend MPT_CONSTEXPR11_FUN bool operator == (self_type a, enum_type b) { return a.load() == value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator != (self_type a, enum_type b) { return a.load() != value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator == (self_type a, enum_type b) noexcept { return a.load() == value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator != (self_type a, enum_type b) noexcept { return a.load() != value_type(b); }
|
||||
|
||||
friend MPT_CONSTEXPR11_FUN bool operator == (enum_type a, self_type b) { return value_type(a) == b.load(); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator != (enum_type a, self_type b) { return value_type(a) != b.load(); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator == (enum_type a, self_type b) noexcept { return value_type(a) == b.load(); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator != (enum_type a, self_type b) noexcept { return value_type(a) != b.load(); }
|
||||
|
||||
friend MPT_CONSTEXPR11_FUN bool operator == (self_type a, Enum<enum_type> b) { return a.load() == value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator != (self_type a, Enum<enum_type> b) { return a.load() != value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator == (self_type a, Enum<enum_type> b) noexcept { return a.load() == value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator != (self_type a, Enum<enum_type> b) noexcept { return a.load() != value_type(b); }
|
||||
|
||||
friend MPT_CONSTEXPR11_FUN bool operator == (Enum<enum_type> a, self_type b) { return value_type(a) == b.load(); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator != (Enum<enum_type> a, self_type b) { return value_type(a) != b.load(); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator == (Enum<enum_type> a, self_type b) noexcept { return value_type(a) == b.load(); }
|
||||
friend MPT_CONSTEXPR11_FUN bool operator != (Enum<enum_type> a, self_type b) noexcept { return value_type(a) != b.load(); }
|
||||
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator | (self_type a, self_type b) { return a.load() | b.load(); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator & (self_type a, self_type b) { return a.load() & b.load(); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator ^ (self_type a, self_type b) { return a.load() ^ b.load(); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator | (self_type a, self_type b) noexcept { return a.load() | b.load(); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator & (self_type a, self_type b) noexcept { return a.load() & b.load(); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator ^ (self_type a, self_type b) noexcept { return a.load() ^ b.load(); }
|
||||
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator | (self_type a, value_type b) { return a.load() | value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator & (self_type a, value_type b) { return a.load() & value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator ^ (self_type a, value_type b) { return a.load() ^ value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator | (self_type a, value_type b) noexcept { return a.load() | value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator & (self_type a, value_type b) noexcept { return a.load() & value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator ^ (self_type a, value_type b) noexcept { return a.load() ^ value_type(b); }
|
||||
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator | (value_type a, self_type b) { return value_type(a) | b.load(); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator & (value_type a, self_type b) { return value_type(a) & b.load(); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator ^ (value_type a, self_type b) { return value_type(a) ^ b.load(); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator | (value_type a, self_type b) noexcept { return value_type(a) | b.load(); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator & (value_type a, self_type b) noexcept { return value_type(a) & b.load(); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator ^ (value_type a, self_type b) noexcept { return value_type(a) ^ b.load(); }
|
||||
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator | (self_type a, enum_type b) { return a.load() | value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator & (self_type a, enum_type b) { return a.load() & value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator ^ (self_type a, enum_type b) { return a.load() ^ value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator | (self_type a, enum_type b) noexcept { return a.load() | value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator & (self_type a, enum_type b) noexcept { return a.load() & value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator ^ (self_type a, enum_type b) noexcept { return a.load() ^ value_type(b); }
|
||||
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator | (enum_type a, self_type b) { return value_type(a) | b.load(); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator & (enum_type a, self_type b) { return value_type(a) & b.load(); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator ^ (enum_type a, self_type b) { return value_type(a) ^ b.load(); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator | (enum_type a, self_type b) noexcept { return value_type(a) | b.load(); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator & (enum_type a, self_type b) noexcept { return value_type(a) & b.load(); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator ^ (enum_type a, self_type b) noexcept { return value_type(a) ^ b.load(); }
|
||||
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator | (self_type a, Enum<enum_type> b) { return a.load() | value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator & (self_type a, Enum<enum_type> b) { return a.load() & value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator ^ (self_type a, Enum<enum_type> b) { return a.load() ^ value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator | (self_type a, Enum<enum_type> b) noexcept { return a.load() | value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator & (self_type a, Enum<enum_type> b) noexcept { return a.load() & value_type(b); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator ^ (self_type a, Enum<enum_type> b) noexcept { return a.load() ^ value_type(b); }
|
||||
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator | (Enum<enum_type> a, self_type b) { return value_type(a) | b.load(); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator & (Enum<enum_type> a, self_type b) { return value_type(a) & b.load(); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator ^ (Enum<enum_type> a, self_type b) { return value_type(a) ^ b.load(); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator | (Enum<enum_type> a, self_type b) noexcept { return value_type(a) | b.load(); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator & (Enum<enum_type> a, self_type b) noexcept { return value_type(a) & b.load(); }
|
||||
friend MPT_CONSTEXPR11_FUN const value_type operator ^ (Enum<enum_type> a, self_type b) noexcept { return value_type(a) ^ b.load(); }
|
||||
|
||||
};
|
||||
|
||||
|
||||
// Declare typesafe logical operators for enum_t
|
||||
#define MPT_DECLARE_ENUM(enum_t) \
|
||||
MPT_CONSTEXPR11_FUN enum_value_type<enum_t> operator | (enum_t a, enum_t b) { return enum_value_type<enum_t>(a) | enum_value_type<enum_t>(b); } \
|
||||
MPT_CONSTEXPR11_FUN enum_value_type<enum_t> operator & (enum_t a, enum_t b) { return enum_value_type<enum_t>(a) & enum_value_type<enum_t>(b); } \
|
||||
MPT_CONSTEXPR11_FUN enum_value_type<enum_t> operator ^ (enum_t a, enum_t b) { return enum_value_type<enum_t>(a) ^ enum_value_type<enum_t>(b); } \
|
||||
MPT_CONSTEXPR11_FUN enum_value_type<enum_t> operator ~ (enum_t a) { return ~enum_value_type<enum_t>(a); } \
|
||||
MPT_CONSTEXPR11_FUN enum_value_type<enum_t> operator | (enum_t a, enum_t b) noexcept { return enum_value_type<enum_t>(a) | enum_value_type<enum_t>(b); } \
|
||||
MPT_CONSTEXPR11_FUN enum_value_type<enum_t> operator & (enum_t a, enum_t b) noexcept { return enum_value_type<enum_t>(a) & enum_value_type<enum_t>(b); } \
|
||||
MPT_CONSTEXPR11_FUN enum_value_type<enum_t> operator ^ (enum_t a, enum_t b) noexcept { return enum_value_type<enum_t>(a) ^ enum_value_type<enum_t>(b); } \
|
||||
MPT_CONSTEXPR11_FUN enum_value_type<enum_t> operator ~ (enum_t a) noexcept { return ~enum_value_type<enum_t>(a); } \
|
||||
/**/
|
||||
|
||||
// backwards compatibility
|
||||
|
|
|
@ -88,10 +88,10 @@ bool IsFacilityActive(const char *facility)
|
|||
#endif
|
||||
|
||||
|
||||
void Logger::SendLogMessage(const Context &context, LogLevel level, const char *facility, const mpt::ustring &text)
|
||||
void Logger::SendLogMessage(const mpt::source_location &loc, LogLevel level, const char *facility, const mpt::ustring &text)
|
||||
{
|
||||
#ifdef MPT_LOG_IS_DISABLED
|
||||
MPT_UNREFERENCED_PARAMETER(context);
|
||||
MPT_UNREFERENCED_PARAMETER(loc);
|
||||
MPT_UNREFERENCED_PARAMETER(level);
|
||||
MPT_UNREFERENCED_PARAMETER(facility);
|
||||
MPT_UNREFERENCED_PARAMETER(text);
|
||||
|
@ -109,10 +109,10 @@ void Logger::SendLogMessage(const Context &context, LogLevel level, const char *
|
|||
MPT_UNREFERENCED_PARAMETER(facility);
|
||||
#endif // MODPLUG_TRACKER
|
||||
// remove eol if already present and add log level prefix
|
||||
const mpt::ustring message = LogLevelToString(level) + MPT_USTRING(": ") + mpt::String::RTrim(text, MPT_USTRING("\r\n"));
|
||||
const mpt::ustring file = mpt::ToUnicode(mpt::CharsetASCII, context.file);
|
||||
const mpt::ustring function = mpt::ToUnicode(mpt::CharsetASCII, context.function);
|
||||
const mpt::ustring line = mpt::ufmt::dec(context.line);
|
||||
const mpt::ustring message = LogLevelToString(level) + U_(": ") + mpt::String::RTrim(text, U_("\r\n"));
|
||||
const mpt::ustring file = mpt::ToUnicode(mpt::CharsetASCII, loc.file_name() ? loc.file_name() : "");
|
||||
const mpt::ustring function = mpt::ToUnicode(mpt::CharsetASCII, loc.function_name() ? loc.function_name() : "");
|
||||
const mpt::ustring line = mpt::ufmt::dec(loc.line());
|
||||
#if defined(MODPLUG_TRACKER) && !defined(MPT_BUILD_WINESUPPORT)
|
||||
#if MPT_OS_WINDOWS
|
||||
static uint64 s_lastlogtime = 0;
|
||||
|
@ -125,30 +125,30 @@ void Logger::SendLogMessage(const Context &context, LogLevel level, const char *
|
|||
#endif
|
||||
if(mpt::log::FileEnabled)
|
||||
{
|
||||
static FILE * s_logfile = nullptr;
|
||||
static mpt::ofstream s_logfile;
|
||||
if(!s_logfile)
|
||||
{
|
||||
s_logfile = mpt_fopen(MPT_PATHSTRING("mptrack.log"), "a");
|
||||
s_logfile.open(P_("mptrack.log"), std::ios::app);
|
||||
}
|
||||
if(s_logfile)
|
||||
{
|
||||
fprintf(s_logfile, mpt::ToCharset(mpt::CharsetUTF8, mpt::format(MPT_USTRING("%1+%2 %3(%4): %5 [%6]\n"))
|
||||
( mpt::Date::ANSI::ToString(cur)
|
||||
, mpt::ufmt::dec<6>(diff)
|
||||
mpt::IO::WriteText(s_logfile, mpt::ToCharset(mpt::CharsetUTF8, mpt::format(U_("%1+%2 %3(%4): %5 [%6]\n"))
|
||||
( mpt::Date::ANSI::ToUString(cur)
|
||||
, mpt::ufmt::right(6, mpt::ufmt::dec(diff))
|
||||
, file
|
||||
, line
|
||||
, message
|
||||
, function
|
||||
)).c_str());
|
||||
fflush(s_logfile);
|
||||
)));
|
||||
mpt::IO::Flush(s_logfile);
|
||||
}
|
||||
}
|
||||
if(mpt::log::DebuggerEnabled)
|
||||
{
|
||||
OutputDebugStringW(mpt::ToWide(mpt::format(MPT_USTRING("%1(%2): +%3 %4 [%5]\n"))
|
||||
OutputDebugStringW(mpt::ToWide(mpt::format(U_("%1(%2): +%3 %4 [%5]\n"))
|
||||
( file
|
||||
, line
|
||||
, mpt::ufmt::dec<6>(diff)
|
||||
, mpt::ufmt::right(6, mpt::ufmt::dec(diff))
|
||||
, message
|
||||
, function
|
||||
)).c_str());
|
||||
|
@ -163,7 +163,7 @@ void Logger::SendLogMessage(const Context &context, LogLevel level, const char *
|
|||
}
|
||||
std::wstring consoletext = mpt::ToWide(message) + L"\r\n";
|
||||
DWORD dummy = 0;
|
||||
WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), consoletext.c_str(), consoletext.length(), &dummy, NULL);
|
||||
WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), consoletext.c_str(), mpt::saturate_cast<DWORD>(consoletext.length()), &dummy, NULL);
|
||||
}
|
||||
#elif defined(MODPLUG_TRACKER) && defined(MPT_BUILD_WINESUPPORT)
|
||||
std::clog
|
||||
|
@ -185,7 +185,7 @@ void Logger::SendLogMessage(const Context &context, LogLevel level, const char *
|
|||
|
||||
void LegacyLogger::operator () (const AnyStringLocale &text)
|
||||
{
|
||||
SendLogMessage(context, MPT_LEGACY_LOGLEVEL, "", text);
|
||||
SendLogMessage(loc, MPT_LEGACY_LOGLEVEL, "", text);
|
||||
}
|
||||
|
||||
void LegacyLogger::operator () (const char *format, ...)
|
||||
|
@ -197,12 +197,12 @@ void LegacyLogger::operator () (const char *format, ...)
|
|||
vsnprintf(message, LOGBUF_SIZE, format, va);
|
||||
va_end(va);
|
||||
message[LOGBUF_SIZE - 1] = '\0';
|
||||
SendLogMessage(context, MPT_LEGACY_LOGLEVEL, "", mpt::ToUnicode(mpt::CharsetLocaleOrUTF8, message));
|
||||
SendLogMessage(loc, MPT_LEGACY_LOGLEVEL, "", mpt::ToUnicode(mpt::CharsetLocaleOrUTF8, message));
|
||||
}
|
||||
|
||||
void LegacyLogger::operator () (LogLevel level, const mpt::ustring &text)
|
||||
{
|
||||
SendLogMessage(context, level, "", text);
|
||||
SendLogMessage(loc, level, "", text);
|
||||
}
|
||||
|
||||
|
||||
|
@ -230,9 +230,10 @@ struct Entry {
|
|||
const char * Function;
|
||||
const char * File;
|
||||
int Line;
|
||||
Direction Direction;
|
||||
};
|
||||
|
||||
inline bool operator < (const Entry &a, const Entry &b)
|
||||
static MPT_FORCEINLINE bool operator < (const Entry &a, const Entry &b) noexcept
|
||||
{
|
||||
/*
|
||||
return false
|
||||
|
@ -266,7 +267,7 @@ void Enable(std::size_t numEntries)
|
|||
Entries.clear();
|
||||
Entries.resize(numEntries);
|
||||
NextIndex.store(0);
|
||||
g_Enabled = true;
|
||||
g_Enabled = (numEntries > 0);
|
||||
}
|
||||
|
||||
void Disable()
|
||||
|
@ -278,11 +279,12 @@ void Disable()
|
|||
g_Enabled = false;
|
||||
}
|
||||
|
||||
MPT_NOINLINE void Trace(const mpt::log::Context & context)
|
||||
MPT_NOINLINE void Trace(const mpt::source_location & loc, Direction direction) noexcept
|
||||
{
|
||||
// This will get called in realtime contexts and hot paths.
|
||||
// No blocking allowed here.
|
||||
const uint32 index = NextIndex.fetch_add(1);
|
||||
const std::size_t numEntries = Entries.size();
|
||||
#if 1
|
||||
LARGE_INTEGER time;
|
||||
time.QuadPart = 0;
|
||||
|
@ -294,13 +296,14 @@ MPT_NOINLINE void Trace(const mpt::log::Context & context)
|
|||
const uint64 timestamp = (static_cast<uint64>(time.dwHighDateTime) << 32) | (static_cast<uint64>(time.dwLowDateTime) << 0);
|
||||
#endif
|
||||
const uint32 threadid = static_cast<uint32>(GetCurrentThreadId());
|
||||
mpt::log::Trace::Entry & entry = Entries[index % Entries.size()];
|
||||
mpt::log::Trace::Entry & entry = Entries[index % numEntries];
|
||||
entry.Index = index;
|
||||
entry.ThreadId = threadid;
|
||||
entry.Timestamp = timestamp;
|
||||
entry.Function = context.function;
|
||||
entry.File = context.file;
|
||||
entry.Line = context.line;
|
||||
entry.Function = loc.function_name();
|
||||
entry.File = loc.file_name();
|
||||
entry.Line = loc.line();
|
||||
entry.Direction = direction;
|
||||
}
|
||||
|
||||
void Seal()
|
||||
|
@ -333,9 +336,9 @@ bool Dump(const mpt::PathString &filename)
|
|||
// sort according to index in case of overflows
|
||||
std::stable_sort(Entries.begin(), Entries.end());
|
||||
|
||||
mpt::ofstream f(filename, std::ios::out);
|
||||
mpt::ofstream f(filename);
|
||||
|
||||
f << "Build: OpenMPT " << MptVersion::GetVersionStringExtended() << std::endl;
|
||||
f << "Build: OpenMPT " << mpt::ToCharset(mpt::CharsetUTF8, Build::GetVersionStringExtended()) << std::endl;
|
||||
|
||||
bool qpcValid = false;
|
||||
|
||||
|
@ -347,7 +350,7 @@ bool Dump(const mpt::PathString &filename)
|
|||
qpcValid = true;
|
||||
}
|
||||
|
||||
f << "Dump: " << mpt::ToCharset(mpt::CharsetUTF8, mpt::Date::ANSI::ToString(ftNow)) << std::endl;
|
||||
f << "Dump: " << mpt::ToCharset(mpt::CharsetUTF8, mpt::Date::ANSI::ToUString(ftNow)) << std::endl;
|
||||
f << "Captured events: " << Entries.size() << std::endl;
|
||||
if(qpcValid && (Entries.size() > 0))
|
||||
{
|
||||
|
@ -357,15 +360,14 @@ bool Dump(const mpt::PathString &filename)
|
|||
f << "Events/second: " << mpt::fmt::fix(eventsPerSecond) << std::endl;
|
||||
}
|
||||
|
||||
for(std::size_t i = 0; i < Entries.size(); ++i)
|
||||
for(auto &entry : Entries)
|
||||
{
|
||||
mpt::log::Trace::Entry & entry = Entries[i];
|
||||
if(!entry.Function) entry.Function = "";
|
||||
if(!entry.File) entry.File = "";
|
||||
std::string time;
|
||||
if(qpcValid)
|
||||
{
|
||||
time = mpt::ToCharset(mpt::CharsetUTF8, mpt::Date::ANSI::ToString( ftNow - static_cast<int64>( static_cast<double>(qpcNow.QuadPart - entry.Timestamp) * (10000000.0 / static_cast<double>(qpcFreq.QuadPart) ) ) ) );
|
||||
time = mpt::ToCharset(mpt::CharsetUTF8, mpt::Date::ANSI::ToUString( ftNow - static_cast<int64>( static_cast<double>(qpcNow.QuadPart - entry.Timestamp) * (10000000.0 / static_cast<double>(qpcFreq.QuadPart) ) ) ) );
|
||||
} else
|
||||
{
|
||||
time = mpt::format("0x%1")(mpt::fmt::hex0<16>(entry.Timestamp));
|
||||
|
@ -387,6 +389,7 @@ bool Dump(const mpt::PathString &filename)
|
|||
{
|
||||
f << " " << mpt::fmt::hex0<8>(entry.ThreadId) << " ";
|
||||
}
|
||||
f << (entry.Direction == mpt::log::Trace::Direction::Enter ? ">" : entry.Direction == mpt::log::Trace::Direction::Leave ? "<" : " ") << " ";
|
||||
f << entry.File << "(" << entry.Line << "): " << entry.Function;
|
||||
f << std::endl;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
@ -42,12 +44,12 @@ CSoundfile::AddToLog.
|
|||
|
||||
Logging a simple message:
|
||||
MPT_LOG(LogWarning, "sounddev", "some message");
|
||||
MPT_LOG(LogWarning, "sounddev", MPT_USTRING("some message"));
|
||||
MPT_LOG(LogWarning, "sounddev", U_("some message"));
|
||||
Facility is some course grained code section identifier (more coarse grained
|
||||
than the current file name probably), useful to do some selective logging.
|
||||
|
||||
Logging a more complex message:
|
||||
MPT_LOG(LogWarning, "sounddev", mpt::format(MPT_USTRING("Some message: foo=%1, bar=0x%2"))(foo, mpt::ufmt::hex0<8>(bar)));
|
||||
MPT_LOG(LogWarning, "sounddev", mpt::format(U_("Some message: foo=%1, bar=0x%2"))(foo, mpt::ufmt::hex0<8>(bar)));
|
||||
|
||||
Note that even with full enabled logging and a runtime configurable logging
|
||||
level, the runtime overhead of a MPT_LOG(level, facility, text) call is just a
|
||||
|
@ -72,13 +74,13 @@ inline mpt::ustring LogLevelToString(LogLevel level)
|
|||
{
|
||||
switch(level)
|
||||
{
|
||||
case LogError: return MPT_USTRING("error"); break;
|
||||
case LogWarning: return MPT_USTRING("warning"); break;
|
||||
case LogNotification: return MPT_USTRING("notify"); break;
|
||||
case LogInformation: return MPT_USTRING("info"); break;
|
||||
case LogDebug: return MPT_USTRING("debug"); break;
|
||||
case LogError: return U_("error"); break;
|
||||
case LogWarning: return U_("warning"); break;
|
||||
case LogNotification: return U_("notify"); break;
|
||||
case LogInformation: return U_("info"); break;
|
||||
case LogDebug: return U_("debug"); break;
|
||||
}
|
||||
return MPT_USTRING("unknown");
|
||||
return U_("unknown");
|
||||
}
|
||||
|
||||
|
||||
|
@ -128,29 +130,6 @@ static MPT_FORCEINLINE bool IsFacilityActive(const char * /*facility*/ ) { retur
|
|||
#endif // !NO_LOGGING
|
||||
|
||||
|
||||
struct Context
|
||||
{
|
||||
const char * const file;
|
||||
const int line;
|
||||
const char * const function;
|
||||
MPT_FORCEINLINE Context(const char *file, int line, const char *function)
|
||||
: file(file)
|
||||
, line(line)
|
||||
, function(function)
|
||||
{
|
||||
return;
|
||||
}
|
||||
MPT_FORCEINLINE Context(const Context &c)
|
||||
: file(c.file)
|
||||
, line(c.line)
|
||||
, function(c.function)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}; // class Context
|
||||
|
||||
#define MPT_LOG_CURRENTCONTEXT() mpt::log::Context( __FILE__ , __LINE__ , __FUNCTION__ )
|
||||
|
||||
|
||||
#ifndef NO_LOGGING
|
||||
|
||||
|
@ -159,13 +138,7 @@ class Logger
|
|||
{
|
||||
public:
|
||||
// facility:ASCII
|
||||
void SendLogMessage(const Context &context, LogLevel level, const char *facility, const mpt::ustring &text);
|
||||
public:
|
||||
// facility:ASCII, text:ASCII (only string literals)
|
||||
template <std::size_t size> MPT_FORCEINLINE void SendLogMessage(const Context &context, LogLevel level, const char *facility, const char (&text)[size])
|
||||
{
|
||||
SendLogMessage(context, level, facility, mpt::ToUnicode(mpt::CharsetASCII, text));
|
||||
}
|
||||
void SendLogMessage(const mpt::source_location &loc, LogLevel level, const char *facility, const mpt::ustring &text);
|
||||
};
|
||||
|
||||
#define MPT_LOG(level, facility, text) \
|
||||
|
@ -175,7 +148,7 @@ public:
|
|||
{ \
|
||||
MPT_MAYBE_CONSTANT_IF(mpt::log::IsFacilityActive(( facility ))) \
|
||||
{ \
|
||||
mpt::log::Logger().SendLogMessage( MPT_LOG_CURRENTCONTEXT() , ( level ), ( facility ), ( text )); \
|
||||
mpt::log::Logger().SendLogMessage( MPT_SOURCE_LOCATION_CURRENT() , ( level ), ( facility ), ( text )); \
|
||||
} \
|
||||
} \
|
||||
} MPT_WHILE_0 \
|
||||
|
@ -187,15 +160,15 @@ public:
|
|||
class LegacyLogger : public Logger
|
||||
{
|
||||
private:
|
||||
const Context context;
|
||||
const mpt::source_location loc;
|
||||
public:
|
||||
LegacyLogger(const Context &context) : context(context) {}
|
||||
constexpr LegacyLogger(mpt::source_location loc) noexcept : loc(loc) {}
|
||||
/* MPT_DEPRECATED */ void MPT_PRINTF_FUNC(2,3) operator () (const char *format, ...); // migrate to type-safe MPT_LOG
|
||||
/* MPT_DEPRECATED */ void operator () (const AnyStringLocale &text); // migrate to properly namespaced MPT_LOG
|
||||
/* MPT_DEPRECATED */ void operator () (LogLevel level, const mpt::ustring &text); // migrate to properly namespaced MPT_LOG
|
||||
};
|
||||
|
||||
#define Log MPT_MAYBE_CONSTANT_IF(mpt::log::GlobalLogLevel < MPT_LEGACY_LOGLEVEL) { } else MPT_MAYBE_CONSTANT_IF(!mpt::log::IsFacilityActive("")) { } else mpt::log::LegacyLogger(MPT_LOG_CURRENTCONTEXT())
|
||||
#define Log MPT_MAYBE_CONSTANT_IF(mpt::log::GlobalLogLevel < MPT_LEGACY_LOGLEVEL) { } else MPT_MAYBE_CONSTANT_IF(!mpt::log::IsFacilityActive("")) { } else mpt::log::LegacyLogger(MPT_SOURCE_LOCATION_CURRENT())
|
||||
|
||||
|
||||
#else // !NO_LOGGING
|
||||
|
@ -229,7 +202,14 @@ namespace Trace {
|
|||
extern bool volatile g_Enabled;
|
||||
static inline bool IsEnabled() { return g_Enabled; }
|
||||
|
||||
MPT_NOINLINE void Trace(const mpt::log::Context & contexxt);
|
||||
enum class Direction : int8
|
||||
{
|
||||
Unknown = 0,
|
||||
Enter = 1,
|
||||
Leave = -1,
|
||||
};
|
||||
|
||||
MPT_NOINLINE void Trace(const mpt::source_location & loc, Direction direction = Direction::Unknown) noexcept;
|
||||
|
||||
enum ThreadKind {
|
||||
ThreadKindGUI,
|
||||
|
@ -247,12 +227,41 @@ uint32 GetThreadId(mpt::log::Trace::ThreadKind kind);
|
|||
void Seal();
|
||||
bool Dump(const mpt::PathString &filename);
|
||||
|
||||
#define MPT_TRACE() MPT_DO { if(mpt::log::Trace::g_Enabled) { mpt::log::Trace::Trace(MPT_LOG_CURRENTCONTEXT()); } } MPT_WHILE_0
|
||||
class Scope
|
||||
{
|
||||
private:
|
||||
const mpt::source_location loc;
|
||||
public:
|
||||
MPT_FORCEINLINE Scope(mpt::source_location loc) noexcept
|
||||
: loc(loc)
|
||||
{
|
||||
if(mpt::log::Trace::g_Enabled)
|
||||
{
|
||||
mpt::log::Trace::Trace(loc, mpt::log::Trace::Direction::Enter);
|
||||
}
|
||||
}
|
||||
MPT_FORCEINLINE ~Scope() noexcept
|
||||
{
|
||||
if(mpt::log::Trace::g_Enabled)
|
||||
{
|
||||
mpt::log::Trace::Trace(loc, mpt::log::Trace::Direction::Leave);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#define MPT_TRACE_CONCAT_HELPER(x, y) x ## y
|
||||
#define MPT_TRACE_CONCAT(x, y) MPT_TRACE_CONCAT_HELPER(x, y)
|
||||
|
||||
#define MPT_TRACE_SCOPE() mpt::log::Trace::Scope MPT_TRACE_CONCAT(MPT_TRACE_VAR, __LINE__)(MPT_SOURCE_LOCATION_CURRENT())
|
||||
|
||||
#define MPT_TRACE() MPT_DO { if(mpt::log::Trace::g_Enabled) { mpt::log::Trace::Trace(MPT_SOURCE_LOCATION_CURRENT()); } } MPT_WHILE_0
|
||||
|
||||
} // namespace Trace
|
||||
|
||||
#else // !MODPLUG_TRACKER
|
||||
|
||||
#define MPT_TRACE_SCOPE() MPT_DO { } MPT_WHILE_0
|
||||
|
||||
#define MPT_TRACE() MPT_DO { } MPT_WHILE_0
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
|
|
@ -112,7 +112,7 @@ std::string Profiler::DumpProfiles()
|
|||
case Profiler::Audio: cat = "Audio"; break;
|
||||
case Profiler::Notify: cat = "Notify"; break;
|
||||
}
|
||||
ret += cat + " " + std::string(stats.profile.Name) + ": " + mpt::fmt::f("%6.3f", stats.usage * 100.0) + "%\r\n";
|
||||
ret += cat + " " + std::string(stats.profile.Name) + ": " + mpt::fmt::right(6, mpt::fmt::fix(stats.usage * 100.0, 3)) + "%\r\n";
|
||||
}
|
||||
}
|
||||
ret += "\r\n";
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
|
||||
#include "../common/mptMutex.h"
|
||||
#include <string>
|
||||
|
|
|
@ -1,410 +0,0 @@
|
|||
/*
|
||||
* StringFixer.h
|
||||
* -------------
|
||||
* Purpose: Various functions for "fixing" char array strings for writing to or
|
||||
* reading from module files, or for securing char arrays in general.
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
namespace mpt { namespace String
|
||||
{
|
||||
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127) // conditional expression is constant
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
|
||||
|
||||
// Sets last character to null in given char array.
|
||||
// Size of the array must be known at compile time.
|
||||
template <size_t size>
|
||||
void SetNullTerminator(char (&buffer)[size])
|
||||
{
|
||||
STATIC_ASSERT(size > 0);
|
||||
buffer[size - 1] = 0;
|
||||
}
|
||||
|
||||
inline void SetNullTerminator(char *buffer, size_t size)
|
||||
{
|
||||
MPT_ASSERT(size > 0);
|
||||
buffer[size - 1] = 0;
|
||||
}
|
||||
|
||||
template <size_t size>
|
||||
void SetNullTerminator(wchar_t (&buffer)[size])
|
||||
{
|
||||
STATIC_ASSERT(size > 0);
|
||||
buffer[size - 1] = 0;
|
||||
}
|
||||
|
||||
inline void SetNullTerminator(wchar_t *buffer, size_t size)
|
||||
{
|
||||
MPT_ASSERT(size > 0);
|
||||
buffer[size - 1] = 0;
|
||||
}
|
||||
|
||||
|
||||
// Remove any chars after the first null char
|
||||
template <size_t size>
|
||||
void FixNullString(char (&buffer)[size])
|
||||
{
|
||||
STATIC_ASSERT(size > 0);
|
||||
SetNullTerminator(buffer);
|
||||
size_t pos = 0;
|
||||
// Find the first null char.
|
||||
while(pos < size && buffer[pos] != '\0')
|
||||
{
|
||||
pos++;
|
||||
}
|
||||
// Remove everything after the null char.
|
||||
while(pos < size)
|
||||
{
|
||||
buffer[pos++] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
inline void FixNullString(std::string & str)
|
||||
{
|
||||
for(std::size_t i = 0; i < str.length(); ++i)
|
||||
{
|
||||
if(str[i] == '\0')
|
||||
{
|
||||
// if we copied \0 in the middle of the buffer, terminate std::string here
|
||||
str.resize(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
enum ReadWriteMode
|
||||
{
|
||||
// Reading / Writing: Standard null-terminated string handling.
|
||||
nullTerminated,
|
||||
// Reading: Source string is not guaranteed to be null-terminated (if it fills the whole char array).
|
||||
// Writing: Destination string is not guaranteed to be null-terminated (if it fills the whole char array).
|
||||
maybeNullTerminated,
|
||||
// Reading: String may contain null characters anywhere. They should be treated as spaces.
|
||||
// Writing: A space-padded string is written.
|
||||
spacePadded,
|
||||
// Reading: String may contain null characters anywhere. The last character is ignored (it is supposed to be 0).
|
||||
// Writing: A space-padded string with a trailing null is written.
|
||||
spacePaddedNull
|
||||
};
|
||||
|
||||
|
||||
namespace detail
|
||||
{
|
||||
static inline char NullToSpace(const char &c)
|
||||
{
|
||||
return (c != '\0') ? c : ' ';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Copy a string from srcBuffer to destBuffer using a given read mode.
|
||||
// Used for reading strings from files.
|
||||
// Only use this version of the function if the size of the source buffer is variable.
|
||||
template <ReadWriteMode mode, typename Tbyte>
|
||||
void Read(std::string &dest, const Tbyte *srcBuffer, size_t srcSize)
|
||||
{
|
||||
|
||||
const char *src = mpt::byte_cast<const char*>(srcBuffer);
|
||||
|
||||
dest.clear();
|
||||
|
||||
if(mode == nullTerminated || mode == spacePaddedNull)
|
||||
{
|
||||
// We assume that the last character of the source buffer is null.
|
||||
if(srcSize > 0)
|
||||
{
|
||||
srcSize -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(mode == nullTerminated || mode == maybeNullTerminated)
|
||||
{
|
||||
|
||||
// Copy null-terminated string, stopping at null.
|
||||
try
|
||||
{
|
||||
dest.assign(src, std::find(src, src + srcSize, '\0'));
|
||||
} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
|
||||
{
|
||||
MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e);
|
||||
}
|
||||
|
||||
} else if(mode == spacePadded || mode == spacePaddedNull)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
// Copy string over.
|
||||
dest.assign(src, src + srcSize);
|
||||
|
||||
// Convert null characters to spaces.
|
||||
std::transform(dest.begin(), dest.end(), dest.begin(), detail::NullToSpace);
|
||||
|
||||
// Trim trailing spaces.
|
||||
dest = mpt::String::RTrim(dest, std::string(" "));
|
||||
|
||||
} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
|
||||
{
|
||||
MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Copy a charset encoded string from srcBuffer to destBuffer using a given read mode.
|
||||
// Used for reading strings from files.
|
||||
// Only use this version of the function if the size of the source buffer is variable.
|
||||
template <ReadWriteMode mode, typename Tbyte>
|
||||
void Read(mpt::ustring &dest, mpt::Charset charset, const Tbyte *srcBuffer, size_t srcSize)
|
||||
{
|
||||
std::string tmp;
|
||||
Read<mode>(tmp, srcBuffer, srcSize);
|
||||
dest = mpt::ToUnicode(charset, tmp);
|
||||
}
|
||||
|
||||
// Used for reading strings from files.
|
||||
// Preferrably use this version of the function, it is safer.
|
||||
template <ReadWriteMode mode, size_t srcSize, typename Tbyte>
|
||||
void Read(std::string &dest, const Tbyte (&srcBuffer)[srcSize])
|
||||
{
|
||||
STATIC_ASSERT(srcSize > 0);
|
||||
Read<mode>(dest, srcBuffer, srcSize);
|
||||
}
|
||||
|
||||
// Used for reading charset encoded strings from files.
|
||||
// Preferrably use this version of the function, it is safer.
|
||||
template <ReadWriteMode mode, size_t srcSize, typename Tbyte>
|
||||
void Read(mpt::ustring &dest, mpt::Charset charset, const Tbyte(&srcBuffer)[srcSize])
|
||||
{
|
||||
std::string tmp;
|
||||
Read<mode>(tmp, srcBuffer);
|
||||
dest = mpt::ToUnicode(charset, tmp);
|
||||
}
|
||||
|
||||
// Copy a string from srcBuffer to destBuffer using a given read mode.
|
||||
// Used for reading strings from files.
|
||||
// Only use this version of the function if the size of the source buffer is variable.
|
||||
template <ReadWriteMode mode, size_t destSize, typename Tbyte>
|
||||
void Read(char (&destBuffer)[destSize], const Tbyte *srcBuffer, size_t srcSize)
|
||||
{
|
||||
STATIC_ASSERT(destSize > 0);
|
||||
|
||||
char *dst = destBuffer;
|
||||
const char *src = mpt::byte_cast<const char*>(srcBuffer);
|
||||
|
||||
if(mode == nullTerminated || mode == spacePaddedNull)
|
||||
{
|
||||
// We assume that the last character of the source buffer is null.
|
||||
if(srcSize > 0)
|
||||
{
|
||||
srcSize -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(mode == nullTerminated || mode == maybeNullTerminated)
|
||||
{
|
||||
|
||||
// Copy string and leave one character space in the destination buffer for null.
|
||||
dst = std::copy(src, std::find(src, src + std::min(srcSize, destSize - 1), '\0'), dst);
|
||||
|
||||
} else if(mode == spacePadded || mode == spacePaddedNull)
|
||||
{
|
||||
|
||||
// Copy string and leave one character space in the destination buffer for null.
|
||||
// Convert nulls to spaces while copying.
|
||||
dst = std::replace_copy(src, src + std::min(srcSize, destSize - 1), dst, '\0', ' ');
|
||||
|
||||
// Rewind dst to the first of any trailing spaces.
|
||||
while(dst - destBuffer > 0)
|
||||
{
|
||||
dst--;
|
||||
char c = *dst;
|
||||
if(c != ' ')
|
||||
{
|
||||
dst++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Fill rest of string with nulls.
|
||||
std::fill(dst, destBuffer + destSize, '\0');
|
||||
|
||||
}
|
||||
|
||||
// Used for reading strings from files.
|
||||
// Preferrably use this version of the function, it is safer.
|
||||
template <ReadWriteMode mode, size_t destSize, size_t srcSize, typename Tbyte>
|
||||
void Read(char (&destBuffer)[destSize], const Tbyte (&srcBuffer)[srcSize])
|
||||
{
|
||||
STATIC_ASSERT(destSize > 0);
|
||||
STATIC_ASSERT(srcSize > 0);
|
||||
Read<mode, destSize>(destBuffer, srcBuffer, srcSize);
|
||||
}
|
||||
|
||||
|
||||
// Copy a string from srcBuffer to destBuffer using a given write mode.
|
||||
// You should only use this function if src and dest are dynamically sized,
|
||||
// otherwise use one of the safer overloads below.
|
||||
template <ReadWriteMode mode>
|
||||
void Write(char *destBuffer, const size_t destSize, const char *srcBuffer, const size_t srcSize)
|
||||
{
|
||||
MPT_ASSERT(destSize > 0);
|
||||
|
||||
const size_t maxSize = std::min(destSize, srcSize);
|
||||
char *dst = destBuffer;
|
||||
const char *src = srcBuffer;
|
||||
|
||||
// First, copy over null-terminated string.
|
||||
size_t pos = maxSize;
|
||||
while(pos > 0)
|
||||
{
|
||||
if((*dst = *src) == '\0')
|
||||
{
|
||||
break;
|
||||
}
|
||||
pos--;
|
||||
dst++;
|
||||
src++;
|
||||
}
|
||||
|
||||
if(mode == nullTerminated || mode == maybeNullTerminated)
|
||||
{
|
||||
// Fill rest of string with nulls.
|
||||
std::fill(dst, dst + destSize - maxSize + pos, '\0');
|
||||
} else if(mode == spacePadded || mode == spacePaddedNull)
|
||||
{
|
||||
// Fill the rest of the destination string with spaces.
|
||||
std::fill(dst, dst + destSize - maxSize + pos, ' ');
|
||||
}
|
||||
|
||||
if(mode == nullTerminated || mode == spacePaddedNull)
|
||||
{
|
||||
// Make sure that destination is really null-terminated.
|
||||
SetNullTerminator(destBuffer, destSize);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy a string from srcBuffer to a dynamically sized std::vector destBuffer using a given write mode.
|
||||
// Used for writing strings to files.
|
||||
// Only use this version of the function if the size of the source buffer is variable and the destination buffer also has variable size.
|
||||
template <ReadWriteMode mode>
|
||||
void Write(std::vector<char> &destBuffer, const char *srcBuffer, const size_t srcSize)
|
||||
{
|
||||
MPT_ASSERT(destBuffer.size() > 0);
|
||||
Write<mode>(destBuffer.data(), destBuffer.size(), srcBuffer, srcSize);
|
||||
}
|
||||
|
||||
// Copy a string from srcBuffer to destBuffer using a given write mode.
|
||||
// Used for writing strings to files.
|
||||
// Only use this version of the function if the size of the source buffer is variable.
|
||||
template <ReadWriteMode mode, size_t destSize>
|
||||
void Write(char (&destBuffer)[destSize], const char *srcBuffer, const size_t srcSize)
|
||||
{
|
||||
STATIC_ASSERT(destSize > 0);
|
||||
Write<mode>(destBuffer, destSize, srcBuffer, srcSize);
|
||||
}
|
||||
|
||||
// Copy a string from srcBuffer to destBuffer using a given write mode.
|
||||
// Used for writing strings to files.
|
||||
// Preferrably use this version of the function, it is safer.
|
||||
template <ReadWriteMode mode, size_t destSize, size_t srcSize>
|
||||
void Write(char (&destBuffer)[destSize], const char (&srcBuffer)[srcSize])
|
||||
{
|
||||
STATIC_ASSERT(destSize > 0);
|
||||
STATIC_ASSERT(srcSize > 0);
|
||||
Write<mode, destSize>(destBuffer, srcBuffer, srcSize);
|
||||
}
|
||||
|
||||
template <ReadWriteMode mode>
|
||||
void Write(char *destBuffer, const size_t destSize, const std::string &src)
|
||||
{
|
||||
MPT_ASSERT(destSize > 0);
|
||||
Write<mode>(destBuffer, destSize, src.c_str(), src.length());
|
||||
}
|
||||
|
||||
template <ReadWriteMode mode>
|
||||
void Write(std::vector<char> &destBuffer, const std::string &src)
|
||||
{
|
||||
MPT_ASSERT(destBuffer.size() > 0);
|
||||
Write<mode>(destBuffer, src.c_str(), src.length());
|
||||
}
|
||||
|
||||
template <ReadWriteMode mode, size_t destSize>
|
||||
void Write(char (&destBuffer)[destSize], const std::string &src)
|
||||
{
|
||||
STATIC_ASSERT(destSize > 0);
|
||||
Write<mode, destSize>(destBuffer, src.c_str(), src.length());
|
||||
}
|
||||
|
||||
|
||||
// Copy from a char array to a fixed size char array.
|
||||
template <size_t destSize>
|
||||
void CopyN(char (&destBuffer)[destSize], const char *srcBuffer, const size_t srcSize = std::numeric_limits<size_t>::max())
|
||||
{
|
||||
const size_t copySize = std::min(destSize - 1u, srcSize);
|
||||
std::strncpy(destBuffer, srcBuffer, copySize);
|
||||
destBuffer[copySize] = '\0';
|
||||
}
|
||||
|
||||
// Copy at most srcSize characters from srcBuffer to a std::string.
|
||||
static inline void CopyN(std::string &dest, const char *srcBuffer, const size_t srcSize = std::numeric_limits<size_t>::max())
|
||||
{
|
||||
dest.assign(srcBuffer, srcBuffer + mpt::strnlen(srcBuffer, srcSize));
|
||||
}
|
||||
|
||||
|
||||
// Copy from one fixed size char array to another one.
|
||||
template <size_t destSize, size_t srcSize>
|
||||
void Copy(char (&destBuffer)[destSize], const char (&srcBuffer)[srcSize])
|
||||
{
|
||||
CopyN(destBuffer, srcBuffer, srcSize);
|
||||
}
|
||||
|
||||
// Copy from a std::string to a fixed size char array.
|
||||
template <size_t destSize>
|
||||
void Copy(char (&destBuffer)[destSize], const std::string &src)
|
||||
{
|
||||
CopyN(destBuffer, src.c_str(), src.length());
|
||||
}
|
||||
|
||||
// Copy from a fixed size char array to a std::string.
|
||||
template <size_t srcSize>
|
||||
void Copy(std::string &dest, const char (&srcBuffer)[srcSize])
|
||||
{
|
||||
CopyN(dest, srcBuffer, srcSize);
|
||||
}
|
||||
|
||||
// Copy from a std::string to a std::string.
|
||||
static inline void Copy(std::string &dest, const std::string &src)
|
||||
{
|
||||
dest.assign(src);
|
||||
}
|
||||
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
|
||||
|
||||
} } // namespace mpt::String
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,73 +0,0 @@
|
|||
/*
|
||||
* WriteMemoryDump.h
|
||||
* -----------------
|
||||
* Purpose: Code for writing memory dumps to a file.
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4091) // 'typedef ': ignored on left of '' when no variable is declared
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
#include <dbghelp.h>
|
||||
#if MPT_COMPILER_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,
|
||||
CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
|
||||
CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
|
||||
CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
|
||||
);
|
||||
|
||||
static bool WriteMemoryDump(_EXCEPTION_POINTERS *pExceptionInfo, const WCHAR *filename, bool fullMemDump)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
HMODULE hDll = ::LoadLibraryW(L"DBGHELP.DLL");
|
||||
if (hDll)
|
||||
{
|
||||
MINIDUMPWRITEDUMP pDump = (MINIDUMPWRITEDUMP)::GetProcAddress(hDll, "MiniDumpWriteDump");
|
||||
if (pDump)
|
||||
{
|
||||
|
||||
HANDLE hFile = ::CreateFileW(filename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
_MINIDUMP_EXCEPTION_INFORMATION ExInfo;
|
||||
|
||||
if(pExceptionInfo)
|
||||
{
|
||||
ExInfo.ThreadId = ::GetCurrentThreadId();
|
||||
ExInfo.ExceptionPointers = pExceptionInfo;
|
||||
ExInfo.ClientPointers = NULL;
|
||||
}
|
||||
|
||||
pDump(GetCurrentProcess(), GetCurrentProcessId(), hFile,
|
||||
fullMemDump ?
|
||||
(MINIDUMP_TYPE)(MiniDumpWithFullMemory | MiniDumpWithHandleData | MiniDumpWithThreadInfo | MiniDumpWithProcessThreadData | MiniDumpWithFullMemoryInfo
|
||||
#if MPT_COMPILER_MSVC
|
||||
| MiniDumpIgnoreInaccessibleMemory | MiniDumpWithTokenInformation
|
||||
#endif
|
||||
)
|
||||
:
|
||||
MiniDumpNormal,
|
||||
pExceptionInfo ? &ExInfo : NULL, NULL, NULL);
|
||||
::CloseHandle(hFile);
|
||||
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
::FreeLibrary(hDll);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -16,58 +16,41 @@ OPENMPT_NAMESPACE_BEGIN
|
|||
|
||||
|
||||
|
||||
#ifdef MODPLUG_TRACKER
|
||||
|
||||
namespace Util
|
||||
{
|
||||
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
|
||||
} // namespace Util
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
namespace Util
|
||||
{
|
||||
|
||||
|
||||
static const MPT_UCHAR_TYPE EncodeNibble[16] = {
|
||||
MPT_UCHAR('0'), MPT_UCHAR('1'), MPT_UCHAR('2'), MPT_UCHAR('3'),
|
||||
MPT_UCHAR('4'), MPT_UCHAR('5'), MPT_UCHAR('6'), MPT_UCHAR('7'),
|
||||
MPT_UCHAR('8'), MPT_UCHAR('9'), MPT_UCHAR('A'), MPT_UCHAR('B'),
|
||||
MPT_UCHAR('C'), MPT_UCHAR('D'), MPT_UCHAR('E'), MPT_UCHAR('F') };
|
||||
UC_('0'), UC_('1'), UC_('2'), UC_('3'),
|
||||
UC_('4'), UC_('5'), UC_('6'), UC_('7'),
|
||||
UC_('8'), UC_('9'), UC_('A'), UC_('B'),
|
||||
UC_('C'), UC_('D'), UC_('E'), UC_('F') };
|
||||
|
||||
static inline bool DecodeByte(uint8 &byte, MPT_UCHAR_TYPE c1, MPT_UCHAR_TYPE c2)
|
||||
{
|
||||
byte = 0;
|
||||
if(MPT_UCHAR('0') <= c1 && c1 <= MPT_UCHAR('9'))
|
||||
if(UC_('0') <= c1 && c1 <= UC_('9'))
|
||||
{
|
||||
byte += static_cast<uint8>((c1 - MPT_UCHAR('0')) << 4);
|
||||
} else if(MPT_UCHAR('A') <= c1 && c1 <= MPT_UCHAR('F'))
|
||||
byte += static_cast<uint8>((c1 - UC_('0')) << 4);
|
||||
} else if(UC_('A') <= c1 && c1 <= UC_('F'))
|
||||
{
|
||||
byte += static_cast<uint8>((c1 - MPT_UCHAR('A') + 10) << 4);
|
||||
} else if(MPT_UCHAR('a') <= c1 && c1 <= MPT_UCHAR('f'))
|
||||
byte += static_cast<uint8>((c1 - UC_('A') + 10) << 4);
|
||||
} else if(UC_('a') <= c1 && c1 <= UC_('f'))
|
||||
{
|
||||
byte += static_cast<uint8>((c1 - MPT_UCHAR('a') + 10) << 4);
|
||||
byte += static_cast<uint8>((c1 - UC_('a') + 10) << 4);
|
||||
} else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(MPT_UCHAR('0') <= c2 && c2 <= MPT_UCHAR('9'))
|
||||
if(UC_('0') <= c2 && c2 <= UC_('9'))
|
||||
{
|
||||
byte += static_cast<uint8>(c2 - MPT_UCHAR('0'));
|
||||
} else if(MPT_UCHAR('A') <= c2 && c2 <= MPT_UCHAR('F'))
|
||||
byte += static_cast<uint8>(c2 - UC_('0'));
|
||||
} else if(UC_('A') <= c2 && c2 <= UC_('F'))
|
||||
{
|
||||
byte += static_cast<uint8>(c2 - MPT_UCHAR('A') + 10);
|
||||
} else if(MPT_UCHAR('a') <= c2 && c2 <= MPT_UCHAR('f'))
|
||||
byte += static_cast<uint8>(c2 - UC_('A') + 10);
|
||||
} else if(UC_('a') <= c2 && c2 <= UC_('f'))
|
||||
{
|
||||
byte += static_cast<uint8>(c2 - MPT_UCHAR('a') + 10);
|
||||
byte += static_cast<uint8>(c2 - UC_('a') + 10);
|
||||
} else
|
||||
{
|
||||
return false;
|
||||
|
@ -79,10 +62,10 @@ mpt::ustring BinToHex(mpt::const_byte_span src)
|
|||
{
|
||||
mpt::ustring result;
|
||||
result.reserve(src.size() * 2);
|
||||
for(uint8 byte : src)
|
||||
for(mpt::byte byte : src)
|
||||
{
|
||||
result.push_back(EncodeNibble[(byte & 0xf0) >> 4]);
|
||||
result.push_back(EncodeNibble[byte & 0x0f]);
|
||||
result.push_back(EncodeNibble[(mpt::byte_cast<uint8>(byte) & 0xf0) >> 4]);
|
||||
result.push_back(EncodeNibble[mpt::byte_cast<uint8>(byte) & 0x0f]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -98,7 +81,7 @@ std::vector<mpt::byte> HexToBin(const mpt::ustring &src)
|
|||
{
|
||||
return result;
|
||||
}
|
||||
result.push_back(byte);
|
||||
result.push_back(mpt::byte_cast<mpt::byte>(byte));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -10,897 +10,39 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
#include "mptAssert.h"
|
||||
#include "mptBaseMacros.h"
|
||||
#include "mptBaseTypes.h"
|
||||
#include "mptBaseUtils.h"
|
||||
#include "mptString.h"
|
||||
|
||||
// old
|
||||
#include "mptBaseUtils.h"
|
||||
#include "mptSpan.h"
|
||||
#include "mptMemory.h"
|
||||
#include "mptExceptionText.h"
|
||||
#include "mptStringFormat.h"
|
||||
#include "mptStringParse.h"
|
||||
#include "mptCPU.h"
|
||||
#include "mptOS.h"
|
||||
#include "mptTime.h"
|
||||
#include "mptLibrary.h"
|
||||
#include "mptTypeTraits.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
// cmath fixups
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
#ifndef M_PI_2
|
||||
#define M_PI_2 1.57079632679489661923
|
||||
#endif
|
||||
#ifndef M_LN2
|
||||
#define M_LN2 0.69314718055994530942
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
namespace mpt { namespace String {
|
||||
|
||||
// Combine a vector of values into a string, separated with the given separator.
|
||||
// No escaping is performed.
|
||||
template<typename T>
|
||||
mpt::ustring Combine(const std::vector<T> &vals, const mpt::ustring &sep=MPT_USTRING(","))
|
||||
{
|
||||
mpt::ustring str;
|
||||
for(std::size_t i = 0; i < vals.size(); ++i)
|
||||
{
|
||||
if(i > 0)
|
||||
{
|
||||
str += sep;
|
||||
}
|
||||
str += mpt::ufmt::val(vals[i]);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
template<typename T>
|
||||
std::string Combine(const std::vector<T> &vals, const std::string &sep=std::string(","))
|
||||
{
|
||||
std::string str;
|
||||
for(std::size_t i = 0; i < vals.size(); ++i)
|
||||
{
|
||||
if(i > 0)
|
||||
{
|
||||
str += sep;
|
||||
}
|
||||
str += mpt::fmt::val(vals[i]);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
// Split the given string at separator positions into individual values returned as a vector.
|
||||
// An empty string results in an empty vector.
|
||||
// Leading or trailing separators result in a default-constructed element being inserted before or after the other elements.
|
||||
template<typename T>
|
||||
std::vector<T> Split(const mpt::ustring &str, const mpt::ustring &sep=MPT_USTRING(","))
|
||||
{
|
||||
std::vector<T> vals;
|
||||
std::size_t pos = 0;
|
||||
while(str.find(sep, pos) != std::string::npos)
|
||||
{
|
||||
vals.push_back(ConvertStrTo<T>(str.substr(pos, str.find(sep, pos) - pos)));
|
||||
pos = str.find(sep, pos) + sep.length();
|
||||
}
|
||||
if(!vals.empty() || (str.substr(pos).length() > 0))
|
||||
{
|
||||
vals.push_back(ConvertStrTo<T>(str.substr(pos)));
|
||||
}
|
||||
return vals;
|
||||
}
|
||||
template<typename T>
|
||||
std::vector<T> Split(const std::string &str, const std::string &sep=std::string(","))
|
||||
{
|
||||
std::vector<T> vals;
|
||||
std::size_t pos = 0;
|
||||
while(str.find(sep, pos) != std::string::npos)
|
||||
{
|
||||
vals.push_back(ConvertStrTo<T>(str.substr(pos, str.find(sep, pos) - pos)));
|
||||
pos = str.find(sep, pos) + sep.length();
|
||||
}
|
||||
if(!vals.empty() || (str.substr(pos).length() > 0))
|
||||
{
|
||||
vals.push_back(ConvertStrTo<T>(str.substr(pos)));
|
||||
}
|
||||
return vals;
|
||||
}
|
||||
|
||||
} } // namespace mpt::String
|
||||
|
||||
|
||||
namespace mpt {
|
||||
|
||||
// GCC 4.5 and up provides templated overloads of std::abs that convert
|
||||
// integer type narrower than int to double.
|
||||
// As this is apparently valid by the current standard, Library Working Group
|
||||
// Issue #2735 has been filed (see
|
||||
// <https://cplusplus.github.io/LWG/lwg-defects.html#2735>).
|
||||
// In any case, avoid this insanity and provide our own mpt::abs implementation
|
||||
// for signed integer and floating point types.
|
||||
// Note: We stick to a C++98-style implementation only overloading int and
|
||||
// greater types in order to keep promotion rules consistent for narrower types,
|
||||
// which a templated version returning the argument type would not do. OpenMPT
|
||||
// probably assumes this semantic when calling abs(int8) in various places.
|
||||
inline int abs(int x)
|
||||
{
|
||||
return std::abs(x);
|
||||
}
|
||||
inline long abs(long x)
|
||||
{
|
||||
return std::abs(x);
|
||||
}
|
||||
inline long long abs(long long x)
|
||||
{
|
||||
return std::abs(x);
|
||||
}
|
||||
inline float abs(float x)
|
||||
{
|
||||
return std::fabs(x);
|
||||
}
|
||||
inline double abs(double x)
|
||||
{
|
||||
return std::fabs(x);
|
||||
}
|
||||
inline long double abs(long double x)
|
||||
{
|
||||
return std::fabs(x);
|
||||
}
|
||||
|
||||
// Modulo with more intuitive behaviour for some contexts:
|
||||
// Instead of being symmetrical around 0, the pattern for positive numbers is repeated in the negative range.
|
||||
// For example, wrapping_modulo(-1, m) == (m - 1).
|
||||
// Behaviour is undefined if m<=0.
|
||||
template<typename T, typename M>
|
||||
MPT_CONSTEXPR11_FUN auto wrapping_modulo(T x, M m) -> decltype(x % m)
|
||||
{
|
||||
return (x >= 0) ? (x % m) : (m - 1 - ((-1 - x) % m));
|
||||
}
|
||||
|
||||
template<typename T, typename D>
|
||||
MPT_CONSTEXPR11_FUN auto wrapping_divide(T x, D d) -> decltype(x / d)
|
||||
{
|
||||
return (x >= 0) ? (x / d) : (((x + 1) / d) - 1);
|
||||
}
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
// Memset given object to zero.
|
||||
template <class T>
|
||||
inline void MemsetZero(T &a)
|
||||
{
|
||||
static_assert(std::is_pointer<T>::value == false, "Won't memset pointers.");
|
||||
#if MPT_GCC_BEFORE(5,1,0) || MPT_CLANG_BEFORE(3,5,0) || (MPT_COMPILER_CLANG && defined(__GLIBCXX__))
|
||||
MPT_STATIC_ASSERT(std::is_standard_layout<T>::value);
|
||||
MPT_STATIC_ASSERT(std::is_trivial<T>::value); // approximation
|
||||
#else // default
|
||||
MPT_STATIC_ASSERT(std::is_standard_layout<T>::value);
|
||||
MPT_STATIC_ASSERT(std::is_trivially_copyable<T>::value); // C++11, but not supported on most compilers we care about
|
||||
#endif
|
||||
std::memset(&a, 0, sizeof(T));
|
||||
}
|
||||
|
||||
|
||||
#ifdef MODPLUG_TRACKER
|
||||
// Copy given object to other location.
|
||||
template <class T>
|
||||
void MemCopy(T &destination, const T &source)
|
||||
{
|
||||
static_assert(std::is_pointer<T>::value == false, "Won't copy pointers.");
|
||||
#if MPT_GCC_BEFORE(5,1,0) || MPT_CLANG_BEFORE(3,5,0) || (MPT_COMPILER_CLANG && defined(__GLIBCXX__))
|
||||
MPT_STATIC_ASSERT(std::is_trivial<T>::value); // approximation
|
||||
#else // default
|
||||
MPT_STATIC_ASSERT(std::is_trivially_copyable<T>::value); // C++11, but not supported on most compilers we care about
|
||||
#endif
|
||||
std::memcpy(&destination, &source, sizeof(T));
|
||||
}
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
namespace mpt {
|
||||
|
||||
|
||||
// Simplified version of gsl::span.
|
||||
// Non-owning read-only or read-write view into a contiguous block of T
|
||||
// objects, i.e. equivalent to a (beg,end) or (data,size) tuple.
|
||||
// Can eventually be replaced without further modifications with a full
|
||||
// gsl::span.
|
||||
template <typename T>
|
||||
class span
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
typedef std::size_t size_type;
|
||||
|
||||
typedef T value_type;
|
||||
typedef T & reference;
|
||||
typedef T * pointer;
|
||||
typedef const T * const_pointer;
|
||||
typedef const T & const_reference;
|
||||
|
||||
typedef pointer iterator;
|
||||
typedef const_pointer const_iterator;
|
||||
|
||||
typedef typename std::iterator_traits<iterator>::difference_type difference_type;
|
||||
|
||||
private:
|
||||
|
||||
T * m_beg;
|
||||
T * m_end;
|
||||
|
||||
public:
|
||||
|
||||
span() : m_beg(nullptr), m_end(nullptr) { }
|
||||
|
||||
span(pointer beg, pointer end) : m_beg(beg), m_end(end) { }
|
||||
|
||||
span(pointer data, size_type size) : m_beg(data), m_end(data + size) { }
|
||||
|
||||
template <typename U, std::size_t N> span(U (&arr)[N]) : m_beg(arr), m_end(arr + N) { }
|
||||
|
||||
template <typename Cont> span(Cont &cont) : m_beg(cont.empty() ? nullptr : &(cont[0])), m_end(cont.empty() ? nullptr : &(cont[0]) + cont.size()) { }
|
||||
|
||||
span(const span &other) : m_beg(other.begin()), m_end(other.end()) { }
|
||||
|
||||
template <typename U> span(const span<U> &other) : m_beg(other.begin()), m_end(other.end()) { }
|
||||
|
||||
span & operator = (span other) { m_beg = other.begin(); m_end = other.end(); return *this; }
|
||||
|
||||
iterator begin() const { return iterator(m_beg); }
|
||||
iterator end() const { return iterator(m_end); }
|
||||
|
||||
const_iterator cbegin() const { return const_iterator(begin()); }
|
||||
const_iterator cend() const { return const_iterator(end()); }
|
||||
|
||||
operator bool () const throw() { return m_beg != nullptr; }
|
||||
|
||||
reference operator[](size_type index) { return at(index); }
|
||||
const_reference operator[](size_type index) const { return at(index); }
|
||||
|
||||
bool operator==(span const & other) const throw() { return size() == other.size() && (m_beg == other.m_beg || std::equal(begin(), end(), other.begin())); }
|
||||
bool operator!=(span const & other) const throw() { return !(*this == other); }
|
||||
|
||||
reference at(size_type index) { return m_beg[index]; }
|
||||
const_reference at(size_type index) const { return m_beg[index]; }
|
||||
|
||||
pointer data() const throw() { return m_beg; }
|
||||
|
||||
bool empty() const throw() { return size() == 0; }
|
||||
|
||||
size_type size() const throw() { return std::distance(m_beg, m_end); }
|
||||
size_type length() const throw() { return size(); }
|
||||
|
||||
}; // class span
|
||||
|
||||
template <typename T> inline span<T> as_span(T * beg, T * end) { return span<T>(beg, end); }
|
||||
|
||||
template <typename T> inline span<T> as_span(T * data, std::size_t size) { return span<T>(data, size); }
|
||||
|
||||
template <typename T, std::size_t N> inline span<T> as_span(T (&arr)[N]) { return span<T>(std::begin(arr), std::end(arr)); }
|
||||
|
||||
template <typename T> inline span<T> as_span(std::vector<T> & cont) { return span<T>(cont); }
|
||||
|
||||
template <typename T> inline span<const T> as_span(const std::vector<T> & cont) { return span<const T>(cont); }
|
||||
|
||||
template <typename T> inline span<T> as_span(std::basic_string<T> & str) { return span<T>(&(str[0]), str.length()); }
|
||||
|
||||
template <typename T> inline span<const T> as_span(const std::basic_string<T> & str) { return span<const T>(&(str[0]), str.length()); }
|
||||
|
||||
|
||||
typedef mpt::span<mpt::byte> byte_span;
|
||||
typedef mpt::span<const mpt::byte> const_byte_span;
|
||||
|
||||
|
||||
|
||||
template <typename T> inline std::vector<typename std::remove_const<T>::type> make_vector(T * beg, T * end) { return std::vector<typename std::remove_const<T>::type>(beg, end); }
|
||||
|
||||
template <typename T> inline std::vector<typename std::remove_const<T>::type> make_vector(T * data, std::size_t size) { return std::vector<typename std::remove_const<T>::type>(data, data + size); }
|
||||
|
||||
template <typename T> inline std::vector<typename std::remove_const<T>::type> make_vector(mpt::span<T> data) { return std::vector<typename std::remove_const<T>::type>(data.data(), data.data() + data.size()); }
|
||||
|
||||
template <typename T, std::size_t N> inline std::vector<typename std::remove_const<T>::type> make_vector(T (&arr)[N]) { return std::vector<typename std::remove_const<T>::type>(std::begin(arr), std::end(arr)); }
|
||||
|
||||
template <typename T> inline std::vector<typename std::remove_const<T>::type> make_vector(const std::basic_string<T> & str) { return std::vector<typename std::remove_const<T>::type>(str.begin(), str.end()); }
|
||||
|
||||
|
||||
|
||||
template <typename Tdst, typename Tsrc>
|
||||
struct byte_cast_impl
|
||||
{
|
||||
inline Tdst operator () (Tsrc src) const
|
||||
{
|
||||
STATIC_ASSERT(sizeof(Tsrc) == sizeof(mpt::byte));
|
||||
STATIC_ASSERT(sizeof(Tdst) == sizeof(mpt::byte));
|
||||
// not checking is_byte_castable here because we are actually
|
||||
// doing a static_cast and converting the value
|
||||
STATIC_ASSERT(std::is_integral<Tsrc>::value);
|
||||
STATIC_ASSERT(std::is_integral<Tdst>::value);
|
||||
return static_cast<Tdst>(src);
|
||||
}
|
||||
};
|
||||
template <typename Tdst, typename Tsrc>
|
||||
struct byte_cast_impl<mpt::span<Tdst>, mpt::span<Tsrc> >
|
||||
{
|
||||
inline mpt::span<Tdst> operator () (mpt::span<Tsrc> src) const
|
||||
{
|
||||
STATIC_ASSERT(sizeof(Tsrc) == sizeof(mpt::byte));
|
||||
STATIC_ASSERT(sizeof(Tdst) == sizeof(mpt::byte));
|
||||
STATIC_ASSERT(mpt::is_byte_castable<Tsrc>::value);
|
||||
STATIC_ASSERT(mpt::is_byte_castable<Tdst>::value);
|
||||
STATIC_ASSERT(std::is_integral<Tsrc>::value);
|
||||
STATIC_ASSERT(std::is_integral<Tdst>::value);
|
||||
return mpt::as_span(mpt::byte_cast_impl<Tdst*, Tsrc*>()(src.begin()), mpt::byte_cast_impl<Tdst*, Tsrc*>()(src.end()));
|
||||
}
|
||||
};
|
||||
template <typename Tdst, typename Tsrc>
|
||||
struct byte_cast_impl<Tdst*, Tsrc*>
|
||||
{
|
||||
inline Tdst* operator () (Tsrc* src) const
|
||||
{
|
||||
STATIC_ASSERT(sizeof(Tsrc) == sizeof(mpt::byte));
|
||||
STATIC_ASSERT(sizeof(Tdst) == sizeof(mpt::byte));
|
||||
STATIC_ASSERT(mpt::is_byte_castable<Tsrc>::value);
|
||||
STATIC_ASSERT(mpt::is_byte_castable<Tdst>::value);
|
||||
STATIC_ASSERT(std::is_integral<Tsrc>::value);
|
||||
STATIC_ASSERT(std::is_integral<Tdst>::value);
|
||||
return reinterpret_cast<Tdst*>(src);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Tdst, typename Tsrc>
|
||||
struct void_cast_impl;
|
||||
|
||||
template <typename Tdst>
|
||||
struct void_cast_impl<Tdst*, void*>
|
||||
{
|
||||
inline Tdst* operator () (void* src) const
|
||||
{
|
||||
STATIC_ASSERT(sizeof(Tdst) == sizeof(mpt::byte));
|
||||
STATIC_ASSERT(mpt::is_byte_castable<Tdst>::value);
|
||||
STATIC_ASSERT(std::is_integral<Tdst>::value);
|
||||
return reinterpret_cast<Tdst*>(src);
|
||||
}
|
||||
};
|
||||
template <typename Tdst>
|
||||
struct void_cast_impl<Tdst*, const void*>
|
||||
{
|
||||
inline Tdst* operator () (const void* src) const
|
||||
{
|
||||
STATIC_ASSERT(sizeof(Tdst) == sizeof(mpt::byte));
|
||||
STATIC_ASSERT(mpt::is_byte_castable<Tdst>::value);
|
||||
STATIC_ASSERT(std::is_integral<Tdst>::value);
|
||||
return reinterpret_cast<Tdst*>(src);
|
||||
}
|
||||
};
|
||||
template <typename Tsrc>
|
||||
struct void_cast_impl<void*, Tsrc*>
|
||||
{
|
||||
inline void* operator () (Tsrc* src) const
|
||||
{
|
||||
STATIC_ASSERT(sizeof(Tsrc) == sizeof(mpt::byte));
|
||||
STATIC_ASSERT(mpt::is_byte_castable<Tsrc>::value);
|
||||
STATIC_ASSERT(std::is_integral<Tsrc>::value);
|
||||
return reinterpret_cast<void*>(src);
|
||||
}
|
||||
};
|
||||
template <typename Tsrc>
|
||||
struct void_cast_impl<const void*, Tsrc*>
|
||||
{
|
||||
inline const void* operator () (Tsrc* src) const
|
||||
{
|
||||
STATIC_ASSERT(sizeof(Tsrc) == sizeof(mpt::byte));
|
||||
STATIC_ASSERT(mpt::is_byte_castable<Tsrc>::value);
|
||||
STATIC_ASSERT(std::is_integral<Tsrc>::value);
|
||||
return reinterpret_cast<const void*>(src);
|
||||
}
|
||||
};
|
||||
|
||||
// casts between different byte (char) types or pointers to these types
|
||||
template <typename Tdst, typename Tsrc>
|
||||
inline Tdst byte_cast(Tsrc src)
|
||||
{
|
||||
return byte_cast_impl<Tdst, Tsrc>()(src);
|
||||
}
|
||||
|
||||
// casts between pointers to void and pointers to byte
|
||||
template <typename Tdst, typename Tsrc>
|
||||
inline Tdst void_cast(Tsrc src)
|
||||
{
|
||||
return void_cast_impl<Tdst, Tsrc>()(src);
|
||||
}
|
||||
|
||||
|
||||
// Saturate the value of src to the domain of Tdst
|
||||
template <typename Tdst, typename Tsrc>
|
||||
inline Tdst saturate_cast(Tsrc src)
|
||||
{
|
||||
// This code tries not only to obviously avoid overflows but also to avoid signed/unsigned comparison warnings and type truncation warnings (which in fact would be safe here) by explicit casting.
|
||||
STATIC_ASSERT(std::numeric_limits<Tdst>::is_integer);
|
||||
STATIC_ASSERT(std::numeric_limits<Tsrc>::is_integer);
|
||||
MPT_CONSTANT_IF(std::numeric_limits<Tdst>::is_signed && std::numeric_limits<Tsrc>::is_signed)
|
||||
{
|
||||
MPT_CONSTANT_IF(sizeof(Tdst) >= sizeof(Tsrc))
|
||||
{
|
||||
return static_cast<Tdst>(src);
|
||||
}
|
||||
return static_cast<Tdst>(std::max<Tsrc>(static_cast<Tsrc>(std::numeric_limits<Tdst>::min()), std::min<Tsrc>(src, static_cast<Tsrc>(std::numeric_limits<Tdst>::max()))));
|
||||
} else MPT_CONSTANT_IF(!std::numeric_limits<Tdst>::is_signed && !std::numeric_limits<Tsrc>::is_signed)
|
||||
{
|
||||
MPT_CONSTANT_IF(sizeof(Tdst) >= sizeof(Tsrc))
|
||||
{
|
||||
return static_cast<Tdst>(src);
|
||||
}
|
||||
return static_cast<Tdst>(std::min<Tsrc>(src, static_cast<Tsrc>(std::numeric_limits<Tdst>::max())));
|
||||
} else MPT_CONSTANT_IF(std::numeric_limits<Tdst>::is_signed && !std::numeric_limits<Tsrc>::is_signed)
|
||||
{
|
||||
MPT_CONSTANT_IF(sizeof(Tdst) > sizeof(Tsrc))
|
||||
{
|
||||
return static_cast<Tdst>(src);
|
||||
}
|
||||
MPT_CONSTANT_IF(sizeof(Tdst) == sizeof(Tsrc))
|
||||
{
|
||||
return static_cast<Tdst>(std::min<Tsrc>(src, static_cast<Tsrc>(std::numeric_limits<Tdst>::max())));
|
||||
}
|
||||
return static_cast<Tdst>(std::min<Tsrc>(src, static_cast<Tsrc>(std::numeric_limits<Tdst>::max())));
|
||||
} else // Tdst unsigned, Tsrc signed
|
||||
{
|
||||
MPT_CONSTANT_IF(sizeof(Tdst) >= sizeof(Tsrc))
|
||||
{
|
||||
return static_cast<Tdst>(std::max<Tsrc>(0, src));
|
||||
}
|
||||
return static_cast<Tdst>(std::max<Tsrc>(0, std::min<Tsrc>(src, static_cast<Tsrc>(std::numeric_limits<Tdst>::max()))));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Tdst>
|
||||
inline Tdst saturate_cast(double src)
|
||||
{
|
||||
if(src >= std::numeric_limits<Tdst>::max())
|
||||
{
|
||||
return std::numeric_limits<Tdst>::max();
|
||||
}
|
||||
if(src <= std::numeric_limits<Tdst>::min())
|
||||
{
|
||||
return std::numeric_limits<Tdst>::min();
|
||||
}
|
||||
return static_cast<Tdst>(src);
|
||||
}
|
||||
|
||||
template <typename Tdst>
|
||||
inline Tdst saturate_cast(float src)
|
||||
{
|
||||
if(src >= std::numeric_limits<Tdst>::max())
|
||||
{
|
||||
return std::numeric_limits<Tdst>::max();
|
||||
}
|
||||
if(src <= std::numeric_limits<Tdst>::min())
|
||||
{
|
||||
return std::numeric_limits<Tdst>::min();
|
||||
}
|
||||
return static_cast<Tdst>(src);
|
||||
}
|
||||
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
// Tracker code requires MIN/MAX to work in constexpr contexts.
|
||||
// We could make MIN/MAX constexpr for supporting compilers,
|
||||
// but that would just needlessly complicate the support matrix
|
||||
// for now.
|
||||
#ifndef MPT_MINMAX_MACROS
|
||||
#define MPT_MINMAX_MACROS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
// MSVC disables a bunch of type conversion warnings once a macro is involved.
|
||||
// Replacing the macro with a template thus spews a TON OF WARNINGS for now.
|
||||
#ifndef MPT_MINMAX_MACROS
|
||||
#define MPT_MINMAX_MACROS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(MPT_MINMAX_MACROS)
|
||||
|
||||
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
#else
|
||||
|
||||
namespace mpt { namespace Legacy {
|
||||
|
||||
template <typename Ta, typename Tb>
|
||||
MPT_FORCEINLINE auto MAX(const Ta &a, const Tb &b) -> decltype((a>b)?a:b)
|
||||
{
|
||||
return (a > b) ? a : b;
|
||||
}
|
||||
|
||||
template <typename Ta, typename Tb>
|
||||
MPT_FORCEINLINE auto MIN(const Ta &a, const Tb &b) -> decltype((a<b)?a:b)
|
||||
{
|
||||
return (a < b) ? a : b;
|
||||
}
|
||||
|
||||
} } // namespace mpt::Legacy
|
||||
|
||||
using namespace mpt::Legacy;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
namespace Util
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <typename Tmod, Tmod m>
|
||||
struct ModIfNotZeroImpl
|
||||
{
|
||||
template <typename Tval>
|
||||
inline Tval mod(Tval x)
|
||||
{
|
||||
STATIC_ASSERT(std::numeric_limits<Tmod>::is_integer);
|
||||
STATIC_ASSERT(!std::numeric_limits<Tmod>::is_signed);
|
||||
STATIC_ASSERT(std::numeric_limits<Tval>::is_integer);
|
||||
STATIC_ASSERT(!std::numeric_limits<Tval>::is_signed);
|
||||
return static_cast<Tval>(x % m);
|
||||
}
|
||||
};
|
||||
template <> struct ModIfNotZeroImpl<uint8 , 0> { template <typename Tval> inline Tval mod(Tval x) { return x; } };
|
||||
template <> struct ModIfNotZeroImpl<uint16, 0> { template <typename Tval> inline Tval mod(Tval x) { return x; } };
|
||||
template <> struct ModIfNotZeroImpl<uint32, 0> { template <typename Tval> inline Tval mod(Tval x) { return x; } };
|
||||
template <> struct ModIfNotZeroImpl<uint64, 0> { template <typename Tval> inline Tval mod(Tval x) { return x; } };
|
||||
} // namespace detail
|
||||
// Returns x % m if m != 0, x otherwise.
|
||||
// i.e. "return (m == 0) ? x : (x % m);", but without causing a warning with stupid older compilers
|
||||
template <typename Tmod, Tmod m, typename Tval>
|
||||
inline Tval ModIfNotZero(Tval x)
|
||||
{
|
||||
return detail::ModIfNotZeroImpl<Tmod, m>().mod(x);
|
||||
}
|
||||
|
||||
// Returns true iff Tdst can represent the value val.
|
||||
// Use as if(Util::TypeCanHoldValue<uint8>(-1)).
|
||||
template <typename Tdst, typename Tsrc>
|
||||
inline bool TypeCanHoldValue(Tsrc val)
|
||||
{
|
||||
return (static_cast<Tsrc>(mpt::saturate_cast<Tdst>(val)) == val);
|
||||
}
|
||||
|
||||
// Grows x with an exponential factor suitable for increasing buffer sizes.
|
||||
// Clamps the result at limit.
|
||||
// And avoids integer overflows while doing its business.
|
||||
// The growth factor is 1.5, rounding down, execpt for the initial x==1 case.
|
||||
template <typename T, typename Tlimit>
|
||||
inline T ExponentialGrow(const T &x, const Tlimit &limit)
|
||||
{
|
||||
MPT_ASSERT(x > 0);
|
||||
MPT_ASSERT(limit > 0);
|
||||
if(x == 1)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
T add = std::min<T>(x >> 1, std::numeric_limits<T>::max() - x);
|
||||
return std::min<T>(x + add, mpt::saturate_cast<T>(limit));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T ExponentialGrow(const T &x)
|
||||
{
|
||||
return Util::ExponentialGrow(x, std::numeric_limits<T>::max());
|
||||
}
|
||||
|
||||
} //namespace Util
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
// C++17 clamp
|
||||
|
||||
template<typename T, typename Compare>
|
||||
MPT_CONSTEXPR11_FUN const T & clamp(const T & v, const T & lo, const T & hi, Compare comp)
|
||||
{
|
||||
return comp(v, lo) ? lo : comp(hi, v) ? hi : v;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
MPT_CONSTEXPR11_FUN const T & clamp(const T & v, const T & lo, const T & hi)
|
||||
{
|
||||
return mpt::clamp(v, lo, hi, std::less<T>());
|
||||
}
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
// Limits 'val' to given range. If 'val' is less than 'lowerLimit', 'val' is set to value 'lowerLimit'.
|
||||
// Similarly if 'val' is greater than 'upperLimit', 'val' is set to value 'upperLimit'.
|
||||
// If 'lowerLimit' > 'upperLimit', 'val' won't be modified.
|
||||
template<class T, class C>
|
||||
inline void Limit(T& val, const C lowerLimit, const C upperLimit)
|
||||
{
|
||||
if(lowerLimit > upperLimit) return;
|
||||
if(val < lowerLimit) val = lowerLimit;
|
||||
else if(val > upperLimit) val = upperLimit;
|
||||
}
|
||||
|
||||
|
||||
// Like Limit, but returns value
|
||||
template<class T, class C>
|
||||
inline T Clamp(T val, const C lowerLimit, const C upperLimit)
|
||||
{
|
||||
if(val < lowerLimit) return lowerLimit;
|
||||
else if(val > upperLimit) return upperLimit;
|
||||
else return val;
|
||||
}
|
||||
|
||||
// Check if val is in [lo,hi] without causing compiler warnings
|
||||
// if theses checks are always true due to the domain of T.
|
||||
// GCC does not warn if the type is templated.
|
||||
template<typename T, typename C>
|
||||
inline bool IsInRange(T val, C lo, C hi)
|
||||
{
|
||||
return lo <= val && val <= hi;
|
||||
}
|
||||
|
||||
// Like Limit, but with upperlimit only.
|
||||
template<class T, class C>
|
||||
inline void LimitMax(T& val, const C upperLimit)
|
||||
{
|
||||
if(val > upperLimit)
|
||||
val = upperLimit;
|
||||
}
|
||||
|
||||
|
||||
// Returns sign of a number (-1 for negative numbers, 1 for positive numbers, 0 for 0)
|
||||
template <class T>
|
||||
int sgn(T value)
|
||||
{
|
||||
return (value > T(0)) - (value < T(0));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// mpt::rshift_signed
|
||||
// mpt::lshift_signed
|
||||
// Shift a signed integer value in a well-defined manner.
|
||||
// Does the same thing as MSVC would do. This is verified by the test suite.
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
MPT_FORCEINLINE auto rshift_signed_standard(T x, int y) -> decltype(x >> y)
|
||||
{
|
||||
MPT_STATIC_ASSERT(std::numeric_limits<T>::is_integer);
|
||||
MPT_STATIC_ASSERT(std::numeric_limits<T>::is_signed);
|
||||
typedef decltype(x >> y) result_type;
|
||||
typedef typename std::make_unsigned<result_type>::type unsigned_result_type;
|
||||
const unsigned_result_type roffset = static_cast<unsigned_result_type>(1) << ((sizeof(result_type) * 8) - 1);
|
||||
result_type rx = x;
|
||||
unsigned_result_type urx = static_cast<unsigned_result_type>(rx);
|
||||
urx += roffset;
|
||||
urx >>= y;
|
||||
urx -= roffset >> y;
|
||||
return static_cast<result_type>(urx);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
MPT_FORCEINLINE auto lshift_signed_standard(T x, int y) -> decltype(x << y)
|
||||
{
|
||||
MPT_STATIC_ASSERT(std::numeric_limits<T>::is_integer);
|
||||
MPT_STATIC_ASSERT(std::numeric_limits<T>::is_signed);
|
||||
typedef decltype(x << y) result_type;
|
||||
typedef typename std::make_unsigned<result_type>::type unsigned_result_type;
|
||||
const unsigned_result_type roffset = static_cast<unsigned_result_type>(1) << ((sizeof(result_type) * 8) - 1);
|
||||
result_type rx = x;
|
||||
unsigned_result_type urx = static_cast<unsigned_result_type>(rx);
|
||||
urx += roffset;
|
||||
urx <<= y;
|
||||
urx -= roffset << y;
|
||||
return static_cast<result_type>(urx);
|
||||
}
|
||||
|
||||
#if MPT_COMPILER_SHIFT_SIGNED
|
||||
|
||||
template <typename T>
|
||||
MPT_FORCEINLINE auto rshift_signed_undefined(T x, int y) -> decltype(x >> y)
|
||||
{
|
||||
MPT_STATIC_ASSERT(std::numeric_limits<T>::is_integer);
|
||||
MPT_STATIC_ASSERT(std::numeric_limits<T>::is_signed);
|
||||
return x >> y;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
MPT_FORCEINLINE auto lshift_signed_undefined(T x, int y) -> decltype(x << y)
|
||||
{
|
||||
MPT_STATIC_ASSERT(std::numeric_limits<T>::is_integer);
|
||||
MPT_STATIC_ASSERT(std::numeric_limits<T>::is_signed);
|
||||
return x << y;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
MPT_FORCEINLINE auto rshift_signed(T x, int y) -> decltype(x >> y)
|
||||
{
|
||||
return mpt::rshift_signed_undefined(x, y);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
MPT_FORCEINLINE auto lshift_signed(T x, int y) -> decltype(x << y)
|
||||
{
|
||||
return mpt::lshift_signed_undefined(x, y);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template <typename T>
|
||||
MPT_FORCEINLINE auto rshift_signed(T x, int y) -> decltype(x >> y)
|
||||
{
|
||||
return mpt::rshift_signed_standard(x, y);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
MPT_FORCEINLINE auto lshift_signed(T x, int y) -> decltype(x << y)
|
||||
{
|
||||
return mpt::lshift_signed_standard(x, y);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
namespace Util
|
||||
{
|
||||
|
||||
// Returns maximum value of given integer type.
|
||||
template <class T> constexpr T MaxValueOfType(const T&) {static_assert(std::numeric_limits<T>::is_integer == true, "Only integer types are allowed."); return (std::numeric_limits<T>::max)();}
|
||||
|
||||
// The following MPT_MAX_* macros are useful as std::numeric_limits is not
|
||||
// usable in constexpr-like contexts like static_assert in pre-C++11
|
||||
// compilers.
|
||||
|
||||
// Returns the maximum value for the signed type or expression at compile time.
|
||||
#define MPT_MAX_SIGNED_VALUE(integral_expression_or_type) ( ( 1ull << ( sizeof(integral_expression_or_type) * 8 - 1 ) ) - 1 )
|
||||
|
||||
// Returns the maximum value for the unsigned type or expression at compile time.
|
||||
// Implemented in terms of MPT_MAX_SIGNED_VALUE in order to avoid overflow in left-shift.
|
||||
#define MPT_MAX_UNSIGNED_VALUE(integral_expression_or_type) ( ( MPT_MAX_SIGNED_VALUE(integral_expression_or_type) << 1 ) | 1ull )
|
||||
|
||||
// Return the maximum value of an integral type at compile time.
|
||||
#define MPT_MAX_VALUE_OF_TYPE(integral_type) ( std::numeric_limits<integral_type>::is_signed ? MPT_MAX_SIGNED_VALUE(integral_type) : MPT_MAX_UNSIGNED_VALUE(integral_type) )
|
||||
|
||||
/// Returns value rounded to nearest integer.
|
||||
#if (MPT_OS_EMSCRIPTEN && MPT_OS_EMSCRIPTEN_ANCIENT)
|
||||
// MSVC before 2013 does not support C99/C++11.
|
||||
// Certain emscripten versions and/or combinations with nodejs (at least the following combination: emscripten 1.34.8, clang 3.7.0, nodejs 0.10.38) fail assert(std::round(1.5)==2.0). The work-around always works.
|
||||
inline double Round(const double& val) {if(val >= 0.0) return std::floor(val + 0.5); else return std::ceil(val - 0.5);}
|
||||
inline float Round(const float& val) {if(val >= 0.0f) return std::floor(val + 0.5f); else return std::ceil(val - 0.5f);}
|
||||
#elif MPT_OS_ANDROID && defined(__GLIBCXX__) && !defined(_LIBCPP_VERSION)
|
||||
// NDK 12b gnustl_shared armeabi-v7a only provides round() in ::.
|
||||
// NDK 12b gnustl_shared arm64-v8a has round() in std::.
|
||||
// NDK 12b c++_shared armeabi-v7a has round() in std::.
|
||||
// Just fallback to :: for Android gnustl_shared.
|
||||
// This work-around can be removed once Android switches to LLVM libc++.
|
||||
// Currently (ndk-r12b), libc++ has problems with exceptions.
|
||||
inline double Round(const double& val) { return ::round(val); }
|
||||
inline float Round(const float& val) { return ::roundf(val); }
|
||||
#else
|
||||
inline double Round(const double& val) { return std::round(val); }
|
||||
inline float Round(const float& val) { return std::round(val); }
|
||||
#endif
|
||||
|
||||
/// Rounds given double value to nearest integer value of type T.
|
||||
template <class T> inline T Round(const double& val)
|
||||
{
|
||||
static_assert(std::numeric_limits<T>::is_integer == true, "Type is a not an integer");
|
||||
const double valRounded = Round(val);
|
||||
MPT_ASSERT(valRounded >= (std::numeric_limits<T>::min)() && valRounded <= (std::numeric_limits<T>::max)());
|
||||
const T intval = static_cast<T>(valRounded);
|
||||
return intval;
|
||||
}
|
||||
|
||||
template <class T> inline T Round(const float& val)
|
||||
{
|
||||
static_assert(std::numeric_limits<T>::is_integer == true, "Type is a not an integer");
|
||||
const float valRounded = Round(val);
|
||||
MPT_ASSERT(valRounded >= (std::numeric_limits<T>::min)() && valRounded <= (std::numeric_limits<T>::max)());
|
||||
const T intval = static_cast<T>(valRounded);
|
||||
return intval;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T Weight(T x)
|
||||
{
|
||||
STATIC_ASSERT(std::numeric_limits<T>::is_integer);
|
||||
T c;
|
||||
for(c = 0; x; x >>= 1)
|
||||
{
|
||||
c += x & 1;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace Util {
|
||||
|
||||
// Multiply two 32-bit integers, receive 64-bit result.
|
||||
// MSVC generates unnecessarily complicated code for the unoptimized variant using _allmul.
|
||||
MPT_FORCEINLINE int64 mul32to64(int32 a, int32 b)
|
||||
{
|
||||
#if MPT_COMPILER_MSVC && (defined(_M_IX86) || defined(_M_X64))
|
||||
return __emul(a, b);
|
||||
#else
|
||||
return static_cast<int64>(a) * b;
|
||||
#endif
|
||||
}
|
||||
|
||||
MPT_FORCEINLINE uint64 mul32to64_unsigned(uint32 a, uint32 b)
|
||||
{
|
||||
#if MPT_COMPILER_MSVC && (defined(_M_IX86) || defined(_M_X64))
|
||||
return __emulu(a, b);
|
||||
#else
|
||||
return static_cast<uint64>(a) * b;
|
||||
#endif
|
||||
}
|
||||
|
||||
MPT_FORCEINLINE int32 muldiv(int32 a, int32 b, int32 c)
|
||||
{
|
||||
return mpt::saturate_cast<int32>( mul32to64( a, b ) / c );
|
||||
}
|
||||
|
||||
MPT_FORCEINLINE int32 muldivr(int32 a, int32 b, int32 c)
|
||||
{
|
||||
return mpt::saturate_cast<int32>( ( mul32to64( a, b ) + ( c / 2 ) ) / c );
|
||||
}
|
||||
|
||||
// Do not use overloading because catching unsigned version by accident results in slower X86 code.
|
||||
MPT_FORCEINLINE uint32 muldiv_unsigned(uint32 a, uint32 b, uint32 c)
|
||||
{
|
||||
return mpt::saturate_cast<uint32>( mul32to64_unsigned( a, b ) / c );
|
||||
}
|
||||
MPT_FORCEINLINE uint32 muldivr_unsigned(uint32 a, uint32 b, uint32 c)
|
||||
{
|
||||
return mpt::saturate_cast<uint32>( ( mul32to64_unsigned( a, b ) + ( c / 2u ) ) / c );
|
||||
}
|
||||
|
||||
MPT_FORCEINLINE int32 muldivrfloor(int64 a, uint32 b, uint32 c)
|
||||
{
|
||||
a *= b;
|
||||
a += c / 2u;
|
||||
return (a >= 0) ? mpt::saturate_cast<int32>(a / c) : mpt::saturate_cast<int32>((a - (c - 1)) / c);
|
||||
}
|
||||
|
||||
// rounds x up to multiples of target
|
||||
template <typename T>
|
||||
inline T AlignUp(T x, T target)
|
||||
{
|
||||
return ((x + (target - 1)) / target) * target;
|
||||
}
|
||||
|
||||
// rounds x down to multiples of target
|
||||
template <typename T>
|
||||
inline T AlignDown(T x, T target)
|
||||
{
|
||||
return (x / target) * target;
|
||||
}
|
||||
|
||||
// Insert a range of items [insStart, insEnd], and possibly shift item fix to the left.
|
||||
template<typename T>
|
||||
void InsertItem(const T insStart, const T insEnd, T &fix)
|
||||
|
@ -969,49 +111,6 @@ namespace Util {
|
|||
} // namespace Util
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
// Greatest Common Divisor. Always returns non-negative number.
|
||||
// compatible with C++17 std::gcd
|
||||
template <typename A, typename B>
|
||||
inline typename std::common_type<A, B>::type gcd(A a_, B b_)
|
||||
{
|
||||
typename std::common_type<A, B>::type a = a_;
|
||||
typename std::common_type<A, B>::type b = b_;
|
||||
if(a < 0)
|
||||
a = -a;
|
||||
if(b < 0)
|
||||
b = -b;
|
||||
for(;;)
|
||||
{
|
||||
if(a == 0)
|
||||
return b;
|
||||
b %= a;
|
||||
if(b == 0)
|
||||
return a;
|
||||
a %= b;
|
||||
}
|
||||
}
|
||||
|
||||
// Least Common Multiple. Always returns non-negative number.
|
||||
// compatible with C++17 std::lcm
|
||||
template <typename A, typename B>
|
||||
inline typename std::common_type<A, B>::type lcm(A a_, B b_)
|
||||
{
|
||||
typename std::common_type<A, B>::type a = a_;
|
||||
typename std::common_type<A, B>::type b = b_;
|
||||
if(a < 0)
|
||||
a = -a;
|
||||
if(b < 0)
|
||||
b = -b;
|
||||
if((a | b) == 0)
|
||||
return 0;
|
||||
return a / mpt::gcd(a, b) * b;
|
||||
}
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
namespace Util
|
||||
{
|
||||
|
|
121
Frameworks/OpenMPT/OpenMPT/common/mptAlloc.cpp
Normal file
121
Frameworks/OpenMPT/OpenMPT/common/mptAlloc.cpp
Normal file
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* mptAlloc.cpp
|
||||
* ------------
|
||||
* Purpose: Dynamic memory allocation.
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "mptAlloc.h"
|
||||
|
||||
#include "mptBaseTypes.h"
|
||||
|
||||
#include <memory>
|
||||
#include <new>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
|
||||
|
||||
#if MPT_CXX_AT_LEAST(17)
|
||||
#else
|
||||
void* align(std::size_t alignment, std::size_t size, void* &ptr, std::size_t &space) noexcept
|
||||
{
|
||||
std::size_t offset = static_cast<std::size_t>(reinterpret_cast<std::uintptr_t>(ptr) & (alignment - 1));
|
||||
if(offset != 0)
|
||||
{
|
||||
offset = alignment - offset;
|
||||
}
|
||||
if((space < offset) || ((space - offset) < size))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
ptr = static_cast<mpt::byte*>(ptr) + offset;
|
||||
space -= offset;
|
||||
return ptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
aligned_raw_memory aligned_alloc_impl(std::size_t size, std::size_t count, std::size_t alignment)
|
||||
{
|
||||
#if MPT_CXX_AT_LEAST(17) && (!MPT_COMPILER_MSVC && !MPT_GCC_BEFORE(8,1,0) && !MPT_CLANG_BEFORE(5,0,0)) && !(MPT_COMPILER_CLANG && defined(__GLIBCXX__)) && !MPT_OS_EMSCRIPTEN
|
||||
std::size_t space = count * size;
|
||||
void* mem = std::aligned_alloc(alignment, space);
|
||||
if(!mem)
|
||||
{
|
||||
MPT_EXCEPTION_THROW_OUT_OF_MEMORY();
|
||||
}
|
||||
return aligned_raw_memory{mem, mem};
|
||||
#elif MPT_COMPILER_MSVC
|
||||
std::size_t space = count * size;
|
||||
void* mem = _aligned_malloc(space, alignment);
|
||||
if(!mem)
|
||||
{
|
||||
MPT_EXCEPTION_THROW_OUT_OF_MEMORY();
|
||||
}
|
||||
return aligned_raw_memory{mem, mem};
|
||||
#else
|
||||
if(alignment > alignof(mpt::max_align_t))
|
||||
{
|
||||
std::size_t space = count * size + (alignment - 1);
|
||||
void* mem = std::malloc(space);
|
||||
if(!mem)
|
||||
{
|
||||
MPT_EXCEPTION_THROW_OUT_OF_MEMORY();
|
||||
}
|
||||
void* aligned_mem = mem;
|
||||
void* aligned = mpt::align(alignment, size * count, aligned_mem, space);
|
||||
if(!aligned)
|
||||
{
|
||||
MPT_EXCEPTION_THROW_OUT_OF_MEMORY();
|
||||
}
|
||||
return aligned_raw_memory{aligned, mem};
|
||||
} else
|
||||
{
|
||||
std::size_t space = count * size;
|
||||
void* mem = std::malloc(space);
|
||||
if(!mem)
|
||||
{
|
||||
MPT_EXCEPTION_THROW_OUT_OF_MEMORY();
|
||||
}
|
||||
return aligned_raw_memory{mem, mem};
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void aligned_free(aligned_raw_memory raw)
|
||||
{
|
||||
#if MPT_CXX_AT_LEAST(17) && (!MPT_COMPILER_MSVC && !MPT_GCC_BEFORE(8,1,0) && !MPT_CLANG_BEFORE(5,0,0)) && !(MPT_COMPILER_CLANG && defined(__GLIBCXX__)) && !MPT_OS_EMSCRIPTEN
|
||||
std::free(raw.mem);
|
||||
#elif MPT_COMPILER_MSVC
|
||||
_aligned_free(raw.mem);
|
||||
#else
|
||||
std::free(raw.mem);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
262
Frameworks/OpenMPT/OpenMPT/common/mptAlloc.h
Normal file
262
Frameworks/OpenMPT/OpenMPT/common/mptAlloc.h
Normal file
|
@ -0,0 +1,262 @@
|
|||
/*
|
||||
* mptAlloc.h
|
||||
* ----------
|
||||
* Purpose: Dynamic memory allocation.
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
|
||||
|
||||
#include "mptBaseMacros.h"
|
||||
#include "mptMemory.h"
|
||||
#include "mptSpan.h"
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
|
||||
namespace mpt {
|
||||
|
||||
|
||||
|
||||
template <typename T> inline span<T> as_span(std::vector<T> & cont) { return span<T>(cont); }
|
||||
|
||||
template <typename T> inline span<const T> as_span(const std::vector<T> & cont) { return span<const T>(cont); }
|
||||
|
||||
|
||||
|
||||
template <typename T> inline std::vector<typename std::remove_const<T>::type> make_vector(T * beg, T * end) { return std::vector<typename std::remove_const<T>::type>(beg, end); }
|
||||
|
||||
template <typename T> inline std::vector<typename std::remove_const<T>::type> make_vector(T * data, std::size_t size) { return std::vector<typename std::remove_const<T>::type>(data, data + size); }
|
||||
|
||||
template <typename T> inline std::vector<typename std::remove_const<T>::type> make_vector(mpt::span<T> data) { return std::vector<typename std::remove_const<T>::type>(data.data(), data.data() + data.size()); }
|
||||
|
||||
template <typename T, std::size_t N> inline std::vector<typename std::remove_const<T>::type> make_vector(T (&arr)[N]) { return std::vector<typename std::remove_const<T>::type>(std::begin(arr), std::end(arr)); }
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct GetRawBytesFunctor<std::vector<T>>
|
||||
{
|
||||
inline mpt::const_byte_span operator () (const std::vector<T> & v) const
|
||||
{
|
||||
STATIC_ASSERT(mpt::is_binary_safe<typename std::remove_const<T>::type>::value);
|
||||
return mpt::as_span(reinterpret_cast<const mpt::byte *>(v.data()), v.size() * sizeof(T));
|
||||
}
|
||||
inline mpt::byte_span operator () (std::vector<T> & v) const
|
||||
{
|
||||
STATIC_ASSERT(mpt::is_binary_safe<typename std::remove_const<T>::type>::value);
|
||||
return mpt::as_span(reinterpret_cast<mpt::byte *>(v.data()), v.size() * sizeof(T));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct GetRawBytesFunctor<const std::vector<T>>
|
||||
{
|
||||
inline mpt::const_byte_span operator () (const std::vector<T> & v) const
|
||||
{
|
||||
STATIC_ASSERT(mpt::is_binary_safe<typename std::remove_const<T>::type>::value);
|
||||
return mpt::as_span(reinterpret_cast<const mpt::byte *>(v.data()), v.size() * sizeof(T));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
#if MPT_CXX_AT_LEAST(14)
|
||||
namespace mpt {
|
||||
using std::make_unique;
|
||||
} // namespace mpt
|
||||
#else
|
||||
namespace mpt {
|
||||
template<typename T, typename... Args>
|
||||
std::unique_ptr<T> make_unique(Args&&... args)
|
||||
{
|
||||
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
||||
}
|
||||
} // namespace mpt
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
|
||||
|
||||
#if MPT_CXX_AT_LEAST(17) && !(MPT_COMPILER_CLANG && defined(__GLIBCXX__))
|
||||
using std::launder;
|
||||
#else
|
||||
template <class T>
|
||||
MPT_NOINLINE T* launder(T* p) noexcept
|
||||
{
|
||||
return p;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if MPT_CXX_AT_LEAST(17)
|
||||
using std::align;
|
||||
#else
|
||||
// pre-C++17, std::align does not support over-alignement
|
||||
void* align(std::size_t alignment, std::size_t size, void* &ptr, std::size_t &space) noexcept;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
struct aligned_raw_memory
|
||||
{
|
||||
void* aligned;
|
||||
void* mem;
|
||||
};
|
||||
|
||||
aligned_raw_memory aligned_alloc_impl(std::size_t size, std::size_t count, std::size_t alignment);
|
||||
|
||||
template <std::size_t alignment>
|
||||
inline aligned_raw_memory aligned_alloc(std::size_t size, std::size_t count)
|
||||
{
|
||||
MPT_STATIC_ASSERT(alignment > 0);
|
||||
MPT_CONSTEXPR14_ASSERT(mpt::weight(alignment) == 1);
|
||||
return aligned_alloc_impl(size, count, alignment);
|
||||
}
|
||||
|
||||
void aligned_free(aligned_raw_memory raw);
|
||||
|
||||
template <typename T>
|
||||
struct aligned_raw_buffer
|
||||
{
|
||||
T* elements;
|
||||
void* mem;
|
||||
};
|
||||
|
||||
template <typename T, std::size_t alignment>
|
||||
inline aligned_raw_buffer<T> aligned_alloc(std::size_t count)
|
||||
{
|
||||
MPT_STATIC_ASSERT(alignment >= alignof(T));
|
||||
aligned_raw_memory raw = aligned_alloc<alignment>(sizeof(T), count);
|
||||
return aligned_raw_buffer<T>{mpt::launder(reinterpret_cast<T*>(raw.aligned)), raw.mem};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void aligned_free(aligned_raw_buffer<T> buf)
|
||||
{
|
||||
aligned_free(aligned_raw_memory{buf.elements, buf.mem});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct aligned_raw_objects
|
||||
{
|
||||
T* elements;
|
||||
std::size_t count;
|
||||
void* mem;
|
||||
};
|
||||
|
||||
template <typename T, std::size_t alignment>
|
||||
inline aligned_raw_objects<T> aligned_new(std::size_t count, T init = T())
|
||||
{
|
||||
aligned_raw_buffer<T> buf = aligned_alloc<T, alignment>(count);
|
||||
std::size_t constructed = 0;
|
||||
try
|
||||
{
|
||||
for(std::size_t i = 0; i < count; ++i)
|
||||
{
|
||||
new(&(buf.elements[i])) T(init);
|
||||
constructed++;
|
||||
}
|
||||
} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
|
||||
{
|
||||
while(constructed--)
|
||||
{
|
||||
mpt::launder(&(buf.elements[constructed - 1]))->~T();
|
||||
}
|
||||
aligned_free(buf);
|
||||
MPT_EXCEPTION_RETHROW_OUT_OF_MEMORY(e);
|
||||
} catch(...)
|
||||
{
|
||||
while(constructed--)
|
||||
{
|
||||
mpt::launder(&(buf.elements[constructed - 1]))->~T();
|
||||
}
|
||||
aligned_free(buf);
|
||||
throw;
|
||||
}
|
||||
return aligned_raw_objects<T>{mpt::launder(buf.elements), count, buf.mem};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void aligned_delete(aligned_raw_objects<T> objs)
|
||||
{
|
||||
if(objs.elements)
|
||||
{
|
||||
std::size_t constructed = objs.count;
|
||||
while(constructed--)
|
||||
{
|
||||
objs.elements[constructed - 1].~T();
|
||||
}
|
||||
}
|
||||
aligned_free(aligned_raw_buffer<T>{objs.elements, objs.mem});
|
||||
}
|
||||
|
||||
template <typename T, std::size_t alignment>
|
||||
class aligned_buffer
|
||||
{
|
||||
private:
|
||||
aligned_raw_objects<T> objs;
|
||||
public:
|
||||
explicit aligned_buffer(std::size_t count = 0)
|
||||
: objs(aligned_new<T, alignment>(count))
|
||||
{
|
||||
}
|
||||
aligned_buffer(const aligned_buffer&) = delete;
|
||||
aligned_buffer& operator=(const aligned_buffer&) = delete;
|
||||
~aligned_buffer()
|
||||
{
|
||||
aligned_delete(objs);
|
||||
}
|
||||
public:
|
||||
void destructive_resize(std::size_t count)
|
||||
{
|
||||
aligned_raw_objects<T> tmpobjs = aligned_new<T, alignment>(count);
|
||||
{
|
||||
using namespace std;
|
||||
swap(objs, tmpobjs);
|
||||
}
|
||||
aligned_delete(tmpobjs);
|
||||
}
|
||||
public:
|
||||
T* begin() noexcept { return objs.elements; }
|
||||
const T* begin() const noexcept { return objs.elements; }
|
||||
T* end() noexcept { return objs.elements + objs.count; }
|
||||
const T* end() const noexcept { return objs.elements + objs.count; }
|
||||
const T* cbegin() const noexcept { return objs.elements; }
|
||||
const T* cend() const noexcept { return objs.elements + objs.count; }
|
||||
T& operator[](std::size_t i) noexcept { return objs.elements[i]; }
|
||||
const T& operator[](std::size_t i) const noexcept { return objs.elements[i]; }
|
||||
T* data() noexcept { return objs.elements; }
|
||||
const T* data() const noexcept { return objs.elements; }
|
||||
std::size_t size() const noexcept { return objs.count; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
153
Frameworks/OpenMPT/OpenMPT/common/mptAssert.h
Normal file
153
Frameworks/OpenMPT/OpenMPT/common/mptAssert.h
Normal file
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* mptAssert.h
|
||||
* -----------
|
||||
* Purpose: assert and static_assert
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
|
||||
|
||||
#include "mptBaseMacros.h"
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
|
||||
// Static code checkers might need to get the knowledge of our assertions transferred to them.
|
||||
#define MPT_CHECKER_ASSUME_ASSERTIONS 1
|
||||
//#define MPT_CHECKER_ASSUME_ASSERTIONS 0
|
||||
|
||||
#ifdef MPT_BUILD_ANALYZED
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
|
||||
#if MPT_CHECKER_ASSUME_ASSERTIONS
|
||||
#define MPT_CHECKER_ASSUME(x) __analysis_assume(!!(x))
|
||||
#endif
|
||||
|
||||
#elif MPT_COMPILER_CLANG
|
||||
|
||||
#if MPT_CHECKER_ASSUME_ASSERTIONS
|
||||
#ifdef NDEBUG
|
||||
#error "Builds for static analyzers depend on assert() being enabled, but the current build has #define NDEBUG. This makes no sense."
|
||||
#endif
|
||||
OPENMPT_NAMESPACE_END
|
||||
#include <cassert>
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
#define MPT_CHECKER_ASSUME(x) assert(!!(x))
|
||||
#endif
|
||||
|
||||
#endif // MPT_COMPILER
|
||||
|
||||
#endif // MPT_BUILD_ANALYZED
|
||||
|
||||
#ifndef MPT_CHECKER_ASSUME
|
||||
#define MPT_CHECKER_ASSUME(x) MPT_DO { } MPT_WHILE_0
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if defined(_MFC_VER) && !defined(MPT_CPPCHECK_CUSTOM)
|
||||
|
||||
#if !defined(ASSERT)
|
||||
#error "MFC is expected to #define ASSERT"
|
||||
#endif // !defined(ASERRT)
|
||||
#define MPT_FRAMEWORK_ASSERT_IS_DEFINED
|
||||
|
||||
#if defined(_DEBUG)
|
||||
#define MPT_FRAMEWORK_ASSERT_IS_ACTIVE 1
|
||||
#else // !_DEBUG
|
||||
#define MPT_FRAMEWORK_ASSERT_IS_ACTIVE 0
|
||||
#endif // _DEBUG
|
||||
|
||||
// let MFC handle our asserts
|
||||
#define MPT_ASSERT_USE_FRAMEWORK 1
|
||||
|
||||
#else // !_MFC_VER
|
||||
|
||||
#if defined(ASSERT)
|
||||
#define MPT_FRAMEWORK_ASSERT_IS_DEFINED
|
||||
#if defined(_DEBUG)
|
||||
#define MPT_FRAMEWORK_ASSERT_IS_ACTIVE 1
|
||||
#else // !_DEBUG
|
||||
#define MPT_FRAMEWORK_ASSERT_IS_ACTIVE 0
|
||||
#endif // _DEBUG
|
||||
#endif // !defined(ASERRT)
|
||||
|
||||
// handle assert in our own way without relying on some platform-/framework-specific assert implementation
|
||||
#define MPT_ASSERT_USE_FRAMEWORK 0
|
||||
|
||||
#endif // _MFC_VER
|
||||
|
||||
#if defined(MPT_FRAMEWORK_ASSERT_IS_DEFINED) && (MPT_ASSERT_USE_FRAMEWORK == 1)
|
||||
|
||||
#define MPT_ASSERT_NOTREACHED() ASSERT(0)
|
||||
#define MPT_ASSERT(expr) ASSERT((expr))
|
||||
#define MPT_ASSERT_MSG(expr, msg) ASSERT((expr) && (msg))
|
||||
#if (MPT_FRAMEWORK_ASSERT_IS_ACTIVE == 1)
|
||||
#define MPT_ASSERT_ALWAYS(expr) ASSERT((expr))
|
||||
#define MPT_ASSERT_ALWAYS_MSG(expr, msg) ASSERT((expr) && (msg))
|
||||
#else
|
||||
#define MPT_ASSERT_ALWAYS(expr) MPT_DO { if(!(expr)) { AssertHandler(MPT_SOURCE_LOCATION_CURRENT(), #expr); } MPT_CHECKER_ASSUME(expr); } MPT_WHILE_0
|
||||
#define MPT_ASSERT_ALWAYS_MSG(expr, msg) MPT_DO { if(!(expr)) { AssertHandler(MPT_SOURCE_LOCATION_CURRENT(), #expr, msg); } MPT_CHECKER_ASSUME(expr); } MPT_WHILE_0
|
||||
#ifndef MPT_ASSERT_HANDLER_NEEDED
|
||||
#define MPT_ASSERT_HANDLER_NEEDED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#elif defined(NO_ASSERTS)
|
||||
|
||||
#define MPT_ASSERT_NOTREACHED() MPT_CHECKER_ASSUME(0)
|
||||
#define MPT_ASSERT(expr) MPT_CHECKER_ASSUME(expr)
|
||||
#define MPT_ASSERT_MSG(expr, msg) MPT_CHECKER_ASSUME(expr)
|
||||
#define MPT_ASSERT_ALWAYS(expr) MPT_DO { if(!(expr)) { AssertHandler(MPT_SOURCE_LOCATION_CURRENT(), #expr); } MPT_CHECKER_ASSUME(expr); } MPT_WHILE_0
|
||||
#define MPT_ASSERT_ALWAYS_MSG(expr, msg) MPT_DO { if(!(expr)) { AssertHandler(MPT_SOURCE_LOCATION_CURRENT(), #expr, msg); } MPT_CHECKER_ASSUME(expr); } MPT_WHILE_0
|
||||
#ifndef MPT_ASSERT_HANDLER_NEEDED
|
||||
#define MPT_ASSERT_HANDLER_NEEDED
|
||||
#endif
|
||||
|
||||
#else // !NO_ASSERTS
|
||||
|
||||
#define MPT_ASSERT_NOTREACHED() MPT_DO { MPT_CONSTANT_IF(!(0)) { AssertHandler(MPT_SOURCE_LOCATION_CURRENT(), "0"); } MPT_CHECKER_ASSUME(0); } MPT_WHILE_0
|
||||
#define MPT_ASSERT(expr) MPT_DO { if(!(expr)) { AssertHandler(MPT_SOURCE_LOCATION_CURRENT(), #expr); } MPT_CHECKER_ASSUME(expr); } MPT_WHILE_0
|
||||
#define MPT_ASSERT_MSG(expr, msg) MPT_DO { if(!(expr)) { AssertHandler(MPT_SOURCE_LOCATION_CURRENT(), #expr, msg); } MPT_CHECKER_ASSUME(expr); } MPT_WHILE_0
|
||||
#define MPT_ASSERT_ALWAYS(expr) MPT_DO { if(!(expr)) { AssertHandler(MPT_SOURCE_LOCATION_CURRENT(), #expr); } MPT_CHECKER_ASSUME(expr); } MPT_WHILE_0
|
||||
#define MPT_ASSERT_ALWAYS_MSG(expr, msg) MPT_DO { if(!(expr)) { AssertHandler(MPT_SOURCE_LOCATION_CURRENT(), #expr, msg); } MPT_CHECKER_ASSUME(expr); } MPT_WHILE_0
|
||||
#ifndef MPT_ASSERT_HANDLER_NEEDED
|
||||
#define MPT_ASSERT_HANDLER_NEEDED
|
||||
#endif
|
||||
|
||||
#endif // NO_ASSERTS
|
||||
|
||||
|
||||
#if defined(MPT_ASSERT_HANDLER_NEEDED)
|
||||
// custom assert handler needed
|
||||
MPT_NOINLINE void AssertHandler(const mpt::source_location &loc, const char *expr, const char *msg=nullptr);
|
||||
#endif // MPT_ASSERT_HANDLER_NEEDED
|
||||
|
||||
|
||||
|
||||
#define MPT_CONSTEXPR11_ASSERT MPT_STATIC_ASSERT
|
||||
#if MPT_CXX_AT_LEAST(14) && !MPT_MSVC_BEFORE(2017,5)
|
||||
#define MPT_CONSTEXPR14_ASSERT MPT_STATIC_ASSERT
|
||||
#else
|
||||
#define MPT_CONSTEXPR14_ASSERT MPT_ASSERT
|
||||
#endif
|
||||
#if MPT_CXX_AT_LEAST(17) && !MPT_MSVC_BEFORE(2017,5)
|
||||
#define MPT_CONSTEXPR17_ASSERT MPT_STATIC_ASSERT
|
||||
#else
|
||||
#define MPT_CONSTEXPR17_ASSERT MPT_ASSERT
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
270
Frameworks/OpenMPT/OpenMPT/common/mptBaseMacros.h
Normal file
270
Frameworks/OpenMPT/OpenMPT/common/mptBaseMacros.h
Normal file
|
@ -0,0 +1,270 @@
|
|||
/*
|
||||
* mptBaseMacros.h
|
||||
* ---------------
|
||||
* Purpose: Basic assorted compiler-related helpers.
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
|
||||
// Compile time assert.
|
||||
#if (MPT_CXX >= 17)
|
||||
#define MPT_STATIC_ASSERT static_assert
|
||||
#else
|
||||
#define MPT_STATIC_ASSERT(expr) static_assert((expr), "compile time assertion failed: " #expr)
|
||||
#endif
|
||||
// legacy
|
||||
#define STATIC_ASSERT(x) MPT_STATIC_ASSERT(x)
|
||||
|
||||
|
||||
|
||||
// Advanced inline attributes
|
||||
#if MPT_COMPILER_MSVC
|
||||
#define MPT_FORCEINLINE __forceinline
|
||||
#define MPT_NOINLINE __declspec(noinline)
|
||||
#elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG
|
||||
#define MPT_FORCEINLINE __attribute__((always_inline)) inline
|
||||
#define MPT_NOINLINE __attribute__((noinline))
|
||||
#else
|
||||
#define MPT_FORCEINLINE inline
|
||||
#define MPT_NOINLINE
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// constexpr
|
||||
#define MPT_CONSTEXPR11_FUN constexpr MPT_FORCEINLINE
|
||||
#define MPT_CONSTEXPR11_VAR constexpr
|
||||
#if MPT_CXX_AT_LEAST(14) && !MPT_MSVC_BEFORE(2017,5)
|
||||
#define MPT_CONSTEXPR14_FUN constexpr MPT_FORCEINLINE
|
||||
#define MPT_CONSTEXPR14_VAR constexpr
|
||||
#else
|
||||
#define MPT_CONSTEXPR14_FUN MPT_FORCEINLINE
|
||||
#define MPT_CONSTEXPR14_VAR const
|
||||
#endif
|
||||
#if MPT_CXX_AT_LEAST(17) && !MPT_MSVC_BEFORE(2017,5)
|
||||
#define MPT_CONSTEXPR17_FUN constexpr MPT_FORCEINLINE
|
||||
#define MPT_CONSTEXPR17_VAR constexpr
|
||||
#else
|
||||
#define MPT_CONSTEXPR17_FUN MPT_FORCEINLINE
|
||||
#define MPT_CONSTEXPR17_VAR const
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// C++17 std::size
|
||||
#if MPT_CXX_AT_LEAST(17)
|
||||
namespace mpt {
|
||||
using std::size;
|
||||
} // namespace mpt
|
||||
#else
|
||||
namespace mpt {
|
||||
template <typename T>
|
||||
MPT_CONSTEXPR11_FUN auto size(const T & v) -> decltype(v.size())
|
||||
{
|
||||
return v.size();
|
||||
}
|
||||
template <typename T, std::size_t N>
|
||||
MPT_CONSTEXPR11_FUN std::size_t size(const T(&)[N]) noexcept
|
||||
{
|
||||
return N;
|
||||
}
|
||||
} // namespace mpt
|
||||
#endif
|
||||
// legacy
|
||||
#if MPT_COMPILER_MSVC
|
||||
OPENMPT_NAMESPACE_END
|
||||
#include <cstdlib>
|
||||
#include <stdlib.h>
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
#define MPT_ARRAY_COUNT(x) _countof(x)
|
||||
#else
|
||||
#define MPT_ARRAY_COUNT(x) (sizeof((x))/sizeof((x)[0]))
|
||||
#endif
|
||||
#define CountOf(x) MPT_ARRAY_COUNT(x)
|
||||
|
||||
|
||||
|
||||
// Use MPT_RESTRICT to indicate that a pointer is guaranteed to not be aliased.
|
||||
#if MPT_COMPILER_MSVC || MPT_COMPILER_GCC || MPT_COMPILER_CLANG
|
||||
#define MPT_RESTRICT __restrict
|
||||
#else
|
||||
#define MPT_RESTRICT
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// Some functions might be deprecated although they are still in use.
|
||||
// Tag them with "MPT_DEPRECATED".
|
||||
#if MPT_COMPILER_MSVC
|
||||
#define MPT_DEPRECATED __declspec(deprecated)
|
||||
#elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG
|
||||
#define MPT_DEPRECATED __attribute__((deprecated))
|
||||
#else
|
||||
#define MPT_DEPRECATED
|
||||
#endif
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
#define MPT_DEPRECATED_TRACKER MPT_DEPRECATED
|
||||
#define MPT_DEPRECATED_LIBOPENMPT
|
||||
#elif defined(LIBOPENMPT_BUILD)
|
||||
#define MPT_DEPRECATED_TRACKER
|
||||
#define MPT_DEPRECATED_LIBOPENMPT MPT_DEPRECATED
|
||||
#else
|
||||
#define MPT_DEPRECATED_TRACKER MPT_DEPRECATED
|
||||
#define MPT_DEPRECATED_LIBOPENMPT MPT_DEPRECATED
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if MPT_CXX_AT_LEAST(17)
|
||||
#define MPT_CONSTANT_IF if constexpr
|
||||
#endif
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
#if !defined(MPT_CONSTANT_IF)
|
||||
#define MPT_CONSTANT_IF(x) \
|
||||
__pragma(warning(push)) \
|
||||
__pragma(warning(disable:4127)) \
|
||||
if(x) \
|
||||
__pragma(warning(pop)) \
|
||||
/**/
|
||||
#endif
|
||||
#define MPT_MAYBE_CONSTANT_IF(x) \
|
||||
__pragma(warning(push)) \
|
||||
__pragma(warning(disable:4127)) \
|
||||
if(x) \
|
||||
__pragma(warning(pop)) \
|
||||
/**/
|
||||
#endif
|
||||
|
||||
#if MPT_COMPILER_GCC
|
||||
#define MPT_MAYBE_CONSTANT_IF(x) \
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wtype-limits\"") \
|
||||
if(x) \
|
||||
_Pragma("GCC diagnostic pop") \
|
||||
/**/
|
||||
#endif
|
||||
|
||||
#if MPT_COMPILER_CLANG
|
||||
#define MPT_MAYBE_CONSTANT_IF(x) \
|
||||
_Pragma("clang diagnostic push") \
|
||||
_Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") \
|
||||
_Pragma("clang diagnostic ignored \"-Wtype-limits\"") \
|
||||
_Pragma("clang diagnostic ignored \"-Wtautological-constant-out-of-range-compare\"") \
|
||||
if(x) \
|
||||
_Pragma("clang diagnostic pop") \
|
||||
/**/
|
||||
#endif
|
||||
|
||||
#if !defined(MPT_CONSTANT_IF)
|
||||
// MPT_CONSTANT_IF disables compiler warnings for conditions that are either always true or always false for some reason (dependent on template arguments for example)
|
||||
#define MPT_CONSTANT_IF(x) if(x)
|
||||
#endif
|
||||
|
||||
#if !defined(MPT_MAYBE_CONSTANT_IF)
|
||||
// MPT_MAYBE_CONSTANT_IF disables compiler warnings for conditions that may in some case be either always false or always true (this may turn out to be useful in ASSERTions in some cases).
|
||||
#define MPT_MAYBE_CONSTANT_IF(x) if(x)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
// MSVC warns for the well-known and widespread "do { } while(0)" idiom with warning level 4 ("conditional expression is constant").
|
||||
// It does not warn with "while(0,0)". However this again causes warnings with other compilers.
|
||||
// Solve it with a macro.
|
||||
#define MPT_DO do
|
||||
#define MPT_WHILE_0 while(0,0)
|
||||
#endif
|
||||
|
||||
#ifndef MPT_DO
|
||||
#define MPT_DO do
|
||||
#endif
|
||||
#ifndef MPT_WHILE_0
|
||||
#define MPT_WHILE_0 while(0)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if MPT_COMPILER_MSVC && defined(UNREFERENCED_PARAMETER)
|
||||
#define MPT_UNREFERENCED_PARAMETER(x) UNREFERENCED_PARAMETER(x)
|
||||
#else
|
||||
#define MPT_UNREFERENCED_PARAMETER(x) (void)(x)
|
||||
#endif
|
||||
|
||||
#define MPT_UNUSED_VARIABLE(x) MPT_UNREFERENCED_PARAMETER(x)
|
||||
|
||||
|
||||
|
||||
// Macro for marking intentional fall-throughs in switch statements - can be used for static analysis if supported.
|
||||
#if (MPT_CXX >= 17)
|
||||
#define MPT_FALLTHROUGH [[fallthrough]]
|
||||
#elif MPT_COMPILER_MSVC
|
||||
#define MPT_FALLTHROUGH __fallthrough
|
||||
#elif MPT_COMPILER_CLANG
|
||||
#define MPT_FALLTHROUGH [[clang::fallthrough]]
|
||||
#elif MPT_COMPILER_GCC && MPT_GCC_AT_LEAST(7,1,0)
|
||||
#define MPT_FALLTHROUGH __attribute__((fallthrough))
|
||||
#elif defined(__has_cpp_attribute)
|
||||
#if __has_cpp_attribute(fallthrough)
|
||||
#define MPT_FALLTHROUGH [[fallthrough]]
|
||||
#else
|
||||
#define MPT_FALLTHROUGH MPT_DO { } MPT_WHILE_0
|
||||
#endif
|
||||
#else
|
||||
#define MPT_FALLTHROUGH MPT_DO { } MPT_WHILE_0
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if MPT_COMPILER_GCC || MPT_COMPILER_CLANG
|
||||
#define MPT_PRINTF_FUNC(formatstringindex,varargsindex) __attribute__((format(printf, formatstringindex, varargsindex)))
|
||||
#else
|
||||
#define MPT_PRINTF_FUNC(formatstringindex,varargsindex)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
// warning LNK4221: no public symbols found; archive member will be inaccessible
|
||||
// There is no way to selectively disable linker warnings.
|
||||
// #pragma warning does not apply and a command line option does not exist.
|
||||
// Some options:
|
||||
// 1. Macro which generates a variable with a unique name for each file (which means we have to pass the filename to the macro)
|
||||
// 2. unnamed namespace containing any symbol (does not work for c++11 compilers because they actually have internal linkage now)
|
||||
// 3. An unused trivial inline function.
|
||||
// Option 3 does not actually solve the problem though, which leaves us with option 1.
|
||||
// In any case, for optimized builds, the linker will just remove the useless symbol.
|
||||
#define MPT_MSVC_WORKAROUND_LNK4221_CONCAT_DETAIL(x,y) x##y
|
||||
#define MPT_MSVC_WORKAROUND_LNK4221_CONCAT(x,y) MPT_MSVC_WORKAROUND_LNK4221_CONCAT_DETAIL(x,y)
|
||||
#define MPT_MSVC_WORKAROUND_LNK4221(x) int MPT_MSVC_WORKAROUND_LNK4221_CONCAT(mpt_msvc_workaround_lnk4221_,x) = 0;
|
||||
#endif
|
||||
|
||||
#ifndef MPT_MSVC_WORKAROUND_LNK4221
|
||||
#define MPT_MSVC_WORKAROUND_LNK4221(x)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
181
Frameworks/OpenMPT/OpenMPT/common/mptBaseTypes.h
Normal file
181
Frameworks/OpenMPT/OpenMPT/common/mptBaseTypes.h
Normal file
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* mptBaseTypes.h
|
||||
* --------------
|
||||
* Purpose: Basic data type definitions.
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
|
||||
|
||||
#include "mptBaseMacros.h"
|
||||
|
||||
#include <array>
|
||||
#include <limits>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#if MPT_GCC_BEFORE(4,9,0)
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
|
||||
typedef std::int8_t int8;
|
||||
typedef std::int16_t int16;
|
||||
typedef std::int32_t int32;
|
||||
typedef std::int64_t int64;
|
||||
typedef std::uint8_t uint8;
|
||||
typedef std::uint16_t uint16;
|
||||
typedef std::uint32_t uint32;
|
||||
typedef std::uint64_t uint64;
|
||||
|
||||
constexpr int8 int8_min = std::numeric_limits<int8>::min();
|
||||
constexpr int16 int16_min = std::numeric_limits<int16>::min();
|
||||
constexpr int32 int32_min = std::numeric_limits<int32>::min();
|
||||
constexpr int64 int64_min = std::numeric_limits<int64>::min();
|
||||
|
||||
constexpr int8 int8_max = std::numeric_limits<int8>::max();
|
||||
constexpr int16 int16_max = std::numeric_limits<int16>::max();
|
||||
constexpr int32 int32_max = std::numeric_limits<int32>::max();
|
||||
constexpr int64 int64_max = std::numeric_limits<int64>::max();
|
||||
|
||||
constexpr uint8 uint8_max = std::numeric_limits<uint8>::max();
|
||||
constexpr uint16 uint16_max = std::numeric_limits<uint16>::max();
|
||||
constexpr uint32 uint32_max = std::numeric_limits<uint32>::max();
|
||||
constexpr uint64 uint64_max = std::numeric_limits<uint64>::max();
|
||||
|
||||
|
||||
typedef float float32;
|
||||
MPT_STATIC_ASSERT(sizeof(float32) == 4);
|
||||
|
||||
typedef double float64;
|
||||
MPT_STATIC_ASSERT(sizeof(float64) == 8);
|
||||
|
||||
|
||||
MPT_STATIC_ASSERT(sizeof(std::uintptr_t) == sizeof(void*));
|
||||
|
||||
|
||||
MPT_STATIC_ASSERT(std::numeric_limits<unsigned char>::digits == 8);
|
||||
|
||||
MPT_STATIC_ASSERT(sizeof(char) == 1);
|
||||
|
||||
#if MPT_CXX_AT_LEAST(17)
|
||||
namespace mpt {
|
||||
using byte = std::byte;
|
||||
} // namespace mpt
|
||||
#define MPT_BYTE_IS_STD_BYTE 1
|
||||
#else
|
||||
// In C++11 and C++14, a C++17 compatible definition of byte would not be required to be allowed to alias other types,
|
||||
// thus just use a typedef for unsigned char which is guaranteed to be allowed to alias.
|
||||
//enum class byte : unsigned char { };
|
||||
namespace mpt {
|
||||
typedef unsigned char byte;
|
||||
} // namespace mpt
|
||||
#define MPT_BYTE_IS_STD_BYTE 0
|
||||
#endif
|
||||
MPT_STATIC_ASSERT(sizeof(mpt::byte) == 1);
|
||||
MPT_STATIC_ASSERT(alignof(mpt::byte) == 1);
|
||||
|
||||
|
||||
namespace mpt {
|
||||
#if MPT_GCC_BEFORE(4,9,0)
|
||||
typedef ::max_align_t max_align_t;
|
||||
#else
|
||||
typedef std::max_align_t max_align_t;
|
||||
#endif
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
namespace mpt {
|
||||
constexpr int arch_bits = sizeof(void*) * 8;
|
||||
constexpr std::size_t pointer_size = sizeof(void*);
|
||||
} // namespace mpt
|
||||
|
||||
MPT_STATIC_ASSERT(mpt::arch_bits == static_cast<int>(mpt::pointer_size) * 8);
|
||||
|
||||
|
||||
|
||||
namespace mpt {
|
||||
|
||||
template <typename T>
|
||||
struct limits
|
||||
{
|
||||
static constexpr typename std::remove_cv<T>::type min() noexcept { return std::numeric_limits<typename std::remove_cv<T>::type>::min(); }
|
||||
static constexpr typename std::remove_cv<T>::type max() noexcept { return std::numeric_limits<typename std::remove_cv<T>::type>::max(); }
|
||||
};
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
// compatible with std::experimental::source_location from Library Fundamentals TS v2.
|
||||
struct source_location
|
||||
{
|
||||
private:
|
||||
const char* m_file_name;
|
||||
const char* m_function_name;
|
||||
uint32 m_line;
|
||||
uint32 m_column;
|
||||
public:
|
||||
constexpr source_location() noexcept
|
||||
: m_file_name("")
|
||||
, m_function_name("")
|
||||
, m_line(0)
|
||||
, m_column(0)
|
||||
{
|
||||
}
|
||||
constexpr source_location(const char* file, const char* function, uint32 line, uint32 column) noexcept
|
||||
: m_file_name(file)
|
||||
, m_function_name(function)
|
||||
, m_line(line)
|
||||
, m_column(column)
|
||||
{
|
||||
}
|
||||
source_location(const source_location&) = default;
|
||||
source_location(source_location&&) = default;
|
||||
//static constexpr current() noexcept; // use MPT_SOURCE_LOCATION_CURRENT()
|
||||
static constexpr source_location current(const char* file, const char* function, uint32 line, uint32 column) noexcept
|
||||
{
|
||||
return source_location(file, function, line, column);
|
||||
}
|
||||
constexpr uint32 line() const noexcept
|
||||
{
|
||||
return m_line;
|
||||
}
|
||||
constexpr uint32 column() const noexcept
|
||||
{
|
||||
return m_column;
|
||||
}
|
||||
constexpr const char* file_name() const noexcept
|
||||
{
|
||||
return m_file_name;
|
||||
}
|
||||
constexpr const char* function_name() const noexcept
|
||||
{
|
||||
return m_function_name;
|
||||
}
|
||||
};
|
||||
|
||||
#define MPT_SOURCE_LOCATION_CURRENT() mpt::source_location::current( __FILE__ , __FUNCTION__ , __LINE__ , 0 )
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
734
Frameworks/OpenMPT/OpenMPT/common/mptBaseUtils.h
Normal file
734
Frameworks/OpenMPT/OpenMPT/common/mptBaseUtils.h
Normal file
|
@ -0,0 +1,734 @@
|
|||
/*
|
||||
* mptBaseUtils.h
|
||||
* --------------
|
||||
* Purpose: Various useful utility functions.
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
|
||||
#include "mptBaseMacros.h"
|
||||
#include "mptBaseTypes.h"
|
||||
|
||||
#include <algorithm>
|
||||
#if MPT_CXX_AT_LEAST(20)
|
||||
#include <bit>
|
||||
#endif
|
||||
#include <limits>
|
||||
#include <numeric>
|
||||
#include <utility>
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
|
||||
// cmath fixups
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
#ifndef M_PI_2
|
||||
#define M_PI_2 1.57079632679489661923
|
||||
#endif
|
||||
#ifndef M_LN2
|
||||
#define M_LN2 0.69314718055994530942
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
namespace mpt {
|
||||
|
||||
// GCC 4.5 and up provides templated overloads of std::abs that convert
|
||||
// integer type narrower than int to double.
|
||||
// This is fixed as of GCC 7.1.
|
||||
// As this is apparently valid by the current standard, Library Working Group
|
||||
// Issue #2735 has been filed (see
|
||||
// <https://cplusplus.github.io/LWG/lwg-defects.html#2735>).
|
||||
// In any case, avoid this insanity and provide our own mpt::abs implementation
|
||||
// for signed integer and floating point types.
|
||||
// Note: We stick to a C++98-style implementation only overloading int and
|
||||
// greater types in order to keep promotion rules consistent for narrower types,
|
||||
// which a templated version returning the argument type would not do. OpenMPT
|
||||
// probably assumes this semantic when calling abs(int8) in various places.
|
||||
inline int abs(int x)
|
||||
{
|
||||
return std::abs(x);
|
||||
}
|
||||
inline long abs(long x)
|
||||
{
|
||||
return std::abs(x);
|
||||
}
|
||||
inline long long abs(long long x)
|
||||
{
|
||||
return std::abs(x);
|
||||
}
|
||||
inline float abs(float x)
|
||||
{
|
||||
return std::fabs(x);
|
||||
}
|
||||
inline double abs(double x)
|
||||
{
|
||||
return std::fabs(x);
|
||||
}
|
||||
inline long double abs(long double x)
|
||||
{
|
||||
return std::fabs(x);
|
||||
}
|
||||
|
||||
// Modulo with more intuitive behaviour for some contexts:
|
||||
// Instead of being symmetrical around 0, the pattern for positive numbers is repeated in the negative range.
|
||||
// For example, wrapping_modulo(-1, m) == (m - 1).
|
||||
// Behaviour is undefined if m<=0.
|
||||
template<typename T, typename M>
|
||||
MPT_CONSTEXPR11_FUN auto wrapping_modulo(T x, M m) -> decltype(x % m)
|
||||
{
|
||||
return (x >= 0) ? (x % m) : (m - 1 - ((-1 - x) % m));
|
||||
}
|
||||
|
||||
template<typename T, typename D>
|
||||
MPT_CONSTEXPR11_FUN auto wrapping_divide(T x, D d) -> decltype(x / d)
|
||||
{
|
||||
return (x >= 0) ? (x / d) : (((x + 1) / d) - 1);
|
||||
}
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
namespace mpt {
|
||||
|
||||
|
||||
|
||||
// Saturate the value of src to the domain of Tdst
|
||||
template <typename Tdst, typename Tsrc>
|
||||
inline Tdst saturate_cast(Tsrc src)
|
||||
{
|
||||
// This code tries not only to obviously avoid overflows but also to avoid signed/unsigned comparison warnings and type truncation warnings (which in fact would be safe here) by explicit casting.
|
||||
STATIC_ASSERT(std::numeric_limits<Tdst>::is_integer);
|
||||
STATIC_ASSERT(std::numeric_limits<Tsrc>::is_integer);
|
||||
MPT_CONSTANT_IF(std::numeric_limits<Tdst>::is_signed && std::numeric_limits<Tsrc>::is_signed)
|
||||
{
|
||||
MPT_CONSTANT_IF(sizeof(Tdst) >= sizeof(Tsrc))
|
||||
{
|
||||
return static_cast<Tdst>(src);
|
||||
} else
|
||||
{
|
||||
return static_cast<Tdst>(std::max<Tsrc>(static_cast<Tsrc>(std::numeric_limits<Tdst>::min()), std::min<Tsrc>(src, static_cast<Tsrc>(std::numeric_limits<Tdst>::max()))));
|
||||
}
|
||||
} else MPT_CONSTANT_IF(!std::numeric_limits<Tdst>::is_signed && !std::numeric_limits<Tsrc>::is_signed)
|
||||
{
|
||||
MPT_CONSTANT_IF(sizeof(Tdst) >= sizeof(Tsrc))
|
||||
{
|
||||
return static_cast<Tdst>(src);
|
||||
} else
|
||||
{
|
||||
return static_cast<Tdst>(std::min<Tsrc>(src, static_cast<Tsrc>(std::numeric_limits<Tdst>::max())));
|
||||
}
|
||||
} else MPT_CONSTANT_IF(std::numeric_limits<Tdst>::is_signed && !std::numeric_limits<Tsrc>::is_signed)
|
||||
{
|
||||
MPT_CONSTANT_IF(sizeof(Tdst) > sizeof(Tsrc))
|
||||
{
|
||||
return static_cast<Tdst>(src);
|
||||
} else MPT_CONSTANT_IF(sizeof(Tdst) == sizeof(Tsrc))
|
||||
{
|
||||
return static_cast<Tdst>(std::min<Tsrc>(src, static_cast<Tsrc>(std::numeric_limits<Tdst>::max())));
|
||||
} else
|
||||
{
|
||||
return static_cast<Tdst>(std::min<Tsrc>(src, static_cast<Tsrc>(std::numeric_limits<Tdst>::max())));
|
||||
}
|
||||
} else // Tdst unsigned, Tsrc signed
|
||||
{
|
||||
MPT_CONSTANT_IF(sizeof(Tdst) >= sizeof(Tsrc))
|
||||
{
|
||||
return static_cast<Tdst>(std::max<Tsrc>(0, src));
|
||||
} else
|
||||
{
|
||||
return static_cast<Tdst>(std::max<Tsrc>(0, std::min<Tsrc>(src, static_cast<Tsrc>(std::numeric_limits<Tdst>::max()))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Tdst>
|
||||
inline Tdst saturate_cast(double src)
|
||||
{
|
||||
if(src >= std::numeric_limits<Tdst>::max())
|
||||
{
|
||||
return std::numeric_limits<Tdst>::max();
|
||||
}
|
||||
if(src <= std::numeric_limits<Tdst>::min())
|
||||
{
|
||||
return std::numeric_limits<Tdst>::min();
|
||||
}
|
||||
return static_cast<Tdst>(src);
|
||||
}
|
||||
|
||||
template <typename Tdst>
|
||||
inline Tdst saturate_cast(float src)
|
||||
{
|
||||
if(src >= std::numeric_limits<Tdst>::max())
|
||||
{
|
||||
return std::numeric_limits<Tdst>::max();
|
||||
}
|
||||
if(src <= std::numeric_limits<Tdst>::min())
|
||||
{
|
||||
return std::numeric_limits<Tdst>::min();
|
||||
}
|
||||
return static_cast<Tdst>(src);
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
MPT_CONSTEXPR14_FUN std::size_t weight(T val) noexcept
|
||||
{
|
||||
MPT_STATIC_ASSERT(std::numeric_limits<T>::is_integer);
|
||||
typedef typename std::make_unsigned<T>::type Tunsigned;
|
||||
Tunsigned uval = static_cast<Tunsigned>(val);
|
||||
std::size_t result = 0;
|
||||
while(uval > 0)
|
||||
{
|
||||
if(uval & 0x1)
|
||||
{
|
||||
result++;
|
||||
}
|
||||
uval >>= 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#if MPT_CXX_AT_LEAST(20)
|
||||
|
||||
using std::ispow2;
|
||||
using std::ceil2;
|
||||
using std::floor2;
|
||||
using std::log2p1;
|
||||
|
||||
#else
|
||||
|
||||
// C++20 <bit> header.
|
||||
// Note that we do not use SFINAE here but instead rely on static_assert.
|
||||
// Also note that for C++11 compilers, these functions are not constexpr.
|
||||
// They could be implemented recursively to make them C++11 constexpr compatible if needed.
|
||||
|
||||
template <typename T>
|
||||
MPT_CONSTEXPR14_FUN bool ispow2(T x) noexcept
|
||||
{
|
||||
MPT_STATIC_ASSERT(std::numeric_limits<T>::is_integer);
|
||||
MPT_STATIC_ASSERT(std::is_unsigned<T>::value);
|
||||
return mpt::weight(x) == 1;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
MPT_CONSTEXPR14_FUN T ceil2(T x) noexcept
|
||||
{
|
||||
MPT_STATIC_ASSERT(std::numeric_limits<T>::is_integer);
|
||||
MPT_STATIC_ASSERT(std::is_unsigned<T>::value);
|
||||
T result = 1;
|
||||
while(result < x)
|
||||
{
|
||||
T newresult = result << 1;
|
||||
if(newresult < result)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
result = newresult;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
MPT_CONSTEXPR14_FUN T floor2(T x) noexcept
|
||||
{
|
||||
MPT_STATIC_ASSERT(std::numeric_limits<T>::is_integer);
|
||||
MPT_STATIC_ASSERT(std::is_unsigned<T>::value);
|
||||
if(x == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
T result = 1;
|
||||
do
|
||||
{
|
||||
T newresult = result << 1;
|
||||
if(newresult < result)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
result = newresult;
|
||||
} while(result <= x);
|
||||
return result >> 1;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
MPT_CONSTEXPR14_FUN T log2p1(T x) noexcept
|
||||
{
|
||||
MPT_STATIC_ASSERT(std::numeric_limits<T>::is_integer);
|
||||
MPT_STATIC_ASSERT(std::is_unsigned<T>::value);
|
||||
T result = 0;
|
||||
while(x > 0)
|
||||
{
|
||||
x >>= 1;
|
||||
result += 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
// Tracker code requires MIN/MAX to work in constexpr contexts.
|
||||
// We could make MIN/MAX constexpr for supporting compilers,
|
||||
// but that would just needlessly complicate the support matrix
|
||||
// for now.
|
||||
#ifndef MPT_MINMAX_MACROS
|
||||
#define MPT_MINMAX_MACROS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
// MSVC disables a bunch of type conversion warnings once a macro is involved.
|
||||
// Replacing the macro with a template thus spews a TON OF WARNINGS for now.
|
||||
#ifndef MPT_MINMAX_MACROS
|
||||
#define MPT_MINMAX_MACROS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(MPT_MINMAX_MACROS)
|
||||
|
||||
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
|
||||
|
||||
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
#else
|
||||
|
||||
namespace mpt { namespace Legacy {
|
||||
|
||||
template <typename Ta, typename Tb>
|
||||
MPT_FORCEINLINE auto MAX(const Ta &a, const Tb &b) -> decltype((a>b)?a:b)
|
||||
{
|
||||
return (a > b) ? a : b;
|
||||
}
|
||||
|
||||
template <typename Ta, typename Tb>
|
||||
MPT_FORCEINLINE auto MIN(const Ta &a, const Tb &b) -> decltype((a<b)?a:b)
|
||||
{
|
||||
return (a < b) ? a : b;
|
||||
}
|
||||
|
||||
} } // namespace mpt::Legacy
|
||||
|
||||
using namespace mpt::Legacy;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
namespace Util
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <typename Tmod, Tmod m>
|
||||
struct ModIfNotZeroImpl
|
||||
{
|
||||
template <typename Tval>
|
||||
inline Tval mod(Tval x)
|
||||
{
|
||||
STATIC_ASSERT(std::numeric_limits<Tmod>::is_integer);
|
||||
STATIC_ASSERT(!std::numeric_limits<Tmod>::is_signed);
|
||||
STATIC_ASSERT(std::numeric_limits<Tval>::is_integer);
|
||||
STATIC_ASSERT(!std::numeric_limits<Tval>::is_signed);
|
||||
return static_cast<Tval>(x % m);
|
||||
}
|
||||
};
|
||||
template <> struct ModIfNotZeroImpl<uint8 , 0> { template <typename Tval> inline Tval mod(Tval x) { return x; } };
|
||||
template <> struct ModIfNotZeroImpl<uint16, 0> { template <typename Tval> inline Tval mod(Tval x) { return x; } };
|
||||
template <> struct ModIfNotZeroImpl<uint32, 0> { template <typename Tval> inline Tval mod(Tval x) { return x; } };
|
||||
template <> struct ModIfNotZeroImpl<uint64, 0> { template <typename Tval> inline Tval mod(Tval x) { return x; } };
|
||||
} // namespace detail
|
||||
// Returns x % m if m != 0, x otherwise.
|
||||
// i.e. "return (m == 0) ? x : (x % m);", but without causing a warning with stupid older compilers
|
||||
template <typename Tmod, Tmod m, typename Tval>
|
||||
inline Tval ModIfNotZero(Tval x)
|
||||
{
|
||||
return detail::ModIfNotZeroImpl<Tmod, m>().mod(x);
|
||||
}
|
||||
|
||||
// Returns true iff Tdst can represent the value val.
|
||||
// Use as if(Util::TypeCanHoldValue<uint8>(-1)).
|
||||
template <typename Tdst, typename Tsrc>
|
||||
inline bool TypeCanHoldValue(Tsrc val)
|
||||
{
|
||||
return (static_cast<Tsrc>(mpt::saturate_cast<Tdst>(val)) == val);
|
||||
}
|
||||
|
||||
// Grows x with an exponential factor suitable for increasing buffer sizes.
|
||||
// Clamps the result at limit.
|
||||
// And avoids integer overflows while doing its business.
|
||||
// The growth factor is 1.5, rounding down, execpt for the initial x==1 case.
|
||||
template <typename T, typename Tlimit>
|
||||
inline T ExponentialGrow(const T &x, const Tlimit &limit)
|
||||
{
|
||||
MPT_ASSERT(x > 0);
|
||||
MPT_ASSERT(limit > 0);
|
||||
if(x == 1)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
T add = std::min<T>(x >> 1, std::numeric_limits<T>::max() - x);
|
||||
return std::min<T>(x + add, mpt::saturate_cast<T>(limit));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T ExponentialGrow(const T &x)
|
||||
{
|
||||
return Util::ExponentialGrow(x, std::numeric_limits<T>::max());
|
||||
}
|
||||
|
||||
} //namespace Util
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
// C++17 clamp
|
||||
|
||||
#if MPT_CXX_AT_LEAST(17)
|
||||
|
||||
using std::clamp;
|
||||
|
||||
#else
|
||||
|
||||
template<typename T, typename Compare>
|
||||
MPT_CONSTEXPR11_FUN const T & clamp(const T & v, const T & lo, const T & hi, Compare comp)
|
||||
{
|
||||
return comp(v, lo) ? lo : comp(hi, v) ? hi : v;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
MPT_CONSTEXPR11_FUN const T & clamp(const T & v, const T & lo, const T & hi)
|
||||
{
|
||||
return mpt::clamp(v, lo, hi, std::less<T>());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
// Limits 'val' to given range. If 'val' is less than 'lowerLimit', 'val' is set to value 'lowerLimit'.
|
||||
// Similarly if 'val' is greater than 'upperLimit', 'val' is set to value 'upperLimit'.
|
||||
// If 'lowerLimit' > 'upperLimit', 'val' won't be modified.
|
||||
template<class T, class C>
|
||||
inline void Limit(T& val, const C lowerLimit, const C upperLimit)
|
||||
{
|
||||
if(lowerLimit > upperLimit) return;
|
||||
if(val < lowerLimit) val = lowerLimit;
|
||||
else if(val > upperLimit) val = upperLimit;
|
||||
}
|
||||
|
||||
|
||||
// Like Limit, but returns value
|
||||
template<class T, class C>
|
||||
inline T Clamp(T val, const C lowerLimit, const C upperLimit)
|
||||
{
|
||||
if(val < lowerLimit) return lowerLimit;
|
||||
else if(val > upperLimit) return upperLimit;
|
||||
else return val;
|
||||
}
|
||||
|
||||
// Check if val is in [lo,hi] without causing compiler warnings
|
||||
// if theses checks are always true due to the domain of T.
|
||||
// GCC does not warn if the type is templated.
|
||||
template<typename T, typename C>
|
||||
inline bool IsInRange(T val, C lo, C hi)
|
||||
{
|
||||
return lo <= val && val <= hi;
|
||||
}
|
||||
|
||||
// Like Limit, but with upperlimit only.
|
||||
template<class T, class C>
|
||||
inline void LimitMax(T& val, const C upperLimit)
|
||||
{
|
||||
if(val > upperLimit)
|
||||
val = upperLimit;
|
||||
}
|
||||
|
||||
|
||||
// Returns sign of a number (-1 for negative numbers, 1 for positive numbers, 0 for 0)
|
||||
template <class T>
|
||||
int sgn(T value)
|
||||
{
|
||||
return (value > T(0)) - (value < T(0));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// mpt::rshift_signed
|
||||
// mpt::lshift_signed
|
||||
// Shift a signed integer value in a well-defined manner.
|
||||
// Does the same thing as MSVC would do. This is verified by the test suite.
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
MPT_FORCEINLINE auto rshift_signed_standard(T x, int y) -> decltype(x >> y)
|
||||
{
|
||||
MPT_STATIC_ASSERT(std::numeric_limits<T>::is_integer);
|
||||
MPT_STATIC_ASSERT(std::numeric_limits<T>::is_signed);
|
||||
typedef decltype(x >> y) result_type;
|
||||
typedef typename std::make_unsigned<result_type>::type unsigned_result_type;
|
||||
const unsigned_result_type roffset = static_cast<unsigned_result_type>(1) << ((sizeof(result_type) * 8) - 1);
|
||||
result_type rx = x;
|
||||
unsigned_result_type urx = static_cast<unsigned_result_type>(rx);
|
||||
urx += roffset;
|
||||
urx >>= y;
|
||||
urx -= roffset >> y;
|
||||
return static_cast<result_type>(urx);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
MPT_FORCEINLINE auto lshift_signed_standard(T x, int y) -> decltype(x << y)
|
||||
{
|
||||
MPT_STATIC_ASSERT(std::numeric_limits<T>::is_integer);
|
||||
MPT_STATIC_ASSERT(std::numeric_limits<T>::is_signed);
|
||||
typedef decltype(x << y) result_type;
|
||||
typedef typename std::make_unsigned<result_type>::type unsigned_result_type;
|
||||
const unsigned_result_type roffset = static_cast<unsigned_result_type>(1) << ((sizeof(result_type) * 8) - 1);
|
||||
result_type rx = x;
|
||||
unsigned_result_type urx = static_cast<unsigned_result_type>(rx);
|
||||
urx += roffset;
|
||||
urx <<= y;
|
||||
urx -= roffset << y;
|
||||
return static_cast<result_type>(urx);
|
||||
}
|
||||
|
||||
#if MPT_COMPILER_SHIFT_SIGNED
|
||||
|
||||
template <typename T>
|
||||
MPT_FORCEINLINE auto rshift_signed_undefined(T x, int y) -> decltype(x >> y)
|
||||
{
|
||||
MPT_STATIC_ASSERT(std::numeric_limits<T>::is_integer);
|
||||
MPT_STATIC_ASSERT(std::numeric_limits<T>::is_signed);
|
||||
return x >> y;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
MPT_FORCEINLINE auto lshift_signed_undefined(T x, int y) -> decltype(x << y)
|
||||
{
|
||||
MPT_STATIC_ASSERT(std::numeric_limits<T>::is_integer);
|
||||
MPT_STATIC_ASSERT(std::numeric_limits<T>::is_signed);
|
||||
return x << y;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
MPT_FORCEINLINE auto rshift_signed(T x, int y) -> decltype(x >> y)
|
||||
{
|
||||
return mpt::rshift_signed_undefined(x, y);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
MPT_FORCEINLINE auto lshift_signed(T x, int y) -> decltype(x << y)
|
||||
{
|
||||
return mpt::lshift_signed_undefined(x, y);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template <typename T>
|
||||
MPT_FORCEINLINE auto rshift_signed(T x, int y) -> decltype(x >> y)
|
||||
{
|
||||
return mpt::rshift_signed_standard(x, y);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
MPT_FORCEINLINE auto lshift_signed(T x, int y) -> decltype(x << y)
|
||||
{
|
||||
return mpt::lshift_signed_standard(x, y);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
namespace Util
|
||||
{
|
||||
|
||||
// Returns maximum value of given integer type.
|
||||
template <class T> constexpr T MaxValueOfType(const T&) {static_assert(std::numeric_limits<T>::is_integer == true, "Only integer types are allowed."); return (std::numeric_limits<T>::max)();}
|
||||
|
||||
}
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
#if MPT_OS_DJGPP
|
||||
|
||||
inline double round(const double& val) { return ::round(val); }
|
||||
inline float round(const float& val) { return ::roundf(val); }
|
||||
|
||||
#else // !MPT_OS_DJGPP
|
||||
|
||||
// C++11 std::round
|
||||
using std::round;
|
||||
|
||||
#endif // MPT_OS_DJGPP
|
||||
|
||||
|
||||
// Rounds given double value to nearest integer value of type T.
|
||||
// Out-of-range values are saturated to the specified integer type's limits.
|
||||
template <class T> inline T saturate_round(double val)
|
||||
{
|
||||
static_assert(std::numeric_limits<T>::is_integer == true, "Type is a not an integer");
|
||||
return mpt::saturate_cast<T>(mpt::round(val));
|
||||
}
|
||||
|
||||
template <class T> inline T saturate_round(float val)
|
||||
{
|
||||
static_assert(std::numeric_limits<T>::is_integer == true, "Type is a not an integer");
|
||||
return mpt::saturate_cast<T>(mpt::round(val));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
namespace Util {
|
||||
|
||||
// Multiply two 32-bit integers, receive 64-bit result.
|
||||
// MSVC generates unnecessarily complicated code for the unoptimized variant using _allmul.
|
||||
MPT_FORCEINLINE int64 mul32to64(int32 a, int32 b)
|
||||
{
|
||||
#if MPT_COMPILER_MSVC && (defined(_M_IX86) || defined(_M_X64))
|
||||
return __emul(a, b);
|
||||
#else
|
||||
return static_cast<int64>(a) * b;
|
||||
#endif
|
||||
}
|
||||
|
||||
MPT_FORCEINLINE uint64 mul32to64_unsigned(uint32 a, uint32 b)
|
||||
{
|
||||
#if MPT_COMPILER_MSVC && (defined(_M_IX86) || defined(_M_X64))
|
||||
return __emulu(a, b);
|
||||
#else
|
||||
return static_cast<uint64>(a) * b;
|
||||
#endif
|
||||
}
|
||||
|
||||
MPT_FORCEINLINE int32 muldiv(int32 a, int32 b, int32 c)
|
||||
{
|
||||
return mpt::saturate_cast<int32>( mul32to64( a, b ) / c );
|
||||
}
|
||||
|
||||
MPT_FORCEINLINE int32 muldivr(int32 a, int32 b, int32 c)
|
||||
{
|
||||
return mpt::saturate_cast<int32>( ( mul32to64( a, b ) + ( c / 2 ) ) / c );
|
||||
}
|
||||
|
||||
// Do not use overloading because catching unsigned version by accident results in slower X86 code.
|
||||
MPT_FORCEINLINE uint32 muldiv_unsigned(uint32 a, uint32 b, uint32 c)
|
||||
{
|
||||
return mpt::saturate_cast<uint32>( mul32to64_unsigned( a, b ) / c );
|
||||
}
|
||||
MPT_FORCEINLINE uint32 muldivr_unsigned(uint32 a, uint32 b, uint32 c)
|
||||
{
|
||||
return mpt::saturate_cast<uint32>( ( mul32to64_unsigned( a, b ) + ( c / 2u ) ) / c );
|
||||
}
|
||||
|
||||
MPT_FORCEINLINE int32 muldivrfloor(int64 a, uint32 b, uint32 c)
|
||||
{
|
||||
a *= b;
|
||||
a += c / 2u;
|
||||
return (a >= 0) ? mpt::saturate_cast<int32>(a / c) : mpt::saturate_cast<int32>((a - (c - 1)) / c);
|
||||
}
|
||||
|
||||
// rounds x up to multiples of target
|
||||
template <typename T>
|
||||
inline T AlignUp(T x, T target)
|
||||
{
|
||||
return ((x + (target - 1)) / target) * target;
|
||||
}
|
||||
|
||||
// rounds x down to multiples of target
|
||||
template <typename T>
|
||||
inline T AlignDown(T x, T target)
|
||||
{
|
||||
return (x / target) * target;
|
||||
}
|
||||
|
||||
} // namespace Util
|
||||
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
#if MPT_CXX_AT_LEAST(17)
|
||||
|
||||
using std::gcd;
|
||||
using std::lcm;
|
||||
|
||||
#else
|
||||
|
||||
// Greatest Common Divisor. Always returns non-negative number.
|
||||
// compatible with C++17 std::gcd
|
||||
template <typename A, typename B>
|
||||
inline typename std::common_type<A, B>::type gcd(A a_, B b_)
|
||||
{
|
||||
typename std::common_type<A, B>::type a = a_;
|
||||
typename std::common_type<A, B>::type b = b_;
|
||||
if(a < 0)
|
||||
a = -a;
|
||||
if(b < 0)
|
||||
b = -b;
|
||||
for(;;)
|
||||
{
|
||||
if(a == 0)
|
||||
return b;
|
||||
b %= a;
|
||||
if(b == 0)
|
||||
return a;
|
||||
a %= b;
|
||||
}
|
||||
}
|
||||
|
||||
// Least Common Multiple. Always returns non-negative number.
|
||||
// compatible with C++17 std::lcm
|
||||
template <typename A, typename B>
|
||||
inline typename std::common_type<A, B>::type lcm(A a_, B b_)
|
||||
{
|
||||
typename std::common_type<A, B>::type a = a_;
|
||||
typename std::common_type<A, B>::type b = b_;
|
||||
if(a < 0)
|
||||
a = -a;
|
||||
if(b < 0)
|
||||
b = -b;
|
||||
if((a | b) == 0)
|
||||
return 0;
|
||||
return a / mpt::gcd(a, b) * b;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
#include <ios>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
|
@ -35,7 +37,7 @@ OPENMPT_NAMESPACE_BEGIN
|
|||
namespace mpt
|
||||
{
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
#ifdef MPT_COMPILER_QUIRK_MSVC_STRINGSTREAM
|
||||
|
||||
class stringbuf
|
||||
: public std::stringbuf
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#include "stdafx.h"
|
||||
#include "mptCPU.h"
|
||||
|
||||
#include "mptStringBuffer.h"
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
@ -21,6 +23,7 @@ OPENMPT_NAMESPACE_BEGIN
|
|||
uint32 RealProcSupport = 0;
|
||||
uint32 ProcSupport = 0;
|
||||
char ProcVendorID[16+1] = "";
|
||||
char ProcBrandID[4*4*3+1] = "";
|
||||
uint16 ProcFamily = 0;
|
||||
uint8 ProcModel = 0;
|
||||
uint8 ProcStepping = 0;
|
||||
|
@ -57,6 +60,27 @@ struct cpuid_result {
|
|||
result[8+3] = (c >>24) & 0xff;
|
||||
return std::string(result, result + 12);
|
||||
}
|
||||
std::string as_string4() const
|
||||
{
|
||||
std::string result;
|
||||
result.push_back(static_cast<uint8>((a >> 0) & 0xff));
|
||||
result.push_back(static_cast<uint8>((a >> 8) & 0xff));
|
||||
result.push_back(static_cast<uint8>((a >> 16) & 0xff));
|
||||
result.push_back(static_cast<uint8>((a >> 24) & 0xff));
|
||||
result.push_back(static_cast<uint8>((b >> 0) & 0xff));
|
||||
result.push_back(static_cast<uint8>((b >> 8) & 0xff));
|
||||
result.push_back(static_cast<uint8>((b >> 16) & 0xff));
|
||||
result.push_back(static_cast<uint8>((b >> 24) & 0xff));
|
||||
result.push_back(static_cast<uint8>((c >> 0) & 0xff));
|
||||
result.push_back(static_cast<uint8>((c >> 8) & 0xff));
|
||||
result.push_back(static_cast<uint8>((c >> 16) & 0xff));
|
||||
result.push_back(static_cast<uint8>((c >> 24) & 0xff));
|
||||
result.push_back(static_cast<uint8>((d >> 0) & 0xff));
|
||||
result.push_back(static_cast<uint8>((d >> 8) & 0xff));
|
||||
result.push_back(static_cast<uint8>((d >> 16) & 0xff));
|
||||
result.push_back(static_cast<uint8>((d >> 24) & 0xff));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -90,35 +114,21 @@ static cpuid_result cpuidex(uint32 function_a, uint32 function_c)
|
|||
#endif
|
||||
|
||||
|
||||
static MPT_NOINLINE bool has_cpuid()
|
||||
{
|
||||
const size_t eflags_cpuid = 1 << 21;
|
||||
size_t eflags_old = __readeflags();
|
||||
size_t eflags_flipped = eflags_old ^ eflags_cpuid;
|
||||
__writeeflags(eflags_flipped);
|
||||
size_t eflags_testchanged = __readeflags();
|
||||
__writeeflags(eflags_old);
|
||||
return ((eflags_testchanged ^ eflags_old) & eflags_cpuid) != 0;
|
||||
}
|
||||
|
||||
|
||||
void InitProcSupport()
|
||||
{
|
||||
|
||||
RealProcSupport = 0;
|
||||
ProcSupport = 0;
|
||||
MemsetZero(ProcVendorID);
|
||||
MemsetZero(ProcBrandID);
|
||||
ProcFamily = 0;
|
||||
ProcModel = 0;
|
||||
ProcStepping = 0;
|
||||
|
||||
if(has_cpuid())
|
||||
{
|
||||
|
||||
ProcSupport |= PROCSUPPORT_CPUID;
|
||||
|
||||
cpuid_result VendorString = cpuid(0x00000000u);
|
||||
std::strcpy(ProcVendorID, VendorString.as_string().c_str());
|
||||
mpt::String::WriteAutoBuf(ProcVendorID) = VendorString.as_string();
|
||||
|
||||
// Cyrix 6x86 and 6x86MX do not specify the value returned in eax.
|
||||
// They both support 0x00000001u however.
|
||||
|
@ -163,9 +173,7 @@ void InitProcSupport()
|
|||
ProcModel = static_cast<uint8>(BaseModel);
|
||||
}
|
||||
ProcStepping = static_cast<uint8>(Stepping);
|
||||
if(StandardFeatureFlags.d & (1<< 4)) ProcSupport |= PROCSUPPORT_TSC;
|
||||
if(StandardFeatureFlags.d & (1<<15)) ProcSupport |= PROCSUPPORT_CMOV;
|
||||
if(StandardFeatureFlags.d & (1<< 0)) ProcSupport |= PROCSUPPORT_FPU;
|
||||
if(StandardFeatureFlags.d & (1<<23)) ProcSupport |= PROCSUPPORT_MMX;
|
||||
if(StandardFeatureFlags.d & (1<<25)) ProcSupport |= PROCSUPPORT_SSE;
|
||||
if(StandardFeatureFlags.d & (1<<26)) ProcSupport |= PROCSUPPORT_SSE2;
|
||||
|
@ -175,6 +183,7 @@ void InitProcSupport()
|
|||
if(StandardFeatureFlags.c & (1<<20)) ProcSupport |= PROCSUPPORT_SSE4_2;
|
||||
}
|
||||
|
||||
bool canExtended = false;
|
||||
// 3DNow! manual recommends to just execute 0x80000000u.
|
||||
// It is totally unknown how earlier CPUs from other vendors
|
||||
// would behave.
|
||||
|
@ -182,25 +191,24 @@ void InitProcSupport()
|
|||
// that we found it documented for and that actually supports 3DNow!.
|
||||
// We only need 0x80000000u in order to detect 3DNow!.
|
||||
// Thus, this is enough for us.
|
||||
if((VendorString.as_string() == "AuthenticAMD") || (VendorString.as_string() == "AMDisbetter!"))
|
||||
if(VendorString.as_string() == "GenuineIntel")
|
||||
{ // Intel
|
||||
|
||||
// 5.9.x : Quark
|
||||
// 6.11.x: P3-S (Tualatin)
|
||||
if((ProcFamily > 6) || ((ProcFamily == 6) && (ProcModel >= 11)) || ((ProcFamily == 5) && (ProcModel >= 9)))
|
||||
{
|
||||
canExtended = true;
|
||||
}
|
||||
|
||||
} else if((VendorString.as_string() == "AuthenticAMD") || (VendorString.as_string() == "AMDisbetter!"))
|
||||
{ // AMD
|
||||
|
||||
if((ProcFamily > 5) || ((ProcFamily == 5) && (ProcModel >= 8)))
|
||||
{ // >= K6-2 (K6 = Family 5, K6-2 = Model 8)
|
||||
// Not sure if earlier AMD CPUs support 0x80000000u.
|
||||
// AMD 5k86 and AMD K5 manuals do not mention it.
|
||||
cpuid_result ExtendedVendorString = cpuid(0x80000000u);
|
||||
if(ExtendedVendorString.a >= 0x80000001u)
|
||||
{
|
||||
cpuid_result ExtendedFeatureFlags = cpuid(0x80000001u);
|
||||
if(ExtendedFeatureFlags.d & (1<< 4)) ProcSupport |= PROCSUPPORT_TSC;
|
||||
if(ExtendedFeatureFlags.d & (1<<15)) ProcSupport |= PROCSUPPORT_CMOV;
|
||||
if(ExtendedFeatureFlags.d & (1<< 0)) ProcSupport |= PROCSUPPORT_FPU;
|
||||
if(ExtendedFeatureFlags.d & (1<<23)) ProcSupport |= PROCSUPPORT_MMX;
|
||||
if(ExtendedFeatureFlags.d & (1<<22)) ProcSupport |= PROCSUPPORT_AMD_MMXEXT;
|
||||
if(ExtendedFeatureFlags.d & (1<<31)) ProcSupport |= PROCSUPPORT_AMD_3DNOW;
|
||||
if(ExtendedFeatureFlags.d & (1<<30)) ProcSupport |= PROCSUPPORT_AMD_3DNOWEXT;
|
||||
}
|
||||
canExtended = true;
|
||||
}
|
||||
|
||||
} else if(VendorString.as_string() == "CentaurHauls")
|
||||
|
@ -211,12 +219,7 @@ void InitProcSupport()
|
|||
|
||||
if(ProcModel >= 8)
|
||||
{ // >= WinChip 2
|
||||
cpuid_result ExtendedVendorString = cpuid(0x80000000u);
|
||||
if(ExtendedVendorString.a >= 0x80000001u)
|
||||
{
|
||||
cpuid_result ExtendedFeatureFlags = cpuid(0x80000001u);
|
||||
if(ExtendedFeatureFlags.d & (1<<31)) ProcSupport |= PROCSUPPORT_AMD_3DNOW;
|
||||
}
|
||||
canExtended = true;
|
||||
}
|
||||
|
||||
} else if(ProcFamily >= 6)
|
||||
|
@ -224,12 +227,7 @@ void InitProcSupport()
|
|||
|
||||
if((ProcFamily >= 7) || ((ProcFamily == 6) && (ProcModel >= 7)))
|
||||
{ // >= C3 Samuel 2
|
||||
cpuid_result ExtendedVendorString = cpuid(0x80000000u);
|
||||
if(ExtendedVendorString.a >= 0x80000001u)
|
||||
{
|
||||
cpuid_result ExtendedFeatureFlags = cpuid(0x80000001u);
|
||||
if(ExtendedFeatureFlags.d & (1<<31)) ProcSupport |= PROCSUPPORT_AMD_3DNOW;
|
||||
}
|
||||
canExtended = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -247,12 +245,7 @@ void InitProcSupport()
|
|||
|
||||
if((ProcFamily == 5) && (ProcModel >= 4))
|
||||
{ // Cyrix MediaGXm
|
||||
cpuid_result ExtendedVendorString = cpuid(0x80000000u);
|
||||
if(ExtendedVendorString.a >= 0x80000001u)
|
||||
{
|
||||
cpuid_result ExtendedFeatureFlags = cpuid(0x80000001u);
|
||||
if(ExtendedFeatureFlags.d & (1<<31)) ProcSupport |= PROCSUPPORT_AMD_3DNOW;
|
||||
}
|
||||
canExtended = true;
|
||||
}
|
||||
|
||||
} else if(VendorString.as_string() == "Geode by NSC")
|
||||
|
@ -260,25 +253,43 @@ void InitProcSupport()
|
|||
|
||||
if((ProcFamily > 5) || ((ProcFamily == 5) && (ProcModel >= 5)))
|
||||
{ // >= Geode GX2
|
||||
canExtended = true;
|
||||
}
|
||||
|
||||
} else
|
||||
{ // unknown, which nowadays most likely means some virtualized CPU
|
||||
|
||||
// we assume extended flags present in this case
|
||||
canExtended = true;
|
||||
|
||||
}
|
||||
|
||||
if(canExtended)
|
||||
{
|
||||
cpuid_result ExtendedVendorString = cpuid(0x80000000u);
|
||||
if(ExtendedVendorString.a >= 0x80000001u)
|
||||
{
|
||||
cpuid_result ExtendedFeatureFlags = cpuid(0x80000001u);
|
||||
if(ExtendedFeatureFlags.d & (1<<31)) ProcSupport |= PROCSUPPORT_AMD_3DNOW;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else
|
||||
if(ExtendedFeatureFlags.d & (1<<29)) ProcSupport |= PROCSUPPORT_LM;
|
||||
if((VendorString.as_string() == "AuthenticAMD") || (VendorString.as_string() == "AMDisbetter!"))
|
||||
{
|
||||
|
||||
ProcSupport |= PROCSUPPORT_FPU; // We assume FPU because we require it.
|
||||
if(ExtendedFeatureFlags.d & (1<<15)) ProcSupport |= PROCSUPPORT_CMOV;
|
||||
if(ExtendedFeatureFlags.d & (1<<23)) ProcSupport |= PROCSUPPORT_MMX;
|
||||
}
|
||||
if(ExtendedFeatureFlags.d & (1<<22)) ProcSupport |= PROCSUPPORT_AMD_MMXEXT;
|
||||
if(ExtendedFeatureFlags.d & (1<<31)) ProcSupport |= PROCSUPPORT_AMD_3DNOW;
|
||||
if(ExtendedFeatureFlags.d & (1<<30)) ProcSupport |= PROCSUPPORT_AMD_3DNOWEXT;
|
||||
}
|
||||
if(ExtendedVendorString.a >= 0x80000004u)
|
||||
{
|
||||
mpt::String::WriteAutoBuf(ProcBrandID) = cpuid(0x80000002u).as_string4() + cpuid(0x80000003u).as_string4() + cpuid(0x80000004u).as_string4();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// We do not have to check if SSE got enabled by the OS because we only do
|
||||
// support Windows >= 98 SE which will always enable SSE if available.
|
||||
// support Windows >= XP. Windows will always enable SSE since Windows 98 SE.
|
||||
|
||||
RealProcSupport = ProcSupport;
|
||||
|
||||
|
|
|
@ -10,16 +10,16 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
#ifdef ENABLE_ASM
|
||||
|
||||
#define PROCSUPPORT_CPUID 0x00001 // Processor supports CPUID instruction (i586)
|
||||
#define PROCSUPPORT_TSC 0x00002 // Processor supports RDTSC instruction (i586)
|
||||
#define PROCSUPPORT_LM 0x00001 // Processor supports long mode (amd64)
|
||||
#define PROCSUPPORT_CMOV 0x00004 // Processor supports conditional move instructions (i686)
|
||||
#define PROCSUPPORT_FPU 0x00008 // Processor supports x87 instructions
|
||||
#define PROCSUPPORT_MMX 0x00010 // Processor supports MMX instructions
|
||||
#define PROCSUPPORT_AMD_MMXEXT 0x00020 // Processor supports AMD MMX extensions
|
||||
#define PROCSUPPORT_AMD_3DNOW 0x00040 // Processor supports AMD 3DNow! instructions
|
||||
|
@ -31,16 +31,16 @@ OPENMPT_NAMESPACE_BEGIN
|
|||
#define PROCSUPPORT_SSE4_1 0x01000 // Processor supports SSE4.1 instructions
|
||||
#define PROCSUPPORT_SSE4_2 0x02000 // Processor supports SSE4.2 instructions
|
||||
|
||||
static const uint32 PROCSUPPORT_i486 = 0u | PROCSUPPORT_FPU ;
|
||||
static const uint32 PROCSUPPORT_i586 = 0u | PROCSUPPORT_CPUID | PROCSUPPORT_FPU ;
|
||||
static const uint32 PROCSUPPORT_i686 = 0u | PROCSUPPORT_CPUID | PROCSUPPORT_CMOV | PROCSUPPORT_FPU ;
|
||||
static const uint32 PROCSUPPORT_x86_SSE = 0u | PROCSUPPORT_CPUID | PROCSUPPORT_CMOV | PROCSUPPORT_FPU | PROCSUPPORT_SSE ;
|
||||
static const uint32 PROCSUPPORT_x86_SSE2 = 0u | PROCSUPPORT_CPUID | PROCSUPPORT_CMOV | PROCSUPPORT_FPU | PROCSUPPORT_SSE | PROCSUPPORT_SSE2;
|
||||
static const uint32 PROCSUPPORT_AMD64 = 0u | PROCSUPPORT_CPUID | PROCSUPPORT_CMOV | PROCSUPPORT_SSE | PROCSUPPORT_SSE2;
|
||||
static const uint32 PROCSUPPORT_i586 = 0u ;
|
||||
static const uint32 PROCSUPPORT_i686 = 0u | PROCSUPPORT_CMOV ;
|
||||
static const uint32 PROCSUPPORT_x86_SSE = 0u | PROCSUPPORT_CMOV | PROCSUPPORT_SSE ;
|
||||
static const uint32 PROCSUPPORT_x86_SSE2 = 0u | PROCSUPPORT_CMOV | PROCSUPPORT_SSE | PROCSUPPORT_SSE2 ;
|
||||
static const uint32 PROCSUPPORT_AMD64 = 0u | PROCSUPPORT_CMOV | PROCSUPPORT_SSE | PROCSUPPORT_SSE2 | PROCSUPPORT_LM;
|
||||
|
||||
extern uint32 RealProcSupport;
|
||||
extern uint32 ProcSupport;
|
||||
extern char ProcVendorID[16+1];
|
||||
extern char ProcBrandID[4*4*3+1];
|
||||
extern uint16 ProcFamily;
|
||||
extern uint8 ProcModel;
|
||||
extern uint8 ProcStepping;
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
namespace mpt
|
||||
|
@ -27,9 +29,9 @@ public:
|
|||
typedef T value_type;
|
||||
typedef uint8 byte_type;
|
||||
|
||||
static const std::size_t size_bytes = sizeof(value_type);
|
||||
static const std::size_t size_bits = sizeof(value_type) * 8;
|
||||
static const value_type top_bit = static_cast<value_type>(1) << ((sizeof(value_type) * 8) - 1);
|
||||
enum : std::size_t { size_bytes = sizeof(value_type) };
|
||||
enum : std::size_t { size_bits = sizeof(value_type) * 8 };
|
||||
enum : value_type { top_bit = static_cast<value_type>(1) << ((sizeof(value_type) * 8) - 1) };
|
||||
|
||||
private:
|
||||
|
||||
|
@ -134,7 +136,7 @@ public:
|
|||
|
||||
inline crc & process(char c)
|
||||
{
|
||||
processByte(static_cast<byte_type>(c));
|
||||
processByte(mpt::byte_cast<byte_type>(c));
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -146,10 +148,18 @@ public:
|
|||
|
||||
inline crc & process(unsigned char c)
|
||||
{
|
||||
processByte(static_cast<byte_type>(c));
|
||||
processByte(mpt::byte_cast<byte_type>(c));
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if MPT_BYTE_IS_STD_BYTE
|
||||
inline crc & process(mpt::byte c)
|
||||
{
|
||||
processByte(mpt::byte_cast<byte_type>(c));
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename InputIt>
|
||||
crc & process(InputIt beg, InputIt end)
|
||||
{
|
||||
|
@ -170,7 +180,7 @@ public:
|
|||
|
||||
inline crc & operator () (char c)
|
||||
{
|
||||
processByte(static_cast<byte_type>(c));
|
||||
processByte(mpt::byte_cast<byte_type>(c));
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -182,10 +192,18 @@ public:
|
|||
|
||||
inline crc & operator () (unsigned char c)
|
||||
{
|
||||
processByte(static_cast<byte_type>(c));
|
||||
processByte(mpt::byte_cast<byte_type>(c));
|
||||
return *this;
|
||||
}
|
||||
|
||||
#if MPT_BYTE_IS_STD_BYTE
|
||||
inline crc & operator () (mpt::byte c)
|
||||
{
|
||||
processByte(mpt::byte_cast<byte_type>(c));
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename InputIt>
|
||||
crc & operator () (InputIt beg, InputIt end)
|
||||
{
|
||||
|
|
56
Frameworks/OpenMPT/OpenMPT/common/mptException.h
Normal file
56
Frameworks/OpenMPT/OpenMPT/common/mptException.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* mptException.h
|
||||
* --------------
|
||||
* Purpose: Exception abstraction, in particular for bad_alloc.
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
|
||||
|
||||
#include "mptBaseMacros.h"
|
||||
|
||||
#include <exception>
|
||||
#if !defined(_MFC_VER)
|
||||
#include <new>
|
||||
#endif // !_MFC_VER
|
||||
|
||||
#if defined(_MFC_VER)
|
||||
// cppcheck-suppress missingInclude
|
||||
#include <afx.h>
|
||||
#endif // _MFC_VER
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
|
||||
// Exception handling helpers, because MFC requires explicit deletion of the exception object,
|
||||
// Thus, always call exactly one of MPT_EXCEPTION_RETHROW_OUT_OF_MEMORY() or MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e).
|
||||
|
||||
#if defined(_MFC_VER)
|
||||
|
||||
#define MPT_EXCEPTION_THROW_OUT_OF_MEMORY() MPT_DO { AfxThrowMemoryException(); } MPT_WHILE_0
|
||||
#define MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e) catch ( CMemoryException * e )
|
||||
#define MPT_EXCEPTION_RETHROW_OUT_OF_MEMORY(e) MPT_DO { MPT_UNUSED_VARIABLE(e); throw; } MPT_WHILE_0
|
||||
#define MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e) MPT_DO { if(e) { e->Delete(); e = nullptr; } } MPT_WHILE_0
|
||||
|
||||
#else // !_MFC_VER
|
||||
|
||||
#define MPT_EXCEPTION_THROW_OUT_OF_MEMORY() MPT_DO { throw std::bad_alloc(); } MPT_WHILE_0
|
||||
#define MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e) catch ( const std::bad_alloc & e )
|
||||
#define MPT_EXCEPTION_RETHROW_OUT_OF_MEMORY(e) MPT_DO { MPT_UNUSED_VARIABLE(e); throw; } MPT_WHILE_0
|
||||
#define MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e) MPT_DO { MPT_UNUSED_VARIABLE(e); } MPT_WHILE_0
|
||||
|
||||
#endif // _MFC_VER
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
76
Frameworks/OpenMPT/OpenMPT/common/mptExceptionText.h
Normal file
76
Frameworks/OpenMPT/OpenMPT/common/mptExceptionText.h
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* mptExceptionText.h
|
||||
* ------------------
|
||||
* Purpose: Guess encoding of exception string
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
|
||||
|
||||
#include "mptException.h"
|
||||
#include "mptString.h"
|
||||
|
||||
#include <exception>
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
template <typename T> T get_exception_text_impl(const std::exception & e) noexcept
|
||||
{
|
||||
if(e.what() && (std::strlen(e.what()) > 0))
|
||||
{
|
||||
return T(e.what());
|
||||
} else if(typeid(e).name() && (std::strlen(typeid(e).name()) > 0))
|
||||
{
|
||||
return T(typeid(e).name());
|
||||
} else
|
||||
{
|
||||
return T("unknown exception");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> inline T get_exception_text(const std::exception & e) noexcept
|
||||
{
|
||||
return mpt::get_exception_text_impl<T>(e);
|
||||
}
|
||||
template <> inline std::string get_exception_text<std::string>(const std::exception & e) noexcept
|
||||
{
|
||||
return mpt::get_exception_text_impl<std::string>(e);
|
||||
}
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
template <> inline mpt::lstring get_exception_text<mpt::lstring>(const std::exception & e) noexcept
|
||||
{
|
||||
return mpt::ToLocale(mpt::CharsetLocaleOrUTF8, mpt::get_exception_text_impl<std::string>(e));
|
||||
}
|
||||
#endif
|
||||
#if MPT_WSTRING_FORMAT
|
||||
template <> inline std::wstring get_exception_text<std::wstring>(const std::exception & e) noexcept
|
||||
{
|
||||
return mpt::ToWide(mpt::CharsetLocaleOrUTF8, mpt::get_exception_text_impl<std::string>(e));
|
||||
}
|
||||
#endif
|
||||
#if MPT_USTRING_MODE_UTF8
|
||||
template <> inline mpt::ustring get_exception_text<mpt::ustring>(const std::exception & e) noexcept
|
||||
{
|
||||
return mpt::ToUnicode(mpt::CharsetLocaleOrUTF8, mpt::get_exception_text_impl<std::string>(e));
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -18,6 +18,12 @@
|
|||
#endif // MPT_OS_WINDOWS
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
#if defined(MPT_ENABLE_FILEIO)
|
||||
#if MPT_COMPILER_MSVC
|
||||
#include <tchar.h>
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
#endif // MPT_ENABLE_FILEIO
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
@ -37,7 +43,7 @@ bool SetFilesystemCompression(HANDLE hFile)
|
|||
USHORT format = COMPRESSION_FORMAT_DEFAULT;
|
||||
DWORD dummy = 0;
|
||||
BOOL result = DeviceIoControl(hFile, FSCTL_SET_COMPRESSION, (LPVOID)&format, sizeof(format), NULL, 0, &dummy /*required*/ , NULL);
|
||||
return result ? true : false;
|
||||
return result != FALSE;
|
||||
}
|
||||
bool SetFilesystemCompression(int fd)
|
||||
{
|
||||
|
@ -53,24 +59,9 @@ bool SetFilesystemCompression(int fd)
|
|||
}
|
||||
return SetFilesystemCompression(hFile);
|
||||
}
|
||||
#if defined(MPT_ENABLE_FILEIO_STDIO)
|
||||
bool SetFilesystemCompression(FILE *file)
|
||||
{
|
||||
if(!file)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int fd = _fileno(file);
|
||||
if(fd == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return SetFilesystemCompression(fd);
|
||||
}
|
||||
#endif // MPT_ENABLE_FILEIO_STDIO
|
||||
bool SetFilesystemCompression(const mpt::PathString &filename)
|
||||
{
|
||||
DWORD attributes = GetFileAttributesW(filename.AsNativePrefixed().c_str());
|
||||
DWORD attributes = GetFileAttributes(filename.AsNativePrefixed().c_str());
|
||||
if(attributes == INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
return false;
|
||||
|
@ -79,14 +70,13 @@ bool SetFilesystemCompression(const mpt::PathString &filename)
|
|||
{
|
||||
return true;
|
||||
}
|
||||
HANDLE hFile = CreateFileW(filename.AsNativePrefixed().c_str(), GENERIC_ALL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
||||
HANDLE hFile = CreateFile(filename.AsNativePrefixed().c_str(), GENERIC_ALL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
||||
if(hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool result = SetFilesystemCompression(hFile);
|
||||
CloseHandle(hFile);
|
||||
hFile = INVALID_HANDLE_VALUE;
|
||||
return result;
|
||||
}
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
@ -94,6 +84,163 @@ bool SetFilesystemCompression(const mpt::PathString &filename)
|
|||
|
||||
|
||||
|
||||
#ifdef MODPLUG_TRACKER
|
||||
|
||||
namespace mpt {
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
|
||||
mpt::tstring SafeOutputFile::convert_mode(std::ios_base::openmode mode, FlushMode flushMode)
|
||||
{
|
||||
mpt::tstring fopen_mode;
|
||||
switch(mode & ~(std::ios_base::ate | std::ios_base::binary))
|
||||
{
|
||||
case std::ios_base::in:
|
||||
fopen_mode = _T("r");
|
||||
break;
|
||||
case std::ios_base::out:
|
||||
MPT_FALLTHROUGH;
|
||||
case std::ios_base::out | std::ios_base::trunc:
|
||||
fopen_mode = _T("w");
|
||||
break;
|
||||
case std::ios_base::app:
|
||||
MPT_FALLTHROUGH;
|
||||
case std::ios_base::out | std::ios_base::app:
|
||||
fopen_mode = _T("a");
|
||||
break;
|
||||
case std::ios_base::out | std::ios_base::in:
|
||||
fopen_mode = _T("r+");
|
||||
break;
|
||||
case std::ios_base::out | std::ios_base::in | std::ios_base::trunc:
|
||||
fopen_mode = _T("w+");
|
||||
break;
|
||||
case std::ios_base::out | std::ios_base::in | std::ios_base::app:
|
||||
MPT_FALLTHROUGH;
|
||||
case std::ios_base::in | std::ios_base::app:
|
||||
fopen_mode = _T("a+");
|
||||
break;
|
||||
}
|
||||
if(fopen_mode.empty())
|
||||
{
|
||||
return fopen_mode;
|
||||
}
|
||||
if(mode & std::ios_base::binary)
|
||||
{
|
||||
fopen_mode += _T("b");
|
||||
}
|
||||
if(flushMode == FlushMode::Full)
|
||||
{
|
||||
fopen_mode += _T("c"); // force commit on fflush (MSVC specific)
|
||||
}
|
||||
return fopen_mode;
|
||||
}
|
||||
|
||||
FILE * SafeOutputFile::internal_fopen(const mpt::PathString &filename, std::ios_base::openmode mode, FlushMode flushMode)
|
||||
{
|
||||
mpt::tstring fopen_mode = convert_mode(mode, flushMode);
|
||||
if(fopen_mode.empty())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
FILE *f =
|
||||
#ifdef UNICODE
|
||||
_wfopen(filename.AsNativePrefixed().c_str(), fopen_mode.c_str())
|
||||
#else
|
||||
fopen(filename.AsNativePrefixed().c_str(), fopen_mode.c_str())
|
||||
#endif
|
||||
;
|
||||
if(!f)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
if(mode & std::ios_base::ate)
|
||||
{
|
||||
if(fseek(f, 0, SEEK_END) != 0)
|
||||
{
|
||||
fclose(f);
|
||||
f = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
m_f = f;
|
||||
return f;
|
||||
}
|
||||
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
|
||||
// cppcheck-suppress exceptThrowInDestructor
|
||||
SafeOutputFile::~SafeOutputFile() noexcept(false)
|
||||
{
|
||||
if(!stream())
|
||||
{
|
||||
return;
|
||||
}
|
||||
if(!stream().rdbuf())
|
||||
{
|
||||
return;
|
||||
}
|
||||
#if MPT_COMPILER_MSVC
|
||||
if(!m_f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
bool errorOnFlush = false;
|
||||
if(m_FlushMode != FlushMode::None)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(stream().rdbuf()->pubsync() != 0)
|
||||
{
|
||||
errorOnFlush = true;
|
||||
}
|
||||
} catch(const std::exception &)
|
||||
{
|
||||
errorOnFlush = true;
|
||||
#if MPT_COMPILER_MSVC
|
||||
if(m_FlushMode != FlushMode::None)
|
||||
{
|
||||
if(fflush(m_f) != 0)
|
||||
{
|
||||
errorOnFlush = true;
|
||||
}
|
||||
}
|
||||
if(fclose(m_f) != 0)
|
||||
{
|
||||
errorOnFlush = true;
|
||||
}
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
// ignore errorOnFlush here, and re-throw the earlier exception
|
||||
throw;
|
||||
}
|
||||
}
|
||||
#if MPT_COMPILER_MSVC
|
||||
if(m_FlushMode != FlushMode::None)
|
||||
{
|
||||
if(fflush(m_f) != 0)
|
||||
{
|
||||
errorOnFlush = true;
|
||||
}
|
||||
}
|
||||
if(fclose(m_f) != 0)
|
||||
{
|
||||
errorOnFlush = true;
|
||||
}
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
if(errorOnFlush && (stream().exceptions() & (std::ios::badbit | std::ios::failbit)))
|
||||
{
|
||||
throw std::ios_base::failure(std::string("Error flushing file buffers."));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
|
||||
#ifdef MODPLUG_TRACKER
|
||||
|
||||
namespace mpt {
|
||||
|
||||
LazyFileRef & LazyFileRef::operator = (const std::vector<mpt::byte> &data)
|
||||
|
@ -170,6 +317,8 @@ LazyFileRef::operator std::string () const
|
|||
|
||||
} // namespace mpt
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
|
||||
#ifdef MODPLUG_TRACKER
|
||||
|
@ -184,7 +333,7 @@ CMappedFile::~CMappedFile()
|
|||
|
||||
bool CMappedFile::Open(const mpt::PathString &filename)
|
||||
{
|
||||
m_hFile = CreateFileW(
|
||||
m_hFile = CreateFile(
|
||||
filename.AsNativePrefixed().c_str(),
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* mptFileIO.h
|
||||
* -----------
|
||||
* Purpose: A wrapper around std::fstream, fixing VS2008 charset conversion braindamage, and enforcing usage of mpt::PathString.
|
||||
* Purpose: A wrapper around std::fstream, enforcing usage of mpt::PathString.
|
||||
* Notes : You should only ever use these wrappers instead of plain std::fstream classes.
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
|
@ -9,6 +9,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
#if defined(MPT_ENABLE_FILEIO)
|
||||
|
||||
#include "../common/mptString.h"
|
||||
|
@ -21,6 +23,14 @@
|
|||
#include <streambuf>
|
||||
#include <utility>
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
#include <cstdio>
|
||||
#endif // !MPT_COMPILER_MSVC
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
#include <stdio.h>
|
||||
#endif // !MPT_COMPILER_MSVC
|
||||
|
||||
#endif // MPT_ENABLE_FILEIO
|
||||
|
||||
|
||||
|
@ -30,20 +40,6 @@ OPENMPT_NAMESPACE_BEGIN
|
|||
#if defined(MPT_ENABLE_FILEIO)
|
||||
|
||||
|
||||
#if defined(MPT_ENABLE_FILEIO_STDIO)
|
||||
|
||||
static inline FILE * mpt_fopen(const mpt::PathString &filename, const char *mode)
|
||||
{
|
||||
#if MPT_OS_WINDOWS
|
||||
return _wfopen(filename.AsNativePrefixed().c_str(), mode ? mpt::ToWide(mpt::CharsetASCII, mode).c_str() : L"");
|
||||
#else // !MPT_OS_WINDOWS
|
||||
return fopen(filename.AsNative().c_str(), mode);
|
||||
#endif // MPT_OS_WINDOWS
|
||||
}
|
||||
|
||||
#endif // MPT_ENABLE_FILEIO_STDIO
|
||||
|
||||
|
||||
// Sets the NTFS compression attribute on the file or directory.
|
||||
// Requires read and write permissions for already opened files.
|
||||
// Returns true if the attribute has been set.
|
||||
|
@ -52,9 +48,6 @@ static inline FILE * mpt_fopen(const mpt::PathString &filename, const char *mode
|
|||
#if MPT_OS_WINDOWS
|
||||
bool SetFilesystemCompression(HANDLE hFile);
|
||||
bool SetFilesystemCompression(int fd);
|
||||
#if defined(MPT_ENABLE_FILEIO_STDIO)
|
||||
bool SetFilesystemCompression(FILE *file);
|
||||
#endif // MPT_ENABLE_FILEIO_STDIO
|
||||
bool SetFilesystemCompression(const mpt::PathString &filename);
|
||||
#endif // MPT_OS_WINDOWS
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
@ -63,22 +56,11 @@ bool SetFilesystemCompression(const mpt::PathString &filename);
|
|||
namespace mpt
|
||||
{
|
||||
|
||||
#if MPT_COMPILER_GCC
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
#if MPT_COMPILER_GCC && MPT_OS_WINDOWS
|
||||
// GCC C++ library has no wchar_t overloads
|
||||
#define MPT_FSTREAM_DO_CONVERSIONS
|
||||
#define MPT_FSTREAM_DO_CONVERSIONS_ANSI
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef MPT_FSTREAM_DO_CONVERSIONS
|
||||
#define MPT_FSTREAM_OPEN(filename, mode) detail::fstream_open<Tbase>(*this, (filename), (mode))
|
||||
#else
|
||||
#define MPT_FSTREAM_OPEN(filename, mode) Tbase::open((filename), (mode))
|
||||
#endif
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
|
@ -92,41 +74,17 @@ inline void fstream_open(Tbase & base, const mpt::PathString & filename, std::io
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef MPT_FSTREAM_DO_CONVERSIONS
|
||||
|
||||
template<typename Tbase>
|
||||
inline void fstream_open(Tbase & base, const std::wstring & filename, std::ios_base::openmode mode)
|
||||
{
|
||||
detail::fstream_open<Tbase>(base, mpt::PathString::FromWide(filename), mode);
|
||||
}
|
||||
|
||||
template<typename Tbase>
|
||||
inline void fstream_open(Tbase & base, const wchar_t * filename, std::ios_base::openmode mode)
|
||||
{
|
||||
detail::fstream_open<Tbase>(base, mpt::PathString::FromWide(filename ? std::wstring(filename) : std::wstring()), mode);
|
||||
}
|
||||
|
||||
template<typename Tbase>
|
||||
inline void fstream_open(Tbase & base, const std::string & filename, std::ios_base::openmode mode)
|
||||
{
|
||||
detail::fstream_open<Tbase>(base, mpt::PathString::FromWide(mpt::ToWide(mpt::CharsetLocale, filename)), mode);
|
||||
}
|
||||
|
||||
template<typename Tbase>
|
||||
inline void fstream_open(Tbase & base, const char * filename, std::ios_base::openmode mode)
|
||||
{
|
||||
detail::fstream_open<Tbase>(base, mpt::PathString::FromWide(mpt::ToWide(mpt::CharsetLocale, filename ? std::string(filename) : std::string())), mode);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace detail
|
||||
|
||||
class SafeOutputFile;
|
||||
|
||||
class fstream
|
||||
: public std::fstream
|
||||
{
|
||||
private:
|
||||
typedef std::fstream Tbase;
|
||||
public:
|
||||
friend SafeOutputFile;
|
||||
public:
|
||||
fstream() {}
|
||||
fstream(const mpt::PathString & filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out)
|
||||
|
@ -137,23 +95,11 @@ public:
|
|||
{
|
||||
detail::fstream_open<Tbase>(*this, filename, mode);
|
||||
}
|
||||
MPT_DEPRECATED_PATH void open(const char * filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out)
|
||||
{
|
||||
MPT_FSTREAM_OPEN(filename, mode);
|
||||
}
|
||||
MPT_DEPRECATED_PATH void open(const std::string & filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out)
|
||||
{
|
||||
MPT_FSTREAM_OPEN(filename.c_str(), mode);
|
||||
}
|
||||
void open(const char * filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) = delete;
|
||||
void open(const std::string & filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) = delete;
|
||||
#if MPT_OS_WINDOWS
|
||||
MPT_DEPRECATED_PATH void open(const wchar_t * filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out)
|
||||
{
|
||||
MPT_FSTREAM_OPEN(filename, mode);
|
||||
}
|
||||
MPT_DEPRECATED_PATH void open(const std::wstring & filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out)
|
||||
{
|
||||
MPT_FSTREAM_OPEN(filename.c_str(), mode);
|
||||
}
|
||||
void open(const wchar_t * filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) = delete;
|
||||
void open(const std::wstring & filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out) = delete;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -162,6 +108,8 @@ class ifstream
|
|||
{
|
||||
private:
|
||||
typedef std::ifstream Tbase;
|
||||
public:
|
||||
friend SafeOutputFile;
|
||||
public:
|
||||
ifstream() {}
|
||||
ifstream(const mpt::PathString & filename, std::ios_base::openmode mode = std::ios_base::in)
|
||||
|
@ -172,23 +120,11 @@ public:
|
|||
{
|
||||
detail::fstream_open<Tbase>(*this, filename, mode);
|
||||
}
|
||||
MPT_DEPRECATED_PATH void open(const char * filename, std::ios_base::openmode mode = std::ios_base::in)
|
||||
{
|
||||
MPT_FSTREAM_OPEN(filename, mode);
|
||||
}
|
||||
MPT_DEPRECATED_PATH void open(const std::string & filename, std::ios_base::openmode mode = std::ios_base::in)
|
||||
{
|
||||
MPT_FSTREAM_OPEN(filename.c_str(), mode);
|
||||
}
|
||||
void open(const char * filename, std::ios_base::openmode mode = std::ios_base::in) = delete;
|
||||
void open(const std::string & filename, std::ios_base::openmode mode = std::ios_base::in) = delete;
|
||||
#if MPT_OS_WINDOWS
|
||||
MPT_DEPRECATED_PATH void open(const wchar_t * filename, std::ios_base::openmode mode = std::ios_base::in)
|
||||
{
|
||||
MPT_FSTREAM_OPEN(filename, mode);
|
||||
}
|
||||
MPT_DEPRECATED_PATH void open(const std::wstring & filename, std::ios_base::openmode mode = std::ios_base::in)
|
||||
{
|
||||
MPT_FSTREAM_OPEN(filename.c_str(), mode);
|
||||
}
|
||||
void open(const wchar_t * filename, std::ios_base::openmode mode = std::ios_base::in) = delete;
|
||||
void open(const std::wstring & filename, std::ios_base::openmode mode = std::ios_base::in) = delete;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -197,40 +133,105 @@ class ofstream
|
|||
{
|
||||
private:
|
||||
typedef std::ofstream Tbase;
|
||||
public:
|
||||
friend SafeOutputFile;
|
||||
public:
|
||||
ofstream() {}
|
||||
ofstream(const mpt::PathString & filename, std::ios_base::openmode mode = std::ios_base::out)
|
||||
{
|
||||
detail::fstream_open<Tbase>(*this, filename, mode);
|
||||
}
|
||||
#if MPT_COMPILER_MSVC
|
||||
protected:
|
||||
ofstream(FILE * file)
|
||||
: std::ofstream(file)
|
||||
{
|
||||
}
|
||||
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
public:
|
||||
void open(const mpt::PathString & filename, std::ios_base::openmode mode = std::ios_base::out)
|
||||
{
|
||||
detail::fstream_open<Tbase>(*this, filename, mode);
|
||||
}
|
||||
MPT_DEPRECATED_PATH void open(const char * filename, std::ios_base::openmode mode = std::ios_base::out)
|
||||
{
|
||||
MPT_FSTREAM_OPEN(filename, mode);
|
||||
}
|
||||
MPT_DEPRECATED_PATH void open(const std::string & filename, std::ios_base::openmode mode = std::ios_base::out)
|
||||
{
|
||||
MPT_FSTREAM_OPEN(filename.c_str(), mode);
|
||||
}
|
||||
void open(const char * filename, std::ios_base::openmode mode = std::ios_base::out) = delete;
|
||||
void open(const std::string & filename, std::ios_base::openmode mode = std::ios_base::out) = delete;
|
||||
#if MPT_OS_WINDOWS
|
||||
MPT_DEPRECATED_PATH void open(const wchar_t * filename, std::ios_base::openmode mode = std::ios_base::out)
|
||||
{
|
||||
MPT_FSTREAM_OPEN(filename, mode);
|
||||
}
|
||||
MPT_DEPRECATED_PATH void open(const std::wstring & filename, std::ios_base::openmode mode = std::ios_base::out)
|
||||
{
|
||||
MPT_FSTREAM_OPEN(filename.c_str(), mode);
|
||||
}
|
||||
void open(const wchar_t * filename, std::ios_base::openmode mode = std::ios_base::out) = delete;
|
||||
void open(const std::wstring & filename, std::ios_base::openmode mode = std::ios_base::out) = delete;
|
||||
#endif
|
||||
};
|
||||
|
||||
#undef MPT_FSTREAM_OPEN
|
||||
enum class FlushMode
|
||||
{
|
||||
None = 0, // no explicit flushes at all
|
||||
Single = 1, // explicitly flush higher-leverl API layers
|
||||
Full = 2, // explicitly flush *all* layers, up to and including disk write caches
|
||||
};
|
||||
|
||||
static inline FlushMode FlushModeFromBool(bool flush)
|
||||
{
|
||||
return flush ? FlushMode::Full : FlushMode::None;
|
||||
}
|
||||
|
||||
#ifdef MODPLUG_TRACKER
|
||||
|
||||
class SafeOutputFile
|
||||
{
|
||||
private:
|
||||
FlushMode m_FlushMode;
|
||||
#if MPT_COMPILER_MSVC
|
||||
FILE *m_f;
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
mpt::ofstream m_s;
|
||||
#if MPT_COMPILER_MSVC
|
||||
static mpt::tstring convert_mode(std::ios_base::openmode mode, FlushMode flushMode);
|
||||
FILE * internal_fopen(const mpt::PathString &filename, std::ios_base::openmode mode, FlushMode flushMode);
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
public:
|
||||
SafeOutputFile() = delete;
|
||||
explicit SafeOutputFile(const mpt::PathString &filename, std::ios_base::openmode mode = std::ios_base::out, FlushMode flushMode = FlushMode::Full)
|
||||
: m_FlushMode(flushMode)
|
||||
#if MPT_COMPILER_MSVC
|
||||
, m_s(internal_fopen(filename, mode | std::ios_base::out, flushMode))
|
||||
#else // !MPT_COMPILER_MSVC
|
||||
, m_s(filename, mode)
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
{
|
||||
}
|
||||
mpt::ofstream& stream()
|
||||
{
|
||||
return m_s;
|
||||
}
|
||||
operator mpt::ofstream& ()
|
||||
{
|
||||
return stream();
|
||||
}
|
||||
const mpt::ofstream& stream() const
|
||||
{
|
||||
return m_s;
|
||||
}
|
||||
operator const mpt::ofstream& () const
|
||||
{
|
||||
return stream();
|
||||
}
|
||||
operator bool() const
|
||||
{
|
||||
return stream() ? true : false;
|
||||
}
|
||||
bool operator!() const
|
||||
{
|
||||
return stream().operator!();
|
||||
}
|
||||
~SafeOutputFile() noexcept(false);
|
||||
};
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
|
||||
#ifdef MODPLUG_TRACKER
|
||||
|
||||
// LazyFileRef is a simple reference to an on-disk file by the means of a
|
||||
// filename which allows easy assignment of the whole file contents to and from
|
||||
// byte buffers.
|
||||
|
@ -252,275 +253,7 @@ public:
|
|||
operator std::string () const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#if defined(MPT_ENABLE_FILEIO_STDIO)
|
||||
|
||||
// class FILE_ostream, FILE_output_streambuf and FILE_output_buffered_streambuf
|
||||
// provide a portable way of wrapping a std::ostream around an FILE* opened for output.
|
||||
// They offer similar functionality to the badly documented
|
||||
// MSVC std::fstream(FILE*) constructor or GCC libstdc++ __gnu_cxx::stdio_sync_filebuf class,
|
||||
// and, for other compilers, provide a race-free alternative to
|
||||
// closing the FILE* and opening it again as a std::ofstream.
|
||||
//
|
||||
// Only output functionality is implemented because we have no need for an input wrapper.
|
||||
//
|
||||
// During the whole lifetime of the iostream wrappers, the FILE* object is assumend to be
|
||||
// either
|
||||
// - NULL
|
||||
// or
|
||||
// - valid
|
||||
// - opened for writing in non-append mode
|
||||
// - opened in binary mode
|
||||
// - seekable
|
||||
// Some of these preconditions cannot be verified,
|
||||
// and even the others do not get verified.
|
||||
// Behaviour in case of any unmet preconditions is undefined.
|
||||
//
|
||||
// The buffered streambuf and the ostream use a buffer of 64KiB by default.
|
||||
//
|
||||
// For FILE_output_streambuf, coherency with the underlying FILE* is always guaranteed.
|
||||
// For FILE_ostream and FILE_output_buffered_streambuf, coherence is only
|
||||
// guaranteed when flush() or pubsync() get called.
|
||||
// The constructors and destructors take care to not violate coherency.
|
||||
// When mixing FILE* and iostream I/O during the lifetime of the iostream objects,
|
||||
// the user is responsible for providing coherency via the appropriate
|
||||
// flush and sync functions.
|
||||
// Behaviour in case of incoherent access is undefined.
|
||||
|
||||
|
||||
class FILE_output_streambuf : public std::streambuf
|
||||
{
|
||||
public:
|
||||
typedef std::streambuf::char_type char_type;
|
||||
typedef std::streambuf::traits_type traits_type;
|
||||
typedef traits_type::int_type int_type;
|
||||
typedef traits_type::pos_type pos_type;
|
||||
typedef traits_type::off_type off_type;
|
||||
protected:
|
||||
FILE *f;
|
||||
public:
|
||||
FILE_output_streambuf(FILE *f)
|
||||
: f(f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
~FILE_output_streambuf()
|
||||
{
|
||||
return;
|
||||
}
|
||||
protected:
|
||||
virtual int_type overflow(int_type ch)
|
||||
{
|
||||
if(!mpt::IO::IsValid(f))
|
||||
{
|
||||
return traits_type::eof();
|
||||
}
|
||||
if(traits_type::eq_int_type(ch, traits_type::eof()))
|
||||
{
|
||||
return traits_type::eof();
|
||||
}
|
||||
char_type c = traits_type::to_char_type(ch);
|
||||
if(!mpt::IO::WriteRaw(f, &c, 1))
|
||||
{
|
||||
return traits_type::eof();
|
||||
}
|
||||
return ch;
|
||||
}
|
||||
virtual int sync()
|
||||
{
|
||||
if(!mpt::IO::IsValid(f))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if(!mpt::IO::Flush(f))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
virtual pos_type seekpos(pos_type pos, std::ios_base::openmode which)
|
||||
{
|
||||
if(!mpt::IO::IsValid(f))
|
||||
{
|
||||
return pos_type(off_type(-1));
|
||||
}
|
||||
return seekoff(pos, std::ios_base::beg, which);
|
||||
}
|
||||
virtual pos_type seekoff(off_type off, std::ios_base::seekdir dir, std::ios_base::openmode which)
|
||||
{
|
||||
if(!mpt::IO::IsValid(f))
|
||||
{
|
||||
return pos_type(off_type(-1));
|
||||
}
|
||||
if(which & std::ios_base::in)
|
||||
{
|
||||
return pos_type(off_type(-1));
|
||||
}
|
||||
if(!(which & std::ios_base::out))
|
||||
{
|
||||
return pos_type(off_type(-1));
|
||||
}
|
||||
mpt::IO::Offset oldpos = mpt::IO::TellWrite(f);
|
||||
if(dir == std::ios_base::beg)
|
||||
{
|
||||
if(!mpt::IO::SeekAbsolute(f, off))
|
||||
{
|
||||
mpt::IO::SeekAbsolute(f, oldpos);
|
||||
return pos_type(off_type(-1));
|
||||
}
|
||||
} else if(dir == std::ios_base::cur)
|
||||
{
|
||||
if(!mpt::IO::SeekRelative(f, off))
|
||||
{
|
||||
mpt::IO::SeekAbsolute(f, oldpos);
|
||||
return pos_type(off_type(-1));
|
||||
}
|
||||
} else if(dir == std::ios_base::end)
|
||||
{
|
||||
if(!(mpt::IO::SeekEnd(f) && mpt::IO::SeekRelative(f, off)))
|
||||
{
|
||||
mpt::IO::SeekAbsolute(f, oldpos);
|
||||
return pos_type(off_type(-1));
|
||||
}
|
||||
} else
|
||||
{
|
||||
return pos_type(off_type(-1));
|
||||
}
|
||||
mpt::IO::Offset newpos = mpt::IO::TellWrite(f);
|
||||
if(!mpt::IO::OffsetFits<off_type>(newpos))
|
||||
{
|
||||
mpt::IO::SeekAbsolute(f, oldpos);
|
||||
return pos_type(off_type(-1));
|
||||
}
|
||||
return pos_type(static_cast<off_type>(newpos));
|
||||
}
|
||||
}; // class FILE_output_streambuf
|
||||
|
||||
|
||||
class FILE_output_buffered_streambuf : public FILE_output_streambuf
|
||||
{
|
||||
public:
|
||||
typedef std::streambuf::char_type char_type;
|
||||
typedef std::streambuf::traits_type traits_type;
|
||||
typedef traits_type::int_type int_type;
|
||||
typedef traits_type::pos_type pos_type;
|
||||
typedef traits_type::off_type off_type;
|
||||
private:
|
||||
typedef FILE_output_streambuf Tparent;
|
||||
std::vector<char_type> buf;
|
||||
public:
|
||||
FILE_output_buffered_streambuf(FILE *f, std::size_t bufSize = 64*1024)
|
||||
: FILE_output_streambuf(f)
|
||||
, buf((bufSize > 0) ? bufSize : 1)
|
||||
{
|
||||
setp(buf.data(), buf.data() + buf.size());
|
||||
}
|
||||
~FILE_output_buffered_streambuf()
|
||||
{
|
||||
if(!mpt::IO::IsValid(f))
|
||||
{
|
||||
return;
|
||||
}
|
||||
WriteOut();
|
||||
}
|
||||
private:
|
||||
bool IsDirty() const
|
||||
{
|
||||
return ((pptr() - pbase()) > 0);
|
||||
}
|
||||
bool WriteOut()
|
||||
{
|
||||
std::ptrdiff_t n = pptr() - pbase();
|
||||
std::ptrdiff_t left = n;
|
||||
while(left > 0)
|
||||
{
|
||||
int backchunk = mpt::saturate_cast<int>(-left);
|
||||
pbump(backchunk);
|
||||
left += backchunk;
|
||||
}
|
||||
return mpt::IO::WriteRaw(f, pbase(), n);
|
||||
}
|
||||
protected:
|
||||
virtual int_type overflow(int_type ch)
|
||||
{
|
||||
if(!mpt::IO::IsValid(f))
|
||||
{
|
||||
return traits_type::eof();
|
||||
}
|
||||
if(traits_type::eq_int_type(ch, traits_type::eof()))
|
||||
{
|
||||
return traits_type::eof();
|
||||
}
|
||||
if(!WriteOut())
|
||||
{
|
||||
return traits_type::eof();
|
||||
}
|
||||
char_type c = traits_type::to_char_type(ch);
|
||||
*pptr() = c;
|
||||
pbump(1);
|
||||
return ch;
|
||||
}
|
||||
virtual int sync()
|
||||
{
|
||||
if(!mpt::IO::IsValid(f))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if(!WriteOut())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return Tparent::sync();
|
||||
}
|
||||
virtual pos_type seekpos(pos_type pos, std::ios_base::openmode which)
|
||||
{
|
||||
if(!mpt::IO::IsValid(f))
|
||||
{
|
||||
return pos_type(off_type(-1));
|
||||
}
|
||||
if(!WriteOut())
|
||||
{
|
||||
return pos_type(off_type(-1));
|
||||
}
|
||||
return Tparent::seekpos(pos, which);
|
||||
}
|
||||
virtual pos_type seekoff(off_type off, std::ios_base::seekdir dir, std::ios_base::openmode which)
|
||||
{
|
||||
if(!mpt::IO::IsValid(f))
|
||||
{
|
||||
return pos_type(off_type(-1));
|
||||
}
|
||||
if(!WriteOut())
|
||||
{
|
||||
return pos_type(off_type(-1));
|
||||
}
|
||||
return Tparent::seekoff(off, dir, which);
|
||||
}
|
||||
}; // class FILE_output_buffered_streambuf
|
||||
|
||||
|
||||
class FILE_ostream : public std::ostream {
|
||||
private:
|
||||
FILE *f;
|
||||
FILE_output_buffered_streambuf buf;
|
||||
public:
|
||||
FILE_ostream(FILE *f, std::size_t bufSize = 64*1024)
|
||||
: std::ostream(&buf)
|
||||
, f(f)
|
||||
, buf(f, bufSize)
|
||||
{
|
||||
if(mpt::IO::IsValid(f)) mpt::IO::Flush(f);
|
||||
}
|
||||
~FILE_ostream()
|
||||
{
|
||||
flush();
|
||||
buf.pubsync();
|
||||
if(mpt::IO::IsValid(f)) mpt::IO::Flush(f);
|
||||
}
|
||||
}; // class FILE_ostream
|
||||
|
||||
#endif // MPT_ENABLE_FILEIO_STDIO
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
} // namespace mpt
|
||||
|
@ -585,5 +318,6 @@ public:
|
|||
#endif // MPT_ENABLE_FILEIO
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
||||
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
* mptIO.cpp
|
||||
* ---------
|
||||
* Purpose: Basic functions for reading/writing binary and endian safe data to/from files/streams.
|
||||
* Notes : This is work-in-progress.
|
||||
* Some useful functions for reading and writing are still missing.
|
||||
* Notes : Some useful functions for reading and writing are still missing.
|
||||
* Authors: Joern Heusipp
|
||||
* OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
|
@ -18,14 +17,9 @@
|
|||
#include <istream>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
#if MPT_COMPILER_MSVC
|
||||
#ifdef MPT_COMPILER_QUIRK_MSVC_STRINGSTREAM
|
||||
#include <typeinfo>
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
|
||||
#if defined(MPT_ENABLE_FILEIO_STDIO)
|
||||
#include <cstdio>
|
||||
#include <stdio.h>
|
||||
#endif // MPT_ENABLE_FILEIO_STDIO
|
||||
#endif // MPT_COMPILER_QUIRK_MSVC_STRINGSTREAM
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
@ -36,7 +30,7 @@ namespace mpt {
|
|||
namespace IO {
|
||||
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
#ifdef MPT_COMPILER_QUIRK_MSVC_STRINGSTREAM
|
||||
|
||||
// MSVC std::stringbuf (and thereby std::ostringstream, std::istringstream and
|
||||
// std::stringstream) fail seekoff() when the stringbuf is currently empty.
|
||||
|
@ -124,7 +118,7 @@ static bool StreamIsStringStreamAndValidAndEmpty(std::iostream & f)
|
|||
return dynamic_cast<std::stringbuf*>(f.rdbuf())->str().empty(); // slow
|
||||
}
|
||||
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
#endif // MPT_COMPILER_QUIRK_MSVC_STRINGSTREAM
|
||||
|
||||
//STATIC_ASSERT(sizeof(std::streamoff) == 8); // Assert 64bit file support.
|
||||
bool IsValid(std::ostream & f) { return !f.fail(); }
|
||||
|
@ -140,7 +134,7 @@ IO::Offset TellWrite(std::ostream & f)
|
|||
}
|
||||
bool SeekBegin(std::ostream & f)
|
||||
{
|
||||
#if MPT_COMPILER_MSVC
|
||||
#ifdef MPT_COMPILER_QUIRK_MSVC_STRINGSTREAM
|
||||
if(StreamIsStringStreamAndValidAndEmpty(f))
|
||||
{ // VS std::stringbuf fail seek when the internal buffer is empty. Work-around it in case the stream is not already in failed state.
|
||||
f.seekp(0); f.clear(f.rdstate() & ~std::ios::failbit); return true;
|
||||
|
@ -150,7 +144,7 @@ bool SeekBegin(std::ostream & f)
|
|||
}
|
||||
bool SeekBegin(std::istream & f)
|
||||
{
|
||||
#if MPT_COMPILER_MSVC
|
||||
#ifdef MPT_COMPILER_QUIRK_MSVC_STRINGSTREAM
|
||||
if(StreamIsStringStreamAndValidAndEmpty(f))
|
||||
{
|
||||
f.seekg(0); f.clear(f.rdstate() & ~std::ios::failbit); return true;
|
||||
|
@ -160,7 +154,7 @@ bool SeekBegin(std::istream & f)
|
|||
}
|
||||
bool SeekBegin(std::iostream & f)
|
||||
{
|
||||
#if MPT_COMPILER_MSVC
|
||||
#ifdef MPT_COMPILER_QUIRK_MSVC_STRINGSTREAM
|
||||
if(StreamIsStringStreamAndValidAndEmpty(f))
|
||||
{
|
||||
f.seekg(0); f.clear(f.rdstate() & ~std::ios::failbit); f.seekp(0); f.clear(f.rdstate() & ~std::ios::failbit); return true;
|
||||
|
@ -170,7 +164,7 @@ bool SeekBegin(std::iostream & f)
|
|||
}
|
||||
bool SeekEnd(std::ostream & f)
|
||||
{
|
||||
#if MPT_COMPILER_MSVC
|
||||
#ifdef MPT_COMPILER_QUIRK_MSVC_STRINGSTREAM
|
||||
if(StreamIsStringStreamAndValidAndEmpty(f))
|
||||
{
|
||||
f.seekp(0); f.clear(f.rdstate() & ~std::ios::failbit); return true;
|
||||
|
@ -180,7 +174,7 @@ bool SeekEnd(std::ostream & f)
|
|||
}
|
||||
bool SeekEnd(std::istream & f)
|
||||
{
|
||||
#if MPT_COMPILER_MSVC
|
||||
#ifdef MPT_COMPILER_QUIRK_MSVC_STRINGSTREAM
|
||||
if(StreamIsStringStreamAndValidAndEmpty(f))
|
||||
{
|
||||
f.seekg(0); f.clear(f.rdstate() & ~std::ios::failbit); return true;
|
||||
|
@ -190,7 +184,7 @@ bool SeekEnd(std::istream & f)
|
|||
}
|
||||
bool SeekEnd(std::iostream & f)
|
||||
{
|
||||
#if MPT_COMPILER_MSVC
|
||||
#ifdef MPT_COMPILER_QUIRK_MSVC_STRINGSTREAM
|
||||
if(StreamIsStringStreamAndValidAndEmpty(f))
|
||||
{
|
||||
f.seekg(0); f.clear(f.rdstate() & ~std::ios::failbit); f.seekp(0); f.clear(f.rdstate() & ~std::ios::failbit); return true;
|
||||
|
@ -201,7 +195,7 @@ bool SeekEnd(std::iostream & f)
|
|||
bool SeekAbsolute(std::ostream & f, IO::Offset pos)
|
||||
{
|
||||
if(!OffsetFits<std::streamoff>(pos)) { return false; }
|
||||
#if MPT_COMPILER_MSVC
|
||||
#ifdef MPT_COMPILER_QUIRK_MSVC_STRINGSTREAM
|
||||
if(StreamIsStringStreamAndValidAndEmpty(f))
|
||||
{
|
||||
if(pos == 0)
|
||||
|
@ -215,7 +209,7 @@ bool SeekAbsolute(std::ostream & f, IO::Offset pos)
|
|||
bool SeekAbsolute(std::istream & f, IO::Offset pos)
|
||||
{
|
||||
if(!OffsetFits<std::streamoff>(pos)) { return false; }
|
||||
#if MPT_COMPILER_MSVC
|
||||
#ifdef MPT_COMPILER_QUIRK_MSVC_STRINGSTREAM
|
||||
if(StreamIsStringStreamAndValidAndEmpty(f))
|
||||
{
|
||||
if(pos == 0)
|
||||
|
@ -229,7 +223,7 @@ bool SeekAbsolute(std::istream & f, IO::Offset pos)
|
|||
bool SeekAbsolute(std::iostream & f, IO::Offset pos)
|
||||
{
|
||||
if(!OffsetFits<std::streamoff>(pos)) { return false; }
|
||||
#if MPT_COMPILER_MSVC
|
||||
#ifdef MPT_COMPILER_QUIRK_MSVC_STRINGSTREAM
|
||||
if(StreamIsStringStreamAndValidAndEmpty(f))
|
||||
{
|
||||
if(pos == 0)
|
||||
|
@ -243,7 +237,7 @@ bool SeekAbsolute(std::iostream & f, IO::Offset pos)
|
|||
bool SeekRelative(std::ostream & f, IO::Offset off)
|
||||
{
|
||||
if(!OffsetFits<std::streamoff>(off)) { return false; }
|
||||
#if MPT_COMPILER_MSVC
|
||||
#ifdef MPT_COMPILER_QUIRK_MSVC_STRINGSTREAM
|
||||
if(StreamIsStringStreamAndValidAndEmpty(f))
|
||||
{
|
||||
if(off == 0)
|
||||
|
@ -257,7 +251,7 @@ bool SeekRelative(std::ostream & f, IO::Offset off)
|
|||
bool SeekRelative(std::istream & f, IO::Offset off)
|
||||
{
|
||||
if(!OffsetFits<std::streamoff>(off)) { return false; }
|
||||
#if MPT_COMPILER_MSVC
|
||||
#ifdef MPT_COMPILER_QUIRK_MSVC_STRINGSTREAM
|
||||
if(StreamIsStringStreamAndValidAndEmpty(f))
|
||||
{
|
||||
if(off == 0)
|
||||
|
@ -271,7 +265,7 @@ bool SeekRelative(std::istream & f, IO::Offset off)
|
|||
bool SeekRelative(std::iostream & f, IO::Offset off)
|
||||
{
|
||||
if(!OffsetFits<std::streamoff>(off)) { return false; }
|
||||
#if MPT_COMPILER_MSVC
|
||||
#ifdef MPT_COMPILER_QUIRK_MSVC_STRINGSTREAM
|
||||
if(StreamIsStringStreamAndValidAndEmpty(f))
|
||||
{
|
||||
if(off == 0)
|
||||
|
@ -289,50 +283,6 @@ bool Flush(std::ostream & f) { f.flush(); return !f.fail(); }
|
|||
|
||||
|
||||
|
||||
#if defined(MPT_ENABLE_FILEIO_STDIO)
|
||||
|
||||
bool IsValid(FILE* & f) { return f != NULL; }
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
|
||||
IO::Offset TellRead(FILE* & f) { return _ftelli64(f); }
|
||||
IO::Offset TellWrite(FILE* & f) { return _ftelli64(f); }
|
||||
bool SeekBegin(FILE* & f) { return _fseeki64(f, 0, SEEK_SET) == 0; }
|
||||
bool SeekEnd(FILE* & f) { return _fseeki64(f, 0, SEEK_END) == 0; }
|
||||
bool SeekAbsolute(FILE* & f, IO::Offset pos) { return _fseeki64(f, pos, SEEK_SET) == 0; }
|
||||
bool SeekRelative(FILE* & f, IO::Offset off) { return _fseeki64(f, off, SEEK_CUR) == 0; }
|
||||
|
||||
#elif defined(_POSIX_SOURCE) && (_POSIX_SOURCE > 0)
|
||||
|
||||
//STATIC_ASSERT(sizeof(off_t) == 8);
|
||||
IO::Offset TellRead(FILE* & f) { return ftello(f); }
|
||||
IO::Offset TellWrite(FILE* & f) { return ftello(f); }
|
||||
bool SeekBegin(FILE* & f) { return fseeko(f, 0, SEEK_SET) == 0; }
|
||||
bool SeekEnd(FILE* & f) { return fseeko(f, 0, SEEK_END) == 0; }
|
||||
bool SeekAbsolute(FILE* & f, IO::Offset pos) { return OffsetFits<off_t>(pos) && (fseek(f, mpt::saturate_cast<off_t>(pos), SEEK_SET) == 0); }
|
||||
bool SeekRelative(FILE* & f, IO::Offset off) { return OffsetFits<off_t>(off) && (fseek(f, mpt::saturate_cast<off_t>(off), SEEK_CUR) == 0); }
|
||||
|
||||
#else
|
||||
|
||||
//STATIC_ASSERT(sizeof(long) == 8); // Fails on 32bit non-POSIX systems for now.
|
||||
IO::Offset TellRead(FILE* & f) { return ftell(f); }
|
||||
IO::Offset TellWrite(FILE* & f) { return ftell(f); }
|
||||
bool SeekBegin(FILE* & f) { return fseek(f, 0, SEEK_SET) == 0; }
|
||||
bool SeekEnd(FILE* & f) { return fseek(f, 0, SEEK_END) == 0; }
|
||||
bool SeekAbsolute(FILE* & f, IO::Offset pos) { return OffsetFits<long>(pos) && (fseek(f, mpt::saturate_cast<long>(pos), SEEK_SET) == 0); }
|
||||
bool SeekRelative(FILE* & f, IO::Offset off) { return OffsetFits<long>(off) && (fseek(f, mpt::saturate_cast<long>(off), SEEK_CUR) == 0); }
|
||||
|
||||
#endif
|
||||
|
||||
IO::Offset ReadRawImpl(FILE * & f, mpt::byte * data, std::size_t size) { return fread(mpt::void_cast<void*>(data), 1, size, f); }
|
||||
bool WriteRawImpl(FILE* & f, const mpt::byte * data, std::size_t size) { return fwrite(mpt::void_cast<const void*>(data), 1, size, f) == size; }
|
||||
bool IsEof(FILE * & f) { return feof(f) != 0; }
|
||||
bool Flush(FILE* & f) { return fflush(f) == 0; }
|
||||
|
||||
#endif // MPT_ENABLE_FILEIO_STDIO
|
||||
|
||||
|
||||
|
||||
} // namespace IO
|
||||
|
||||
} // namespace mpt
|
||||
|
@ -350,10 +300,6 @@ FileDataContainerSeekable::FileDataContainerSeekable(off_t streamLength)
|
|||
return;
|
||||
}
|
||||
|
||||
FileDataContainerSeekable::~FileDataContainerSeekable()
|
||||
{
|
||||
return;
|
||||
}
|
||||
void FileDataContainerSeekable::CacheStream() const
|
||||
{
|
||||
if(cached)
|
||||
|
@ -461,11 +407,6 @@ FileDataContainerStdStreamSeekable::FileDataContainerStdStreamSeekable(std::istr
|
|||
return;
|
||||
}
|
||||
|
||||
FileDataContainerStdStreamSeekable::~FileDataContainerStdStreamSeekable()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IFileDataContainer::off_t FileDataContainerStdStreamSeekable::InternalRead(mpt::byte *dst, off_t pos, off_t count) const
|
||||
{
|
||||
stream->clear(); // tellg needs eof and fail bits unset
|
||||
|
@ -485,11 +426,6 @@ FileDataContainerUnseekable::FileDataContainerUnseekable()
|
|||
return;
|
||||
}
|
||||
|
||||
FileDataContainerUnseekable::~FileDataContainerUnseekable()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void FileDataContainerUnseekable::EnsureCacheBuffer(std::size_t requiredbuffersize) const
|
||||
{
|
||||
if(cache.size() >= cachesize + requiredbuffersize)
|
||||
|
@ -627,11 +563,6 @@ FileDataContainerStdStream::FileDataContainerStdStream(std::istream *s)
|
|||
return;
|
||||
}
|
||||
|
||||
FileDataContainerStdStream::~FileDataContainerStdStream()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool FileDataContainerStdStream::InternalEof() const
|
||||
{
|
||||
if(*stream)
|
||||
|
@ -739,11 +670,6 @@ FileDataContainerCallbackStreamSeekable::FileDataContainerCallbackStreamSeekable
|
|||
return;
|
||||
}
|
||||
|
||||
FileDataContainerCallbackStreamSeekable::~FileDataContainerCallbackStreamSeekable()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IFileDataContainer::off_t FileDataContainerCallbackStreamSeekable::InternalRead(mpt::byte *dst, off_t pos, off_t count) const
|
||||
{
|
||||
if(!stream.read)
|
||||
|
@ -779,11 +705,6 @@ FileDataContainerCallbackStream::FileDataContainerCallbackStream(CallbackStream
|
|||
return;
|
||||
}
|
||||
|
||||
FileDataContainerCallbackStream::~FileDataContainerCallbackStream()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool FileDataContainerCallbackStream::InternalEof() const
|
||||
{
|
||||
return eof_reached;
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
* mptIO.h
|
||||
* -------
|
||||
* Purpose: Basic functions for reading/writing binary and endian safe data to/from files/streams.
|
||||
* Notes : This is work-in-progress.
|
||||
* Some useful functions for reading and writing are still missing.
|
||||
* Notes : Some useful functions for reading and writing are still missing.
|
||||
* Authors: Joern Heusipp
|
||||
* OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
|
@ -12,20 +11,16 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
|
||||
#include "../common/typedefs.h"
|
||||
#include "../common/mptTypeTraits.h"
|
||||
#include "../common/Endianness.h"
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <iosfwd>
|
||||
#include <limits>
|
||||
#include <cstring>
|
||||
|
||||
#if defined(MPT_ENABLE_FILEIO_STDIO)
|
||||
#include <cstdio>
|
||||
#include <stdio.h>
|
||||
#endif // MPT_ENABLE_FILEIO_STDIO
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
@ -36,10 +31,10 @@ namespace IO {
|
|||
|
||||
typedef int64 Offset;
|
||||
|
||||
static const std::size_t BUFFERSIZE_TINY = 1 * 1024; // on stack usage
|
||||
static const std::size_t BUFFERSIZE_SMALL = 4 * 1024; // on heap
|
||||
static const std::size_t BUFFERSIZE_NORMAL = 64 * 1024; // FILE I/O
|
||||
static const std::size_t BUFFERSIZE_LARGE = 1024 * 1024;
|
||||
static constexpr std::size_t BUFFERSIZE_TINY = 1 * 1024; // on stack usage
|
||||
static constexpr std::size_t BUFFERSIZE_SMALL = 4 * 1024; // on heap
|
||||
static constexpr std::size_t BUFFERSIZE_NORMAL = 64 * 1024; // FILE I/O
|
||||
static constexpr std::size_t BUFFERSIZE_LARGE = 1024 * 1024;
|
||||
|
||||
|
||||
|
||||
|
@ -76,21 +71,21 @@ bool Flush(std::ostream & f);
|
|||
|
||||
|
||||
|
||||
#if defined(MPT_ENABLE_FILEIO_STDIO)
|
||||
template <typename Tfile> class WriteBuffer;
|
||||
|
||||
template <typename Tfile> bool IsValid(WriteBuffer<Tfile> & f) { return IsValid(f.file()); }
|
||||
template <typename Tfile> IO::Offset TellRead(WriteBuffer<Tfile> & f) { return TellRead(f.file()); }
|
||||
template <typename Tfile> IO::Offset TellWrite(WriteBuffer<Tfile> & f) { return TellWrite(f.file()); }
|
||||
template <typename Tfile> bool SeekBegin(WriteBuffer<Tfile> & f) { return SeekBegin(f.file()); }
|
||||
template <typename Tfile> bool SeekEnd(WriteBuffer<Tfile> & f) { return SeekEnd(f.file()); }
|
||||
template <typename Tfile> bool SeekAbsolute(WriteBuffer<Tfile> & f, IO::Offset pos) { return SeekAbsolute(f.file(), pos); }
|
||||
template <typename Tfile> bool SeekRelative(WriteBuffer<Tfile> & f, IO::Offset off) { return SeekRelative(f.file(), off); }
|
||||
template <typename Tfile> IO::Offset ReadRawImpl(WriteBuffer<Tfile> & f, mpt::byte * data, std::size_t size) { return ReadRawImpl(f.file(), data, size); }
|
||||
template <typename Tfile> bool WriteRawImpl(WriteBuffer<Tfile> & f, const mpt::byte * data, std::size_t size) { return f.Write(mpt::as_span(data, size)); }
|
||||
template <typename Tfile> bool IsEof(WriteBuffer<Tfile> & f) { return IsEof(f.file()); }
|
||||
template <typename Tfile> bool Flush(WriteBuffer<Tfile> & f) { return Flush(f.file()); }
|
||||
|
||||
bool IsValid(FILE* & f);
|
||||
IO::Offset TellRead(FILE* & f);
|
||||
IO::Offset TellWrite(FILE* & f);
|
||||
bool SeekBegin(FILE* & f);
|
||||
bool SeekEnd(FILE* & f);
|
||||
bool SeekAbsolute(FILE* & f, IO::Offset pos);
|
||||
bool SeekRelative(FILE* & f, IO::Offset off);
|
||||
IO::Offset ReadRawImpl(FILE * & f, mpt::byte * data, std::size_t size);
|
||||
bool WriteRawImpl(FILE* & f, const mpt::byte * data, std::size_t size);
|
||||
bool IsEof(FILE * & f);
|
||||
bool Flush(FILE* & f);
|
||||
|
||||
#endif // MPT_ENABLE_FILEIO_STDIO
|
||||
|
||||
|
||||
|
||||
|
@ -182,29 +177,65 @@ inline IO::Offset ReadRaw(Tfile & f, Tbyte * data, std::size_t size)
|
|||
return IO::ReadRawImpl(f, mpt::byte_cast<mpt::byte*>(data), size);
|
||||
}
|
||||
|
||||
template <typename Tbyte, typename Tfile>
|
||||
inline IO::Offset ReadRaw(Tfile & f, mpt::span<Tbyte> data)
|
||||
{
|
||||
return IO::ReadRawImpl(f, mpt::byte_cast<mpt::byte*>(data.data()), data.size());
|
||||
}
|
||||
|
||||
template <typename Tbyte, typename Tfile>
|
||||
inline bool WriteRaw(Tfile & f, const Tbyte * data, std::size_t size)
|
||||
{
|
||||
return IO::WriteRawImpl(f, mpt::byte_cast<const mpt::byte*>(data), size);
|
||||
}
|
||||
|
||||
template <typename Tbyte, typename Tfile>
|
||||
inline bool WriteRaw(Tfile & f, mpt::span<Tbyte> data)
|
||||
{
|
||||
return IO::WriteRawImpl(f, mpt::byte_cast<const mpt::byte*>(data.data()), data.size());
|
||||
}
|
||||
|
||||
template <typename Tbinary, typename Tfile>
|
||||
inline bool Read(Tfile & f, Tbinary & v)
|
||||
{
|
||||
return IO::ReadRaw(f, mpt::as_raw_memory(v), sizeof(Tbinary)) == sizeof(Tbinary);
|
||||
return IO::ReadRaw(f, mpt::as_raw_memory(v)) == mpt::saturate_cast<mpt::IO::Offset>(mpt::as_raw_memory(v).size());
|
||||
}
|
||||
|
||||
template <typename Tbinary, typename Tfile>
|
||||
inline bool Write(Tfile & f, const Tbinary & v)
|
||||
{
|
||||
return IO::WriteRaw(f, mpt::as_raw_memory(v), sizeof(Tbinary));
|
||||
return IO::WriteRaw(f, mpt::as_raw_memory(v));
|
||||
}
|
||||
|
||||
template <typename Tbinary, typename Tfile>
|
||||
inline bool Write(Tfile & f, const std::vector<Tbinary> & v)
|
||||
{
|
||||
STATIC_ASSERT(mpt::is_binary_safe<Tbinary>::value);
|
||||
return IO::WriteRaw(f, mpt::as_raw_memory(v));
|
||||
}
|
||||
|
||||
template <typename T, typename Tfile>
|
||||
inline bool WritePartial(Tfile & f, const T & v, size_t size = sizeof(T))
|
||||
{
|
||||
MPT_ASSERT(size <= sizeof(T));
|
||||
return IO::WriteRaw(f, mpt::as_raw_memory(v), size);
|
||||
return IO::WriteRaw(f, mpt::as_span(mpt::as_raw_memory(v).data(), size));
|
||||
}
|
||||
|
||||
template <typename Tfile>
|
||||
inline bool ReadByte(Tfile & f, mpt::byte & v)
|
||||
{
|
||||
bool result = false;
|
||||
mpt::byte byte = mpt::as_byte(0);
|
||||
const IO::Offset readResult = IO::ReadRaw(f, &byte, sizeof(mpt::byte));
|
||||
if(readResult < 0)
|
||||
{
|
||||
result = false;
|
||||
} else
|
||||
{
|
||||
result = (static_cast<uint64>(readResult) == sizeof(mpt::byte));
|
||||
}
|
||||
v = byte;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, typename Tfile>
|
||||
|
@ -212,7 +243,7 @@ inline bool ReadBinaryTruncatedLE(Tfile & f, T & v, std::size_t size)
|
|||
{
|
||||
bool result = false;
|
||||
MPT_STATIC_ASSERT(std::numeric_limits<T>::is_integer);
|
||||
mpt::byte bytes[sizeof(T)];
|
||||
uint8 bytes[sizeof(T)];
|
||||
std::memset(bytes, 0, sizeof(T));
|
||||
const IO::Offset readResult = IO::ReadRaw(f, bytes, std::min(size, sizeof(T)));
|
||||
if(readResult < 0)
|
||||
|
@ -222,10 +253,9 @@ inline bool ReadBinaryTruncatedLE(Tfile & f, T & v, std::size_t size)
|
|||
{
|
||||
result = (static_cast<uint64>(readResult) == std::min(size, sizeof(T)));
|
||||
}
|
||||
#ifdef MPT_PLATFORM_BIG_ENDIAN
|
||||
std::reverse(bytes, bytes + sizeof(T));
|
||||
#endif
|
||||
std::memcpy(&v, bytes, sizeof(T));
|
||||
typename mpt::make_le<T>::type val;
|
||||
std::memcpy(&val, bytes, sizeof(T));
|
||||
v = val;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -234,7 +264,7 @@ inline bool ReadIntLE(Tfile & f, T & v)
|
|||
{
|
||||
bool result = false;
|
||||
STATIC_ASSERT(std::numeric_limits<T>::is_integer);
|
||||
mpt::byte bytes[sizeof(T)];
|
||||
uint8 bytes[sizeof(T)];
|
||||
std::memset(bytes, 0, sizeof(T));
|
||||
const IO::Offset readResult = IO::ReadRaw(f, bytes, sizeof(T));
|
||||
if(readResult < 0)
|
||||
|
@ -244,9 +274,9 @@ inline bool ReadIntLE(Tfile & f, T & v)
|
|||
{
|
||||
result = (static_cast<uint64>(readResult) == sizeof(T));
|
||||
}
|
||||
T val = 0;
|
||||
typename mpt::make_le<T>::type val;
|
||||
std::memcpy(&val, bytes, sizeof(T));
|
||||
v = SwapBytesLE(val);
|
||||
v = val;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -255,7 +285,7 @@ inline bool ReadIntBE(Tfile & f, T & v)
|
|||
{
|
||||
bool result = false;
|
||||
STATIC_ASSERT(std::numeric_limits<T>::is_integer);
|
||||
mpt::byte bytes[sizeof(T)];
|
||||
uint8 bytes[sizeof(T)];
|
||||
std::memset(bytes, 0, sizeof(T));
|
||||
const IO::Offset readResult = IO::ReadRaw(f, bytes, sizeof(T));
|
||||
if(readResult < 0)
|
||||
|
@ -265,9 +295,9 @@ inline bool ReadIntBE(Tfile & f, T & v)
|
|||
{
|
||||
result = (static_cast<uint64>(readResult) == sizeof(T));
|
||||
}
|
||||
T val = 0;
|
||||
typename mpt::make_be<T>::type val;
|
||||
std::memcpy(&val, bytes, sizeof(T));
|
||||
v = SwapBytesBE(val);
|
||||
v = val;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -275,17 +305,17 @@ template <typename Tfile>
|
|||
inline bool ReadAdaptiveInt16LE(Tfile & f, uint16 & v)
|
||||
{
|
||||
bool result = true;
|
||||
mpt::byte byte = 0;
|
||||
uint8 byte = 0;
|
||||
std::size_t additionalBytes = 0;
|
||||
v = 0;
|
||||
byte = 0;
|
||||
if(!IO::ReadIntLE<mpt::byte>(f, byte)) result = false;
|
||||
if(!IO::ReadIntLE<uint8>(f, byte)) result = false;
|
||||
additionalBytes = (byte & 0x01);
|
||||
v = byte >> 1;
|
||||
for(std::size_t i = 0; i < additionalBytes; ++i)
|
||||
{
|
||||
byte = 0;
|
||||
if(!IO::ReadIntLE<mpt::byte>(f, byte)) result = false;
|
||||
if(!IO::ReadIntLE<uint8>(f, byte)) result = false;
|
||||
v |= (static_cast<uint16>(byte) << (((i+1)*8) - 1));
|
||||
}
|
||||
return result;
|
||||
|
@ -295,17 +325,17 @@ template <typename Tfile>
|
|||
inline bool ReadAdaptiveInt32LE(Tfile & f, uint32 & v)
|
||||
{
|
||||
bool result = true;
|
||||
mpt::byte byte = 0;
|
||||
uint8 byte = 0;
|
||||
std::size_t additionalBytes = 0;
|
||||
v = 0;
|
||||
byte = 0;
|
||||
if(!IO::ReadIntLE<mpt::byte>(f, byte)) result = false;
|
||||
if(!IO::ReadIntLE<uint8>(f, byte)) result = false;
|
||||
additionalBytes = (byte & 0x03);
|
||||
v = byte >> 2;
|
||||
for(std::size_t i = 0; i < additionalBytes; ++i)
|
||||
{
|
||||
byte = 0;
|
||||
if(!IO::ReadIntLE<mpt::byte>(f, byte)) result = false;
|
||||
if(!IO::ReadIntLE<uint8>(f, byte)) result = false;
|
||||
v |= (static_cast<uint32>(byte) << (((i+1)*8) - 2));
|
||||
}
|
||||
return result;
|
||||
|
@ -315,17 +345,17 @@ template <typename Tfile>
|
|||
inline bool ReadAdaptiveInt64LE(Tfile & f, uint64 & v)
|
||||
{
|
||||
bool result = true;
|
||||
mpt::byte byte = 0;
|
||||
uint8 byte = 0;
|
||||
std::size_t additionalBytes = 0;
|
||||
v = 0;
|
||||
byte = 0;
|
||||
if(!IO::ReadIntLE<mpt::byte>(f, byte)) result = false;
|
||||
if(!IO::ReadIntLE<uint8>(f, byte)) result = false;
|
||||
additionalBytes = (1 << (byte & 0x03)) - 1;
|
||||
v = byte >> 2;
|
||||
for(std::size_t i = 0; i < additionalBytes; ++i)
|
||||
{
|
||||
byte = 0;
|
||||
if(!IO::ReadIntLE<mpt::byte>(f, byte)) result = false;
|
||||
if(!IO::ReadIntLE<uint8>(f, byte)) result = false;
|
||||
v |= (static_cast<uint64>(byte) << (((i+1)*8) - 2));
|
||||
}
|
||||
return result;
|
||||
|
@ -362,32 +392,32 @@ template <typename T, typename Tfile>
|
|||
inline bool WriteIntLE(Tfile & f, const T v)
|
||||
{
|
||||
STATIC_ASSERT(std::numeric_limits<T>::is_integer);
|
||||
const T val = SwapBytesLE(v);
|
||||
mpt::byte bytes[sizeof(T)];
|
||||
std::memcpy(bytes, &val, sizeof(T));
|
||||
return IO::WriteRaw(f, bytes, sizeof(T));
|
||||
return IO::Write(f, mpt::as_le(v));
|
||||
}
|
||||
|
||||
template <typename T, typename Tfile>
|
||||
inline bool WriteIntBE(Tfile & f, const T v)
|
||||
{
|
||||
STATIC_ASSERT(std::numeric_limits<T>::is_integer);
|
||||
const T val = SwapBytesBE(v);
|
||||
mpt::byte bytes[sizeof(T)];
|
||||
std::memcpy(bytes, &val, sizeof(T));
|
||||
return IO::WriteRaw(f, bytes, sizeof(T));
|
||||
return IO::Write(f, mpt::as_be(v));
|
||||
}
|
||||
|
||||
template <typename Tfile>
|
||||
inline bool WriteAdaptiveInt16LE(Tfile & f, const uint16 v, std::size_t minSize = 0, std::size_t maxSize = 0)
|
||||
inline bool WriteAdaptiveInt16LE(Tfile & f, const uint16 v, std::size_t fixedSize = 0)
|
||||
{
|
||||
std::size_t minSize = fixedSize;
|
||||
std::size_t maxSize = fixedSize;
|
||||
MPT_ASSERT(minSize == 0 || minSize == 1 || minSize == 2);
|
||||
MPT_ASSERT(maxSize == 0 || maxSize == 1 || maxSize == 2);
|
||||
MPT_ASSERT(maxSize == 0 || maxSize >= minSize);
|
||||
if(v < 0x80 && minSize <= 1 && (1 <= maxSize || maxSize == 0))
|
||||
if(maxSize == 0)
|
||||
{
|
||||
maxSize = 2;
|
||||
}
|
||||
if(v < 0x80 && minSize <= 1 && 1 <= maxSize)
|
||||
{
|
||||
return IO::WriteIntLE<uint8>(f, static_cast<uint8>(v << 1) | 0x00);
|
||||
} else if(v < 0x8000 && minSize <= 2 && (2 <= maxSize || maxSize == 0))
|
||||
} else if(v < 0x8000 && minSize <= 2 && 2 <= maxSize)
|
||||
{
|
||||
return IO::WriteIntLE<uint16>(f, static_cast<uint16>(v << 1) | 0x01);
|
||||
} else
|
||||
|
@ -398,18 +428,24 @@ inline bool WriteAdaptiveInt16LE(Tfile & f, const uint16 v, std::size_t minSize
|
|||
}
|
||||
|
||||
template <typename Tfile>
|
||||
inline bool WriteAdaptiveInt32LE(Tfile & f, const uint32 v, std::size_t minSize = 0, std::size_t maxSize = 0)
|
||||
inline bool WriteAdaptiveInt32LE(Tfile & f, const uint32 v, std::size_t fixedSize = 0)
|
||||
{
|
||||
std::size_t minSize = fixedSize;
|
||||
std::size_t maxSize = fixedSize;
|
||||
MPT_ASSERT(minSize == 0 || minSize == 1 || minSize == 2 || minSize == 3 || minSize == 4);
|
||||
MPT_ASSERT(maxSize == 0 || maxSize == 1 || maxSize == 2 || maxSize == 3 || maxSize == 4);
|
||||
MPT_ASSERT(maxSize == 0 || maxSize >= minSize);
|
||||
if(v < 0x40 && minSize <= 1 && (1 <= maxSize || maxSize == 0))
|
||||
if(maxSize == 0)
|
||||
{
|
||||
maxSize = 4;
|
||||
}
|
||||
if(v < 0x40 && minSize <= 1 && 1 <= maxSize)
|
||||
{
|
||||
return IO::WriteIntLE<uint8>(f, static_cast<uint8>(v << 2) | 0x00);
|
||||
} else if(v < 0x4000 && minSize <= 2 && (2 <= maxSize || maxSize == 0))
|
||||
} else if(v < 0x4000 && minSize <= 2 && 2 <= maxSize)
|
||||
{
|
||||
return IO::WriteIntLE<uint16>(f, static_cast<uint16>(v << 2) | 0x01);
|
||||
} else if(v < 0x400000 && minSize <= 3 && (3 <= maxSize || maxSize == 0))
|
||||
} else if(v < 0x400000 && minSize <= 3 && 3 <= maxSize)
|
||||
{
|
||||
uint32 value = static_cast<uint32>(v << 2) | 0x02;
|
||||
mpt::byte bytes[3];
|
||||
|
@ -417,7 +453,7 @@ inline bool WriteAdaptiveInt32LE(Tfile & f, const uint32 v, std::size_t minSize
|
|||
bytes[1] = static_cast<mpt::byte>(value >> 8);
|
||||
bytes[2] = static_cast<mpt::byte>(value >> 16);
|
||||
return IO::WriteRaw(f, bytes, 3);
|
||||
} else if(v < 0x40000000 && minSize <= 4 && (4 <= maxSize || maxSize == 0))
|
||||
} else if(v < 0x40000000 && minSize <= 4 && 4 <= maxSize)
|
||||
{
|
||||
return IO::WriteIntLE<uint32>(f, static_cast<uint32>(v << 2) | 0x03);
|
||||
} else
|
||||
|
@ -428,21 +464,27 @@ inline bool WriteAdaptiveInt32LE(Tfile & f, const uint32 v, std::size_t minSize
|
|||
}
|
||||
|
||||
template <typename Tfile>
|
||||
inline bool WriteAdaptiveInt64LE(Tfile & f, const uint64 v, std::size_t minSize = 0, std::size_t maxSize = 0)
|
||||
inline bool WriteAdaptiveInt64LE(Tfile & f, const uint64 v, std::size_t fixedSize = 0)
|
||||
{
|
||||
std::size_t minSize = fixedSize;
|
||||
std::size_t maxSize = fixedSize;
|
||||
MPT_ASSERT(minSize == 0 || minSize == 1 || minSize == 2 || minSize == 4 || minSize == 8);
|
||||
MPT_ASSERT(maxSize == 0 || maxSize == 1 || maxSize == 2 || maxSize == 4 || maxSize == 8);
|
||||
MPT_ASSERT(maxSize == 0 || maxSize >= minSize);
|
||||
if(v < 0x40 && minSize <= 1 && (1 <= maxSize || maxSize == 0))
|
||||
if(maxSize == 0)
|
||||
{
|
||||
maxSize = 8;
|
||||
}
|
||||
if(v < 0x40 && minSize <= 1 && 1 <= maxSize)
|
||||
{
|
||||
return IO::WriteIntLE<uint8>(f, static_cast<uint8>(v << 2) | 0x00);
|
||||
} else if(v < 0x4000 && minSize <= 2 && (2 <= maxSize || maxSize == 0))
|
||||
} else if(v < 0x4000 && minSize <= 2 && 2 <= maxSize)
|
||||
{
|
||||
return IO::WriteIntLE<uint16>(f, static_cast<uint16>(v << 2) | 0x01);
|
||||
} else if(v < 0x40000000 && minSize <= 4 && (4 <= maxSize || maxSize == 0))
|
||||
} else if(v < 0x40000000 && minSize <= 4 && 4 <= maxSize)
|
||||
{
|
||||
return IO::WriteIntLE<uint32>(f, static_cast<uint32>(v << 2) | 0x02);
|
||||
} else if(v < 0x4000000000000000ull && minSize <= 8 && (8 <= maxSize || maxSize == 0))
|
||||
} else if(v < 0x4000000000000000ull && minSize <= 8 && 8 <= maxSize)
|
||||
{
|
||||
return IO::WriteIntLE<uint64>(f, static_cast<uint64>(v << 2) | 0x03);
|
||||
} else
|
||||
|
@ -523,6 +565,105 @@ inline bool WriteTextLF(Tfile &f, const std::string &s)
|
|||
return mpt::IO::WriteText(f, s) && mpt::IO::WriteTextLF(f);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// WriteBuffer class that avoids calling to the underlying file writing
|
||||
// functions for every operation, which would involve rather slow un-inlinable
|
||||
// virtual calls in the iostream and FILE* cases. It is the users responabiliy
|
||||
// to call HasWriteError() to check for writeback errors at this buffering
|
||||
// level.
|
||||
|
||||
template <typename Tfile>
|
||||
class WriteBuffer
|
||||
{
|
||||
private:
|
||||
mpt::byte_span buffer;
|
||||
std::size_t size = 0;
|
||||
Tfile & f;
|
||||
bool writeError = false;
|
||||
public:
|
||||
WriteBuffer(const WriteBuffer &) = delete;
|
||||
WriteBuffer & operator=(const WriteBuffer &) = delete;
|
||||
public:
|
||||
inline WriteBuffer(Tfile & f_, mpt::byte_span buffer_)
|
||||
: buffer(buffer_)
|
||||
, f(f_)
|
||||
{
|
||||
}
|
||||
inline ~WriteBuffer() noexcept(false)
|
||||
{
|
||||
if(!writeError)
|
||||
{
|
||||
FlushLocal();
|
||||
}
|
||||
}
|
||||
public:
|
||||
inline Tfile & file() const
|
||||
{
|
||||
if(IsDirty())
|
||||
{
|
||||
FlushLocal();
|
||||
}
|
||||
return f;
|
||||
}
|
||||
public:
|
||||
inline bool HasWriteError() const
|
||||
{
|
||||
return writeError;
|
||||
}
|
||||
inline void ClearError()
|
||||
{
|
||||
writeError = false;
|
||||
}
|
||||
inline bool IsDirty() const
|
||||
{
|
||||
return size > 0;
|
||||
}
|
||||
inline bool IsClean() const
|
||||
{
|
||||
return size == 0;
|
||||
}
|
||||
inline bool IsFull() const
|
||||
{
|
||||
return size == buffer.size();
|
||||
}
|
||||
inline bool Write(mpt::const_byte_span data)
|
||||
{
|
||||
bool result = true;
|
||||
for(std::size_t i = 0; i < data.size(); ++i)
|
||||
{
|
||||
buffer[size] = data[i];
|
||||
size++;
|
||||
if(IsFull())
|
||||
{
|
||||
FlushLocal();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
inline void FlushLocal()
|
||||
{
|
||||
if(IsClean())
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
if(!mpt::IO::WriteRaw(f, mpt::as_span(buffer.data(), size)))
|
||||
{
|
||||
writeError = true;
|
||||
}
|
||||
} catch (const std::exception &)
|
||||
{
|
||||
writeError = true;
|
||||
throw;
|
||||
}
|
||||
size = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace IO
|
||||
|
||||
|
||||
|
@ -536,9 +677,11 @@ class IFileDataContainer {
|
|||
public:
|
||||
typedef std::size_t off_t;
|
||||
protected:
|
||||
IFileDataContainer() { }
|
||||
IFileDataContainer() = default;
|
||||
public:
|
||||
virtual ~IFileDataContainer() { }
|
||||
IFileDataContainer(const IFileDataContainer&) = default;
|
||||
IFileDataContainer & operator=(const IFileDataContainer&) = default;
|
||||
virtual ~IFileDataContainer() = default;
|
||||
public:
|
||||
virtual bool IsValid() const = 0;
|
||||
virtual bool HasFastGetLength() const = 0;
|
||||
|
@ -547,6 +690,11 @@ public:
|
|||
virtual off_t GetLength() const = 0;
|
||||
virtual off_t Read(mpt::byte *dst, off_t pos, off_t count) const = 0;
|
||||
|
||||
virtual off_t Read(off_t pos, mpt::byte_span dst) const
|
||||
{
|
||||
return Read(dst.data(), pos, dst.size());
|
||||
}
|
||||
|
||||
virtual bool CanRead(off_t pos, off_t length) const
|
||||
{
|
||||
off_t dataLength = GetLength();
|
||||
|
@ -576,33 +724,32 @@ public:
|
|||
class FileDataContainerDummy : public IFileDataContainer {
|
||||
public:
|
||||
FileDataContainerDummy() { }
|
||||
virtual ~FileDataContainerDummy() { }
|
||||
public:
|
||||
bool IsValid() const
|
||||
bool IsValid() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HasFastGetLength() const
|
||||
bool HasFastGetLength() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HasPinnedView() const
|
||||
bool HasPinnedView() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
const mpt::byte *GetRawData() const
|
||||
const mpt::byte *GetRawData() const override
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
off_t GetLength() const
|
||||
off_t GetLength() const override
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
off_t Read(mpt::byte * /*dst*/, off_t /*pos*/, off_t /*count*/) const
|
||||
off_t Read(mpt::byte * /*dst*/, off_t /*pos*/, off_t /*count*/) const override
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -617,27 +764,28 @@ private:
|
|||
const off_t dataLength;
|
||||
public:
|
||||
FileDataContainerWindow(std::shared_ptr<const IFileDataContainer> src, off_t off, off_t len) : data(src), dataOffset(off), dataLength(len) { }
|
||||
virtual ~FileDataContainerWindow() { }
|
||||
|
||||
bool IsValid() const
|
||||
bool IsValid() const override
|
||||
{
|
||||
return data->IsValid();
|
||||
}
|
||||
bool HasFastGetLength() const
|
||||
bool HasFastGetLength() const override
|
||||
{
|
||||
return data->HasFastGetLength();
|
||||
}
|
||||
bool HasPinnedView() const
|
||||
bool HasPinnedView() const override
|
||||
{
|
||||
return data->HasPinnedView();
|
||||
}
|
||||
const mpt::byte *GetRawData() const {
|
||||
const mpt::byte *GetRawData() const override
|
||||
{
|
||||
return data->GetRawData() + dataOffset;
|
||||
}
|
||||
off_t GetLength() const {
|
||||
off_t GetLength() const override
|
||||
{
|
||||
return dataLength;
|
||||
}
|
||||
off_t Read(mpt::byte *dst, off_t pos, off_t count) const
|
||||
off_t Read(mpt::byte *dst, off_t pos, off_t count) const override
|
||||
{
|
||||
if(pos >= dataLength)
|
||||
{
|
||||
|
@ -645,7 +793,8 @@ public:
|
|||
}
|
||||
return data->Read(dst, dataOffset + pos, std::min(count, dataLength - pos));
|
||||
}
|
||||
bool CanRead(off_t pos, off_t length) const {
|
||||
bool CanRead(off_t pos, off_t length) const override
|
||||
{
|
||||
if((pos == dataLength) && (length == 0))
|
||||
{
|
||||
return true;
|
||||
|
@ -656,7 +805,7 @@ public:
|
|||
}
|
||||
return (length <= dataLength - pos);
|
||||
}
|
||||
off_t GetReadableLength(off_t pos, off_t length) const
|
||||
off_t GetReadableLength(off_t pos, off_t length) const override
|
||||
{
|
||||
if(pos >= dataLength)
|
||||
{
|
||||
|
@ -679,7 +828,6 @@ private:
|
|||
protected:
|
||||
|
||||
FileDataContainerSeekable(off_t length);
|
||||
virtual ~FileDataContainerSeekable();
|
||||
|
||||
private:
|
||||
|
||||
|
@ -687,12 +835,12 @@ private:
|
|||
|
||||
public:
|
||||
|
||||
bool IsValid() const;
|
||||
bool HasFastGetLength() const;
|
||||
bool HasPinnedView() const;
|
||||
const mpt::byte *GetRawData() const;
|
||||
off_t GetLength() const;
|
||||
off_t Read(mpt::byte *dst, off_t pos, off_t count) const;
|
||||
bool IsValid() const override;
|
||||
bool HasFastGetLength() const override;
|
||||
bool HasPinnedView() const override;
|
||||
const mpt::byte *GetRawData() const override;
|
||||
off_t GetLength() const override;
|
||||
off_t Read(mpt::byte *dst, off_t pos, off_t count) const override;
|
||||
|
||||
private:
|
||||
|
||||
|
@ -710,14 +858,13 @@ private:
|
|||
public:
|
||||
|
||||
FileDataContainerStdStreamSeekable(std::istream *s);
|
||||
virtual ~FileDataContainerStdStreamSeekable();
|
||||
|
||||
static bool IsSeekable(std::istream *stream);
|
||||
static off_t GetLength(std::istream *stream);
|
||||
|
||||
private:
|
||||
|
||||
off_t InternalRead(mpt::byte *dst, off_t pos, off_t count) const;
|
||||
off_t InternalRead(mpt::byte *dst, off_t pos, off_t count) const override;
|
||||
|
||||
};
|
||||
|
||||
|
@ -733,12 +880,13 @@ private:
|
|||
protected:
|
||||
|
||||
FileDataContainerUnseekable();
|
||||
virtual ~FileDataContainerUnseekable();
|
||||
|
||||
private:
|
||||
|
||||
static const std::size_t QUANTUM_SIZE = mpt::IO::BUFFERSIZE_SMALL;
|
||||
static const std::size_t BUFFER_SIZE = mpt::IO::BUFFERSIZE_NORMAL;
|
||||
enum : std::size_t {
|
||||
QUANTUM_SIZE = mpt::IO::BUFFERSIZE_SMALL,
|
||||
BUFFER_SIZE = mpt::IO::BUFFERSIZE_NORMAL
|
||||
};
|
||||
|
||||
void EnsureCacheBuffer(std::size_t requiredbuffersize) const;
|
||||
void CacheStream() const;
|
||||
|
@ -750,14 +898,14 @@ private:
|
|||
|
||||
public:
|
||||
|
||||
bool IsValid() const;
|
||||
bool HasFastGetLength() const;
|
||||
bool HasPinnedView() const;
|
||||
const mpt::byte *GetRawData() const;
|
||||
off_t GetLength() const;
|
||||
off_t Read(mpt::byte *dst, off_t pos, off_t count) const;
|
||||
bool CanRead(off_t pos, off_t length) const;
|
||||
off_t GetReadableLength(off_t pos, off_t length) const;
|
||||
bool IsValid() const override;
|
||||
bool HasFastGetLength() const override;
|
||||
bool HasPinnedView() const override;
|
||||
const mpt::byte *GetRawData() const override;
|
||||
off_t GetLength() const override;
|
||||
off_t Read(mpt::byte *dst, off_t pos, off_t count) const override;
|
||||
bool CanRead(off_t pos, off_t length) const override;
|
||||
off_t GetReadableLength(off_t pos, off_t length) const override;
|
||||
|
||||
private:
|
||||
|
||||
|
@ -776,12 +924,11 @@ private:
|
|||
public:
|
||||
|
||||
FileDataContainerStdStream(std::istream *s);
|
||||
virtual ~FileDataContainerStdStream();
|
||||
|
||||
private:
|
||||
|
||||
bool InternalEof() const;
|
||||
off_t InternalRead(mpt::byte *dst, off_t count) const;
|
||||
bool InternalEof() const override;
|
||||
off_t InternalRead(mpt::byte *dst, off_t count) const override;
|
||||
|
||||
};
|
||||
|
||||
|
@ -791,9 +938,11 @@ private:
|
|||
|
||||
struct CallbackStream
|
||||
{
|
||||
static const int SeekSet = 0;
|
||||
static const int SeekCur = 1;
|
||||
static const int SeekEnd = 2;
|
||||
enum : int {
|
||||
SeekSet = 0,
|
||||
SeekCur = 1,
|
||||
SeekEnd = 2
|
||||
};
|
||||
void *stream;
|
||||
std::size_t (*read)( void * stream, void * dst, std::size_t bytes );
|
||||
int (*seek)( void * stream, int64 offset, int whence );
|
||||
|
@ -809,9 +958,8 @@ public:
|
|||
static bool IsSeekable(CallbackStream stream);
|
||||
static off_t GetLength(CallbackStream stream);
|
||||
FileDataContainerCallbackStreamSeekable(CallbackStream s);
|
||||
virtual ~FileDataContainerCallbackStreamSeekable();
|
||||
private:
|
||||
off_t InternalRead(mpt::byte *dst, off_t pos, off_t count) const;
|
||||
off_t InternalRead(mpt::byte *dst, off_t pos, off_t count) const override;
|
||||
};
|
||||
|
||||
|
||||
|
@ -822,10 +970,9 @@ private:
|
|||
mutable bool eof_reached;
|
||||
public:
|
||||
FileDataContainerCallbackStream(CallbackStream s);
|
||||
virtual ~FileDataContainerCallbackStream();
|
||||
private:
|
||||
bool InternalEof() const;
|
||||
off_t InternalRead(mpt::byte *dst, off_t count) const;
|
||||
bool InternalEof() const override;
|
||||
off_t InternalRead(mpt::byte *dst, off_t count) const override;
|
||||
};
|
||||
|
||||
|
||||
|
@ -841,6 +988,12 @@ class FileDataContainerMemory
|
|||
#endif
|
||||
{
|
||||
|
||||
#if defined(MPT_FILEREADER_STD_ISTREAM)
|
||||
#define MPT_FILEDATACONTAINERMEMORY_OVERRIDE override
|
||||
#else
|
||||
#define MPT_FILEDATACONTAINERMEMORY_OVERRIDE
|
||||
#endif
|
||||
|
||||
#if !defined(MPT_FILEREADER_STD_ISTREAM)
|
||||
public:
|
||||
typedef std::size_t off_t;
|
||||
|
@ -854,39 +1007,35 @@ private:
|
|||
public:
|
||||
FileDataContainerMemory() : streamData(nullptr), streamLength(0) { }
|
||||
FileDataContainerMemory(mpt::const_byte_span data) : streamData(data.data()), streamLength(data.size()) { }
|
||||
#if defined(MPT_FILEREADER_STD_ISTREAM)
|
||||
virtual
|
||||
#endif
|
||||
~FileDataContainerMemory() { }
|
||||
|
||||
public:
|
||||
|
||||
bool IsValid() const
|
||||
bool IsValid() const MPT_FILEDATACONTAINERMEMORY_OVERRIDE
|
||||
{
|
||||
return streamData != nullptr;
|
||||
}
|
||||
|
||||
bool HasFastGetLength() const
|
||||
bool HasFastGetLength() const MPT_FILEDATACONTAINERMEMORY_OVERRIDE
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HasPinnedView() const
|
||||
bool HasPinnedView() const MPT_FILEDATACONTAINERMEMORY_OVERRIDE
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
const mpt::byte *GetRawData() const
|
||||
const mpt::byte *GetRawData() const MPT_FILEDATACONTAINERMEMORY_OVERRIDE
|
||||
{
|
||||
return streamData;
|
||||
}
|
||||
|
||||
off_t GetLength() const
|
||||
off_t GetLength() const MPT_FILEDATACONTAINERMEMORY_OVERRIDE
|
||||
{
|
||||
return streamLength;
|
||||
}
|
||||
|
||||
off_t Read(mpt::byte *dst, off_t pos, off_t count) const
|
||||
off_t Read(mpt::byte *dst, off_t pos, off_t count) const MPT_FILEDATACONTAINERMEMORY_OVERRIDE
|
||||
{
|
||||
if(pos >= streamLength)
|
||||
{
|
||||
|
@ -897,7 +1046,12 @@ public:
|
|||
return avail;
|
||||
}
|
||||
|
||||
bool CanRead(off_t pos, off_t length) const
|
||||
off_t Read(off_t pos, mpt::byte_span dst) const MPT_FILEDATACONTAINERMEMORY_OVERRIDE
|
||||
{
|
||||
return Read(dst.data(), pos, dst.size());
|
||||
}
|
||||
|
||||
bool CanRead(off_t pos, off_t length) const MPT_FILEDATACONTAINERMEMORY_OVERRIDE
|
||||
{
|
||||
if((pos == streamLength) && (length == 0))
|
||||
{
|
||||
|
@ -910,7 +1064,7 @@ public:
|
|||
return (length <= streamLength - pos);
|
||||
}
|
||||
|
||||
off_t GetReadableLength(off_t pos, off_t length) const
|
||||
off_t GetReadableLength(off_t pos, off_t length) const MPT_FILEDATACONTAINERMEMORY_OVERRIDE
|
||||
{
|
||||
if(pos >= streamLength)
|
||||
{
|
||||
|
|
|
@ -119,10 +119,10 @@ public:
|
|||
switch(path.GetSearchPath())
|
||||
{
|
||||
case mpt::LibrarySearchPathDefault:
|
||||
hModule = LoadLibraryExW(path.GetFileName().AsNative().c_str(), NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
|
||||
hModule = LoadLibraryEx(path.GetFileName().AsNative().c_str(), NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
|
||||
break;
|
||||
case mpt::LibrarySearchPathSystem:
|
||||
hModule = LoadLibraryExW(path.GetFileName().AsNative().c_str(), NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
|
||||
hModule = LoadLibraryEx(path.GetFileName().AsNative().c_str(), NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
|
||||
break;
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
// Using restricted search paths applies to potential DLL dependencies
|
||||
|
@ -136,20 +136,20 @@ public:
|
|||
const mpt::PathString dllPath = mpt::GetAppPath();
|
||||
if(!dllPath.empty() && mpt::PathIsAbsolute(dllPath) && dllPath.IsDirectory())
|
||||
{
|
||||
hModule = LoadLibraryW((dllPath + path.GetFileName()).AsNative().c_str());
|
||||
hModule = LoadLibrary((dllPath + path.GetFileName()).AsNative().c_str());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case mpt::LibrarySearchPathFullPath:
|
||||
hModule = LoadLibraryW(path.GetFileName().AsNative().c_str());
|
||||
hModule = LoadLibrary(path.GetFileName().AsNative().c_str());
|
||||
break;
|
||||
#else
|
||||
// For libopenmpt, do the safe thing.
|
||||
case mpt::LibrarySearchPathApplication:
|
||||
hModule = LoadLibraryExW(path.GetFileName().AsNative().c_str(), NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR);
|
||||
hModule = LoadLibraryEx(path.GetFileName().AsNative().c_str(), NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR);
|
||||
break;
|
||||
case mpt::LibrarySearchPathFullPath:
|
||||
hModule = LoadLibraryExW(path.GetFileName().AsNative().c_str(), NULL, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR);
|
||||
hModule = LoadLibraryEx(path.GetFileName().AsNative().c_str(), NULL, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR);
|
||||
break;
|
||||
#endif
|
||||
case mpt::LibrarySearchPathInvalid:
|
||||
|
@ -161,14 +161,14 @@ public:
|
|||
switch(path.GetSearchPath())
|
||||
{
|
||||
case mpt::LibrarySearchPathDefault:
|
||||
hModule = LoadLibraryW(path.GetFileName().AsNative().c_str());
|
||||
hModule = LoadLibrary(path.GetFileName().AsNative().c_str());
|
||||
break;
|
||||
case mpt::LibrarySearchPathApplication:
|
||||
{
|
||||
const mpt::PathString dllPath = mpt::GetAppPath();
|
||||
if(!dllPath.empty() && mpt::PathIsAbsolute(dllPath) && dllPath.IsDirectory())
|
||||
{
|
||||
hModule = LoadLibraryW((dllPath + path.GetFileName()).AsNative().c_str());
|
||||
hModule = LoadLibrary((dllPath + path.GetFileName()).AsNative().c_str());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -177,12 +177,12 @@ public:
|
|||
const mpt::PathString dllPath = mpt::GetSystemPath();
|
||||
if(!dllPath.empty() && mpt::PathIsAbsolute(dllPath) && dllPath.IsDirectory())
|
||||
{
|
||||
hModule = LoadLibraryW((dllPath + path.GetFileName()).AsNative().c_str());
|
||||
hModule = LoadLibrary((dllPath + path.GetFileName()).AsNative().c_str());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case mpt::LibrarySearchPathFullPath:
|
||||
hModule = LoadLibraryW(path.GetFileName().AsNative().c_str());
|
||||
hModule = LoadLibrary(path.GetFileName().AsNative().c_str());
|
||||
break;
|
||||
case mpt::LibrarySearchPathInvalid:
|
||||
MPT_ASSERT_NOTREACHED();
|
||||
|
@ -432,15 +432,15 @@ mpt::PathString LibraryPath::GetFileName() const
|
|||
mpt::PathString LibraryPath::GetDefaultPrefix()
|
||||
{
|
||||
#if MPT_OS_WINDOWS
|
||||
return MPT_PATHSTRING("");
|
||||
return P_("");
|
||||
#elif MPT_OS_ANDROID
|
||||
return MPT_PATHSTRING("lib");
|
||||
return P_("lib");
|
||||
#elif defined(MPT_WITH_LTDL)
|
||||
return MPT_PATHSTRING("lib");
|
||||
return P_("lib");
|
||||
#elif defined(MPT_WITH_DL)
|
||||
return MPT_PATHSTRING("lib");
|
||||
return P_("lib");
|
||||
#else
|
||||
return MPT_PATHSTRING("lib");
|
||||
return P_("lib");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -448,13 +448,13 @@ mpt::PathString LibraryPath::GetDefaultPrefix()
|
|||
mpt::PathString LibraryPath::GetDefaultSuffix()
|
||||
{
|
||||
#if MPT_OS_WINDOWS
|
||||
return MPT_PATHSTRING(".dll");
|
||||
return P_(".dll");
|
||||
#elif MPT_OS_ANDROID
|
||||
return MPT_PATHSTRING(".so");
|
||||
return P_(".so");
|
||||
#elif defined(MPT_WITH_LTDL)
|
||||
return MPT_PATHSTRING(""); // handled by libltdl
|
||||
return P_(""); // handled by libltdl
|
||||
#elif defined(MPT_WITH_DL)
|
||||
return MPT_PATHSTRING(".so");
|
||||
return P_(".so");
|
||||
#else
|
||||
return mpt::PathString();
|
||||
#endif
|
||||
|
@ -479,7 +479,7 @@ LibraryPath LibraryPath::AppDataFullName(const mpt::PathString &fullname, const
|
|||
{
|
||||
if(appdata.empty())
|
||||
{
|
||||
return LibraryPath(mpt::LibrarySearchPathInvalid, MPT_PATHSTRING(""));
|
||||
return LibraryPath(mpt::LibrarySearchPathInvalid, P_(""));
|
||||
}
|
||||
return LibraryPath(mpt::LibrarySearchPathFullPath, appdata.WithTrailingSlash() + fullname + GetDefaultSuffix());
|
||||
}
|
||||
|
@ -544,6 +544,12 @@ FuncPtr Library::GetProcAddress(const std::string &symbol) const
|
|||
} // namespace mpt
|
||||
|
||||
|
||||
#else // !MPT_ENABLE_DYNBIND
|
||||
|
||||
|
||||
MPT_MSVC_WORKAROUND_LNK4221(mptLibrary)
|
||||
|
||||
|
||||
#endif // MPT_ENABLE_DYNBIND
|
||||
|
||||
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
|
370
Frameworks/OpenMPT/OpenMPT/common/mptMemory.h
Normal file
370
Frameworks/OpenMPT/OpenMPT/common/mptMemory.h
Normal file
|
@ -0,0 +1,370 @@
|
|||
/*
|
||||
* mptMemory.h
|
||||
* -----------
|
||||
* Purpose: Raw memory manipulation
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
|
||||
#include "mptAssert.h"
|
||||
#include "mptBaseTypes.h"
|
||||
#include "mptSpan.h"
|
||||
|
||||
#if MPT_CXX_AT_LEAST(20)
|
||||
#include <bit>
|
||||
#endif
|
||||
#include <utility>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
|
||||
namespace mpt {
|
||||
|
||||
|
||||
|
||||
typedef mpt::span<mpt::byte> byte_span;
|
||||
typedef mpt::span<const mpt::byte> const_byte_span;
|
||||
|
||||
|
||||
|
||||
// Tell which types are safe for mpt::byte_cast.
|
||||
// signed char is actually not allowed to alias into an object representation,
|
||||
// which means that, if the actual type is not itself signed char but char or
|
||||
// unsigned char instead, dereferencing the signed char pointer is undefined
|
||||
// behaviour.
|
||||
template <typename T> struct is_byte_castable : public std::false_type { };
|
||||
template <> struct is_byte_castable<char> : public std::true_type { };
|
||||
template <> struct is_byte_castable<unsigned char> : public std::true_type { };
|
||||
#if MPT_BYTE_IS_STD_BYTE
|
||||
template <> struct is_byte_castable<mpt::byte> : public std::true_type { };
|
||||
#endif
|
||||
template <> struct is_byte_castable<const char> : public std::true_type { };
|
||||
template <> struct is_byte_castable<const unsigned char> : public std::true_type { };
|
||||
#if MPT_BYTE_IS_STD_BYTE
|
||||
template <> struct is_byte_castable<const mpt::byte> : public std::true_type { };
|
||||
#endif
|
||||
|
||||
|
||||
template <typename T> struct is_byte : public std::false_type { };
|
||||
template <> struct is_byte<mpt::byte> : public std::true_type { };
|
||||
template <> struct is_byte<const mpt::byte> : public std::true_type { };
|
||||
|
||||
|
||||
// Tell which types are safe to binary write into files.
|
||||
// By default, no types are safe.
|
||||
// When a safe type gets defined,
|
||||
// also specialize this template so that IO functions will work.
|
||||
template <typename T> struct is_binary_safe : public std::false_type { };
|
||||
|
||||
// Specialization for byte types.
|
||||
template <> struct is_binary_safe<char> : public std::true_type { };
|
||||
template <> struct is_binary_safe<uint8> : public std::true_type { };
|
||||
template <> struct is_binary_safe<int8> : public std::true_type { };
|
||||
#if MPT_BYTE_IS_STD_BYTE
|
||||
template <> struct is_binary_safe<mpt::byte> : public std::true_type { };
|
||||
#endif
|
||||
|
||||
// Generic Specialization for arrays.
|
||||
template <typename T, std::size_t N> struct is_binary_safe<T[N]> : public is_binary_safe<T> { };
|
||||
template <typename T, std::size_t N> struct is_binary_safe<const T[N]> : public is_binary_safe<T> { };
|
||||
template <typename T, std::size_t N> struct is_binary_safe<std::array<T, N>> : public is_binary_safe<T> { };
|
||||
template <typename T, std::size_t N> struct is_binary_safe<const std::array<T, N>> : public is_binary_safe<T> { };
|
||||
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
#define MPT_BINARY_STRUCT(type, size) \
|
||||
MPT_STATIC_ASSERT(sizeof( type ) == (size) ); \
|
||||
MPT_STATIC_ASSERT(alignof( type ) == 1); \
|
||||
MPT_STATIC_ASSERT(std::is_standard_layout< type >::value); \
|
||||
namespace mpt { \
|
||||
template <> struct is_binary_safe< type > : public std::true_type { }; \
|
||||
} \
|
||||
/**/
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct value_initializer
|
||||
{
|
||||
inline void operator () (T & x)
|
||||
{
|
||||
x = T();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
struct value_initializer<T[N]>
|
||||
{
|
||||
inline void operator () (T (& a)[N])
|
||||
{
|
||||
for(auto & e : a)
|
||||
{
|
||||
value_initializer<T>()(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline void Clear(T & x)
|
||||
{
|
||||
MPT_STATIC_ASSERT(!std::is_pointer<T>::value);
|
||||
value_initializer<T>()(x);
|
||||
}
|
||||
|
||||
|
||||
// Memset given object to zero.
|
||||
template <class T>
|
||||
inline void MemsetZero(T &a)
|
||||
{
|
||||
static_assert(std::is_pointer<T>::value == false, "Won't memset pointers.");
|
||||
#if MPT_GCC_BEFORE(5,1,0) || (MPT_COMPILER_CLANG && defined(__GLIBCXX__))
|
||||
MPT_STATIC_ASSERT(std::is_standard_layout<T>::value);
|
||||
MPT_STATIC_ASSERT(std::is_trivial<T>::value || mpt::is_binary_safe<T>::value); // approximation
|
||||
#else // default
|
||||
MPT_STATIC_ASSERT(std::is_standard_layout<T>::value);
|
||||
MPT_STATIC_ASSERT((std::is_trivially_default_constructible<T>::value && std::is_trivially_copyable<T>::value) || mpt::is_binary_safe<T>::value); // C++11, but not supported on most compilers we care about
|
||||
#endif
|
||||
std::memset(&a, 0, sizeof(T));
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace mpt {
|
||||
|
||||
|
||||
|
||||
#if MPT_CXX_AT_LEAST(20)
|
||||
using std::bit_cast;
|
||||
#else
|
||||
// C++2a compatible bit_cast.
|
||||
// See <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0476r1.html>.
|
||||
// Not implementing constexpr because this is not easily possible pre C++2a.
|
||||
template <typename Tdst, typename Tsrc>
|
||||
MPT_FORCEINLINE Tdst bit_cast(const Tsrc & src) noexcept
|
||||
{
|
||||
MPT_STATIC_ASSERT(sizeof(Tdst) == sizeof(Tsrc));
|
||||
#if MPT_GCC_BEFORE(5,1,0) || (MPT_COMPILER_CLANG && defined(__GLIBCXX__))
|
||||
MPT_STATIC_ASSERT(std::is_trivial<Tdst>::value); // approximation
|
||||
MPT_STATIC_ASSERT(std::is_trivial<Tsrc>::value); // approximation
|
||||
#else // default
|
||||
MPT_STATIC_ASSERT(std::is_trivially_copyable<Tdst>::value);
|
||||
MPT_STATIC_ASSERT(std::is_trivially_copyable<Tsrc>::value);
|
||||
#endif
|
||||
#if MPT_COMPILER_GCC || MPT_COMPILER_MSVC
|
||||
// Compiler supports type-punning through unions. This is not stricly standard-conforming.
|
||||
// For GCC, this is documented, for MSVC this is apparently not documented, but we assume it.
|
||||
union {
|
||||
Tsrc src;
|
||||
Tdst dst;
|
||||
} conv;
|
||||
conv.src = src;
|
||||
return conv.dst;
|
||||
#else // MPT_COMPILER
|
||||
// Compiler does not support type-punning through unions. std::memcpy is used instead.
|
||||
// This is the safe fallback and strictly standard-conforming.
|
||||
// Another standard-compliant alternative would be casting pointers to a character type pointer.
|
||||
// This results in rather unreadable code and,
|
||||
// in most cases, compilers generate better code by just inlining the memcpy anyway.
|
||||
// (see <http://blog.regehr.org/archives/959>).
|
||||
Tdst dst{};
|
||||
std::memcpy(&dst, &src, sizeof(Tdst));
|
||||
return dst;
|
||||
#endif // MPT_COMPILER
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
template <typename Tdst, typename Tsrc>
|
||||
struct byte_cast_impl
|
||||
{
|
||||
inline Tdst operator () (Tsrc src) const
|
||||
{
|
||||
STATIC_ASSERT(sizeof(Tsrc) == sizeof(mpt::byte));
|
||||
STATIC_ASSERT(sizeof(Tdst) == sizeof(mpt::byte));
|
||||
// not checking is_byte_castable here because we are actually
|
||||
// doing a static_cast and converting the value
|
||||
STATIC_ASSERT(std::is_integral<Tsrc>::value || mpt::is_byte<Tsrc>::value);
|
||||
STATIC_ASSERT(std::is_integral<Tdst>::value || mpt::is_byte<Tdst>::value);
|
||||
return static_cast<Tdst>(src);
|
||||
}
|
||||
};
|
||||
template <typename Tdst, typename Tsrc>
|
||||
struct byte_cast_impl<mpt::span<Tdst>, mpt::span<Tsrc> >
|
||||
{
|
||||
inline mpt::span<Tdst> operator () (mpt::span<Tsrc> src) const
|
||||
{
|
||||
STATIC_ASSERT(sizeof(Tsrc) == sizeof(mpt::byte));
|
||||
STATIC_ASSERT(sizeof(Tdst) == sizeof(mpt::byte));
|
||||
STATIC_ASSERT(mpt::is_byte_castable<Tsrc>::value);
|
||||
STATIC_ASSERT(mpt::is_byte_castable<Tdst>::value);
|
||||
STATIC_ASSERT(std::is_integral<Tsrc>::value || mpt::is_byte<Tsrc>::value);
|
||||
STATIC_ASSERT(std::is_integral<Tdst>::value || mpt::is_byte<Tdst>::value);
|
||||
return mpt::as_span(mpt::byte_cast_impl<Tdst*, Tsrc*>()(src.begin()), mpt::byte_cast_impl<Tdst*, Tsrc*>()(src.end()));
|
||||
}
|
||||
};
|
||||
template <typename Tdst, typename Tsrc>
|
||||
struct byte_cast_impl<Tdst*, Tsrc*>
|
||||
{
|
||||
inline Tdst* operator () (Tsrc* src) const
|
||||
{
|
||||
STATIC_ASSERT(sizeof(Tsrc) == sizeof(mpt::byte));
|
||||
STATIC_ASSERT(sizeof(Tdst) == sizeof(mpt::byte));
|
||||
STATIC_ASSERT(mpt::is_byte_castable<Tsrc>::value);
|
||||
STATIC_ASSERT(mpt::is_byte_castable<Tdst>::value);
|
||||
STATIC_ASSERT(std::is_integral<Tsrc>::value || mpt::is_byte<Tsrc>::value);
|
||||
STATIC_ASSERT(std::is_integral<Tdst>::value || mpt::is_byte<Tdst>::value);
|
||||
return reinterpret_cast<Tdst*>(src);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Tdst, typename Tsrc>
|
||||
struct void_cast_impl;
|
||||
|
||||
template <typename Tdst>
|
||||
struct void_cast_impl<Tdst*, void*>
|
||||
{
|
||||
inline Tdst* operator () (void* src) const
|
||||
{
|
||||
STATIC_ASSERT(sizeof(Tdst) == sizeof(mpt::byte));
|
||||
STATIC_ASSERT(mpt::is_byte_castable<Tdst>::value);
|
||||
STATIC_ASSERT(std::is_integral<Tdst>::value || mpt::is_byte<Tdst>::value);
|
||||
return reinterpret_cast<Tdst*>(src);
|
||||
}
|
||||
};
|
||||
template <typename Tdst>
|
||||
struct void_cast_impl<Tdst*, const void*>
|
||||
{
|
||||
inline Tdst* operator () (const void* src) const
|
||||
{
|
||||
STATIC_ASSERT(sizeof(Tdst) == sizeof(mpt::byte));
|
||||
STATIC_ASSERT(mpt::is_byte_castable<Tdst>::value);
|
||||
STATIC_ASSERT(std::is_integral<Tdst>::value || mpt::is_byte<Tdst>::value);
|
||||
return reinterpret_cast<Tdst*>(src);
|
||||
}
|
||||
};
|
||||
template <typename Tsrc>
|
||||
struct void_cast_impl<void*, Tsrc*>
|
||||
{
|
||||
inline void* operator () (Tsrc* src) const
|
||||
{
|
||||
STATIC_ASSERT(sizeof(Tsrc) == sizeof(mpt::byte));
|
||||
STATIC_ASSERT(mpt::is_byte_castable<Tsrc>::value);
|
||||
STATIC_ASSERT(std::is_integral<Tsrc>::value || mpt::is_byte<Tsrc>::value);
|
||||
return reinterpret_cast<void*>(src);
|
||||
}
|
||||
};
|
||||
template <typename Tsrc>
|
||||
struct void_cast_impl<const void*, Tsrc*>
|
||||
{
|
||||
inline const void* operator () (Tsrc* src) const
|
||||
{
|
||||
STATIC_ASSERT(sizeof(Tsrc) == sizeof(mpt::byte));
|
||||
STATIC_ASSERT(mpt::is_byte_castable<Tsrc>::value);
|
||||
STATIC_ASSERT(std::is_integral<Tsrc>::value || mpt::is_byte<Tsrc>::value);
|
||||
return reinterpret_cast<const void*>(src);
|
||||
}
|
||||
};
|
||||
|
||||
// casts between different byte (char) types or pointers to these types
|
||||
template <typename Tdst, typename Tsrc>
|
||||
inline Tdst byte_cast(Tsrc src)
|
||||
{
|
||||
return byte_cast_impl<Tdst, Tsrc>()(src);
|
||||
}
|
||||
|
||||
// casts between pointers to void and pointers to byte
|
||||
template <typename Tdst, typename Tsrc>
|
||||
inline Tdst void_cast(Tsrc src)
|
||||
{
|
||||
return void_cast_impl<Tdst, Tsrc>()(src);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
MPT_CONSTEXPR14_FUN mpt::byte as_byte(T src) noexcept
|
||||
{
|
||||
MPT_STATIC_ASSERT(std::is_integral<T>::value);
|
||||
return static_cast<mpt::byte>(static_cast<uint8>(src));
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct GetRawBytesFunctor
|
||||
{
|
||||
inline mpt::const_byte_span operator () (const T & v) const
|
||||
{
|
||||
STATIC_ASSERT(mpt::is_binary_safe<typename std::remove_const<T>::type>::value);
|
||||
return mpt::as_span(reinterpret_cast<const mpt::byte *>(&v), sizeof(T));
|
||||
}
|
||||
inline mpt::byte_span operator () (T & v) const
|
||||
{
|
||||
STATIC_ASSERT(mpt::is_binary_safe<typename std::remove_const<T>::type>::value);
|
||||
return mpt::as_span(reinterpret_cast<mpt::byte *>(&v), sizeof(T));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
struct GetRawBytesFunctor<T[N]>
|
||||
{
|
||||
inline mpt::const_byte_span operator () (const T (&v)[N]) const
|
||||
{
|
||||
STATIC_ASSERT(mpt::is_binary_safe<typename std::remove_const<T>::type>::value);
|
||||
return mpt::as_span(reinterpret_cast<const mpt::byte *>(v), N * sizeof(T));
|
||||
}
|
||||
inline mpt::byte_span operator () (T (&v)[N]) const
|
||||
{
|
||||
STATIC_ASSERT(mpt::is_binary_safe<typename std::remove_const<T>::type>::value);
|
||||
return mpt::as_span(reinterpret_cast<mpt::byte *>(v), N * sizeof(T));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
struct GetRawBytesFunctor<const T[N]>
|
||||
{
|
||||
inline mpt::const_byte_span operator () (const T (&v)[N]) const
|
||||
{
|
||||
STATIC_ASSERT(mpt::is_binary_safe<typename std::remove_const<T>::type>::value);
|
||||
return mpt::as_span(reinterpret_cast<const mpt::byte *>(v), N * sizeof(T));
|
||||
}
|
||||
};
|
||||
|
||||
// In order to be able to partially specialize it,
|
||||
// as_raw_memory is implemented via a class template.
|
||||
// Do not overload or specialize as_raw_memory directly.
|
||||
// Using a wrapper (by default just around a cast to const mpt::byte *),
|
||||
// allows for implementing raw memory access
|
||||
// via on-demand generating a cached serialized representation.
|
||||
template <typename T> inline mpt::const_byte_span as_raw_memory(const T & v)
|
||||
{
|
||||
return mpt::GetRawBytesFunctor<T>()(v);
|
||||
}
|
||||
template <typename T> inline mpt::byte_span as_raw_memory(T & v)
|
||||
{
|
||||
return mpt::GetRawBytesFunctor<T>()(v);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
#include <vector> // some C++ header in order to have the C++ standard library version information available
|
||||
|
||||
#if !MPT_PLATFORM_MULTITHREADED
|
||||
|
@ -19,27 +21,27 @@
|
|||
#define MPT_MUTEX_STD 0
|
||||
#define MPT_MUTEX_PTHREAD 0
|
||||
#define MPT_MUTEX_WIN32 0
|
||||
#elif MPT_COMPILER_GENERIC && !defined(MPT_QUIRK_NO_CPP_THREAD)
|
||||
#elif MPT_COMPILER_GENERIC
|
||||
#define MPT_MUTEX_STD 1
|
||||
#define MPT_MUTEX_PTHREAD 0
|
||||
#define MPT_MUTEX_WIN32 0
|
||||
#elif MPT_COMPILER_MSVC && !defined(MPT_QUIRK_NO_CPP_THREAD)
|
||||
#elif (defined(__MINGW32__) || defined(__MINGW64__)) && !defined(_GLIBCXX_HAS_GTHREADS) && defined(MPT_WITH_MINGWSTDTHREADS)
|
||||
#define MPT_MUTEX_STD 1
|
||||
#define MPT_MUTEX_PTHREAD 0
|
||||
#define MPT_MUTEX_WIN32 0
|
||||
#elif MPT_COMPILER_GCC && !MPT_OS_WINDOWS && !defined(MPT_QUIRK_NO_CPP_THREAD)
|
||||
#elif (defined(__MINGW32__) || defined(__MINGW64__)) && !defined(_GLIBCXX_HAS_GTHREADS)
|
||||
#define MPT_MUTEX_STD 0
|
||||
#define MPT_MUTEX_PTHREAD 0
|
||||
#define MPT_MUTEX_WIN32 1
|
||||
#elif MPT_COMPILER_MSVC
|
||||
#define MPT_MUTEX_STD 1
|
||||
#define MPT_MUTEX_PTHREAD 0
|
||||
#define MPT_MUTEX_WIN32 0
|
||||
#elif MPT_COMPILER_CLANG && defined(__GLIBCXX__) && !defined(MPT_QUIRK_NO_CPP_THREAD)
|
||||
#elif MPT_COMPILER_GCC
|
||||
#define MPT_MUTEX_STD 1
|
||||
#define MPT_MUTEX_PTHREAD 0
|
||||
#define MPT_MUTEX_WIN32 0
|
||||
#elif (MPT_OS_MACOSX_OR_IOS || MPT_OS_FREEBSD) && MPT_COMPILER_CLANG && !defined(MPT_QUIRK_NO_CPP_THREAD)
|
||||
#define MPT_MUTEX_STD 1
|
||||
#define MPT_MUTEX_PTHREAD 0
|
||||
#define MPT_MUTEX_WIN32 0
|
||||
#elif MPT_CLANG_AT_LEAST(3,6,0) && defined(_LIBCPP_VERSION) && !defined(MPT_QUIRK_NO_CPP_THREAD)
|
||||
#elif MPT_COMPILER_CLANG
|
||||
#define MPT_MUTEX_STD 1
|
||||
#define MPT_MUTEX_PTHREAD 0
|
||||
#define MPT_MUTEX_WIN32 0
|
||||
|
@ -49,7 +51,7 @@
|
|||
#define MPT_MUTEX_WIN32 1
|
||||
#else
|
||||
#define MPT_MUTEX_STD 0
|
||||
#define MPT_MUTEX_PTHREAD 0
|
||||
#define MPT_MUTEX_PTHREAD 1
|
||||
#define MPT_MUTEX_WIN32 0
|
||||
#endif
|
||||
|
||||
|
@ -64,7 +66,11 @@
|
|||
#endif
|
||||
|
||||
#if MPT_MUTEX_STD
|
||||
#if (defined(__MINGW32__) || defined(__MINGW64__)) && !defined(_GLIBCXX_HAS_GTHREADS) && defined(MPT_WITH_MINGWSTDTHREADS)
|
||||
#include <mingw.mutex.h>
|
||||
#else
|
||||
#include <mutex>
|
||||
#endif
|
||||
#elif MPT_MUTEX_WIN32
|
||||
#include <windows.h>
|
||||
#elif MPT_MUTEX_PTHREAD
|
||||
|
|
|
@ -28,28 +28,10 @@ namespace Windows
|
|||
#if MPT_OS_WINDOWS
|
||||
|
||||
|
||||
#if !MPT_OS_WINDOWS_WINRT
|
||||
|
||||
static uint32 VersionDecimalTo_WIN32_WINNT(uint32 major, uint32 minor)
|
||||
{
|
||||
// GetVersionEx returns decimal.
|
||||
// _WIN32_WINNT macro uses BCD for the minor byte (see Windows 98 / ME).
|
||||
// We use what _WIN32_WINNT does.
|
||||
uint32 result = 0;
|
||||
minor = mpt::clamp<uint32>(minor, 0, 99);
|
||||
result |= major;
|
||||
result <<= 8;
|
||||
result |= minor/10*0x10 + minor%10;
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // !MPT_OS_WINDOWS_WINRT
|
||||
|
||||
|
||||
static void GatherWindowsVersion(uint32 & SystemVersion)
|
||||
static mpt::Windows::Version VersionFromNTDDI_VERSION() noexcept
|
||||
{
|
||||
// Initialize to used SDK version
|
||||
SystemVersion =
|
||||
mpt::Windows::Version::System System =
|
||||
#if NTDDI_VERSION >= 0x0A000000 // NTDDI_WIN10
|
||||
mpt::Windows::Version::Win10
|
||||
#elif NTDDI_VERSION >= 0x06030000 // NTDDI_WINBLUE
|
||||
|
@ -70,7 +52,25 @@ static void GatherWindowsVersion(uint32 & SystemVersion)
|
|||
mpt::Windows::Version::WinNT4
|
||||
#endif
|
||||
;
|
||||
#if !MPT_OS_WINDOWS_WINRT
|
||||
return mpt::Windows::Version(System, mpt::Windows::Version::ServicePack(((NTDDI_VERSION & 0xffffu) >> 8) & 0xffu, ((NTDDI_VERSION & 0xffffu) >> 0) & 0xffu), 0);
|
||||
}
|
||||
|
||||
|
||||
static mpt::Windows::Version::System SystemVersionFrom_WIN32_WINNT() noexcept
|
||||
{
|
||||
#if defined(_WIN32_WINNT)
|
||||
return mpt::Windows::Version::System((static_cast<uint64>(_WIN32_WINNT) & 0xff00u) >> 8, (static_cast<uint64>(_WIN32_WINNT) & 0x00ffu) >> 0);
|
||||
#else
|
||||
return mpt::Windows::Version::System();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static mpt::Windows::Version GatherWindowsVersion() noexcept
|
||||
{
|
||||
#if MPT_OS_WINDOWS_WINRT
|
||||
return VersionFromNTDDI_VERSION();
|
||||
#else // !MPT_OS_WINDOWS_WINRT
|
||||
OSVERSIONINFOEXW versioninfoex;
|
||||
MemsetZero(versioninfoex);
|
||||
versioninfoex.dwOSVersionInfoSize = sizeof(versioninfoex);
|
||||
|
@ -78,19 +78,30 @@ static void GatherWindowsVersion(uint32 & SystemVersion)
|
|||
#pragma warning(push)
|
||||
#pragma warning(disable:4996) // 'GetVersionExW': was declared deprecated
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
#if MPT_COMPILER_CLANG || MPT_COMPILER_MSVCCLANGC2
|
||||
#if MPT_COMPILER_CLANG
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif // MPT_COMPILER_CLANG
|
||||
GetVersionExW((LPOSVERSIONINFOW)&versioninfoex);
|
||||
if(GetVersionExW((LPOSVERSIONINFOW)&versioninfoex) == FALSE)
|
||||
{
|
||||
return VersionFromNTDDI_VERSION();
|
||||
}
|
||||
#if MPT_COMPILER_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
#if MPT_COMPILER_CLANG || MPT_COMPILER_MSVCCLANGC2
|
||||
#if MPT_COMPILER_CLANG
|
||||
#pragma clang diagnostic pop
|
||||
#endif // MPT_COMPILER_CLANG
|
||||
SystemVersion = VersionDecimalTo_WIN32_WINNT(versioninfoex.dwMajorVersion, versioninfoex.dwMinorVersion);
|
||||
#endif // !MPT_OS_WINDOWS_WINRT
|
||||
if(versioninfoex.dwPlatformId != VER_PLATFORM_WIN32_NT)
|
||||
{
|
||||
return VersionFromNTDDI_VERSION();
|
||||
}
|
||||
return mpt::Windows::Version(
|
||||
mpt::Windows::Version::System(versioninfoex.dwMajorVersion, versioninfoex.dwMinorVersion),
|
||||
mpt::Windows::Version::ServicePack(versioninfoex.wServicePackMajor, versioninfoex.wServicePackMinor),
|
||||
versioninfoex.dwBuildNumber
|
||||
);
|
||||
#endif // MPT_OS_WINDOWS_WINRT
|
||||
}
|
||||
|
||||
|
||||
|
@ -99,19 +110,18 @@ static void GatherWindowsVersion(uint32 & SystemVersion)
|
|||
namespace {
|
||||
struct WindowsVersionCache
|
||||
{
|
||||
uint32 SystemVersion;
|
||||
WindowsVersionCache()
|
||||
: SystemVersion(mpt::Windows::Version::WinNT4)
|
||||
mpt::Windows::Version version;
|
||||
WindowsVersionCache() noexcept
|
||||
: version(GatherWindowsVersion())
|
||||
{
|
||||
GatherWindowsVersion(SystemVersion);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static void GatherWindowsVersionFromCache(uint32 & SystemVersion)
|
||||
static mpt::Windows::Version GatherWindowsVersionFromCache() noexcept
|
||||
{
|
||||
static WindowsVersionCache gs_WindowsVersionCache;
|
||||
SystemVersion = gs_WindowsVersionCache.SystemVersion;
|
||||
return gs_WindowsVersionCache.version;
|
||||
}
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
@ -120,80 +130,183 @@ static void GatherWindowsVersionFromCache(uint32 & SystemVersion)
|
|||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
|
||||
Version::Version()
|
||||
: SystemIsWindows(false)
|
||||
, SystemVersion(mpt::Windows::Version::WinNT4)
|
||||
Version::Version() noexcept
|
||||
: m_SystemIsWindows(false)
|
||||
, m_System()
|
||||
, m_ServicePack()
|
||||
, m_Build()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
mpt::Windows::Version Version::Current()
|
||||
Version Version::NoWindows() noexcept
|
||||
{
|
||||
return Version();
|
||||
}
|
||||
|
||||
|
||||
Version::Version(mpt::Windows::Version::System system, mpt::Windows::Version::ServicePack servicePack, mpt::Windows::Version::Build build) noexcept
|
||||
: m_SystemIsWindows(true)
|
||||
, m_System(system)
|
||||
, m_ServicePack(servicePack)
|
||||
, m_Build(build)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
mpt::Windows::Version Version::Current() noexcept
|
||||
{
|
||||
mpt::Windows::Version result;
|
||||
#if MPT_OS_WINDOWS
|
||||
result.SystemIsWindows = true;
|
||||
#ifdef MODPLUG_TRACKER
|
||||
GatherWindowsVersionFromCache(result.SystemVersion);
|
||||
return GatherWindowsVersionFromCache();
|
||||
#else // !MODPLUG_TRACKER
|
||||
GatherWindowsVersion(result.SystemVersion);
|
||||
return GatherWindowsVersion();
|
||||
#endif // MODPLUG_TRACKER
|
||||
#else // !MPT_OS_WINDOWS
|
||||
return mpt::Windows::Version::NoWindows();
|
||||
#endif // MPT_OS_WINDOWS
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool Version::IsWindows() const
|
||||
bool Version::IsWindows() const noexcept
|
||||
{
|
||||
return SystemIsWindows;
|
||||
return m_SystemIsWindows;
|
||||
}
|
||||
|
||||
|
||||
bool Version::IsBefore(mpt::Windows::Version::Number version) const
|
||||
bool Version::IsBefore(mpt::Windows::Version::System version) const noexcept
|
||||
{
|
||||
if(!SystemIsWindows)
|
||||
if(!m_SystemIsWindows)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return (SystemVersion < static_cast<uint32>(version));
|
||||
return m_System < version;
|
||||
}
|
||||
|
||||
|
||||
bool Version::IsAtLeast(mpt::Windows::Version::Number version) const
|
||||
bool Version::IsBefore(mpt::Windows::Version::System version, mpt::Windows::Version::ServicePack servicePack) const noexcept
|
||||
{
|
||||
if(!SystemIsWindows)
|
||||
if(!m_SystemIsWindows)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return (SystemVersion >= static_cast<uint32>(version));
|
||||
if(m_System > version)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(m_System < version)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return m_ServicePack < servicePack;
|
||||
}
|
||||
|
||||
|
||||
static MPT_CONSTEXPR11_VAR struct { Version::Number version; const MPT_UCHAR_TYPE * name; } versionMap[] =
|
||||
bool Version::IsBefore(mpt::Windows::Version::System version, mpt::Windows::Version::Build build) const noexcept
|
||||
{
|
||||
{ mpt::Windows::Version::WinNewer, MPT_ULITERAL("Windows 10 (or newer)") },
|
||||
{ mpt::Windows::Version::Win10, MPT_ULITERAL("Windows 10") },
|
||||
{ mpt::Windows::Version::Win81, MPT_ULITERAL("Windows 8.1") },
|
||||
{ mpt::Windows::Version::Win8, MPT_ULITERAL("Windows 8") },
|
||||
{ mpt::Windows::Version::Win7, MPT_ULITERAL("Windows 7") },
|
||||
{ mpt::Windows::Version::WinVista, MPT_ULITERAL("Windows Vista") },
|
||||
{ mpt::Windows::Version::WinXP64, MPT_ULITERAL("Windows XP x64 / Windows Server 2003") },
|
||||
{ mpt::Windows::Version::WinXP, MPT_ULITERAL("Windows XP") },
|
||||
{ mpt::Windows::Version::Win2000, MPT_ULITERAL("Windows 2000") },
|
||||
{ mpt::Windows::Version::WinME, MPT_ULITERAL("Windows ME") },
|
||||
{ mpt::Windows::Version::Win98, MPT_ULITERAL("Windows 98") },
|
||||
{ mpt::Windows::Version::WinNT4, MPT_ULITERAL("Windows NT4") }
|
||||
if(!m_SystemIsWindows)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(m_System > version)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(m_System < version)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return m_Build < build;
|
||||
}
|
||||
|
||||
|
||||
bool Version::IsAtLeast(mpt::Windows::Version::System version) const noexcept
|
||||
{
|
||||
if(!m_SystemIsWindows)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return m_System >= version;
|
||||
}
|
||||
|
||||
|
||||
bool Version::IsAtLeast(mpt::Windows::Version::System version, mpt::Windows::Version::ServicePack servicePack) const noexcept
|
||||
{
|
||||
if(!m_SystemIsWindows)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(m_System < version)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(m_System > version)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return m_ServicePack >= servicePack;
|
||||
}
|
||||
|
||||
|
||||
bool Version::IsAtLeast(mpt::Windows::Version::System version, mpt::Windows::Version::Build build) const noexcept
|
||||
{
|
||||
if(!m_SystemIsWindows)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(m_System < version)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(m_System > version)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return m_Build >= build;
|
||||
}
|
||||
|
||||
|
||||
mpt::Windows::Version::System Version::GetSystem() const noexcept
|
||||
{
|
||||
return m_System;
|
||||
}
|
||||
|
||||
|
||||
mpt::Windows::Version::ServicePack Version::GetServicePack() const noexcept
|
||||
{
|
||||
return m_ServicePack;
|
||||
}
|
||||
|
||||
|
||||
mpt::Windows::Version::Build Version::GetBuild() const noexcept
|
||||
{
|
||||
return m_Build;
|
||||
}
|
||||
|
||||
|
||||
static MPT_CONSTEXPR11_VAR struct { Version::System version; const MPT_UCHAR_TYPE * name; bool showDetails; } versionMap[] =
|
||||
{
|
||||
{ mpt::Windows::Version::WinNewer, UL_("Windows 10 (or newer)"), false },
|
||||
{ mpt::Windows::Version::Win10, UL_("Windows 10"), true },
|
||||
{ mpt::Windows::Version::Win81, UL_("Windows 8.1"), true },
|
||||
{ mpt::Windows::Version::Win8, UL_("Windows 8"), true },
|
||||
{ mpt::Windows::Version::Win7, UL_("Windows 7"), true },
|
||||
{ mpt::Windows::Version::WinVista, UL_("Windows Vista"), true },
|
||||
{ mpt::Windows::Version::WinXP64, UL_("Windows XP x64 / Windows Server 2003"), true },
|
||||
{ mpt::Windows::Version::WinXP, UL_("Windows XP"), true },
|
||||
{ mpt::Windows::Version::Win2000, UL_("Windows 2000"), true },
|
||||
{ mpt::Windows::Version::WinNT4, UL_("Windows NT4"), true }
|
||||
};
|
||||
|
||||
|
||||
mpt::ustring Version::VersionToString(uint16 version)
|
||||
mpt::ustring Version::VersionToString(mpt::Windows::Version::System version)
|
||||
{
|
||||
mpt::ustring result;
|
||||
for(const auto &v : versionMap)
|
||||
{
|
||||
if(version > v.version)
|
||||
{
|
||||
result = MPT_USTRING("> ") + v.name;
|
||||
result = U_("> ") + v.name;
|
||||
break;
|
||||
} else if(version == v.version)
|
||||
{
|
||||
|
@ -203,30 +316,45 @@ mpt::ustring Version::VersionToString(uint16 version)
|
|||
}
|
||||
if(result.empty())
|
||||
{
|
||||
result = mpt::format(MPT_USTRING("0x%1"))(mpt::ufmt::dec0<4>(version));
|
||||
result = mpt::format(U_("0x%1"))(mpt::ufmt::hex0<16>(static_cast<uint64>(version)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
mpt::ustring Version::VersionToString(Number version)
|
||||
{
|
||||
return VersionToString(static_cast<uint16>(version));
|
||||
}
|
||||
|
||||
|
||||
mpt::ustring Version::GetName() const
|
||||
{
|
||||
mpt::ustring name = MPT_USTRING("Generic Windows NT");
|
||||
mpt::ustring name = U_("Generic Windows NT");
|
||||
bool showDetails = false;
|
||||
for(const auto &v : versionMap)
|
||||
{
|
||||
if(mpt::Windows::Version::IsAtLeast(v.version))
|
||||
if(IsAtLeast(v.version))
|
||||
{
|
||||
name = v.name;
|
||||
showDetails = v.showDetails;
|
||||
break;
|
||||
}
|
||||
}
|
||||
name += U_(" (");
|
||||
name += mpt::format(U_("Version %1.%2"))(m_System.Major, m_System.Minor);
|
||||
if(showDetails)
|
||||
{
|
||||
if(m_ServicePack.HasServicePack())
|
||||
{
|
||||
if(m_ServicePack.Minor)
|
||||
{
|
||||
name += mpt::format(U_(" Service Pack %1.%2"))(m_ServicePack.Major, m_ServicePack.Minor);
|
||||
} else
|
||||
{
|
||||
name += mpt::format(U_(" Service Pack %1"))(m_ServicePack.Major);
|
||||
}
|
||||
}
|
||||
if(m_Build != 0)
|
||||
{
|
||||
name += mpt::format(U_(" (Build %1)"))(m_Build);
|
||||
}
|
||||
}
|
||||
name += U_(")");
|
||||
mpt::ustring result = name;
|
||||
#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
|
||||
if(mpt::Windows::IsWine())
|
||||
|
@ -234,13 +362,13 @@ mpt::ustring Version::GetName() const
|
|||
mpt::Wine::VersionContext v;
|
||||
if(v.Version().IsValid())
|
||||
{
|
||||
result = mpt::format(MPT_USTRING("Wine %1 (%2)"))(
|
||||
result = mpt::format(U_("Wine %1 (%2)"))(
|
||||
v.Version().AsString()
|
||||
, name
|
||||
);
|
||||
} else
|
||||
{
|
||||
result = mpt::format(MPT_USTRING("Wine (unknown version: '%1') (%2)"))(
|
||||
result = mpt::format(U_("Wine (unknown version: '%1') (%2)"))(
|
||||
mpt::ToUnicode(mpt::CharsetUTF8, v.RawVersion())
|
||||
, name
|
||||
);
|
||||
|
@ -260,48 +388,237 @@ mpt::ustring Version::GetNameShort() const
|
|||
mpt::Wine::VersionContext v;
|
||||
if(v.Version().IsValid())
|
||||
{
|
||||
name = mpt::format(MPT_USTRING("wine-%1"))(v.Version().AsString());
|
||||
name = mpt::format(U_("wine-%1"))(v.Version().AsString());
|
||||
} else if(v.RawVersion().length() > 0)
|
||||
{
|
||||
name = MPT_USTRING("wine-") + Util::BinToHex(mpt::as_span(v.RawVersion()));
|
||||
name = U_("wine-") + Util::BinToHex(mpt::as_span(v.RawVersion()));
|
||||
} else
|
||||
{
|
||||
name = MPT_USTRING("wine-");
|
||||
name = U_("wine-");
|
||||
}
|
||||
name += MPT_USTRING("-") + Util::BinToHex(mpt::as_span(v.RawHostSysName()));
|
||||
name += U_("-") + Util::BinToHex(mpt::as_span(v.RawHostSysName()));
|
||||
} else
|
||||
{
|
||||
name = mpt::format(MPT_USTRING("%1.%2"))(mpt::ufmt::dec(SystemVersion >> 8), mpt::ufmt::HEX0<2>(SystemVersion & 0xFF));
|
||||
name = mpt::format(U_("%1.%2"))(mpt::ufmt::dec(m_System.Major), mpt::ufmt::dec0<2>(m_System.Minor));
|
||||
}
|
||||
return name;
|
||||
}
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
mpt::Windows::Version::Number Version::GetMinimumKernelLevel()
|
||||
mpt::Windows::Version::System Version::GetMinimumKernelLevel() noexcept
|
||||
{
|
||||
uint16 minimumKernelVersion = 0;
|
||||
uint64 minimumKernelVersion = 0;
|
||||
#if MPT_OS_WINDOWS && MPT_COMPILER_MSVC
|
||||
#if !defined(MPT_BUILD_TARGET_XP)
|
||||
minimumKernelVersion = std::max<uint16>(minimumKernelVersion, mpt::Windows::Version::WinVista);
|
||||
minimumKernelVersion = std::max<uint64>(minimumKernelVersion, mpt::Windows::Version::WinVista);
|
||||
#else
|
||||
minimumKernelVersion = std::max<uint16>(minimumKernelVersion, mpt::Windows::Version::WinXP);
|
||||
minimumKernelVersion = std::max<uint64>(minimumKernelVersion, mpt::Windows::Version::WinXP);
|
||||
#endif
|
||||
#endif
|
||||
return static_cast<mpt::Windows::Version::Number>(minimumKernelVersion);
|
||||
return mpt::Windows::Version::System(minimumKernelVersion);
|
||||
}
|
||||
|
||||
|
||||
mpt::Windows::Version::Number Version::GetMinimumAPILevel()
|
||||
mpt::Windows::Version::System Version::GetMinimumAPILevel() noexcept
|
||||
{
|
||||
uint16 minimumApiVersion = 0;
|
||||
#if MPT_OS_WINDOWS && defined(_WIN32_WINNT)
|
||||
minimumApiVersion = std::max<uint16>(minimumApiVersion, _WIN32_WINNT);
|
||||
#endif
|
||||
return static_cast<mpt::Windows::Version::Number>(minimumApiVersion);
|
||||
#if MPT_OS_WINDOWS
|
||||
return SystemVersionFrom_WIN32_WINNT();
|
||||
#else // !MPT_OS_WINDOWS
|
||||
return mpt::Windows::Version::System();
|
||||
#endif // MPT_OS_WINDOWS
|
||||
}
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
|
||||
|
||||
|
||||
#ifndef PROCESSOR_ARCHITECTURE_NEUTRAL
|
||||
#define PROCESSOR_ARCHITECTURE_NEUTRAL 11
|
||||
#endif
|
||||
#ifndef PROCESSOR_ARCHITECTURE_ARM64
|
||||
#define PROCESSOR_ARCHITECTURE_ARM64 12
|
||||
#endif
|
||||
#ifndef PROCESSOR_ARCHITECTURE_ARM32_ON_WIN64
|
||||
#define PROCESSOR_ARCHITECTURE_ARM32_ON_WIN64 13
|
||||
#endif
|
||||
#ifndef PROCESSOR_ARCHITECTURE_IA32_ON_ARM64
|
||||
#define PROCESSOR_ARCHITECTURE_IA32_ON_ARM64 14
|
||||
#endif
|
||||
|
||||
|
||||
struct OSArchitecture
|
||||
{
|
||||
uint16 ProcessorArchitectur;
|
||||
Architecture Host;
|
||||
Architecture Process;
|
||||
};
|
||||
static constexpr OSArchitecture architectures [] = {
|
||||
{ PROCESSOR_ARCHITECTURE_INTEL , Architecture::x86 , Architecture::x86 },
|
||||
{ PROCESSOR_ARCHITECTURE_AMD64 , Architecture::amd64 , Architecture::amd64 },
|
||||
{ PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 , Architecture::amd64 , Architecture::x86 },
|
||||
{ PROCESSOR_ARCHITECTURE_ARM , Architecture::arm , Architecture::arm },
|
||||
{ PROCESSOR_ARCHITECTURE_ARM64 , Architecture::arm64 , Architecture::arm64 },
|
||||
{ PROCESSOR_ARCHITECTURE_ARM32_ON_WIN64, Architecture::arm64 , Architecture::arm },
|
||||
{ PROCESSOR_ARCHITECTURE_IA32_ON_ARM64 , Architecture::arm64 , Architecture::x86 },
|
||||
{ PROCESSOR_ARCHITECTURE_MIPS , Architecture::mips , Architecture::mips },
|
||||
{ PROCESSOR_ARCHITECTURE_PPC , Architecture::ppc , Architecture::ppc },
|
||||
{ PROCESSOR_ARCHITECTURE_SHX , Architecture::shx , Architecture::shx },
|
||||
{ PROCESSOR_ARCHITECTURE_ALPHA , Architecture::alpha , Architecture::alpha },
|
||||
{ PROCESSOR_ARCHITECTURE_ALPHA64 , Architecture::alpha64, Architecture::alpha64 },
|
||||
{ PROCESSOR_ARCHITECTURE_IA64 , Architecture::ia64 , Architecture::ia64 },
|
||||
{ PROCESSOR_ARCHITECTURE_MSIL , Architecture::unknown, Architecture::unknown },
|
||||
{ PROCESSOR_ARCHITECTURE_NEUTRAL , Architecture::unknown, Architecture::unknown },
|
||||
{ PROCESSOR_ARCHITECTURE_UNKNOWN , Architecture::unknown, Architecture::unknown }
|
||||
};
|
||||
|
||||
|
||||
struct HostArchitecture
|
||||
{
|
||||
Architecture Host;
|
||||
Architecture Process;
|
||||
EmulationLevel Emulation;
|
||||
};
|
||||
static constexpr HostArchitecture hostArchitectureCanRun [] = {
|
||||
{ Architecture::x86 , Architecture::x86 , EmulationLevel::Native },
|
||||
{ Architecture::amd64 , Architecture::amd64 , EmulationLevel::Native },
|
||||
{ Architecture::amd64 , Architecture::x86 , EmulationLevel::Virtual },
|
||||
{ Architecture::arm , Architecture::arm , EmulationLevel::Native },
|
||||
{ Architecture::arm64 , Architecture::arm64 , EmulationLevel::Native },
|
||||
{ Architecture::arm64 , Architecture::arm , EmulationLevel::Virtual },
|
||||
{ Architecture::arm64 , Architecture::x86 , EmulationLevel::Software },
|
||||
{ Architecture::mips , Architecture::mips , EmulationLevel::Native },
|
||||
{ Architecture::ppc , Architecture::ppc , EmulationLevel::Native },
|
||||
{ Architecture::shx , Architecture::shx , EmulationLevel::Native },
|
||||
{ Architecture::alpha , Architecture::alpha , EmulationLevel::Native },
|
||||
{ Architecture::alpha64, Architecture::alpha64, EmulationLevel::Native },
|
||||
{ Architecture::alpha64, Architecture::alpha , EmulationLevel::Virtual },
|
||||
{ Architecture::ia64 , Architecture::ia64 , EmulationLevel::Native },
|
||||
{ Architecture::ia64 , Architecture::x86 , EmulationLevel::Hardware }
|
||||
};
|
||||
|
||||
|
||||
struct ArchitectureInfo
|
||||
{
|
||||
Architecture Arch;
|
||||
int Bitness;
|
||||
const MPT_UCHAR_TYPE * Name;
|
||||
};
|
||||
static constexpr ArchitectureInfo architectureInfo [] = {
|
||||
{ Architecture::x86 , 32, UL_("x86") },
|
||||
{ Architecture::amd64 , 64, UL_("amd64") },
|
||||
{ Architecture::arm , 32, UL_("arm") },
|
||||
{ Architecture::arm64 , 64, UL_("arm64") },
|
||||
{ Architecture::mips , 32, UL_("mips") },
|
||||
{ Architecture::ppc , 32, UL_("ppc") },
|
||||
{ Architecture::shx , 32, UL_("shx") },
|
||||
{ Architecture::alpha , 32, UL_("alpha") },
|
||||
{ Architecture::alpha64, 64, UL_("alpha64") },
|
||||
{ Architecture::ia64 , 64, UL_("ia64") }
|
||||
};
|
||||
|
||||
|
||||
int Bitness(Architecture arch) noexcept
|
||||
{
|
||||
for(const auto &info : architectureInfo)
|
||||
{
|
||||
if(arch == info.Arch)
|
||||
{
|
||||
return info.Bitness;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
mpt::ustring Name(Architecture arch)
|
||||
{
|
||||
for(const auto &info : architectureInfo)
|
||||
{
|
||||
if(arch == info.Arch)
|
||||
{
|
||||
return info.Name;
|
||||
}
|
||||
}
|
||||
return mpt::ustring();
|
||||
}
|
||||
|
||||
|
||||
Architecture GetHostArchitecture() noexcept
|
||||
{
|
||||
SYSTEM_INFO systemInfo;
|
||||
MemsetZero(systemInfo);
|
||||
GetNativeSystemInfo(&systemInfo);
|
||||
for(const auto &arch : architectures)
|
||||
{
|
||||
if(systemInfo.wProcessorArchitecture == arch.ProcessorArchitectur)
|
||||
{
|
||||
return arch.Host;
|
||||
}
|
||||
}
|
||||
return Architecture::unknown;
|
||||
}
|
||||
|
||||
|
||||
Architecture GetProcessArchitecture() noexcept
|
||||
{
|
||||
SYSTEM_INFO systemInfo;
|
||||
MemsetZero(systemInfo);
|
||||
GetSystemInfo(&systemInfo);
|
||||
for(const auto &arch : architectures)
|
||||
{
|
||||
if(systemInfo.wProcessorArchitecture == arch.ProcessorArchitectur)
|
||||
{
|
||||
return arch.Process;
|
||||
}
|
||||
}
|
||||
return Architecture::unknown;
|
||||
}
|
||||
|
||||
|
||||
EmulationLevel HostCanRun(Architecture host, Architecture process) noexcept
|
||||
{
|
||||
for(const auto & can : hostArchitectureCanRun)
|
||||
{
|
||||
if(can.Host == host && can.Process == process)
|
||||
{
|
||||
return can.Emulation;
|
||||
}
|
||||
}
|
||||
return EmulationLevel::NA;
|
||||
}
|
||||
|
||||
|
||||
std::vector<Architecture> GetSupportedProcessArchitectures(Architecture host)
|
||||
{
|
||||
std::vector<Architecture> result;
|
||||
for(const auto & entry : hostArchitectureCanRun)
|
||||
{
|
||||
if(entry.Host == host)
|
||||
{
|
||||
result.push_back(entry.Process);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
uint64 GetSystemMemorySize()
|
||||
{
|
||||
MEMORYSTATUSEX memoryStatus;
|
||||
MemsetZero(memoryStatus);
|
||||
memoryStatus.dwLength = sizeof(MEMORYSTATUSEX);
|
||||
if(GlobalMemoryStatusEx(&memoryStatus) == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return memoryStatus.ullTotalPhys;
|
||||
}
|
||||
|
||||
|
||||
#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
|
||||
|
||||
|
@ -310,7 +627,7 @@ mpt::Windows::Version::Number Version::GetMinimumAPILevel()
|
|||
static bool GatherSystemIsWine()
|
||||
{
|
||||
bool SystemIsWine = false;
|
||||
HMODULE hNTDLL = LoadLibraryW(L"ntdll.dll");
|
||||
HMODULE hNTDLL = LoadLibrary(TEXT("ntdll.dll"));
|
||||
if(hNTDLL)
|
||||
{
|
||||
SystemIsWine = (GetProcAddress(hNTDLL, "wine_get_version") != NULL);
|
||||
|
@ -320,10 +637,6 @@ static bool GatherSystemIsWine()
|
|||
return SystemIsWine;
|
||||
}
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
|
||||
|
||||
namespace {
|
||||
struct SystemIsWineCache
|
||||
{
|
||||
|
@ -341,20 +654,17 @@ struct SystemIsWineCache
|
|||
};
|
||||
}
|
||||
|
||||
#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
static bool SystemIsWine(bool allowDetection = true)
|
||||
{
|
||||
#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
|
||||
#if MPT_OS_WINDOWS
|
||||
static SystemIsWineCache gs_SystemIsWineCache = allowDetection ? SystemIsWineCache() : SystemIsWineCache(false);
|
||||
if(!allowDetection)
|
||||
{ // catch too late calls of PreventWineDetection
|
||||
MPT_ASSERT(!gs_SystemIsWineCache.SystemIsWine);
|
||||
}
|
||||
return gs_SystemIsWineCache.SystemIsWine;
|
||||
#elif MPT_OS_WINDOWS
|
||||
MPT_UNREFERENCED_PARAMETER(allowDetection);
|
||||
return GatherSystemIsWine();
|
||||
#else
|
||||
MPT_UNREFERENCED_PARAMETER(allowDetection);
|
||||
return false;
|
||||
|
@ -413,12 +723,12 @@ Version::Version(const mpt::ustring &rawVersion)
|
|||
{
|
||||
return;
|
||||
}
|
||||
std::vector<uint8> version = mpt::String::Split<uint8>(rawVersion, MPT_USTRING("."));
|
||||
std::vector<uint8> version = mpt::String::Split<uint8>(rawVersion, U_("."));
|
||||
if(version.size() < 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
mpt::ustring parsedVersion = mpt::String::Combine(version, MPT_USTRING("."));
|
||||
mpt::ustring parsedVersion = mpt::String::Combine(version, U_("."));
|
||||
std::size_t len = std::min(parsedVersion.length(), rawVersion.length());
|
||||
if(len == 0)
|
||||
{
|
||||
|
@ -464,7 +774,7 @@ bool Version::IsValid() const
|
|||
|
||||
mpt::ustring Version::AsString() const
|
||||
{
|
||||
return mpt::ufmt::dec(vmajor) + MPT_USTRING(".") + mpt::ufmt::dec(vminor) + MPT_USTRING(".") + mpt::ufmt::dec(vupdate);
|
||||
return mpt::ufmt::dec(vmajor) + U_(".") + mpt::ufmt::dec(vminor) + U_(".") + mpt::ufmt::dec(vupdate);
|
||||
}
|
||||
|
||||
|
||||
|
@ -498,15 +808,27 @@ bool Version::IsAtLeast(mpt::Wine::Version other) const
|
|||
}
|
||||
|
||||
|
||||
uint8 Version::GetMajor() const
|
||||
{
|
||||
return vmajor;
|
||||
}
|
||||
|
||||
uint8 Version::GetMinor() const
|
||||
{
|
||||
return vminor;
|
||||
}
|
||||
|
||||
uint8 Version::GetUpdate() const
|
||||
{
|
||||
return vupdate;
|
||||
}
|
||||
|
||||
|
||||
mpt::Wine::Version GetMinimumWineVersion()
|
||||
{
|
||||
mpt::Wine::Version minimumWineVersion = mpt::Wine::Version(0,0,0);
|
||||
#if MPT_OS_WINDOWS && MPT_COMPILER_MSVC
|
||||
#if !defined(MPT_BUILD_TARGET_XP)
|
||||
minimumWineVersion = mpt::Wine::Version(1,8,0);
|
||||
#else
|
||||
minimumWineVersion = mpt::Wine::Version(1,6,0);
|
||||
#endif
|
||||
#endif
|
||||
return minimumWineVersion;
|
||||
}
|
||||
|
@ -523,7 +845,7 @@ VersionContext::VersionContext()
|
|||
{
|
||||
return;
|
||||
}
|
||||
m_NTDLL = mpt::Library(mpt::LibraryPath::FullPath(MPT_PATHSTRING("ntdll.dll")));
|
||||
m_NTDLL = mpt::Library(mpt::LibraryPath::FullPath(P_("ntdll.dll")));
|
||||
if(m_NTDLL.IsValid())
|
||||
{
|
||||
const char * (__cdecl * wine_get_version)(void) = nullptr;
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
|
||||
#include "mptLibrary.h"
|
||||
|
||||
|
@ -22,53 +24,113 @@ namespace mpt
|
|||
namespace Windows
|
||||
{
|
||||
|
||||
|
||||
class Version
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
enum Number
|
||||
enum Number : uint64
|
||||
{
|
||||
|
||||
WinNT4 = 0x0400,
|
||||
Win98 = 0x0410,
|
||||
WinME = 0x0490,
|
||||
Win2000 = 0x0500,
|
||||
WinXP = 0x0501,
|
||||
WinXP64 = 0x0502,
|
||||
WinVista = 0x0600,
|
||||
Win7 = 0x0601,
|
||||
Win8 = 0x0602,
|
||||
Win81 = 0x0603,
|
||||
Win10 = 0x0a00,
|
||||
|
||||
WinNewer = Win10 + 1
|
||||
|
||||
WinNT4 = 0x0000000400000000ull,
|
||||
Win2000 = 0x0000000500000000ull,
|
||||
WinXP = 0x0000000500000001ull,
|
||||
WinXP64 = 0x0000000500000002ull,
|
||||
WinVista = 0x0000000600000000ull,
|
||||
Win7 = 0x0000000600000001ull,
|
||||
Win8 = 0x0000000600000002ull,
|
||||
Win81 = 0x0000000600000003ull,
|
||||
Win10 = 0x0000000a00000000ull,
|
||||
WinNewer = Win10 + 1ull
|
||||
};
|
||||
|
||||
static mpt::ustring VersionToString(uint16 version);
|
||||
static mpt::ustring VersionToString(Number version);
|
||||
struct System
|
||||
{
|
||||
uint32 Major = 0;
|
||||
uint32 Minor = 0;
|
||||
System() = default;
|
||||
constexpr System(Number number) noexcept
|
||||
: Major(static_cast<uint32>((static_cast<uint64>(number) >> 32) & 0xffffffffu))
|
||||
, Minor(static_cast<uint32>((static_cast<uint64>(number) >> 0) & 0xffffffffu))
|
||||
{
|
||||
}
|
||||
explicit constexpr System(uint64 number) noexcept
|
||||
: Major(static_cast<uint32>((number >> 32) & 0xffffffffu))
|
||||
, Minor(static_cast<uint32>((number >> 0) & 0xffffffffu))
|
||||
{
|
||||
}
|
||||
explicit constexpr System(uint32 major, uint32 minor) noexcept
|
||||
: Major(major)
|
||||
, Minor(minor)
|
||||
{
|
||||
}
|
||||
constexpr operator uint64 () const noexcept
|
||||
{
|
||||
return (static_cast<uint64>(Major) << 32) | (static_cast<uint64>(Minor) << 0);
|
||||
}
|
||||
};
|
||||
|
||||
struct ServicePack
|
||||
{
|
||||
uint16 Major = 0;
|
||||
uint16 Minor = 0;
|
||||
ServicePack() = default;
|
||||
explicit constexpr ServicePack(uint16 major, uint16 minor) noexcept
|
||||
: Major(major)
|
||||
, Minor(minor)
|
||||
{
|
||||
}
|
||||
constexpr bool HasServicePack() const noexcept
|
||||
{
|
||||
return Major != 0 || Minor != 0;
|
||||
}
|
||||
constexpr operator uint32 () const noexcept
|
||||
{
|
||||
return (static_cast<uint32>(Major) << 16) | (static_cast<uint32>(Minor) << 0);
|
||||
}
|
||||
};
|
||||
|
||||
typedef uint32 Build;
|
||||
|
||||
static mpt::ustring VersionToString(mpt::Windows::Version::System version);
|
||||
|
||||
private:
|
||||
|
||||
bool SystemIsWindows;
|
||||
bool m_SystemIsWindows;
|
||||
|
||||
uint32 SystemVersion;
|
||||
System m_System;
|
||||
ServicePack m_ServicePack;
|
||||
Build m_Build;
|
||||
|
||||
private:
|
||||
|
||||
Version();
|
||||
Version() noexcept;
|
||||
|
||||
public:
|
||||
|
||||
static mpt::Windows::Version Current();
|
||||
static Version NoWindows() noexcept;
|
||||
|
||||
Version(mpt::Windows::Version::System system, mpt::Windows::Version::ServicePack servicePack, mpt::Windows::Version::Build build) noexcept;
|
||||
|
||||
public:
|
||||
|
||||
bool IsWindows() const;
|
||||
static mpt::Windows::Version Current() noexcept;
|
||||
|
||||
bool IsBefore(mpt::Windows::Version::Number version) const;
|
||||
bool IsAtLeast(mpt::Windows::Version::Number version) const;
|
||||
public:
|
||||
|
||||
bool IsWindows() const noexcept;
|
||||
|
||||
bool IsBefore(mpt::Windows::Version::System version) const noexcept;
|
||||
bool IsBefore(mpt::Windows::Version::System version, mpt::Windows::Version::ServicePack servicePack) const noexcept;
|
||||
bool IsBefore(mpt::Windows::Version::System version, mpt::Windows::Version::Build build) const noexcept;
|
||||
|
||||
bool IsAtLeast(mpt::Windows::Version::System version) const noexcept;
|
||||
bool IsAtLeast(mpt::Windows::Version::System version, mpt::Windows::Version::ServicePack servicePack) const noexcept;
|
||||
bool IsAtLeast(mpt::Windows::Version::System version, mpt::Windows::Version::Build build) const noexcept;
|
||||
|
||||
mpt::Windows::Version::System GetSystem() const noexcept;
|
||||
mpt::Windows::Version::ServicePack GetServicePack() const noexcept;
|
||||
mpt::Windows::Version::Build GetBuild() const noexcept;
|
||||
|
||||
mpt::ustring GetName() const;
|
||||
#ifdef MODPLUG_TRACKER
|
||||
|
@ -77,11 +139,57 @@ public:
|
|||
|
||||
public:
|
||||
|
||||
static mpt::Windows::Version::Number GetMinimumKernelLevel();
|
||||
static mpt::Windows::Version::Number GetMinimumAPILevel();
|
||||
static mpt::Windows::Version::System GetMinimumKernelLevel() noexcept;
|
||||
static mpt::Windows::Version::System GetMinimumAPILevel() noexcept;
|
||||
|
||||
}; // class Version
|
||||
|
||||
#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
|
||||
|
||||
enum class Architecture
|
||||
{
|
||||
unknown = -1,
|
||||
|
||||
x86 = 0x0401,
|
||||
amd64 = 0x0801,
|
||||
arm = 0x0402,
|
||||
arm64 = 0x0802,
|
||||
|
||||
mips = 0x0403,
|
||||
ppc = 0x0404,
|
||||
shx = 0x0405,
|
||||
|
||||
alpha = 0x0406,
|
||||
alpha64 = 0x0806,
|
||||
|
||||
ia64 = 0x0807,
|
||||
};
|
||||
|
||||
enum class EmulationLevel
|
||||
{
|
||||
Native,
|
||||
Virtual,
|
||||
Hardware,
|
||||
Software,
|
||||
NA,
|
||||
};
|
||||
|
||||
int Bitness(Architecture arch) noexcept;
|
||||
|
||||
mpt::ustring Name(Architecture arch);
|
||||
|
||||
Architecture GetHostArchitecture() noexcept;
|
||||
Architecture GetProcessArchitecture() noexcept;
|
||||
|
||||
EmulationLevel HostCanRun(Architecture host, Architecture process) noexcept;
|
||||
|
||||
std::vector<Architecture> GetSupportedProcessArchitectures(Architecture host);
|
||||
|
||||
uint64 GetSystemMemorySize();
|
||||
|
||||
#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
|
||||
void PreventWineDetection();
|
||||
|
@ -123,6 +231,9 @@ private:
|
|||
public:
|
||||
bool IsBefore(mpt::Wine::Version other) const;
|
||||
bool IsAtLeast(mpt::Wine::Version other) const;
|
||||
uint8 GetMajor() const;
|
||||
uint8 GetMinor() const;
|
||||
uint8 GetUpdate() const;
|
||||
};
|
||||
|
||||
mpt::Wine::Version GetMinimumWineVersion();
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#if defined(MODPLUG_TRACKER)
|
||||
#include <shlwapi.h>
|
||||
#endif
|
||||
#include <tchar.h>
|
||||
#endif
|
||||
|
||||
#if MPT_OS_WINDOWS && MPT_OS_WINDOWS_WINRT
|
||||
|
@ -26,18 +27,15 @@
|
|||
// MinGW-w64 headers do not declare this for WinRT, which is wrong.
|
||||
extern "C" {
|
||||
WINBASEAPI DWORD WINAPI GetFullPathNameW(LPCWSTR lpFileName, DWORD nBufferLength, LPWSTR lpBuffer, LPWSTR *lpFilePart);
|
||||
#ifndef GetFullPathName
|
||||
#define GetFullPathName GetFullPathNameW
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
#define MPT_PATHSTRING_LITERAL(x) ( L ## x )
|
||||
#else
|
||||
#define MPT_PATHSTRING_LITERAL(x) ( x )
|
||||
#endif
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
namespace mpt
|
||||
|
@ -46,20 +44,20 @@ namespace mpt
|
|||
|
||||
RawPathString PathString::AsNativePrefixed() const
|
||||
{
|
||||
if(path.length() <= MAX_PATH || path.substr(0, 4) == MPT_PATHSTRING_LITERAL("\\\\?\\"))
|
||||
if(path.length() <= MAX_PATH || path.substr(0, 4) == PL_("\\\\?\\"))
|
||||
{
|
||||
// Path is short enough or already in prefixed form
|
||||
return path;
|
||||
}
|
||||
const RawPathString absPath = mpt::GetAbsolutePath(path).AsNative();
|
||||
if(absPath.substr(0, 2) == MPT_PATHSTRING_LITERAL("\\\\"))
|
||||
const RawPathString absPath = mpt::GetAbsolutePath(*this).AsNative();
|
||||
if(absPath.substr(0, 2) == PL_("\\\\"))
|
||||
{
|
||||
// Path is a network share: \\server\foo.bar -> \\?\UNC\server\foo.bar
|
||||
return MPT_PATHSTRING_LITERAL("\\\\?\\UNC") + absPath.substr(1);
|
||||
return PL_("\\\\?\\UNC") + absPath.substr(1);
|
||||
} else
|
||||
{
|
||||
// Regular file: C:\foo.bar -> \\?\C:\foo.bar
|
||||
return MPT_PATHSTRING_LITERAL("\\\\?\\") + absPath;
|
||||
return PL_("\\\\?\\") + absPath;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,7 +66,7 @@ RawPathString PathString::AsNativePrefixed() const
|
|||
|
||||
int PathString::CompareNoCase(const PathString & a, const PathString & b)
|
||||
{
|
||||
return lstrcmpiW(a.path.c_str(), b.path.c_str());
|
||||
return lstrcmpi(a.path.c_str(), b.path.c_str());
|
||||
}
|
||||
|
||||
#endif // !MPT_OS_WINDOWS_WINRT
|
||||
|
@ -86,42 +84,42 @@ PathString PathString::Simplify() const
|
|||
std::vector<RawPathString> components;
|
||||
RawPathString root;
|
||||
RawPathString::size_type startPos = 0;
|
||||
if(path.size() >= 2 && path[1] == MPT_PATHSTRING_LITERAL(':'))
|
||||
if(path.size() >= 2 && path[1] == PC_(':'))
|
||||
{
|
||||
// Drive letter
|
||||
root = path.substr(0, 2) + MPT_PATHSTRING_LITERAL('\\');
|
||||
root = path.substr(0, 2) + PC_('\\');
|
||||
startPos = 2;
|
||||
} else if(path.substr(0, 2) == MPT_PATHSTRING_LITERAL("\\\\"))
|
||||
} else if(path.substr(0, 2) == PL_("\\\\"))
|
||||
{
|
||||
// Network share
|
||||
root = MPT_PATHSTRING_LITERAL("\\\\");
|
||||
root = PL_("\\\\");
|
||||
startPos = 2;
|
||||
} else if(path.substr(0, 2) == MPT_PATHSTRING_LITERAL(".\\") || path.substr(0, 2) == MPT_PATHSTRING_LITERAL("./"))
|
||||
} else if(path.substr(0, 2) == PL_(".\\") || path.substr(0, 2) == PL_("./"))
|
||||
{
|
||||
// Special case for relative paths
|
||||
root = MPT_PATHSTRING_LITERAL(".\\");
|
||||
root = PL_(".\\");
|
||||
startPos = 2;
|
||||
} else if(path.size() >= 1 && (path[0] == MPT_PATHSTRING_LITERAL('\\') || path[0] == MPT_PATHSTRING_LITERAL('/')))
|
||||
} else if(path.size() >= 1 && (path[0] == PC_('\\') || path[0] == PC_('/')))
|
||||
{
|
||||
// Special case for relative paths
|
||||
root = MPT_PATHSTRING_LITERAL("\\");
|
||||
root = PL_("\\");
|
||||
startPos = 1;
|
||||
}
|
||||
|
||||
while(startPos < path.size())
|
||||
{
|
||||
auto pos = path.find_first_of(MPT_PATHSTRING_LITERAL("\\/"), startPos);
|
||||
auto pos = path.find_first_of(PL_("\\/"), startPos);
|
||||
if(pos == RawPathString::npos)
|
||||
pos = path.size();
|
||||
mpt::RawPathString dir = path.substr(startPos, pos - startPos);
|
||||
if(dir == MPT_PATHSTRING_LITERAL(".."))
|
||||
if(dir == PL_(".."))
|
||||
{
|
||||
// Go back one directory
|
||||
if(!components.empty())
|
||||
{
|
||||
components.pop_back();
|
||||
}
|
||||
} else if(dir == MPT_PATHSTRING_LITERAL("."))
|
||||
} else if(dir == PL_("."))
|
||||
{
|
||||
// nop
|
||||
} else if(!dir.empty())
|
||||
|
@ -135,11 +133,11 @@ PathString PathString::Simplify() const
|
|||
result.reserve(path.size());
|
||||
for(const auto &component : components)
|
||||
{
|
||||
result += component + MPT_PATHSTRING_LITERAL("\\");
|
||||
result += component + PL_("\\");
|
||||
}
|
||||
if(!components.empty())
|
||||
result.pop_back();
|
||||
return result;
|
||||
return mpt::PathString(result);
|
||||
}
|
||||
|
||||
} // namespace mpt
|
||||
|
@ -168,25 +166,25 @@ void PathString::SplitPath(PathString *drive, PathString *dir, PathString *fname
|
|||
mpt::RawPathString p = path;
|
||||
|
||||
// remove \\?\\ prefix
|
||||
if(p.substr(0, 8) == MPT_PATHSTRING_LITERAL("\\\\?\\UNC\\"))
|
||||
if(p.substr(0, 8) == PL_("\\\\?\\UNC\\"))
|
||||
{
|
||||
p = MPT_PATHSTRING_LITERAL("\\\\") + p.substr(8);
|
||||
} else if(p.substr(0, 4) == MPT_PATHSTRING_LITERAL("\\\\?\\"))
|
||||
p = PL_("\\\\") + p.substr(8);
|
||||
} else if(p.substr(0, 4) == PL_("\\\\?\\"))
|
||||
{
|
||||
p = p.substr(4);
|
||||
}
|
||||
|
||||
if (p.length() >= 2 && (
|
||||
p.substr(0, 2) == MPT_PATHSTRING_LITERAL("\\\\")
|
||||
|| p.substr(0, 2) == MPT_PATHSTRING_LITERAL("\\/")
|
||||
|| p.substr(0, 2) == MPT_PATHSTRING_LITERAL("/\\")
|
||||
|| p.substr(0, 2) == MPT_PATHSTRING_LITERAL("//")
|
||||
p.substr(0, 2) == PL_("\\\\")
|
||||
|| p.substr(0, 2) == PL_("\\/")
|
||||
|| p.substr(0, 2) == PL_("/\\")
|
||||
|| p.substr(0, 2) == PL_("//")
|
||||
))
|
||||
{ // UNC
|
||||
mpt::RawPathString::size_type first_slash = p.substr(2).find_first_of(MPT_PATHSTRING_LITERAL("\\/"));
|
||||
mpt::RawPathString::size_type first_slash = p.substr(2).find_first_of(PL_("\\/"));
|
||||
if(first_slash != mpt::RawPathString::npos)
|
||||
{
|
||||
mpt::RawPathString::size_type second_slash = p.substr(2 + first_slash + 1).find_first_of(MPT_PATHSTRING_LITERAL("\\/"));
|
||||
mpt::RawPathString::size_type second_slash = p.substr(2 + first_slash + 1).find_first_of(PL_("\\/"));
|
||||
if(second_slash != mpt::RawPathString::npos)
|
||||
{
|
||||
if(drive) *drive = mpt::PathString::FromNative(p.substr(0, 2 + first_slash + 1 + second_slash));
|
||||
|
@ -203,7 +201,7 @@ void PathString::SplitPath(PathString *drive, PathString *dir, PathString *fname
|
|||
}
|
||||
} else
|
||||
{ // local
|
||||
if(p.length() >= 2 && (p[1] == MPT_PATHSTRING_LITERAL(':')))
|
||||
if(p.length() >= 2 && (p[1] == PC_(':')))
|
||||
{
|
||||
if(drive) *drive = mpt::PathString::FromNative(p.substr(0, 2));
|
||||
p = p.substr(2);
|
||||
|
@ -212,7 +210,7 @@ void PathString::SplitPath(PathString *drive, PathString *dir, PathString *fname
|
|||
if(drive) *drive = mpt::PathString();
|
||||
}
|
||||
}
|
||||
mpt::RawPathString::size_type last_slash = p.find_last_of(MPT_PATHSTRING_LITERAL("\\/"));
|
||||
mpt::RawPathString::size_type last_slash = p.find_last_of(PL_("\\/"));
|
||||
if(last_slash != mpt::RawPathString::npos)
|
||||
{
|
||||
if(dir) *dir = mpt::PathString::FromNative(p.substr(0, last_slash + 1));
|
||||
|
@ -221,7 +219,7 @@ void PathString::SplitPath(PathString *drive, PathString *dir, PathString *fname
|
|||
{
|
||||
if(dir) *dir = mpt::PathString();
|
||||
}
|
||||
mpt::RawPathString::size_type last_dot = p.find_last_of(MPT_PATHSTRING_LITERAL("."));
|
||||
mpt::RawPathString::size_type last_dot = p.find_last_of(PL_("."));
|
||||
if(last_dot == mpt::RawPathString::npos)
|
||||
{
|
||||
if(fname) *fname = mpt::PathString::FromNative(p);
|
||||
|
@ -285,7 +283,7 @@ bool PathString::IsDirectory() const
|
|||
}
|
||||
DWORD dwAttrib = data.dwFileAttributes;
|
||||
#else // !MPT_OS_WINDOWS_WINRT
|
||||
DWORD dwAttrib = ::GetFileAttributesW(path.c_str());
|
||||
DWORD dwAttrib = ::GetFileAttributes(path.c_str());
|
||||
#endif // MPT_OS_WINDOWS_WINRT
|
||||
return ((dwAttrib != INVALID_FILE_ATTRIBUTES) && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
|
||||
}
|
||||
|
@ -301,7 +299,7 @@ bool PathString::IsFile() const
|
|||
}
|
||||
DWORD dwAttrib = data.dwFileAttributes;
|
||||
#else // !MPT_OS_WINDOWS_WINRT
|
||||
DWORD dwAttrib = ::GetFileAttributesW(path.c_str());
|
||||
DWORD dwAttrib = ::GetFileAttributes(path.c_str());
|
||||
#endif // MPT_OS_WINDOWS_WINRT
|
||||
return ((dwAttrib != INVALID_FILE_ATTRIBUTES) && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
|
||||
}
|
||||
|
@ -313,7 +311,7 @@ bool PathString::IsFile() const
|
|||
|
||||
bool PathString::FileOrDirectoryExists() const
|
||||
{
|
||||
return ::PathFileExistsW(path.c_str()) != FALSE;
|
||||
return ::PathFileExists(path.c_str()) != FALSE;
|
||||
}
|
||||
|
||||
#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS
|
||||
|
@ -338,17 +336,17 @@ PathString PathString::SanitizeComponent() const
|
|||
// Convert an absolute path to a path that's relative to "&relativeTo".
|
||||
PathString PathString::AbsolutePathToRelative(const PathString &relativeTo) const
|
||||
{
|
||||
mpt::PathString result = path;
|
||||
mpt::PathString result = *this;
|
||||
if(path.empty())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
if(!_wcsnicmp(relativeTo.AsNative().c_str(), AsNative().c_str(), relativeTo.AsNative().length()))
|
||||
if(!_tcsncicmp(relativeTo.AsNative().c_str(), AsNative().c_str(), relativeTo.AsNative().length()))
|
||||
{
|
||||
// Path is OpenMPT's directory or a sub directory ("C:\OpenMPT\Somepath" => ".\Somepath")
|
||||
result = MPT_PATHSTRING(".\\"); // ".\"
|
||||
result = P_(".\\"); // ".\"
|
||||
result += mpt::PathString::FromNative(AsNative().substr(relativeTo.AsNative().length()));
|
||||
} else if(!_wcsnicmp(relativeTo.AsNative().c_str(), AsNative().c_str(), 2))
|
||||
} else if(!_tcsncicmp(relativeTo.AsNative().c_str(), AsNative().c_str(), 2))
|
||||
{
|
||||
// Path is on the same drive as OpenMPT ("C:\Somepath" => "\Somepath")
|
||||
result = mpt::PathString::FromNative(AsNative().substr(2));
|
||||
|
@ -360,17 +358,17 @@ PathString PathString::AbsolutePathToRelative(const PathString &relativeTo) cons
|
|||
// Convert a path that is relative to "&relativeTo" to an absolute path.
|
||||
PathString PathString::RelativePathToAbsolute(const PathString &relativeTo) const
|
||||
{
|
||||
mpt::PathString result = path;
|
||||
mpt::PathString result = *this;
|
||||
if(path.empty())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
if(path.length() >= 2 && path.at(0) == MPT_PATHSTRING_LITERAL('\\') && path.at(1) != MPT_PATHSTRING_LITERAL('\\'))
|
||||
if(path.length() >= 2 && path.at(0) == PC_('\\') && path.at(1) != PC_('\\'))
|
||||
{
|
||||
// Path is on the same drive as OpenMPT ("\Somepath\" => "C:\Somepath\"), but ignore network paths starting with "\\"
|
||||
result = mpt::PathString::FromNative(relativeTo.AsNative().substr(0, 2));
|
||||
result += path;
|
||||
} else if(path.length() >= 2 && path.substr(0, 2) == MPT_PATHSTRING_LITERAL(".\\"))
|
||||
result += mpt::PathString(path);
|
||||
} else if(path.length() >= 2 && path.substr(0, 2) == PL_(".\\"))
|
||||
{
|
||||
// Path is OpenMPT's directory or a sub directory (".\Somepath\" => "C:\OpenMPT\Somepath\")
|
||||
result = relativeTo; // "C:\OpenMPT\"
|
||||
|
@ -380,81 +378,56 @@ PathString PathString::RelativePathToAbsolute(const PathString &relativeTo) cons
|
|||
}
|
||||
|
||||
|
||||
#if defined(_MFC_VER)
|
||||
|
||||
mpt::PathString PathString::TunnelOutofCString(const CString &path)
|
||||
{
|
||||
#ifdef UNICODE
|
||||
return mpt::PathString::FromWide(path.GetString());
|
||||
#else
|
||||
// Since MFC code can call into our code from a lot of places, we cannot assume
|
||||
// that filenames we get from MFC are always encoded in our hacked UTF8-in-CString encoding.
|
||||
// Instead, we use a rough heuristic: if the string is parseable as UTF8, we assume it is.
|
||||
// This fails for CP_ACP strings, that are also valid UTF8. That's the trade-off here.
|
||||
if(mpt::IsUTF8(path.GetString()))
|
||||
{
|
||||
// utf8
|
||||
return mpt::PathString::FromUTF8(path.GetString());
|
||||
} else
|
||||
{
|
||||
// ANSI
|
||||
return mpt::PathString::FromWide(mpt::ToWide(path));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
CString PathString::TunnelIntoCString(const mpt::PathString &path)
|
||||
{
|
||||
#ifdef UNICODE
|
||||
return path.ToWide().c_str();
|
||||
#else
|
||||
return path.ToUTF8().c_str();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // MFC
|
||||
|
||||
#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
bool PathString::IsPathSeparator(RawPathString::value_type c)
|
||||
{
|
||||
#if MPT_OS_WINDOWS
|
||||
return (c == PC_('\\')) || (c == PC_('/'));
|
||||
#else
|
||||
return c == PC_('/');
|
||||
#endif
|
||||
}
|
||||
|
||||
RawPathString::value_type PathString::GetDefaultPathSeparator()
|
||||
{
|
||||
#if MPT_OS_WINDOWS
|
||||
return PC_('\\');
|
||||
#else
|
||||
return PC_('/');
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
|
||||
bool IsPathSeparator(mpt::RawPathString::value_type c) {
|
||||
#if MPT_OS_WINDOWS
|
||||
return (c == MPT_PATHSTRING_LITERAL('\\')) || (c == MPT_PATHSTRING_LITERAL('/'));
|
||||
#else
|
||||
return c == MPT_PATHSTRING_LITERAL('/');
|
||||
#endif
|
||||
}
|
||||
|
||||
bool PathIsAbsolute(const mpt::PathString &path) {
|
||||
mpt::RawPathString rawpath = path.AsNative();
|
||||
#if MPT_OS_WINDOWS
|
||||
if(rawpath.substr(0, 8) == MPT_PATHSTRING_LITERAL("\\\\?\\UNC\\"))
|
||||
if(rawpath.substr(0, 8) == PL_("\\\\?\\UNC\\"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if(rawpath.substr(0, 4) == MPT_PATHSTRING_LITERAL("\\\\?\\"))
|
||||
if(rawpath.substr(0, 4) == PL_("\\\\?\\"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if(rawpath.substr(0, 2) == MPT_PATHSTRING_LITERAL("\\\\"))
|
||||
if(rawpath.substr(0, 2) == PL_("\\\\"))
|
||||
{
|
||||
return true; // UNC
|
||||
}
|
||||
if(rawpath.substr(0, 2) == MPT_PATHSTRING_LITERAL("//"))
|
||||
if(rawpath.substr(0, 2) == PL_("//"))
|
||||
{
|
||||
return true; // UNC
|
||||
}
|
||||
return (rawpath.length()) >= 3 && (rawpath[1] == ':') && IsPathSeparator(rawpath[2]);
|
||||
return (rawpath.length()) >= 3 && (rawpath[1] == ':') && mpt::PathString::IsPathSeparator(rawpath[2]);
|
||||
#else
|
||||
return (rawpath.length() >= 1) && IsPathSeparator(rawpath[0]);
|
||||
return (rawpath.length() >= 1) && mpt::PathString::IsPathSeparator(rawpath[0]);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -463,13 +436,13 @@ bool PathIsAbsolute(const mpt::PathString &path) {
|
|||
|
||||
mpt::PathString GetAbsolutePath(const mpt::PathString &path)
|
||||
{
|
||||
DWORD size = GetFullPathNameW(path.AsNative().c_str(), 0, nullptr, nullptr);
|
||||
DWORD size = GetFullPathName(path.AsNative().c_str(), 0, nullptr, nullptr);
|
||||
if(size == 0)
|
||||
{
|
||||
return path;
|
||||
}
|
||||
std::vector<WCHAR> fullPathName(size, L'\0');
|
||||
if(GetFullPathNameW(path.AsNative().c_str(), size, fullPathName.data(), nullptr) == 0)
|
||||
std::vector<TCHAR> fullPathName(size, TEXT('\0'));
|
||||
if(GetFullPathName(path.AsNative().c_str(), size, fullPathName.data(), nullptr) == 0)
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
@ -484,7 +457,7 @@ bool DeleteWholeDirectoryTree(mpt::PathString path)
|
|||
{
|
||||
return false;
|
||||
}
|
||||
if(PathIsRelativeW(path.AsNative().c_str()) == TRUE)
|
||||
if(PathIsRelative(path.AsNative().c_str()) == TRUE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -498,15 +471,15 @@ bool DeleteWholeDirectoryTree(mpt::PathString path)
|
|||
}
|
||||
path.EnsureTrailingSlash();
|
||||
HANDLE hFind = NULL;
|
||||
WIN32_FIND_DATAW wfd;
|
||||
WIN32_FIND_DATA wfd;
|
||||
MemsetZero(wfd);
|
||||
hFind = FindFirstFileW((path + MPT_PATHSTRING("*.*")).AsNative().c_str(), &wfd);
|
||||
hFind = FindFirstFile((path + P_("*.*")).AsNative().c_str(), &wfd);
|
||||
if(hFind != NULL && hFind != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
do
|
||||
{
|
||||
mpt::PathString filename = mpt::PathString::FromNative(wfd.cFileName);
|
||||
if(filename != MPT_PATHSTRING(".") && filename != MPT_PATHSTRING(".."))
|
||||
if(filename != P_(".") && filename != P_(".."))
|
||||
{
|
||||
filename = path + filename;
|
||||
if(filename.IsDirectory())
|
||||
|
@ -517,16 +490,16 @@ bool DeleteWholeDirectoryTree(mpt::PathString path)
|
|||
}
|
||||
} else if(filename.IsFile())
|
||||
{
|
||||
if(DeleteFileW(filename.AsNative().c_str()) == 0)
|
||||
if(DeleteFile(filename.AsNative().c_str()) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while(FindNextFileW(hFind, &wfd));
|
||||
} while(FindNextFile(hFind, &wfd));
|
||||
FindClose(hFind);
|
||||
}
|
||||
if(RemoveDirectoryW(path.AsNative().c_str()) == 0)
|
||||
if(RemoveDirectory(path.AsNative().c_str()) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -545,8 +518,8 @@ bool DeleteWholeDirectoryTree(mpt::PathString path)
|
|||
|
||||
mpt::PathString GetAppPath()
|
||||
{
|
||||
std::vector<WCHAR> exeFileName(MAX_PATH);
|
||||
while(GetModuleFileNameW(0, exeFileName.data(), mpt::saturate_cast<DWORD>(exeFileName.size())) >= exeFileName.size())
|
||||
std::vector<TCHAR> exeFileName(MAX_PATH);
|
||||
while(GetModuleFileName(0, exeFileName.data(), mpt::saturate_cast<DWORD>(exeFileName.size())) >= exeFileName.size())
|
||||
{
|
||||
if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
|
@ -566,13 +539,13 @@ mpt::PathString GetAppPath()
|
|||
|
||||
mpt::PathString GetSystemPath()
|
||||
{
|
||||
DWORD size = GetSystemDirectoryW(nullptr, 0);
|
||||
std::vector<WCHAR> path(size + 1);
|
||||
if(!GetSystemDirectoryW(path.data(), size + 1))
|
||||
DWORD size = GetSystemDirectory(nullptr, 0);
|
||||
std::vector<TCHAR> path(size + 1);
|
||||
if(!GetSystemDirectory(path.data(), size + 1))
|
||||
{
|
||||
return mpt::PathString();
|
||||
}
|
||||
return mpt::PathString::FromNative(path.data()) + MPT_PATHSTRING("\\");
|
||||
return mpt::PathString::FromNative(path.data()) + P_("\\");
|
||||
}
|
||||
|
||||
#endif // !MPT_OS_WINDOWS_WINRT
|
||||
|
@ -588,11 +561,11 @@ mpt::PathString GetSystemPath()
|
|||
|
||||
mpt::PathString GetTempDirectory()
|
||||
{
|
||||
DWORD size = GetTempPathW(0, nullptr);
|
||||
DWORD size = GetTempPath(0, nullptr);
|
||||
if(size)
|
||||
{
|
||||
std::vector<WCHAR> tempPath(size + 1);
|
||||
if(GetTempPathW(size + 1, tempPath.data()))
|
||||
std::vector<TCHAR> tempPath(size + 1);
|
||||
if(GetTempPath(size + 1, tempPath.data()))
|
||||
{
|
||||
return mpt::PathString::FromNative(tempPath.data());
|
||||
}
|
||||
|
@ -604,9 +577,9 @@ mpt::PathString GetTempDirectory()
|
|||
mpt::PathString CreateTempFileName(const mpt::PathString &fileNamePrefix, const mpt::PathString &fileNameExtension)
|
||||
{
|
||||
mpt::PathString filename = mpt::GetTempDirectory();
|
||||
filename += (!fileNamePrefix.empty() ? fileNamePrefix + MPT_PATHSTRING("_") : mpt::PathString());
|
||||
filename += (!fileNamePrefix.empty() ? fileNamePrefix + P_("_") : mpt::PathString());
|
||||
filename += mpt::PathString::FromUnicode(mpt::UUID::GenerateLocalUseOnly().ToUString());
|
||||
filename += (!fileNameExtension.empty() ? MPT_PATHSTRING(".") + fileNameExtension : mpt::PathString());
|
||||
filename += (!fileNameExtension.empty() ? P_(".") + fileNameExtension : mpt::PathString());
|
||||
return filename;
|
||||
}
|
||||
|
||||
|
@ -625,7 +598,7 @@ TempFileGuard::~TempFileGuard()
|
|||
{
|
||||
if(!filename.empty())
|
||||
{
|
||||
DeleteFileW(filename.AsNative().c_str());
|
||||
DeleteFile(filename.AsNative().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -638,7 +611,7 @@ TempDirGuard::TempDirGuard(const mpt::PathString &dirname_)
|
|||
{
|
||||
return;
|
||||
}
|
||||
if(::CreateDirectoryW(dirname.AsNative().c_str(), NULL) == 0)
|
||||
if(::CreateDirectory(dirname.AsNative().c_str(), NULL) == 0)
|
||||
{ // fail
|
||||
dirname = mpt::PathString();
|
||||
}
|
||||
|
@ -787,7 +760,7 @@ mpt::PathString FileType::AsFilterString(FlagSet<FileTypeFormat> format) const
|
|||
const auto extensions = GetExtensions();
|
||||
if(format[FileTypeFormatShowExtensions])
|
||||
{
|
||||
filter += MPT_PATHSTRING(" (");
|
||||
filter += P_(" (");
|
||||
bool first = true;
|
||||
for(const auto &ext : extensions)
|
||||
{
|
||||
|
@ -796,14 +769,14 @@ mpt::PathString FileType::AsFilterString(FlagSet<FileTypeFormat> format) const
|
|||
first = false;
|
||||
} else
|
||||
{
|
||||
filter += MPT_PATHSTRING(",");
|
||||
filter += P_(",");
|
||||
}
|
||||
filter += MPT_PATHSTRING("*.");
|
||||
filter += P_("*.");
|
||||
filter += ext;
|
||||
}
|
||||
filter += MPT_PATHSTRING(")");
|
||||
filter += P_(")");
|
||||
}
|
||||
filter += MPT_PATHSTRING("|");
|
||||
filter += P_("|");
|
||||
{
|
||||
bool first = true;
|
||||
for(const auto &ext : extensions)
|
||||
|
@ -813,13 +786,13 @@ mpt::PathString FileType::AsFilterString(FlagSet<FileTypeFormat> format) const
|
|||
first = false;
|
||||
} else
|
||||
{
|
||||
filter += MPT_PATHSTRING(";");
|
||||
filter += P_(";");
|
||||
}
|
||||
filter += MPT_PATHSTRING("*.");
|
||||
filter += P_("*.");
|
||||
filter += ext;
|
||||
}
|
||||
}
|
||||
filter += MPT_PATHSTRING("|");
|
||||
filter += P_("|");
|
||||
return filter;
|
||||
}
|
||||
|
||||
|
@ -837,9 +810,9 @@ mpt::PathString FileType::AsFilterOnlyString() const
|
|||
first = false;
|
||||
} else
|
||||
{
|
||||
filter += MPT_PATHSTRING(";");
|
||||
filter += P_(";");
|
||||
}
|
||||
filter += MPT_PATHSTRING("*.");
|
||||
filter += P_("*.");
|
||||
filter += ext;
|
||||
}
|
||||
}
|
||||
|
@ -867,7 +840,7 @@ mpt::PathString ToFilterString(const std::vector<FileType> &fileTypes, FlagSet<F
|
|||
mpt::PathString ToFilterOnlyString(const FileType &fileType, bool prependSemicolonWhenNotEmpty)
|
||||
{
|
||||
mpt::PathString filter = fileType.AsFilterOnlyString();
|
||||
return filter.empty() ? filter : (prependSemicolonWhenNotEmpty ? MPT_PATHSTRING(";") : MPT_PATHSTRING("")) + filter;
|
||||
return filter.empty() ? filter : (prependSemicolonWhenNotEmpty ? P_(";") : P_("")) + filter;
|
||||
}
|
||||
|
||||
|
||||
|
@ -878,7 +851,7 @@ mpt::PathString ToFilterOnlyString(const std::vector<FileType> &fileTypes, bool
|
|||
{
|
||||
filter += type.AsFilterOnlyString();
|
||||
}
|
||||
return filter.empty() ? filter : (prependSemicolonWhenNotEmpty ? MPT_PATHSTRING(";") : MPT_PATHSTRING("")) + filter;
|
||||
return filter.empty() ? filter : (prependSemicolonWhenNotEmpty ? P_(";") : P_("")) + filter;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "FlagSet.h"
|
||||
|
@ -27,7 +29,7 @@ namespace mpt
|
|||
{
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
typedef std::wstring RawPathString;
|
||||
typedef mpt::winstring RawPathString;
|
||||
#else // !MPT_OS_WINDOWS
|
||||
typedef std::string RawPathString;
|
||||
#endif // if MPT_OS_WINDOWS
|
||||
|
@ -43,7 +45,7 @@ private:
|
|||
|
||||
private:
|
||||
|
||||
PathString(const RawPathString & path)
|
||||
explicit PathString(const RawPathString & path)
|
||||
: path(path)
|
||||
{
|
||||
return;
|
||||
|
@ -135,6 +137,9 @@ public:
|
|||
|
||||
#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS
|
||||
|
||||
static bool IsPathSeparator(RawPathString::value_type c);
|
||||
static RawPathString::value_type GetDefaultPathSeparator();
|
||||
|
||||
#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
|
||||
|
||||
// Return the same path string with a different (or appended) extension (including "."), e.g. "foo.bar",".txt" -> "foo.txt" or "C:\OpenMPT\foo",".txt" -> "C:\OpenMPT\foo.txt"
|
||||
|
@ -147,24 +152,18 @@ public:
|
|||
|
||||
bool HasTrailingSlash() const
|
||||
{
|
||||
if(empty())
|
||||
if(path.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
RawPathString::value_type c = path[path.length() - 1];
|
||||
#if MPT_OS_WINDOWS
|
||||
return (c == L'\\' || c == L'/');
|
||||
#else
|
||||
return (c == '/');
|
||||
#endif
|
||||
return IsPathSeparator(c);
|
||||
}
|
||||
mpt::PathString &EnsureTrailingSlash()
|
||||
{
|
||||
if(!path.empty() && !HasTrailingSlash())
|
||||
{
|
||||
#if MPT_OS_WINDOWS
|
||||
path += L'\\';
|
||||
#else
|
||||
path += '/';
|
||||
#endif
|
||||
path += GetDefaultPathSeparator();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
@ -178,7 +177,7 @@ public:
|
|||
{
|
||||
return result;
|
||||
}
|
||||
result = result.AsNative().substr(0, result.AsNative().length() - 1);
|
||||
result = mpt::PathString(result.AsNative().substr(0, result.AsNative().length() - 1));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -208,37 +207,23 @@ public:
|
|||
MPT_DEPRECATED_PATH std::string ToLocale() const { return mpt::ToCharset(mpt::CharsetLocale, path); }
|
||||
#endif
|
||||
std::string ToUTF8() const { return mpt::ToCharset(mpt::CharsetUTF8, path); }
|
||||
std::wstring ToWide() const { return path; }
|
||||
std::wstring ToWide() const { return mpt::ToWide(path); }
|
||||
mpt::ustring ToUnicode() const { return mpt::ToUnicode(path); }
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
MPT_DEPRECATED_PATH static PathString FromLocale(const std::string &path) { return PathString(mpt::ToWide(mpt::CharsetLocale, path)); }
|
||||
static PathString FromLocaleSilent(const std::string &path) { return PathString(mpt::ToWide(mpt::CharsetLocale, path)); }
|
||||
MPT_DEPRECATED_PATH static PathString FromLocale(const std::string &path) { return PathString(mpt::ToWin(mpt::CharsetLocale, path)); }
|
||||
static PathString FromLocaleSilent(const std::string &path) { return PathString(mpt::ToWin(mpt::CharsetLocale, path)); }
|
||||
#endif
|
||||
static PathString FromUTF8(const std::string &path) { return PathString(mpt::ToWide(mpt::CharsetUTF8, path)); }
|
||||
static PathString FromWide(const std::wstring &path) { return PathString(path); }
|
||||
static PathString FromUnicode(const mpt::ustring &path) { return PathString(mpt::ToWide(path)); }
|
||||
static PathString FromUTF8(const std::string &path) { return PathString(mpt::ToWin(mpt::CharsetUTF8, path)); }
|
||||
static PathString FromWide(const std::wstring &path) { return PathString(mpt::ToWin(path)); }
|
||||
static PathString FromUnicode(const mpt::ustring &path) { return PathString(mpt::ToWin(path)); }
|
||||
RawPathString AsNative() const { return path; }
|
||||
// Return native string, with possible \\?\ prefix if it exceeds MAX_PATH characters.
|
||||
RawPathString AsNativePrefixed() const;
|
||||
static PathString FromNative(const RawPathString &path) { return PathString(path); }
|
||||
#if defined(_MFC_VER)
|
||||
// CString TCHAR, so this is CHAR or WCHAR, depending on UNICODE
|
||||
MPT_DEPRECATED_PATH CString ToCString() const { return mpt::ToCString(path); }
|
||||
MPT_DEPRECATED_PATH static PathString FromCString(const CString &path) { return PathString(mpt::ToWide(path)); }
|
||||
// Non-warning-generating versions of the above. Use with extra care.
|
||||
CString ToCStringSilent() const { return mpt::ToCString(path); }
|
||||
static PathString FromCStringSilent(const CString &path) { return PathString(mpt::ToWide(path)); }
|
||||
// really special purpose, if !UNICODE, encode unicode in CString as UTF8:
|
||||
static mpt::PathString TunnelOutofCString(const CString &path);
|
||||
static CString TunnelIntoCString(const mpt::PathString &path);
|
||||
// CStringW
|
||||
#ifdef UNICODE
|
||||
MPT_DEPRECATED_PATH CString ToCStringW() const { return mpt::ToCString(path); }
|
||||
MPT_DEPRECATED_PATH static PathString FromCStringW(const CString &path) { return PathString(mpt::ToWide(path)); }
|
||||
#else
|
||||
CStringW ToCStringW() const { return mpt::ToCStringW(path); }
|
||||
static PathString FromCStringW(const CStringW &path) { return PathString(mpt::ToWide(path)); }
|
||||
#endif
|
||||
CString ToCString() const { return mpt::ToCString(path); }
|
||||
static PathString FromCString(const CString &path) { return PathString(mpt::ToWin(path)); }
|
||||
#endif
|
||||
|
||||
// Convert a path to its simplified form, i.e. remove ".\" and "..\" entries
|
||||
|
@ -270,7 +255,7 @@ public:
|
|||
std::wstring ToWide() const { return mpt::ToWide(mpt::CharsetUTF8, path); }
|
||||
#endif
|
||||
mpt::ustring ToUnicode() const { return mpt::ToUnicode(mpt::CharsetUTF8, path); }
|
||||
static PathString FromUTF8(const std::string &path) { return path; }
|
||||
static PathString FromUTF8(const std::string &path) { return PathString(path); }
|
||||
#if MPT_WSTRING_CONVERT
|
||||
static PathString FromWide(const std::wstring &path) { return PathString(mpt::ToCharset(mpt::CharsetUTF8, path)); }
|
||||
#endif
|
||||
|
@ -281,7 +266,7 @@ public:
|
|||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
|
||||
// Convert a path to its simplified form (currently only implemented on Windows)
|
||||
MPT_DEPRECATED mpt::PathString Simplify() const { return path; }
|
||||
MPT_DEPRECATED mpt::PathString Simplify() const { return PathString(path); }
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
|
@ -290,8 +275,16 @@ public:
|
|||
|
||||
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
#if MPT_OS_WINDOWS
|
||||
#ifdef UNICODE
|
||||
MPT_DEPRECATED static inline std::string ToString(const mpt::PathString & x) { return mpt::ToCharset(mpt::CharsetLocale, x.ToUnicode()); }
|
||||
#else
|
||||
MPT_DEPRECATED_PATH static inline std::string ToString(const mpt::PathString & x) { return mpt::ToCharset(mpt::CharsetLocale, x.AsNative()); }
|
||||
#endif
|
||||
#else
|
||||
MPT_DEPRECATED_PATH static inline std::string ToString(const mpt::PathString & x) { return mpt::ToCharset(mpt::CharsetLocale, x.ToUnicode()); }
|
||||
#endif
|
||||
#endif
|
||||
static inline mpt::ustring ToUString(const mpt::PathString & x) { return x.ToUnicode(); }
|
||||
#if MPT_WSTRING_FORMAT
|
||||
static inline std::wstring ToWString(const mpt::PathString & x) { return x.ToWide(); }
|
||||
|
@ -301,20 +294,28 @@ static inline std::wstring ToWString(const mpt::PathString & x) { return x.ToWid
|
|||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
#ifdef UNICODE
|
||||
#define MPT_PATHSTRING_LITERAL(x) ( L ## x )
|
||||
#define MPT_PATHSTRING(x) mpt::PathString::FromNative( L ## x )
|
||||
#else
|
||||
#define MPT_PATHSTRING_LITERAL(x) ( x )
|
||||
#define MPT_PATHSTRING(x) mpt::PathString::FromNative( x )
|
||||
#endif
|
||||
|
||||
#else // !MPT_OS_WINDOWS
|
||||
|
||||
#define MPT_PATHSTRING_LITERAL(x) ( x )
|
||||
#define MPT_PATHSTRING(x) mpt::PathString::FromNative( x )
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
#define PC_(x) MPT_PATHSTRING_LITERAL(x)
|
||||
#define PL_(x) MPT_PATHSTRING_LITERAL(x)
|
||||
#define P_(x) MPT_PATHSTRING(x)
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
bool IsPathSeparator(mpt::RawPathString::value_type c);
|
||||
|
||||
|
||||
|
||||
bool PathIsAbsolute(const mpt::PathString &path);
|
||||
|
||||
|
@ -361,7 +362,7 @@ mpt::PathString GetSystemPath();
|
|||
mpt::PathString GetTempDirectory();
|
||||
|
||||
// Returns a new unique absolute path.
|
||||
mpt::PathString CreateTempFileName(const mpt::PathString &fileNamePrefix = mpt::PathString(), const mpt::PathString &fileNameExtension = MPT_PATHSTRING("tmp"));
|
||||
mpt::PathString CreateTempFileName(const mpt::PathString &fileNamePrefix = mpt::PathString(), const mpt::PathString &fileNameExtension = P_("tmp"));
|
||||
|
||||
|
||||
|
||||
|
@ -465,7 +466,7 @@ public:
|
|||
}
|
||||
static FileType Any()
|
||||
{
|
||||
return FileType().ShortName(MPT_USTRING("*")).Description(MPT_USTRING("All Files")).AddExtension(MPT_PATHSTRING("*"));
|
||||
return FileType().ShortName(U_("*")).Description(U_("All Files")).AddExtension(P_("*"));
|
||||
}
|
||||
public:
|
||||
FileType& ShortName(const mpt::ustring &shortName) { m_ShortName = shortName; return *this; }
|
||||
|
|
|
@ -14,16 +14,11 @@
|
|||
#include "Endianness.h"
|
||||
#include "mptCRC.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
|
||||
#include <cmath>
|
||||
#include <ctime>
|
||||
#include <cstdlib>
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
#include <windows.h>
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
@ -89,30 +84,18 @@ static T generate_timeseed()
|
|||
#else // !MPT_BUILD_FUZZER
|
||||
|
||||
{
|
||||
#if MPT_OS_WINDOWS
|
||||
FILETIME t;
|
||||
MemsetZero(t);
|
||||
GetSystemTimeAsFileTime(&t);
|
||||
#else // !MPT_OS_WINDOWS
|
||||
std::time_t t = std::time(nullptr);
|
||||
#endif // MPT_OS_WINDOWS
|
||||
mpt::byte bytes[sizeof(t)];
|
||||
std::memcpy(bytes, &t, sizeof(t));
|
||||
MPT_MAYBE_CONSTANT_IF(mpt::endian_is_little())
|
||||
{
|
||||
std::reverse(std::begin(bytes), std::end(bytes));
|
||||
}
|
||||
uint64be time;
|
||||
time = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock().now().time_since_epoch()).count();
|
||||
mpt::byte bytes[sizeof(time)];
|
||||
std::memcpy(bytes, &time, sizeof(time));
|
||||
hash(std::begin(bytes), std::end(bytes));
|
||||
}
|
||||
|
||||
{
|
||||
std::clock_t c = std::clock();
|
||||
mpt::byte bytes[sizeof(c)];
|
||||
std::memcpy(bytes, &c, sizeof(c));
|
||||
MPT_MAYBE_CONSTANT_IF(mpt::endian_is_little())
|
||||
{
|
||||
std::reverse(std::begin(bytes), std::end(bytes));
|
||||
}
|
||||
uint64be time;
|
||||
time = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock().now().time_since_epoch()).count();
|
||||
mpt::byte bytes[sizeof(time)];
|
||||
std::memcpy(bytes, &time, sizeof(time));
|
||||
hash(std::begin(bytes), std::end(bytes));
|
||||
}
|
||||
|
||||
|
@ -273,16 +256,16 @@ uint64 prng_random_device_seeder::generate_seed64()
|
|||
#if defined(MODPLUG_TRACKER) && !defined(MPT_BUILD_WINESUPPORT)
|
||||
|
||||
static mpt::random_device *g_rd = nullptr;
|
||||
static mpt::thread_safe_prng<mpt::best_prng> *g_best_prng = nullptr;
|
||||
static mpt::thread_safe_prng<mpt::default_prng> *g_global_prng = nullptr;
|
||||
|
||||
void set_global_random_device(mpt::random_device *rd)
|
||||
{
|
||||
g_rd = rd;
|
||||
}
|
||||
|
||||
void set_global_prng(mpt::thread_safe_prng<mpt::best_prng> *prng)
|
||||
void set_global_prng(mpt::thread_safe_prng<mpt::default_prng> *prng)
|
||||
{
|
||||
g_best_prng = prng;
|
||||
g_global_prng = prng;
|
||||
}
|
||||
|
||||
mpt::random_device & global_random_device()
|
||||
|
@ -290,9 +273,9 @@ mpt::random_device & global_random_device()
|
|||
return *g_rd;
|
||||
}
|
||||
|
||||
mpt::thread_safe_prng<mpt::best_prng> & global_prng()
|
||||
mpt::thread_safe_prng<mpt::default_prng> & global_prng()
|
||||
{
|
||||
return *g_best_prng;
|
||||
return *g_global_prng;
|
||||
}
|
||||
|
||||
#else
|
||||
|
@ -303,10 +286,10 @@ mpt::random_device & global_random_device()
|
|||
return g_rd;
|
||||
}
|
||||
|
||||
mpt::thread_safe_prng<mpt::best_prng> & global_prng()
|
||||
mpt::thread_safe_prng<mpt::default_prng> & global_prng()
|
||||
{
|
||||
static mpt::thread_safe_prng<mpt::best_prng> g_best_prng(mpt::make_prng<mpt::best_prng>(global_random_device()));
|
||||
return g_best_prng;
|
||||
static mpt::thread_safe_prng<mpt::default_prng> g_global_prng(mpt::make_prng<mpt::default_prng>(global_random_device()));
|
||||
return g_global_prng;
|
||||
}
|
||||
|
||||
#endif // MODPLUG_TRACKER && !MPT_BUILD_WINESUPPORT
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
#include "mptMutex.h"
|
||||
|
||||
#include <limits>
|
||||
|
@ -184,15 +186,15 @@ inline T random(Trng & rng, std::size_t required_entropy_bits)
|
|||
template <typename Tf> struct float_traits { };
|
||||
template <> struct float_traits<float> {
|
||||
typedef uint32 mantissa_uint_type;
|
||||
static const int mantissa_bits = 24;
|
||||
enum : int { mantissa_bits = 24 };
|
||||
};
|
||||
template <> struct float_traits<double> {
|
||||
typedef uint64 mantissa_uint_type;
|
||||
static const int mantissa_bits = 53;
|
||||
enum : int { mantissa_bits = 53 };
|
||||
};
|
||||
template <> struct float_traits<long double> {
|
||||
typedef uint64 mantissa_uint_type;
|
||||
static const int mantissa_bits = 63;
|
||||
enum : int { mantissa_bits = 63 };
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
@ -402,33 +404,33 @@ public:
|
|||
// List the ones we are likely to use.
|
||||
|
||||
template <> struct engine_traits<std::mt19937> {
|
||||
static const std::size_t seed_bits = sizeof(std::mt19937::result_type) * 8 * std::mt19937::state_size;
|
||||
enum : std::size_t { seed_bits = sizeof(std::mt19937::result_type) * 8 * std::mt19937::state_size };
|
||||
typedef std::mt19937 rng_type;
|
||||
typedef rng_type::result_type result_type;
|
||||
static MPT_CONSTEXPR11_FUN int result_bits() { return rng_type::word_size; }
|
||||
template<typename Trd> static inline rng_type make(Trd & rd)
|
||||
{
|
||||
mpt::seed_seq_values<seed_bits / sizeof(unsigned int)> values(rd);
|
||||
std::seed_seq seed(values.begin(), values.end());
|
||||
std::unique_ptr<mpt::seed_seq_values<seed_bits / sizeof(unsigned int)>> values = mpt::make_unique<mpt::seed_seq_values<seed_bits / sizeof(unsigned int)>>(rd);
|
||||
std::seed_seq seed(values->begin(), values->end());
|
||||
return rng_type(seed);
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct engine_traits<std::mt19937_64> {
|
||||
static const std::size_t seed_bits = sizeof(std::mt19937_64::result_type) * 8 * std::mt19937_64::state_size;
|
||||
enum : std::size_t { seed_bits = sizeof(std::mt19937_64::result_type) * 8 * std::mt19937_64::state_size };
|
||||
typedef std::mt19937_64 rng_type;
|
||||
typedef rng_type::result_type result_type;
|
||||
static MPT_CONSTEXPR11_FUN int result_bits() { return rng_type::word_size; }
|
||||
template<typename Trd> static inline rng_type make(Trd & rd)
|
||||
{
|
||||
mpt::seed_seq_values<seed_bits / sizeof(unsigned int)> values(rd);
|
||||
std::seed_seq seed(values.begin(), values.end());
|
||||
std::unique_ptr<mpt::seed_seq_values<seed_bits / sizeof(unsigned int)>> values = mpt::make_unique<mpt::seed_seq_values<seed_bits / sizeof(unsigned int)>>(rd);
|
||||
std::seed_seq seed(values->begin(), values->end());
|
||||
return rng_type(seed);
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct engine_traits<std::ranlux24_base> {
|
||||
static const std::size_t seed_bits = std::ranlux24_base::word_size;
|
||||
enum : std::size_t { seed_bits = std::ranlux24_base::word_size };
|
||||
typedef std::ranlux24_base rng_type;
|
||||
typedef rng_type::result_type result_type;
|
||||
static MPT_CONSTEXPR11_FUN int result_bits() { return rng_type::word_size; }
|
||||
|
@ -441,7 +443,7 @@ template <> struct engine_traits<std::ranlux24_base> {
|
|||
};
|
||||
|
||||
template <> struct engine_traits<std::ranlux48_base> {
|
||||
static const std::size_t seed_bits = std::ranlux48_base::word_size;
|
||||
enum : std::size_t { seed_bits = std::ranlux48_base::word_size };
|
||||
typedef std::ranlux48_base rng_type;
|
||||
typedef rng_type::result_type result_type;
|
||||
static MPT_CONSTEXPR11_FUN int result_bits() { return rng_type::word_size; }
|
||||
|
@ -454,7 +456,7 @@ template <> struct engine_traits<std::ranlux48_base> {
|
|||
};
|
||||
|
||||
template <> struct engine_traits<std::ranlux24> {
|
||||
static const std::size_t seed_bits = std::ranlux24_base::word_size;
|
||||
enum : std::size_t { seed_bits = std::ranlux24_base::word_size };
|
||||
typedef std::ranlux24 rng_type;
|
||||
typedef rng_type::result_type result_type;
|
||||
static MPT_CONSTEXPR11_FUN int result_bits() { return std::ranlux24_base::word_size; }
|
||||
|
@ -467,7 +469,7 @@ template <> struct engine_traits<std::ranlux24> {
|
|||
};
|
||||
|
||||
template <> struct engine_traits<std::ranlux48> {
|
||||
static const std::size_t seed_bits = std::ranlux48_base::word_size;
|
||||
enum : std::size_t { seed_bits = std::ranlux48_base::word_size };
|
||||
typedef std::ranlux48 rng_type;
|
||||
typedef rng_type::result_type result_type;
|
||||
static MPT_CONSTEXPR11_FUN int result_bits() { return std::ranlux48_base::word_size; }
|
||||
|
@ -546,8 +548,7 @@ typedef mpt::prng_random_device<mpt::rng::lcg_musl> random_device;
|
|||
// 2. Use fast PRNGs in order to not waste time fuzzing more complex PRNG
|
||||
// implementations.
|
||||
typedef mpt::rng::lcg_msvc fast_prng;
|
||||
typedef mpt::rng::lcg_c99 main_prng;
|
||||
typedef mpt::rng::lcg_musl best_prng;
|
||||
typedef mpt::rng::lcg_musl good_prng;
|
||||
|
||||
#else // !MPT_BUILD_FUZZER
|
||||
|
||||
|
@ -557,26 +558,12 @@ typedef mpt::sane_random_device random_device;
|
|||
// We cannot use std::minstd_rand here because it has not a power-of-2 sized
|
||||
// output domain which we rely upon.
|
||||
typedef mpt::rng::lcg_msvc fast_prng; // about 3 ALU operations, ~32bit of state, suited for inner loops
|
||||
typedef std::mt19937 main_prng;
|
||||
#if MPT_MSVC_AT_LEAST(2017,5) && defined(_MSC_FULL_VER)
|
||||
#if (_MSC_FULL_VER < 191225831)
|
||||
// work-around compiler crash
|
||||
// c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.12.25827\include\random(978): fatal error C1001: An internal error has occurred in the compiler.
|
||||
// (compiler file 'f:\dd\vctools\compiler\utc\src\p2\main.c', line 258)
|
||||
// reported at: https://developercommunity.visualstudio.com/content/problem/162089/random-engines-crashing-vs-155-optimizer.html?childToView=164098#comment-164098
|
||||
typedef std::mt19937_64 best_prng;
|
||||
#else
|
||||
typedef std::ranlux48 best_prng;
|
||||
#endif
|
||||
#else
|
||||
typedef std::ranlux48 best_prng;
|
||||
#endif
|
||||
typedef std::ranlux48 good_prng;
|
||||
|
||||
#endif // MPT_BUILD_FUZZER
|
||||
|
||||
|
||||
typedef mpt::main_prng default_prng;
|
||||
typedef mpt::main_prng prng;
|
||||
typedef mpt::good_prng default_prng;
|
||||
|
||||
|
||||
template <typename Trng, typename Trd>
|
||||
|
@ -629,11 +616,11 @@ public:
|
|||
|
||||
|
||||
mpt::random_device & global_random_device();
|
||||
mpt::thread_safe_prng<mpt::best_prng> & global_prng();
|
||||
mpt::thread_safe_prng<mpt::default_prng> & global_prng();
|
||||
|
||||
#if defined(MODPLUG_TRACKER) && !defined(MPT_BUILD_WINESUPPORT)
|
||||
void set_global_random_device(mpt::random_device *rd);
|
||||
void set_global_prng(mpt::thread_safe_prng<mpt::best_prng> *rng);
|
||||
void set_global_prng(mpt::thread_safe_prng<mpt::default_prng> *rng);
|
||||
#endif // MODPLUG_TRACKER && !MPT_BUILD_WINESUPPORT
|
||||
|
||||
|
||||
|
|
121
Frameworks/OpenMPT/OpenMPT/common/mptSpan.h
Normal file
121
Frameworks/OpenMPT/OpenMPT/common/mptSpan.h
Normal file
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* mptSpan.h
|
||||
* ---------
|
||||
* Purpose: Various useful utility functions.
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
|
||||
#include "mptBaseTypes.h"
|
||||
|
||||
#include <array>
|
||||
#include <iterator>
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
|
||||
|
||||
namespace mpt {
|
||||
|
||||
|
||||
|
||||
// Simplified version of gsl::span.
|
||||
// Non-owning read-only or read-write view into a contiguous block of T
|
||||
// objects, i.e. equivalent to a (beg,end) or (data,size) tuple.
|
||||
// Can eventually be replaced without further modifications with a full C++20
|
||||
// std::span.
|
||||
template <typename T>
|
||||
class span
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
typedef std::size_t size_type;
|
||||
|
||||
typedef T value_type;
|
||||
typedef T & reference;
|
||||
typedef T * pointer;
|
||||
typedef const T * const_pointer;
|
||||
typedef const T & const_reference;
|
||||
|
||||
typedef pointer iterator;
|
||||
typedef const_pointer const_iterator;
|
||||
|
||||
typedef typename std::iterator_traits<iterator>::difference_type difference_type;
|
||||
|
||||
private:
|
||||
|
||||
T * m_beg;
|
||||
T * m_end;
|
||||
|
||||
public:
|
||||
|
||||
span() : m_beg(nullptr), m_end(nullptr) { }
|
||||
|
||||
span(pointer beg, pointer end) : m_beg(beg), m_end(end) { }
|
||||
|
||||
span(pointer data, size_type size) : m_beg(data), m_end(data + size) { }
|
||||
|
||||
template <typename U, std::size_t N> span(U (&arr)[N]) : m_beg(arr), m_end(arr + N) { }
|
||||
|
||||
template <typename Cont> span(Cont &cont) : m_beg(cont.empty() ? nullptr : &(cont[0])), m_end(cont.empty() ? nullptr : &(cont[0]) + cont.size()) { }
|
||||
|
||||
span(const span &other) : m_beg(other.begin()), m_end(other.end()) { }
|
||||
|
||||
template <typename U> span(const span<U> &other) : m_beg(other.begin()), m_end(other.end()) { }
|
||||
|
||||
span & operator = (span other) { m_beg = other.begin(); m_end = other.end(); return *this; }
|
||||
|
||||
iterator begin() const { return iterator(m_beg); }
|
||||
iterator end() const { return iterator(m_end); }
|
||||
|
||||
const_iterator cbegin() const { return const_iterator(begin()); }
|
||||
const_iterator cend() const { return const_iterator(end()); }
|
||||
|
||||
operator bool () const noexcept { return m_beg != nullptr; }
|
||||
|
||||
reference operator[](size_type index) { return at(index); }
|
||||
const_reference operator[](size_type index) const { return at(index); }
|
||||
|
||||
bool operator==(span const & other) const noexcept { return size() == other.size() && (m_beg == other.m_beg || std::equal(begin(), end(), other.begin())); }
|
||||
bool operator!=(span const & other) const noexcept { return !(*this == other); }
|
||||
|
||||
reference at(size_type index) { return m_beg[index]; }
|
||||
const_reference at(size_type index) const { return m_beg[index]; }
|
||||
|
||||
pointer data() const noexcept { return m_beg; }
|
||||
|
||||
bool empty() const noexcept { return size() == 0; }
|
||||
|
||||
size_type size() const noexcept { return static_cast<size_type>(std::distance(m_beg, m_end)); }
|
||||
size_type length() const noexcept { return size(); }
|
||||
|
||||
}; // class span
|
||||
|
||||
template <typename T> inline span<T> as_span(T * beg, T * end) { return span<T>(beg, end); }
|
||||
|
||||
template <typename T> inline span<T> as_span(T * data, std::size_t size) { return span<T>(data, size); }
|
||||
|
||||
template <typename T, std::size_t N> inline span<T> as_span(T (&arr)[N]) { return span<T>(std::begin(arr), std::end(arr)); }
|
||||
|
||||
template <typename T, std::size_t N> inline span<T> as_span(std::array<T, N> & cont) { return span<T>(cont); }
|
||||
|
||||
template <typename T, std::size_t N> inline span<const T> as_span(const std::array<T, N> & cont) { return span<const T>(cont); }
|
||||
|
||||
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -72,6 +72,10 @@ List of string types
|
|||
UTF16 (on windows) or UTF32 (otherwise). Do not use unless there is an
|
||||
obvious reason to do so.
|
||||
|
||||
* mpt::lstring (OpenMPT)
|
||||
OpenMPT locale string type. The encoding is always CP_ACP. Do not use unless
|
||||
there is an obvious reason to do so.
|
||||
|
||||
* char* (OpenMPT, libopenmpt)
|
||||
C string of unspecified encoding. Use only for static literals or in
|
||||
performance critical inner loops where full control and avoidance of memory
|
||||
|
@ -82,27 +86,29 @@ List of string types
|
|||
performance critical inner loops where full control and avoidance of memory
|
||||
allocation is required.
|
||||
|
||||
* mpt::winstring (OpenMPT)
|
||||
OpenMPT type-safe string to interface with native WinAPI, either encoded in
|
||||
locale/CP_ACP (if !UNICODE) or UTF16 (if UNICODE).
|
||||
|
||||
* CString (OpenMPT)
|
||||
MFC string type, either encoded in locale/CP_ACP (if !UNICODE) or UTF16 (if
|
||||
UNICODE). Specify literals with _T(""). Use in MFC GUI code.
|
||||
|
||||
* CStringA (OpenMPT)
|
||||
MFC ANSI string type. The encoding is always CP_ACP. Do not use unless there
|
||||
is an obvious reason to do so.
|
||||
MFC ANSI string type. The encoding is always CP_ACP. Do not use.
|
||||
|
||||
* CStringW (OpenMPT)
|
||||
MFC Unicode string type. Use in MFC GUI code when explicit Unicode support
|
||||
is required.
|
||||
MFC Unicode string type. Do not use.
|
||||
|
||||
* mpt::PathString (OpenMPT, libopenmpt)
|
||||
String type representing paths and filenames. Always use for these in order
|
||||
to avoid potentially lossy conversions. Use MPT_PATHSTRING("") macro for
|
||||
to avoid potentially lossy conversions. Use P_("") macro for
|
||||
literals.
|
||||
|
||||
* mpt::ustring (OpenMPT, libopenmpt)
|
||||
The default unicode string type. Can be encoded in UTF8 or UTF16 or UTF32,
|
||||
depending on MPT_USTRING_MODE_* and sizeof(wchar_t). Literals can written as
|
||||
MPT_USTRING(""). Use as your default string type if no other string type is
|
||||
U_(""). Use as your default string type if no other string type is
|
||||
a measurably better fit.
|
||||
|
||||
* MPT_UTF8 (OpenMPT, libopenmpt)
|
||||
|
@ -154,7 +160,7 @@ heuristic.
|
|||
* AnyString (OpenMPT, libopenmpt)
|
||||
Tries to do the smartest auto-magic we can do.
|
||||
|
||||
* AnyLocaleString (OpenMPT, libopenmpt)
|
||||
* AnyStringLocale (OpenMPT, libopenmpt)
|
||||
char-based strings are assumed to be in locale encoding.
|
||||
|
||||
* AnyStringUTF8orLocale (OpenMPT, libopenmpt)
|
||||
|
@ -215,17 +221,10 @@ else
|
|||
else
|
||||
T = mpt::PathString
|
||||
fi
|
||||
elif winapi interfacing code
|
||||
T = mpt::winstring
|
||||
elif mfc/gui code
|
||||
if directly interface with wide winapi
|
||||
T = CStringW
|
||||
elif needs unicode support
|
||||
T = CStringW
|
||||
else
|
||||
T = CString
|
||||
fi
|
||||
else
|
||||
if directly interfacing with wide winapi
|
||||
T = std::wstring
|
||||
else
|
||||
if constexpr context or global data
|
||||
T = MPT_UCHAR_TYPE* / MPT_ULITERAL
|
||||
|
@ -233,7 +232,6 @@ else
|
|||
T = mpt::ustring
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
This boils down to: Prefer mpt::PathString and mpt::ustring, and only use any
|
||||
|
@ -293,10 +291,14 @@ when converting between different Unicode encodings.
|
|||
Interfacing with WinAPI
|
||||
-----------------------
|
||||
|
||||
When in MFC code, use CString or CStringW as appropriate.
|
||||
When in non MFC code, either use std::wstring when directly interfacing with the
|
||||
Unicode API, or use the TCHAR helper functions: ToTcharBuf, FromTcharBuf,
|
||||
ToTcharStr, FromTcharStr.
|
||||
When in MFC code, use CString.
|
||||
When in non MFC code, either use std::wstring when directly interfacing with
|
||||
APIs only available in WCHAR variants, or use mpt::winstring and
|
||||
mpt::WinStringBuf helpers otherwise.
|
||||
Specify TCHAR string literals with _T("foo") in mptrack/, and with TEXT("foo")
|
||||
in common/ or sounddev/. _T() requires <tchar.h> which is specific to the MSVC
|
||||
runtime and not portable across compilers. TEXT() is from <windows.h>. We use
|
||||
_T() in mptrack/ only because it is shorter.
|
||||
|
||||
|
||||
|
||||
|
@ -437,20 +439,28 @@ static const uint32 CharsetTableCP437AMS2[256] = {
|
|||
|
||||
#undef C
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
#pragma warning(disable:4428) // universal-character-name encountered in source
|
||||
#endif
|
||||
|
||||
static std::wstring From8bit(const std::string &str, const uint32 (&table)[256], wchar_t replacement = L'\uFFFD')
|
||||
#if defined(MPT_COMPILER_QUIRK_NO_WCHAR)
|
||||
typedef char32_t widechar;
|
||||
typedef std::u32string widestring;
|
||||
static constexpr widechar wide_default_replacement = 0xFFFD;
|
||||
#else // !MPT_COMPILER_QUIRK_NO_WCHAR
|
||||
typedef wchar_t widechar;
|
||||
typedef std::wstring widestring;
|
||||
static constexpr widechar wide_default_replacement = L'\uFFFD';
|
||||
#endif // !MPT_COMPILER_QUIRK_NO_WCHAR
|
||||
|
||||
|
||||
static widestring From8bit(const std::string &str, const uint32 (&table)[256], widechar replacement = wide_default_replacement)
|
||||
{
|
||||
std::wstring res;
|
||||
widestring res;
|
||||
res.reserve(str.length());
|
||||
for(std::size_t i = 0; i < str.length(); ++i)
|
||||
{
|
||||
uint32 c = static_cast<uint32>(static_cast<uint8>(str[i]));
|
||||
if(c < mpt::size(table))
|
||||
{
|
||||
res.push_back(static_cast<wchar_t>(static_cast<uint32>(table[c])));
|
||||
res.push_back(static_cast<widechar>(static_cast<uint32>(table[c])));
|
||||
} else
|
||||
{
|
||||
res.push_back(replacement);
|
||||
|
@ -459,7 +469,7 @@ static std::wstring From8bit(const std::string &str, const uint32 (&table)[256],
|
|||
return res;
|
||||
}
|
||||
|
||||
static std::string To8bit(const std::wstring &str, const uint32 (&table)[256], char replacement = '?')
|
||||
static std::string To8bit(const widestring &str, const uint32 (&table)[256], char replacement = '?')
|
||||
{
|
||||
std::string res;
|
||||
res.reserve(str.length());
|
||||
|
@ -502,16 +512,16 @@ static std::string To8bit(const std::wstring &str, const uint32 (&table)[256], c
|
|||
|
||||
#if defined(MPT_CHARSET_CODECVTUTF8) || defined(MPT_CHARSET_INTERNAL) || defined(MPT_CHARSET_WIN32)
|
||||
|
||||
static std::wstring FromAscii(const std::string &str, wchar_t replacement = L'\uFFFD')
|
||||
static widestring FromAscii(const std::string &str, widechar replacement = wide_default_replacement)
|
||||
{
|
||||
std::wstring res;
|
||||
widestring res;
|
||||
res.reserve(str.length());
|
||||
for(std::size_t i = 0; i < str.length(); ++i)
|
||||
{
|
||||
uint8 c = str[i];
|
||||
if(c <= 0x7f)
|
||||
{
|
||||
res.push_back(static_cast<wchar_t>(static_cast<uint32>(c)));
|
||||
res.push_back(static_cast<widechar>(static_cast<uint32>(c)));
|
||||
} else
|
||||
{
|
||||
res.push_back(replacement);
|
||||
|
@ -520,7 +530,7 @@ static std::wstring FromAscii(const std::string &str, wchar_t replacement = L'\u
|
|||
return res;
|
||||
}
|
||||
|
||||
static std::string ToAscii(const std::wstring &str, char replacement = '?')
|
||||
static std::string ToAscii(const widestring &str, char replacement = '?')
|
||||
{
|
||||
std::string res;
|
||||
res.reserve(str.length());
|
||||
|
@ -538,20 +548,20 @@ static std::string ToAscii(const std::wstring &str, char replacement = '?')
|
|||
return res;
|
||||
}
|
||||
|
||||
static std::wstring FromISO_8859_1(const std::string &str, wchar_t replacement = L'\uFFFD')
|
||||
static widestring FromISO_8859_1(const std::string &str, widechar replacement = wide_default_replacement)
|
||||
{
|
||||
MPT_UNREFERENCED_PARAMETER(replacement);
|
||||
std::wstring res;
|
||||
widestring res;
|
||||
res.reserve(str.length());
|
||||
for(std::size_t i = 0; i < str.length(); ++i)
|
||||
{
|
||||
uint8 c = str[i];
|
||||
res.push_back(static_cast<wchar_t>(static_cast<uint32>(c)));
|
||||
res.push_back(static_cast<widechar>(static_cast<uint32>(c)));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static std::string ToISO_8859_1(const std::wstring &str, char replacement = '?')
|
||||
static std::string ToISO_8859_1(const widestring &str, char replacement = '?')
|
||||
{
|
||||
std::string res;
|
||||
res.reserve(str.length());
|
||||
|
@ -569,18 +579,19 @@ static std::string ToISO_8859_1(const std::wstring &str, char replacement = '?')
|
|||
return res;
|
||||
}
|
||||
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE) && !defined(MPT_LOCALE_ASSUME_CHARSET)
|
||||
|
||||
// Note:
|
||||
//
|
||||
// std::codecvt::out in LLVM libc++ does not advance in and out pointers when
|
||||
// running into a non-convertible cahracter. This can happen when no locale is
|
||||
// running into a non-convertible character. This can happen when no locale is
|
||||
// set on FreeBSD or MacOSX. This behaviour violates the C++ standard.
|
||||
//
|
||||
// We apply the following (albeit costly, even on other platforms) work-around:
|
||||
// If the conversion errors out and does not advance the pointers at all, we
|
||||
// retry the conversion with a space character prepended to the string. If it
|
||||
// still does error our, we retry the whole conversion character by character.
|
||||
// still does error out, we retry the whole conversion character by character.
|
||||
// This is costly even on other platforms in one single case: The first
|
||||
// character is an invalid Unicode code point or otherwise not convertible. Any
|
||||
// following non-convertible characters are not a problem.
|
||||
|
@ -815,7 +826,7 @@ static std::string ToLocale(const std::wstring &str, char replacement = '?')
|
|||
return String::ToAscii(str, replacement); // fallback
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE && !MPT_LOCALE_ASSUME_CHARSET
|
||||
|
||||
#endif // MPT_CHARSET_CODECVTUTF8 || MPT_CHARSET_INTERNAL || MPT_CHARSET_WIN32
|
||||
|
||||
|
@ -839,11 +850,11 @@ static std::string ToUTF8(const std::wstring &str, char replacement = '?')
|
|||
|
||||
#if defined(MPT_CHARSET_INTERNAL) || defined(MPT_CHARSET_WIN32)
|
||||
|
||||
static std::wstring FromUTF8(const std::string &str, wchar_t replacement = L'\uFFFD')
|
||||
static widestring FromUTF8(const std::string &str, widechar replacement = wide_default_replacement)
|
||||
{
|
||||
const std::string &in = str;
|
||||
|
||||
std::wstring out;
|
||||
widestring out;
|
||||
|
||||
// state:
|
||||
std::size_t charsleft = 0;
|
||||
|
@ -882,7 +893,7 @@ static std::wstring FromUTF8(const std::string &str, wchar_t replacement = L'\uF
|
|||
charsleft--;
|
||||
|
||||
if ( charsleft == 0 ) {
|
||||
MPT_CONSTANT_IF ( sizeof( wchar_t ) == 2 ) {
|
||||
MPT_CONSTANT_IF ( sizeof( widechar ) == 2 ) {
|
||||
if ( ucs4 > 0x1fffff ) {
|
||||
out.push_back( replacement );
|
||||
ucs4 = 0;
|
||||
|
@ -898,7 +909,7 @@ static std::wstring FromUTF8(const std::string &str, wchar_t replacement = L'\uF
|
|||
out.push_back( lo_sur );
|
||||
}
|
||||
} else {
|
||||
out.push_back( static_cast<wchar_t>( ucs4 ) );
|
||||
out.push_back( static_cast<widechar>( ucs4 ) );
|
||||
}
|
||||
ucs4 = 0;
|
||||
}
|
||||
|
@ -917,9 +928,9 @@ static std::wstring FromUTF8(const std::string &str, wchar_t replacement = L'\uF
|
|||
|
||||
}
|
||||
|
||||
static std::string ToUTF8(const std::wstring &str, char replacement = '?')
|
||||
static std::string ToUTF8(const widestring &str, char replacement = '?')
|
||||
{
|
||||
const std::wstring &in = str;
|
||||
const widestring &in = str;
|
||||
|
||||
std::string out;
|
||||
|
||||
|
@ -928,7 +939,7 @@ static std::string ToUTF8(const std::wstring &str, char replacement = '?')
|
|||
wchar_t wc = in[i];
|
||||
|
||||
uint32 ucs4 = 0;
|
||||
MPT_CONSTANT_IF ( sizeof( wchar_t ) == 2 ) {
|
||||
MPT_CONSTANT_IF ( sizeof( widechar ) == 2 ) {
|
||||
uint16 c = static_cast<uint16>( wc );
|
||||
if ( i + 1 < in.length() ) {
|
||||
// check for surrogate pair
|
||||
|
@ -1107,6 +1118,7 @@ static const char * Charset_wchar_t()
|
|||
{
|
||||
return "UTF-16BE";
|
||||
}
|
||||
return "UTF-16";
|
||||
} else if(sizeof(wchar_t) == 4)
|
||||
{
|
||||
// "UTF-32" generates BOM
|
||||
|
@ -1118,8 +1130,8 @@ static const char * Charset_wchar_t()
|
|||
{
|
||||
return "UTF-32BE";
|
||||
}
|
||||
return "UTF-32";
|
||||
}
|
||||
return "";
|
||||
#endif // !MPT_ICONV_NO_WCHAR | MPT_ICONV_NO_WCHAR
|
||||
}
|
||||
|
||||
|
@ -1128,14 +1140,15 @@ static const char * Charset_wchar_t()
|
|||
|
||||
#if !defined(MPT_CHARSET_ICONV)
|
||||
template<typename Tdststring>
|
||||
Tdststring EncodeImplFallback(Charset charset, const std::wstring &src);
|
||||
static Tdststring EncodeImplFallback(Charset charset, const widestring &src);
|
||||
#endif // !MPT_CHARSET_ICONV
|
||||
|
||||
// templated on 8bit strings because of type-safe variants
|
||||
template<typename Tdststring>
|
||||
Tdststring EncodeImpl(Charset charset, const std::wstring &src)
|
||||
static Tdststring EncodeImpl(Charset charset, const widestring &src)
|
||||
{
|
||||
STATIC_ASSERT(sizeof(typename Tdststring::value_type) == sizeof(char));
|
||||
MPT_STATIC_ASSERT(sizeof(typename Tdststring::value_type) == sizeof(char));
|
||||
MPT_STATIC_ASSERT((std::is_same<typename Tdststring::value_type, char>::value));
|
||||
if(charset == CharsetCP437AMS || charset == CharsetCP437AMS2)
|
||||
{
|
||||
std::string out;
|
||||
|
@ -1162,9 +1175,16 @@ Tdststring EncodeImpl(Charset charset, const std::wstring &src)
|
|||
{
|
||||
return Tdststring();
|
||||
}
|
||||
#if MPT_CXX_AT_LEAST(17)
|
||||
Tdststring encoded_string(required_size, char());
|
||||
WideCharToMultiByte(codepage, 0, src.c_str(), -1, encoded_string.data(), required_size, nullptr, nullptr);
|
||||
encoded_string.resize(encoded_string.size() - 1); // remove \0
|
||||
return encoded_string;
|
||||
#else
|
||||
std::vector<CHAR> encoded_string(required_size);
|
||||
WideCharToMultiByte(codepage, 0, src.c_str(), -1, encoded_string.data(), required_size, nullptr, nullptr);
|
||||
return reinterpret_cast<const typename Tdststring::value_type*>(encoded_string.data());
|
||||
#endif
|
||||
#elif defined(MPT_CHARSET_ICONV)
|
||||
iconv_t conv = iconv_t();
|
||||
conv = iconv_open(CharsetToStringTranslit(charset), Charset_wchar_t());
|
||||
|
@ -1176,18 +1196,18 @@ Tdststring EncodeImpl(Charset charset, const std::wstring &src)
|
|||
throw std::runtime_error("iconv conversion not working");
|
||||
}
|
||||
}
|
||||
std::vector<wchar_t> wide_string(src.c_str(), src.c_str() + src.length() + 1);
|
||||
std::vector<widechar> wide_string(src.c_str(), src.c_str() + src.length() + 1);
|
||||
std::vector<char> encoded_string(wide_string.size() * 8); // large enough
|
||||
char * inbuf = reinterpret_cast<char*>(wide_string.data());
|
||||
size_t inbytesleft = wide_string.size() * sizeof(wchar_t);
|
||||
size_t inbytesleft = wide_string.size() * sizeof(widechar);
|
||||
char * outbuf = encoded_string.data();
|
||||
size_t outbytesleft = encoded_string.size();
|
||||
while(iconv(conv, &inbuf, &inbytesleft, &outbuf, &outbytesleft) == static_cast<size_t>(-1))
|
||||
{
|
||||
if(errno == EILSEQ || errno == EILSEQ)
|
||||
{
|
||||
inbuf += sizeof(wchar_t);
|
||||
inbytesleft -= sizeof(wchar_t);
|
||||
inbuf += sizeof(widechar);
|
||||
inbytesleft -= sizeof(widechar);
|
||||
outbuf[0] = '?';
|
||||
outbuf++;
|
||||
outbytesleft--;
|
||||
|
@ -1210,13 +1230,25 @@ Tdststring EncodeImpl(Charset charset, const std::wstring &src)
|
|||
|
||||
#if !defined(MPT_CHARSET_ICONV)
|
||||
template<typename Tdststring>
|
||||
Tdststring EncodeImplFallback(Charset charset, const std::wstring &src)
|
||||
static Tdststring EncodeImplFallback(Charset charset, const widestring &src)
|
||||
{
|
||||
std::string out;
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
#if defined(MPT_LOCALE_ASSUME_CHARSET)
|
||||
if(charset == CharsetLocale)
|
||||
{
|
||||
charset = MPT_LOCALE_ASSUME_CHARSET;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
switch(charset)
|
||||
{
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
#if defined(MPT_LOCALE_ASSUME_CHARSET)
|
||||
case CharsetLocale: MPT_ASSERT_NOTREACHED(); break;
|
||||
#else
|
||||
case CharsetLocale: out = String::ToLocale(src); break;
|
||||
#endif
|
||||
#endif
|
||||
case CharsetUTF8: out = String::ToUTF8(src); break;
|
||||
case CharsetASCII: out = String::ToAscii(src); break;
|
||||
|
@ -1234,18 +1266,19 @@ Tdststring EncodeImplFallback(Charset charset, const std::wstring &src)
|
|||
|
||||
#if !defined(MPT_CHARSET_ICONV)
|
||||
template<typename Tsrcstring>
|
||||
std::wstring DecodeImplFallback(Charset charset, const Tsrcstring &src);
|
||||
static widestring DecodeImplFallback(Charset charset, const Tsrcstring &src);
|
||||
#endif // !MPT_CHARSET_ICONV
|
||||
|
||||
// templated on 8bit strings because of type-safe variants
|
||||
template<typename Tsrcstring>
|
||||
std::wstring DecodeImpl(Charset charset, const Tsrcstring &src)
|
||||
static widestring DecodeImpl(Charset charset, const Tsrcstring &src)
|
||||
{
|
||||
STATIC_ASSERT(sizeof(typename Tsrcstring::value_type) == sizeof(char));
|
||||
MPT_STATIC_ASSERT(sizeof(typename Tsrcstring::value_type) == sizeof(char));
|
||||
MPT_STATIC_ASSERT((std::is_same<typename Tsrcstring::value_type, char>::value));
|
||||
if(charset == CharsetCP437AMS || charset == CharsetCP437AMS2)
|
||||
{
|
||||
std::string in(src.begin(), src.end());
|
||||
std::wstring out;
|
||||
widestring out;
|
||||
if(charset == CharsetCP437AMS ) out = String::From8bit(in, CharsetTableCP437AMS );
|
||||
if(charset == CharsetCP437AMS2) out = String::From8bit(in, CharsetTableCP437AMS2);
|
||||
return out;
|
||||
|
@ -1267,11 +1300,18 @@ std::wstring DecodeImpl(Charset charset, const Tsrcstring &src)
|
|||
int required_size = MultiByteToWideChar(codepage, 0, reinterpret_cast<const char*>(src.c_str()), -1, nullptr, 0);
|
||||
if(required_size <= 0)
|
||||
{
|
||||
return std::wstring();
|
||||
return widestring();
|
||||
}
|
||||
#if MPT_CXX_AT_LEAST(17)
|
||||
widestring decoded_string(required_size, widechar());
|
||||
MultiByteToWideChar(codepage, 0, reinterpret_cast<const char*>(src.c_str()), -1, decoded_string.data(), required_size);
|
||||
decoded_string.resize(decoded_string.size() - 1); // remove \0
|
||||
return decoded_string;
|
||||
#else
|
||||
std::vector<WCHAR> decoded_string(required_size);
|
||||
MultiByteToWideChar(codepage, 0, reinterpret_cast<const char*>(src.c_str()), -1, decoded_string.data(), required_size);
|
||||
return decoded_string.data();
|
||||
#endif
|
||||
#elif defined(MPT_CHARSET_ICONV)
|
||||
iconv_t conv = iconv_t();
|
||||
conv = iconv_open(Charset_wchar_t(), CharsetToString(charset));
|
||||
|
@ -1280,43 +1320,31 @@ std::wstring DecodeImpl(Charset charset, const Tsrcstring &src)
|
|||
throw std::runtime_error("iconv conversion not working");
|
||||
}
|
||||
std::vector<char> encoded_string(reinterpret_cast<const char*>(src.c_str()), reinterpret_cast<const char*>(src.c_str()) + src.length() + 1);
|
||||
std::vector<wchar_t> wide_string(encoded_string.size() * 8); // large enough
|
||||
std::vector<widechar> wide_string(encoded_string.size() * 8); // large enough
|
||||
char * inbuf = encoded_string.data();
|
||||
size_t inbytesleft = encoded_string.size();
|
||||
char * outbuf = reinterpret_cast<char*>(wide_string.data());
|
||||
size_t outbytesleft = wide_string.size() * sizeof(wchar_t);
|
||||
size_t outbytesleft = wide_string.size() * sizeof(widechar);
|
||||
while(iconv(conv, &inbuf, &inbytesleft, &outbuf, &outbytesleft) == static_cast<size_t>(-1))
|
||||
{
|
||||
if(errno == EILSEQ || errno == EILSEQ)
|
||||
{
|
||||
inbuf++;
|
||||
inbytesleft--;
|
||||
for(std::size_t i = 0; i < sizeof(wchar_t); ++i)
|
||||
for(std::size_t i = 0; i < sizeof(widechar); ++i)
|
||||
{
|
||||
outbuf[i] = 0;
|
||||
}
|
||||
#if defined(MPT_PLATFORM_LITTLE_ENDIAN)
|
||||
outbuf[1] = uint8(0xff); outbuf[0] = uint8(0xfd);
|
||||
#elif defined(MPT_PLATFORM_BIG_ENDIAN)
|
||||
outbuf[sizeof(wchar_t)-1 - 1] = uint8(0xff); outbuf[sizeof(wchar_t)-1 - 0] = uint8(0xfd);
|
||||
#else
|
||||
MPT_MAYBE_CONSTANT_IF(mpt::endian_is_little())
|
||||
{
|
||||
outbuf[1] = uint8(0xff); outbuf[0] = uint8(0xfd);
|
||||
}
|
||||
MPT_MAYBE_CONSTANT_IF(mpt::endian_is_big())
|
||||
{
|
||||
outbuf[sizeof(wchar_t)-1 - 1] = uint8(0xff); outbuf[sizeof(wchar_t)-1 - 0] = uint8(0xfd);
|
||||
}
|
||||
#endif
|
||||
outbuf += sizeof(wchar_t);
|
||||
outbytesleft -= sizeof(wchar_t);
|
||||
widechar tmp = 0xfffd;
|
||||
std::memcpy(outbuf, &tmp, sizeof(widechar));
|
||||
outbuf += sizeof(widechar);
|
||||
outbytesleft -= sizeof(widechar);
|
||||
iconv(conv, NULL, NULL, NULL, NULL); // reset state
|
||||
} else
|
||||
{
|
||||
iconv_close(conv);
|
||||
conv = iconv_t();
|
||||
return std::wstring();
|
||||
return widestring();
|
||||
}
|
||||
}
|
||||
iconv_close(conv);
|
||||
|
@ -1329,14 +1357,26 @@ std::wstring DecodeImpl(Charset charset, const Tsrcstring &src)
|
|||
|
||||
#if !defined(MPT_CHARSET_ICONV)
|
||||
template<typename Tsrcstring>
|
||||
std::wstring DecodeImplFallback(Charset charset, const Tsrcstring &src)
|
||||
static widestring DecodeImplFallback(Charset charset, const Tsrcstring &src)
|
||||
{
|
||||
std::string in(src.begin(), src.end());
|
||||
std::wstring out;
|
||||
widestring out;
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
#if defined(MPT_LOCALE_ASSUME_CHARSET)
|
||||
if(charset == CharsetLocale)
|
||||
{
|
||||
charset = MPT_LOCALE_ASSUME_CHARSET;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
switch(charset)
|
||||
{
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
#if defined(MPT_LOCALE_ASSUME_CHARSET)
|
||||
case CharsetLocale: MPT_ASSERT_NOTREACHED(); break;
|
||||
#else
|
||||
case CharsetLocale: out = String::FromLocale(in); break;
|
||||
#endif
|
||||
#endif
|
||||
case CharsetUTF8: out = String::FromUTF8(in); break;
|
||||
case CharsetASCII: out = String::FromAscii(in); break;
|
||||
|
@ -1354,7 +1394,7 @@ std::wstring DecodeImplFallback(Charset charset, const Tsrcstring &src)
|
|||
|
||||
// templated on 8bit strings because of type-safe variants
|
||||
template<typename Tdststring, typename Tsrcstring>
|
||||
Tdststring ConvertImpl(Charset to, Charset from, const Tsrcstring &src)
|
||||
static Tdststring ConvertImpl(Charset to, Charset from, const Tsrcstring &src)
|
||||
{
|
||||
STATIC_ASSERT(sizeof(typename Tdststring::value_type) == sizeof(char));
|
||||
STATIC_ASSERT(sizeof(typename Tsrcstring::value_type) == sizeof(char));
|
||||
|
@ -1411,6 +1451,7 @@ Tdststring ConvertImpl(Charset to, Charset from, const Tsrcstring &src)
|
|||
}
|
||||
|
||||
|
||||
|
||||
} // namespace String
|
||||
|
||||
|
||||
|
@ -1425,6 +1466,12 @@ std::wstring ToWide(Charset from, const std::string &str)
|
|||
{
|
||||
return String::DecodeImpl(from, str);
|
||||
}
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
std::wstring ToWide(const mpt::lstring &str)
|
||||
{
|
||||
return String::DecodeImpl(CharsetLocale, str);
|
||||
}
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
#endif
|
||||
|
||||
#if MPT_WSTRING_CONVERT
|
||||
|
@ -1437,6 +1484,56 @@ std::string ToCharset(Charset to, Charset from, const std::string &str)
|
|||
{
|
||||
return String::ConvertImpl<std::string>(to, from, str);
|
||||
}
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
std::string ToCharset(Charset to, const mpt::lstring &str)
|
||||
{
|
||||
return String::ConvertImpl<std::string>(to, CharsetLocale, str);
|
||||
}
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
#if MPT_WSTRING_CONVERT
|
||||
mpt::lstring ToLocale(const std::wstring &str)
|
||||
{
|
||||
return String::EncodeImpl<mpt::lstring>(CharsetLocale, str);
|
||||
}
|
||||
#endif
|
||||
mpt::lstring ToLocale(Charset from, const std::string &str)
|
||||
{
|
||||
return String::ConvertImpl<mpt::lstring>(CharsetLocale, from, str);
|
||||
}
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
#if MPT_WSTRING_CONVERT
|
||||
mpt::winstring ToWin(const std::wstring &str)
|
||||
{
|
||||
#ifdef UNICODE
|
||||
return str;
|
||||
#else
|
||||
return ToLocale(str);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
mpt::winstring ToWin(Charset from, const std::string &str)
|
||||
{
|
||||
#ifdef UNICODE
|
||||
return ToWide(from, str);
|
||||
#else
|
||||
return ToLocale(from, str);
|
||||
#endif
|
||||
}
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
mpt::winstring ToWin(const mpt::lstring &str)
|
||||
{
|
||||
#ifdef UNICODE
|
||||
return ToWide(str);
|
||||
#else
|
||||
return str;
|
||||
#endif
|
||||
}
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
|
||||
#if defined(_MFC_VER)
|
||||
|
@ -1473,39 +1570,30 @@ std::string ToCharset(Charset to, const CString &str)
|
|||
return ToCharset(to, CharsetLocale, str.GetString());
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef UNICODE
|
||||
// inline
|
||||
#else // !UNICODE
|
||||
CStringW ToCStringW(const CString &str)
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
CString ToCString(const mpt::lstring &str)
|
||||
{
|
||||
#ifdef UNICODE
|
||||
return ToWide(str).c_str();
|
||||
}
|
||||
CStringW ToCStringW(const std::wstring &str)
|
||||
{
|
||||
#else
|
||||
return str.c_str();
|
||||
#endif
|
||||
}
|
||||
CStringW ToCStringW(Charset from, const std::string &str)
|
||||
mpt::lstring ToLocale(const CString &str)
|
||||
{
|
||||
return ToWide(from, str).c_str();
|
||||
#ifdef UNICODE
|
||||
return String::EncodeImpl<mpt::lstring>(CharsetLocale, str.GetString());
|
||||
#else
|
||||
return str.GetString();
|
||||
#endif
|
||||
}
|
||||
CStringW ToCStringW(const CStringW &str)
|
||||
{
|
||||
return str;
|
||||
}
|
||||
std::wstring ToWide(const CStringW &str)
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
#if MPT_OS_WINDOWS
|
||||
mpt::winstring ToWin(const CString &str)
|
||||
{
|
||||
return str.GetString();
|
||||
}
|
||||
std::string ToCharset(Charset to, const CStringW &str)
|
||||
{
|
||||
return ToCharset(to, str.GetString());
|
||||
}
|
||||
CString ToCString(const CStringW &str)
|
||||
{
|
||||
return ToCharset(CharsetLocale, str).c_str();
|
||||
}
|
||||
#endif // UNICODE
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
#endif // MFC
|
||||
|
||||
|
@ -1523,6 +1611,12 @@ mpt::ustring ToUnicode(Charset from, const std::string &str)
|
|||
{
|
||||
return String::ConvertImpl<mpt::ustring>(mpt::CharsetUTF8, from, str);
|
||||
}
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
mpt::ustring ToUnicode(const mpt::lstring &str)
|
||||
{
|
||||
return String::ConvertImpl<mpt::ustring>(mpt::CharsetUTF8, mpt::CharsetLocale, str);
|
||||
}
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
#if defined(_MFC_VER)
|
||||
mpt::ustring ToUnicode(const CString &str)
|
||||
{
|
||||
|
@ -1532,12 +1626,6 @@ mpt::ustring ToUnicode(const CString &str)
|
|||
return String::ConvertImpl<mpt::ustring, std::string>(mpt::CharsetUTF8, mpt::CharsetLocale, str.GetString());
|
||||
#endif // UNICODE
|
||||
}
|
||||
#ifndef UNICODE
|
||||
mpt::ustring ToUnicode(const CStringW &str)
|
||||
{
|
||||
return String::EncodeImpl<mpt::ustring>(mpt::CharsetUTF8, str.GetString());
|
||||
}
|
||||
#endif // !UNICODE
|
||||
#endif // MFC
|
||||
#endif // MPT_USTRING_MODE_WIDE
|
||||
|
||||
|
@ -1554,6 +1642,22 @@ std::string ToCharset(Charset to, const mpt::ustring &str)
|
|||
{
|
||||
return String::ConvertImpl<std::string, mpt::ustring>(to, mpt::CharsetUTF8, str);
|
||||
}
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
mpt::lstring ToLocale(const mpt::ustring &str)
|
||||
{
|
||||
return String::ConvertImpl<mpt::lstring, mpt::ustring>(mpt::CharsetLocale, mpt::CharsetUTF8, str);
|
||||
}
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
#if MPT_OS_WINDOWS
|
||||
mpt::winstring ToWin(const mpt::ustring &str)
|
||||
{
|
||||
#ifdef UNICODE
|
||||
return String::DecodeImpl<mpt::ustring>(mpt::CharsetUTF8, str);
|
||||
#else
|
||||
return String::ConvertImpl<mpt::lstring, mpt::ustring>(mpt::CharsetLocale, mpt::CharsetUTF8, str);
|
||||
#endif
|
||||
}
|
||||
#endif // MPT_OS_WINDOWS
|
||||
#if defined(_MFC_VER)
|
||||
CString ToCString(const mpt::ustring &str)
|
||||
{
|
||||
|
@ -1570,6 +1674,94 @@ CString ToCString(const mpt::ustring &str)
|
|||
|
||||
|
||||
|
||||
static mpt::Charset CharsetFromCodePage(uint16 codepage, mpt::Charset fallback, bool * isFallback = nullptr)
|
||||
{
|
||||
mpt::Charset result = fallback;
|
||||
switch(codepage)
|
||||
{
|
||||
case 65001:
|
||||
result = mpt::CharsetUTF8;
|
||||
if(isFallback) *isFallback = false;
|
||||
break;
|
||||
case 20127:
|
||||
result = mpt::CharsetASCII;
|
||||
if(isFallback) *isFallback = false;
|
||||
break;
|
||||
case 28591:
|
||||
result = mpt::CharsetISO8859_1;
|
||||
if(isFallback) *isFallback = false;
|
||||
break;
|
||||
case 28605:
|
||||
result = mpt::CharsetISO8859_15;
|
||||
if(isFallback) *isFallback = false;
|
||||
break;
|
||||
case 437:
|
||||
result = mpt::CharsetCP437;
|
||||
if(isFallback) *isFallback = false;
|
||||
break;
|
||||
case 1252:
|
||||
result = mpt::CharsetWindows1252;
|
||||
if(isFallback) *isFallback = false;
|
||||
break;
|
||||
default:
|
||||
result = fallback;
|
||||
if(isFallback) *isFallback = true;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
static bool TestCodePage(uint16 codepage)
|
||||
{
|
||||
return IsValidCodePage(codepage) ? true : false;
|
||||
}
|
||||
|
||||
static mpt::ustring FromCodePageDirect(uint16 codepage, const std::string & src)
|
||||
{
|
||||
int required_size = MultiByteToWideChar(codepage, 0, src.c_str(), -1, nullptr, 0);
|
||||
if(required_size <= 0)
|
||||
{
|
||||
return mpt::ustring();
|
||||
}
|
||||
#if MPT_CXX_AT_LEAST(17)
|
||||
std::wstring decoded_string(required_size, wchar_t());
|
||||
MultiByteToWideChar(codepage, 0, src.c_str(), -1, decoded_string.data(), required_size);
|
||||
decoded_string.resize(decoded_string.size() - 1); // remove \0
|
||||
return mpt::ToUnicode(decoded_string);
|
||||
#else
|
||||
std::vector<WCHAR> decoded_string(required_size);
|
||||
MultiByteToWideChar(codepage, 0, src.c_str(), -1, decoded_string.data(), required_size);
|
||||
return mpt::ToUnicode(std::wstring(decoded_string.data()));
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
mpt::ustring ToUnicode(uint16 codepage, mpt::Charset fallback, const std::string &str)
|
||||
{
|
||||
#if MPT_OS_WINDOWS
|
||||
mpt::ustring result;
|
||||
bool noCharsetMatch = true;
|
||||
mpt::Charset fileCharset = mpt::CharsetFromCodePage(codepage, fallback, &noCharsetMatch);
|
||||
if(noCharsetMatch && TestCodePage(codepage))
|
||||
{
|
||||
result = mpt::FromCodePageDirect(codepage, str);
|
||||
} else
|
||||
{
|
||||
result = mpt::ToUnicode(fileCharset, str);
|
||||
}
|
||||
return result;
|
||||
#else // !MPT_OS_WINDOWS
|
||||
return mpt::ToUnicode(mpt::CharsetFromCodePage(codepage, fallback), str);
|
||||
#endif // MPT_OS_WINDOWS
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
char ToLowerCaseAscii(char c)
|
||||
{
|
||||
if('A' <= c && c <= 'Z')
|
||||
|
@ -1650,9 +1842,9 @@ mpt::ustring ToLowerCase(const mpt::ustring &s)
|
|||
tmp.MakeLower();
|
||||
return mpt::ToUnicode(tmp);
|
||||
#else // !UNICODE
|
||||
CStringW tmp = mpt::ToCStringW(s);
|
||||
CStringW tmp = mpt::ToWide(s).c_str();
|
||||
tmp.MakeLower();
|
||||
return mpt::ToUnicode(tmp);
|
||||
return mpt::ToUnicode(tmp.GetString());
|
||||
#endif // UNICODE
|
||||
#else // !_MFC_VER
|
||||
std::wstring ws = mpt::ToWide(s);
|
||||
|
@ -1669,9 +1861,9 @@ mpt::ustring ToUpperCase(const mpt::ustring &s)
|
|||
tmp.MakeUpper();
|
||||
return mpt::ToUnicode(tmp);
|
||||
#else // !UNICODE
|
||||
CStringW tmp = mpt::ToCStringW(s);
|
||||
CStringW tmp = mpt::ToWide(s).c_str();
|
||||
tmp.MakeUpper();
|
||||
return mpt::ToUnicode(tmp);
|
||||
return mpt::ToUnicode(tmp.GetString());
|
||||
#endif // UNICODE
|
||||
#else // !_MFC_VER
|
||||
std::wstring ws = mpt::ToWide(s);
|
||||
|
|
|
@ -10,7 +10,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "mptTypeTraits.h"
|
||||
#include "BuildSettings.h"
|
||||
|
||||
#include "mptAlloc.h"
|
||||
#include "mptBaseTypes.h"
|
||||
#include "mptSpan.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
@ -26,21 +30,94 @@ namespace mpt
|
|||
{
|
||||
|
||||
|
||||
|
||||
template <typename T> inline span<T> as_span(std::basic_string<T> & str) { return span<T>(&(str[0]), str.length()); }
|
||||
|
||||
template <typename T> inline span<const T> as_span(const std::basic_string<T> & str) { return span<const T>(&(str[0]), str.length()); }
|
||||
|
||||
|
||||
|
||||
template <typename T> inline std::vector<typename std::remove_const<T>::type> make_vector(const std::basic_string<T> & str) { return std::vector<typename std::remove_const<T>::type>(str.begin(), str.end()); }
|
||||
|
||||
|
||||
|
||||
// string_traits abstract the API of underlying string classes, in particular they allow adopting to CString without having to specialize for CString explicitly
|
||||
|
||||
template <typename Tstring>
|
||||
struct string_traits
|
||||
{
|
||||
|
||||
typedef Tstring string_type;
|
||||
typedef typename string_type::size_type size_type;
|
||||
typedef typename string_type::value_type char_type;
|
||||
|
||||
static inline std::size_t length(const string_type &str) { return str.length(); }
|
||||
|
||||
static inline void reserve(string_type &str, std::size_t size) { str.reserve(size); }
|
||||
|
||||
static inline string_type& append(string_type &str, const string_type &a) { return str.append(a); }
|
||||
static inline string_type& append(string_type &str, string_type &&a) { return str.append(std::move(a)); }
|
||||
static inline string_type& append(string_type &str, std::size_t count, char_type c) { return str.append(count, c); }
|
||||
|
||||
static inline string_type pad(string_type str, std::size_t left, std::size_t right)
|
||||
{
|
||||
str.insert(str.begin(), left, char_type(' '));
|
||||
str.insert(str.end(), right, char_type(' '));
|
||||
return str;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#if defined(_MFC_VER)
|
||||
template <>
|
||||
struct string_traits<CString>
|
||||
{
|
||||
|
||||
typedef CString string_type;
|
||||
typedef int size_type;
|
||||
typedef typename CString::XCHAR char_type;
|
||||
|
||||
static inline size_type length(const string_type &str) { return str.GetLength(); }
|
||||
|
||||
static inline void reserve(string_type &str, size_type size) { str.Preallocate(size); }
|
||||
|
||||
static inline string_type& append(string_type &str, const string_type &a) { str += a; return str; }
|
||||
static inline string_type& append(string_type &str, size_type count, char_type c) { while(count--) str.AppendChar(c); return str; }
|
||||
|
||||
static inline string_type pad(const string_type &str, size_type left, size_type right)
|
||||
{
|
||||
CString tmp;
|
||||
while(left--) tmp.AppendChar(char_type(' '));
|
||||
tmp += str;
|
||||
while(right--) tmp.AppendChar(char_type(' '));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
namespace String
|
||||
{
|
||||
|
||||
|
||||
template <typename Tstring> struct Traits {
|
||||
static const char * GetDefaultWhitespace() { return " \n\r\t"; }
|
||||
static MPT_FORCEINLINE const char * GetDefaultWhitespace() noexcept { return " \n\r\t"; }
|
||||
static MPT_FORCEINLINE bool IsLineEnding(char c) noexcept { return c == '\r' || c == '\n'; }
|
||||
};
|
||||
|
||||
template <> struct Traits<std::string> {
|
||||
static const char * GetDefaultWhitespace() { return " \n\r\t"; }
|
||||
static MPT_FORCEINLINE const char * GetDefaultWhitespace() noexcept { return " \n\r\t"; }
|
||||
static MPT_FORCEINLINE bool IsLineEnding(char c) noexcept { return c == '\r' || c == '\n'; }
|
||||
};
|
||||
|
||||
#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR)
|
||||
template <> struct Traits<std::wstring> {
|
||||
static const wchar_t * GetDefaultWhitespace() { return L" \n\r\t"; }
|
||||
static MPT_FORCEINLINE const wchar_t * GetDefaultWhitespace() noexcept { return L" \n\r\t"; }
|
||||
static MPT_FORCEINLINE bool IsLineEnding(wchar_t c) noexcept { return c == L'\r' || c == L'\n'; }
|
||||
};
|
||||
#endif // !MPT_COMPILER_QUIRK_NO_WCHAR
|
||||
|
||||
|
||||
// Remove whitespace at start of string
|
||||
|
@ -123,9 +200,6 @@ static inline std::size_t strnlen(const char *str, std::size_t n)
|
|||
|
||||
|
||||
enum Charset {
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
CharsetLocale, // CP_ACP on windows, current C locale otherwise
|
||||
#endif
|
||||
|
||||
CharsetUTF8,
|
||||
|
||||
|
@ -140,6 +214,10 @@ enum Charset {
|
|||
|
||||
CharsetWindows1252,
|
||||
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
CharsetLocale, // CP_ACP on windows, current C locale otherwise
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -173,14 +251,38 @@ bool IsUTF8(const std::string &str);
|
|||
#define MPT_WSTRING(x) std::wstring( L ## x )
|
||||
|
||||
|
||||
#if MPT_ENABLE_U8STRING
|
||||
|
||||
template <mpt::Charset charset_tag>
|
||||
struct charset_char_traits : std::char_traits<char> {
|
||||
static mpt::Charset charset() { return charset_tag; }
|
||||
};
|
||||
#define MPT_ENCODED_STRING_TYPE(charset) std::basic_string< char, mpt::charset_char_traits< charset > >
|
||||
|
||||
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
|
||||
typedef MPT_ENCODED_STRING_TYPE(mpt::CharsetLocale) lstring;
|
||||
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
template <typename Tchar> struct windows_char_traits { };
|
||||
template <> struct windows_char_traits<char> { typedef mpt::lstring string_type; };
|
||||
template <> struct windows_char_traits<wchar_t> { typedef std::wstring string_type; };
|
||||
|
||||
#ifdef UNICODE
|
||||
typedef windows_char_traits<wchar_t>::string_type tstring;
|
||||
#else
|
||||
typedef windows_char_traits<char>::string_type tstring;
|
||||
#endif
|
||||
|
||||
typedef mpt::tstring winstring;
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
|
||||
#if MPT_ENABLE_U8STRING
|
||||
|
||||
typedef MPT_ENCODED_STRING_TYPE(mpt::CharsetUTF8) u8string;
|
||||
|
||||
#define MPT_U8CHAR_TYPE char
|
||||
|
@ -214,6 +316,9 @@ static inline std::wstring ToWide(const std::wstring &str) { return str; }
|
|||
static inline std::wstring ToWide(const wchar_t * str) { return (str ? std::wstring(str) : std::wstring()); }
|
||||
std::wstring ToWide(Charset from, const std::string &str);
|
||||
static inline std::wstring ToWide(Charset from, const char * str) { return ToWide(from, str ? std::string(str) : std::string()); }
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
std::wstring ToWide(const mpt::lstring &str);
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
#endif
|
||||
|
||||
// Convert to a string encoded in the 'to'-specified character set.
|
||||
|
@ -228,6 +333,31 @@ static inline std::string ToCharset(Charset to, const wchar_t * str) { return To
|
|||
#endif
|
||||
std::string ToCharset(Charset to, Charset from, const std::string &str);
|
||||
static inline std::string ToCharset(Charset to, Charset from, const char * str) { return ToCharset(to, from, str ? std::string(str) : std::string()); }
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
std::string ToCharset(Charset to, const mpt::lstring &str);
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
#if MPT_WSTRING_CONVERT
|
||||
mpt::lstring ToLocale(const std::wstring &str);
|
||||
static inline mpt::lstring ToLocale(const wchar_t * str) { return ToLocale(str ? std::wstring(str): std::wstring()); }
|
||||
#endif
|
||||
mpt::lstring ToLocale(Charset from, const std::string &str);
|
||||
static inline mpt::lstring ToLocale(Charset from, const char * str) { return ToLocale(from, str ? std::string(str): std::string()); }
|
||||
static inline mpt::lstring ToLocale(const mpt::lstring &str) { return str; }
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
#if MPT_WSTRING_CONVERT
|
||||
mpt::winstring ToWin(const std::wstring &str);
|
||||
static inline mpt::winstring ToWin(const wchar_t * str) { return ToWin(str ? std::wstring(str): std::wstring()); }
|
||||
#endif
|
||||
mpt::winstring ToWin(Charset from, const std::string &str);
|
||||
static inline mpt::winstring ToWin(Charset from, const char * str) { return ToWin(from, str ? std::string(str): std::string()); }
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
mpt::winstring ToWin(const mpt::lstring &str);
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
|
||||
#if defined(_MFC_VER)
|
||||
|
@ -243,6 +373,13 @@ CString ToCString(const std::wstring &str);
|
|||
static inline CString ToCString(const wchar_t * str) { return ToCString(str ? std::wstring(str) : std::wstring()); }
|
||||
CString ToCString(Charset from, const std::string &str);
|
||||
static inline CString ToCString(Charset from, const char * str) { return ToCString(from, str ? std::string(str) : std::string()); }
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
CString ToCString(const mpt::lstring &str);
|
||||
mpt::lstring ToLocale(const CString &str);
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
#if MPT_OS_WINDOWS
|
||||
mpt::winstring ToWin(const CString &str);
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
// Convert from a MFC CString. The CString encoding depends on UNICODE.
|
||||
// This should also be used when converting from TCHAR strings.
|
||||
|
@ -250,22 +387,6 @@ static inline CString ToCString(Charset from, const char * str) { return ToCStri
|
|||
std::wstring ToWide(const CString &str);
|
||||
std::string ToCharset(Charset to, const CString &str);
|
||||
|
||||
#ifdef UNICODE
|
||||
MPT_DEPRECATED static inline CString ToCStringW(const CString &str) { return ToCString(str); }
|
||||
MPT_DEPRECATED static inline CString ToCStringW(const std::wstring &str) { return ToCString(str); }
|
||||
MPT_DEPRECATED static inline CString ToCStringW(Charset from, const std::string &str) { return ToCString(from, str); }
|
||||
MPT_DEPRECATED static inline CString ToCStringW(Charset from, const char * str) { return ToCString(from, str ? std::string(str) : std::string()); }
|
||||
#else // !UNICODE
|
||||
CStringW ToCStringW(const CString &str);
|
||||
CStringW ToCStringW(const std::wstring &str);
|
||||
CStringW ToCStringW(Charset from, const std::string &str);
|
||||
static inline CStringW ToCStringW(Charset from, const char * str) { return ToCStringW(from, str ? std::string(str) : std::string()); }
|
||||
CStringW ToCStringW(const CStringW &str);
|
||||
std::wstring ToWide(const CStringW &str);
|
||||
std::string ToCharset(Charset to, const CStringW &str);
|
||||
CString ToCString(const CStringW &str);
|
||||
#endif // UNICODE
|
||||
|
||||
#endif // MFC
|
||||
|
||||
|
||||
|
@ -316,6 +437,10 @@ typedef mpt::u8string ustring;
|
|||
|
||||
#endif // MPT_USTRING_MODE_UTF8
|
||||
|
||||
#define UC_(x) MPT_UCHAR(x)
|
||||
#define UL_(x) MPT_ULITERAL(x)
|
||||
#define U_(x) MPT_USTRING(x)
|
||||
|
||||
#if MPT_USTRING_MODE_WIDE
|
||||
#if !(MPT_WSTRING_CONVERT)
|
||||
#error "MPT_USTRING_MODE_WIDE depends on MPT_WSTRING_CONVERT)"
|
||||
|
@ -324,11 +449,11 @@ static inline mpt::ustring ToUnicode(const std::wstring &str) { return str; }
|
|||
static inline mpt::ustring ToUnicode(const wchar_t * str) { return (str ? std::wstring(str) : std::wstring()); }
|
||||
static inline mpt::ustring ToUnicode(Charset from, const std::string &str) { return ToWide(from, str); }
|
||||
static inline mpt::ustring ToUnicode(Charset from, const char * str) { return ToUnicode(from, str ? std::string(str) : std::string()); }
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
static inline mpt::ustring ToUnicode(const mpt::lstring &str) { return ToWide(str); }
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
#if defined(_MFC_VER)
|
||||
static inline mpt::ustring ToUnicode(const CString &str) { return ToWide(str); }
|
||||
#ifndef UNICODE
|
||||
static inline mpt::ustring ToUnicode(const CStringW &str) { return ToWide(str); }
|
||||
#endif // !UNICODE
|
||||
#endif // MFC
|
||||
#else // !MPT_USTRING_MODE_WIDE
|
||||
static inline mpt::ustring ToUnicode(const mpt::ustring &str) { return str; }
|
||||
|
@ -338,11 +463,11 @@ static inline mpt::ustring ToUnicode(const wchar_t * str) { return ToUnicode(str
|
|||
#endif
|
||||
mpt::ustring ToUnicode(Charset from, const std::string &str);
|
||||
static inline mpt::ustring ToUnicode(Charset from, const char * str) { return ToUnicode(from, str ? std::string(str) : std::string()); }
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
mpt::ustring ToUnicode(const mpt::lstring &str);
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
#if defined(_MFC_VER)
|
||||
mpt::ustring ToUnicode(const CString &str);
|
||||
#ifndef UNICODE
|
||||
mpt::ustring ToUnicode(const CStringW &str);
|
||||
#endif // !UNICODE
|
||||
#endif // MFC
|
||||
#endif // MPT_USTRING_MODE_WIDE
|
||||
|
||||
|
@ -356,13 +481,14 @@ mpt::ustring ToUnicode(const CStringW &str);
|
|||
std::wstring ToWide(const mpt::ustring &str);
|
||||
#endif
|
||||
std::string ToCharset(Charset to, const mpt::ustring &str);
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
mpt::lstring ToLocale(const mpt::ustring &str);
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
#if MPT_OS_WINDOWS
|
||||
mpt::winstring ToWin(const mpt::ustring &str);
|
||||
#endif // MPT_OS_WINDOWS
|
||||
#if defined(_MFC_VER)
|
||||
CString ToCString(const mpt::ustring &str);
|
||||
#ifdef UNICODE
|
||||
MPT_DEPRECATED static inline CString ToCStringW(const mpt::ustring &str) { return ToCString(str); }
|
||||
#else // !UNICODE
|
||||
static inline CStringW ToCStringW(const mpt::ustring &str) { return ToCStringW(ToWide(str)); }
|
||||
#endif // UNICODE
|
||||
#endif // MFC
|
||||
#endif // MPT_USTRING_MODE_WIDE
|
||||
|
||||
|
@ -377,143 +503,7 @@ static inline CStringW ToCStringW(const mpt::ustring &str) { return ToCStringW(T
|
|||
|
||||
|
||||
|
||||
#ifdef MODPLUG_TRACKER
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
namespace String { namespace detail
|
||||
{
|
||||
|
||||
template <mpt::Charset charset, std::size_t size>
|
||||
inline mpt::ustring StringFromBuffer(const char (&buf)[size])
|
||||
{
|
||||
STATIC_ASSERT(size > 0);
|
||||
std::size_t len = std::find(buf, buf + size, '\0') - buf; // terminate at \0
|
||||
return mpt::ToUnicode(charset, std::string(buf, buf + len));
|
||||
}
|
||||
|
||||
template <mpt::Charset charset, std::size_t size>
|
||||
inline mpt::ustring StringFromBuffer(const wchar_t (&buf)[size])
|
||||
{
|
||||
STATIC_ASSERT(size > 0);
|
||||
std::size_t len = std::find(buf, buf + size, L'\0') - buf; // terminate at \0
|
||||
return mpt::ToUnicode(std::wstring(buf, buf + len));
|
||||
}
|
||||
|
||||
template <mpt::Charset charset, std::size_t size>
|
||||
inline bool StringToBuffer(char (&buf)[size], const mpt::ustring &str)
|
||||
{
|
||||
STATIC_ASSERT(size > 0);
|
||||
MemsetZero(buf);
|
||||
std::string encoded = mpt::ToCharset(charset, str);
|
||||
std::copy(encoded.data(), encoded.data() + std::min(encoded.length(), size - 1), buf);
|
||||
buf[size - 1] = '\0';
|
||||
return (encoded.length() <= size - 1);
|
||||
}
|
||||
|
||||
template <mpt::Charset charset, std::size_t size>
|
||||
inline bool StringToBuffer(wchar_t (&buf)[size], const mpt::ustring &str)
|
||||
{
|
||||
STATIC_ASSERT(size > 0);
|
||||
MemsetZero(buf);
|
||||
std::wstring encoded = mpt::ToWide(str);
|
||||
std::copy(encoded.data(), encoded.data() + std::min(encoded.length(), size - 1), buf);
|
||||
buf[size - 1] = L'\0';
|
||||
return (encoded.length() <= size - 1);
|
||||
}
|
||||
|
||||
} } // namespace String::detail
|
||||
|
||||
// mpt::FromTcharBuf
|
||||
// A lot of expecially older WinAPI functions return strings by filling in
|
||||
// fixed-width TCHAR arrays inside some struct.
|
||||
// mpt::FromTcharBuf converts these string to mpt::ustring regardless of whether
|
||||
// in ANSI or UNICODE build and properly handles potentially missing NULL
|
||||
// termination.
|
||||
|
||||
template <typename Tchar, std::size_t size>
|
||||
inline mpt::ustring FromTcharBuf(const Tchar (&buf)[size])
|
||||
{
|
||||
return mpt::String::detail::StringFromBuffer<mpt::CharsetLocale>(buf);
|
||||
}
|
||||
|
||||
// mpt::FromTcharStr
|
||||
// Converts TCHAR strings to mpt::ustring in both ANSI and UNICODE builds.
|
||||
// Useful when going through CString is not appropriate.
|
||||
|
||||
template <typename Tchar> mpt::ustring FromTcharStr(const Tchar *str);
|
||||
template <> inline mpt::ustring FromTcharStr<char>(const char *str)
|
||||
{
|
||||
if(!str)
|
||||
{
|
||||
return mpt::ustring();
|
||||
}
|
||||
return mpt::ToUnicode(mpt::CharsetLocale, std::string(str));
|
||||
}
|
||||
template <> inline mpt::ustring FromTcharStr<wchar_t>(const wchar_t *str)
|
||||
{
|
||||
if(!str)
|
||||
{
|
||||
return mpt::ustring();
|
||||
}
|
||||
return mpt::ToUnicode(std::wstring(str));
|
||||
}
|
||||
|
||||
// mpt::ToTcharBuf
|
||||
// The inverse of mpt::FromTcharBuf.
|
||||
// Always NULL-terminates the buffer.
|
||||
// Return false if the string has been truncated to fit.
|
||||
|
||||
template <typename Tchar, std::size_t size>
|
||||
inline bool ToTcharBuf(Tchar (&buf)[size], const mpt::ustring &str)
|
||||
{
|
||||
return mpt::String::detail::StringToBuffer<mpt::CharsetLocale>(buf, str);
|
||||
}
|
||||
|
||||
// mpt::ToTcharStr
|
||||
// Converts mpt::ustring to std::basic_stringy<TCHAR>,
|
||||
// which is usable in both ANSI and UNICODE builds.
|
||||
// Useful when going through CString is not appropriate.
|
||||
|
||||
template <typename Tchar> std::basic_string<Tchar> ToTcharStrImpl(const mpt::ustring &str);
|
||||
template <> inline std::string ToTcharStrImpl<char>(const mpt::ustring &str)
|
||||
{
|
||||
return mpt::ToCharset(mpt::CharsetLocale, str);
|
||||
}
|
||||
template <> inline std::wstring ToTcharStrImpl<wchar_t>(const mpt::ustring &str)
|
||||
{
|
||||
return mpt::ToWide(str);
|
||||
}
|
||||
|
||||
inline std::basic_string<TCHAR> ToTcharStr(const mpt::ustring &str)
|
||||
{
|
||||
return ToTcharStrImpl<TCHAR>(str);
|
||||
}
|
||||
|
||||
#if defined(_MFC_VER)
|
||||
|
||||
template <std::size_t size>
|
||||
inline CString CStringFromBuffer(const TCHAR (&buf)[size])
|
||||
{
|
||||
MPT_STATIC_ASSERT(size > 0);
|
||||
std::size_t len = std::find(buf, buf + size, _T('\0')) - buf; // terminate at \0
|
||||
return CString(buf, len);
|
||||
}
|
||||
|
||||
template <std::size_t size>
|
||||
inline void CopyCStringToBuffer(TCHAR (&buf)[size], const CString &str)
|
||||
{
|
||||
MPT_STATIC_ASSERT(size > 0);
|
||||
MemsetZero(buf);
|
||||
std::copy(str.GetString(), str.GetString() + std::min(static_cast<std::size_t>(str.GetLength()), size - 1), buf);
|
||||
buf[size - 1] = _T('\0');
|
||||
}
|
||||
|
||||
#endif // _MFC_VER
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
mpt::ustring ToUnicode(uint16 codepage, mpt::Charset fallback, const std::string &str);
|
||||
|
||||
|
||||
|
||||
|
@ -587,6 +577,11 @@ public:
|
|||
BasicAnyString(const char *str) : mpt::ustring(From8bit(str ? str : std::string())) { }
|
||||
BasicAnyString(const std::string str) : mpt::ustring(From8bit(str)) { }
|
||||
|
||||
// locale
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
BasicAnyString(const mpt::lstring str) : mpt::ustring(mpt::ToUnicode(str)) { }
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
|
||||
// unicode
|
||||
BasicAnyString(const mpt::ustring &str) : mpt::ustring(str) { }
|
||||
BasicAnyString(mpt::ustring &&str) : mpt::ustring(std::move(str)) { }
|
||||
|
@ -600,9 +595,6 @@ public:
|
|||
// mfc
|
||||
#if defined(_MFC_VER)
|
||||
BasicAnyString(const CString &str) : mpt::ustring(mpt::ToUnicode(str)) { }
|
||||
#ifndef UNICODE
|
||||
BasicAnyString(const CStringW &str) : mpt::ustring(mpt::ToUnicode(str)) { }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// fallback for custom string types
|
||||
|
@ -617,6 +609,11 @@ class AnyUnicodeString : public mpt::ustring
|
|||
|
||||
public:
|
||||
|
||||
// locale
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
AnyUnicodeString(const mpt::lstring &str) : mpt::ustring(mpt::ToUnicode(str)) { }
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
|
||||
// unicode
|
||||
AnyUnicodeString(const mpt::ustring &str) : mpt::ustring(str) { }
|
||||
AnyUnicodeString(mpt::ustring &&str) : mpt::ustring(std::move(str)) { }
|
||||
|
@ -630,9 +627,6 @@ public:
|
|||
// mfc
|
||||
#if defined(_MFC_VER)
|
||||
AnyUnicodeString(const CString &str) : mpt::ustring(mpt::ToUnicode(str)) { }
|
||||
#ifndef UNICODE
|
||||
AnyUnicodeString(const CStringW &str) : mpt::ustring(mpt::ToUnicode(str)) { }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// fallback for custom string types
|
||||
|
|
117
Frameworks/OpenMPT/OpenMPT/common/mptStringBuffer.cpp
Normal file
117
Frameworks/OpenMPT/OpenMPT/common/mptStringBuffer.cpp
Normal file
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* mptStringBuffer.cpp
|
||||
* -------------------
|
||||
* Purpose: Various functions for "fixing" char array strings for writing to or
|
||||
* reading from module files, or for securing char arrays in general.
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "mptStringBuffer.h"
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
namespace String
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
std::string ReadStringBuffer(String::ReadWriteMode mode, const char *srcBuffer, std::size_t srcSize)
|
||||
{
|
||||
|
||||
std::string dest;
|
||||
const char *src = srcBuffer;
|
||||
|
||||
if(mode == nullTerminated || mode == spacePaddedNull)
|
||||
{
|
||||
// We assume that the last character of the source buffer is null.
|
||||
if(srcSize > 0)
|
||||
{
|
||||
srcSize -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(mode == nullTerminated || mode == maybeNullTerminated)
|
||||
{
|
||||
|
||||
// Copy null-terminated string, stopping at null.
|
||||
dest.assign(src, std::find(src, src + srcSize, '\0'));
|
||||
|
||||
} else if(mode == spacePadded || mode == spacePaddedNull)
|
||||
{
|
||||
|
||||
// Copy string over.
|
||||
dest.assign(src, src + srcSize);
|
||||
|
||||
// Convert null characters to spaces.
|
||||
std::transform(dest.begin(), dest.end(), dest.begin(), [] (char c) -> char { return (c != '\0') ? c : ' '; });
|
||||
|
||||
// Trim trailing spaces.
|
||||
dest = mpt::String::RTrim(dest, std::string(" "));
|
||||
|
||||
}
|
||||
|
||||
return dest;
|
||||
|
||||
}
|
||||
|
||||
void WriteStringBuffer(String::ReadWriteMode mode, char *destBuffer, const std::size_t destSize, const char *srcBuffer, const std::size_t srcSize)
|
||||
{
|
||||
|
||||
MPT_ASSERT(destSize > 0);
|
||||
|
||||
const size_t maxSize = std::min(destSize, srcSize);
|
||||
char *dst = destBuffer;
|
||||
const char *src = srcBuffer;
|
||||
|
||||
// First, copy over null-terminated string.
|
||||
size_t pos = maxSize;
|
||||
while(pos > 0)
|
||||
{
|
||||
if((*dst = *src) == '\0')
|
||||
{
|
||||
break;
|
||||
}
|
||||
pos--;
|
||||
dst++;
|
||||
src++;
|
||||
}
|
||||
|
||||
if(mode == nullTerminated || mode == maybeNullTerminated)
|
||||
{
|
||||
// Fill rest of string with nulls.
|
||||
std::fill(dst, dst + destSize - maxSize + pos, '\0');
|
||||
} else if(mode == spacePadded || mode == spacePaddedNull)
|
||||
{
|
||||
// Fill the rest of the destination string with spaces.
|
||||
std::fill(dst, dst + destSize - maxSize + pos, ' ');
|
||||
}
|
||||
|
||||
if(mode == nullTerminated || mode == spacePaddedNull)
|
||||
{
|
||||
// Make sure that destination is really null-terminated.
|
||||
SetNullTerminator(destBuffer, destSize);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace String
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
692
Frameworks/OpenMPT/OpenMPT/common/mptStringBuffer.h
Normal file
692
Frameworks/OpenMPT/OpenMPT/common/mptStringBuffer.h
Normal file
|
@ -0,0 +1,692 @@
|
|||
/*
|
||||
* mptStringBuffer.h
|
||||
* -----------------
|
||||
* Purpose: Various functions for "fixing" char array strings for writing to or
|
||||
* reading from module files, or for securing char arrays in general.
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
#include "mptString.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
|
||||
namespace String
|
||||
{
|
||||
|
||||
|
||||
enum ReadWriteMode
|
||||
{
|
||||
// Reading / Writing: Standard null-terminated string handling.
|
||||
nullTerminated,
|
||||
// Reading: Source string is not guaranteed to be null-terminated (if it fills the whole char array).
|
||||
// Writing: Destination string is not guaranteed to be null-terminated (if it fills the whole char array).
|
||||
maybeNullTerminated,
|
||||
// Reading: String may contain null characters anywhere. They should be treated as spaces.
|
||||
// Writing: A space-padded string is written.
|
||||
spacePadded,
|
||||
// Reading: String may contain null characters anywhere. The last character is ignored (it is supposed to be 0).
|
||||
// Writing: A space-padded string with a trailing null is written.
|
||||
spacePaddedNull
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
std::string ReadStringBuffer(String::ReadWriteMode mode, const char *srcBuffer, std::size_t srcSize);
|
||||
|
||||
void WriteStringBuffer(String::ReadWriteMode mode, char *destBuffer, const std::size_t destSize, const char *srcBuffer, const std::size_t srcSize);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
||||
} // namespace String
|
||||
|
||||
|
||||
|
||||
template <typename Tstring, typename Tchar>
|
||||
class StringBufRefImpl
|
||||
{
|
||||
private:
|
||||
Tchar * buf;
|
||||
std::size_t size;
|
||||
public:
|
||||
// cppcheck false-positive
|
||||
// cppcheck-suppress uninitMemberVar
|
||||
explicit StringBufRefImpl(Tchar * buf, std::size_t size)
|
||||
: buf(buf)
|
||||
, size(size)
|
||||
{
|
||||
MPT_STATIC_ASSERT(sizeof(Tchar) == sizeof(typename Tstring::value_type));
|
||||
MPT_ASSERT(size > 0);
|
||||
}
|
||||
StringBufRefImpl(const StringBufRefImpl &) = delete;
|
||||
StringBufRefImpl(StringBufRefImpl &&) = default;
|
||||
StringBufRefImpl & operator = (const StringBufRefImpl &) = delete;
|
||||
StringBufRefImpl & operator = (StringBufRefImpl &&) = delete;
|
||||
operator Tstring () const
|
||||
{
|
||||
std::size_t len = std::find(buf, buf + size, Tchar('\0')) - buf; // terminate at \0
|
||||
return Tstring(buf, buf + len);
|
||||
}
|
||||
StringBufRefImpl & operator = (const Tstring & str)
|
||||
{
|
||||
std::fill(buf, buf + size, Tchar('\0'));
|
||||
std::copy(str.data(), str.data() + std::min(str.length(), size - 1), buf);
|
||||
std::fill(buf + std::min(str.length(), size - 1), buf + size, Tchar('\0'));
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Tstring, typename Tchar>
|
||||
class StringBufRefImpl<Tstring, const Tchar>
|
||||
{
|
||||
private:
|
||||
const Tchar * buf;
|
||||
std::size_t size;
|
||||
public:
|
||||
// cppcheck false-positive
|
||||
// cppcheck-suppress uninitMemberVar
|
||||
explicit StringBufRefImpl(const Tchar * buf, std::size_t size)
|
||||
: buf(buf)
|
||||
, size(size)
|
||||
{
|
||||
MPT_STATIC_ASSERT(sizeof(Tchar) == sizeof(typename Tstring::value_type));
|
||||
MPT_ASSERT(size > 0);
|
||||
}
|
||||
StringBufRefImpl(const StringBufRefImpl &) = delete;
|
||||
StringBufRefImpl(StringBufRefImpl &&) = default;
|
||||
StringBufRefImpl & operator = (const StringBufRefImpl &) = delete;
|
||||
StringBufRefImpl & operator = (StringBufRefImpl &&) = delete;
|
||||
operator Tstring () const
|
||||
{
|
||||
std::size_t len = std::find(buf, buf + size, Tchar('\0')) - buf; // terminate at \0
|
||||
return Tstring(buf, buf + len);
|
||||
}
|
||||
};
|
||||
|
||||
namespace String {
|
||||
template <typename Tstring, typename Tchar, std::size_t size>
|
||||
inline StringBufRefImpl<Tstring, typename std::add_const<Tchar>::type> ReadTypedBuf(Tchar (&buf)[size])
|
||||
{
|
||||
return StringBufRefImpl<Tstring, typename std::add_const<Tchar>::type>(buf, size);
|
||||
}
|
||||
template <typename Tstring, typename Tchar>
|
||||
inline StringBufRefImpl<Tstring, typename std::add_const<Tchar>::type> ReadTypedBuf(Tchar * buf, std::size_t size)
|
||||
{
|
||||
return StringBufRefImpl<Tstring, typename std::add_const<Tchar>::type>(buf, size);
|
||||
}
|
||||
template <typename Tstring, typename Tchar, std::size_t size>
|
||||
inline StringBufRefImpl<Tstring, Tchar> WriteTypedBuf(Tchar (&buf)[size])
|
||||
{
|
||||
return StringBufRefImpl<Tstring, Tchar>(buf, size);
|
||||
}
|
||||
template <typename Tstring, typename Tchar>
|
||||
inline StringBufRefImpl<Tstring, Tchar> WriteTypedBuf(Tchar * buf, std::size_t size)
|
||||
{
|
||||
return StringBufRefImpl<Tstring, Tchar>(buf, size);
|
||||
}
|
||||
} // namespace String
|
||||
|
||||
namespace String {
|
||||
template <typename Tchar, std::size_t size>
|
||||
inline StringBufRefImpl<typename std::basic_string<typename std::remove_const<Tchar>::type>, typename std::add_const<Tchar>::type> ReadAutoBuf(Tchar (&buf)[size])
|
||||
{
|
||||
return StringBufRefImpl<typename std::basic_string<typename std::remove_const<Tchar>::type>, typename std::add_const<Tchar>::type>(buf, size);
|
||||
}
|
||||
template <typename Tchar>
|
||||
inline StringBufRefImpl<typename std::basic_string<typename std::remove_const<Tchar>::type>, typename std::add_const<Tchar>::type> ReadAutoBuf(Tchar * buf, std::size_t size)
|
||||
{
|
||||
return StringBufRefImpl<typename std::basic_string<typename std::remove_const<Tchar>::type>, typename std::add_const<Tchar>::type>(buf, size);
|
||||
}
|
||||
template <typename Tchar, std::size_t size>
|
||||
inline StringBufRefImpl<typename std::basic_string<typename std::remove_const<Tchar>::type>, Tchar> WriteAutoBuf(Tchar (&buf)[size])
|
||||
{
|
||||
return StringBufRefImpl<typename std::basic_string<typename std::remove_const<Tchar>::type>, Tchar>(buf, size);
|
||||
}
|
||||
template <typename Tchar>
|
||||
inline StringBufRefImpl<typename std::basic_string<typename std::remove_const<Tchar>::type>, Tchar> WriteAutoBuf(Tchar * buf, std::size_t size)
|
||||
{
|
||||
return StringBufRefImpl<typename std::basic_string<typename std::remove_const<Tchar>::type>, Tchar>(buf, size);
|
||||
}
|
||||
} // namespace String
|
||||
|
||||
template <typename Tchar>
|
||||
class StringModeBufRefImpl
|
||||
{
|
||||
private:
|
||||
Tchar * buf;
|
||||
std::size_t size;
|
||||
String::ReadWriteMode mode;
|
||||
public:
|
||||
// cppcheck false-positive
|
||||
// cppcheck-suppress uninitMemberVar
|
||||
StringModeBufRefImpl(Tchar * buf, std::size_t size, String::ReadWriteMode mode)
|
||||
: buf(buf)
|
||||
, size(size)
|
||||
, mode(mode)
|
||||
{
|
||||
MPT_STATIC_ASSERT(sizeof(Tchar) == 1);
|
||||
MPT_ASSERT(size > 0);
|
||||
}
|
||||
StringModeBufRefImpl(const StringModeBufRefImpl &) = delete;
|
||||
StringModeBufRefImpl(StringModeBufRefImpl &&) = default;
|
||||
StringModeBufRefImpl & operator = (const StringModeBufRefImpl &) = delete;
|
||||
StringModeBufRefImpl & operator = (StringModeBufRefImpl &&) = delete;
|
||||
operator std::string () const
|
||||
{
|
||||
return String::detail::ReadStringBuffer(mode, buf, size);
|
||||
}
|
||||
StringModeBufRefImpl & operator = (const std::string & str)
|
||||
{
|
||||
String::detail::WriteStringBuffer(mode, buf, size, str.data(), str.size());
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Tchar>
|
||||
class StringModeBufRefImpl<const Tchar>
|
||||
{
|
||||
private:
|
||||
const Tchar * buf;
|
||||
std::size_t size;
|
||||
String::ReadWriteMode mode;
|
||||
public:
|
||||
// cppcheck false-positive
|
||||
// cppcheck-suppress uninitMemberVar
|
||||
StringModeBufRefImpl(const Tchar * buf, std::size_t size, String::ReadWriteMode mode)
|
||||
: buf(buf)
|
||||
, size(size)
|
||||
, mode(mode)
|
||||
{
|
||||
MPT_STATIC_ASSERT(sizeof(Tchar) == 1);
|
||||
MPT_ASSERT(size > 0);
|
||||
}
|
||||
StringModeBufRefImpl(const StringModeBufRefImpl &) = delete;
|
||||
StringModeBufRefImpl(StringModeBufRefImpl &&) = default;
|
||||
StringModeBufRefImpl & operator = (const StringModeBufRefImpl &) = delete;
|
||||
StringModeBufRefImpl & operator = (StringModeBufRefImpl &&) = delete;
|
||||
operator std::string () const
|
||||
{
|
||||
return String::detail::ReadStringBuffer(mode, buf, size);
|
||||
}
|
||||
};
|
||||
|
||||
namespace String {
|
||||
template <typename Tchar, std::size_t size>
|
||||
inline StringModeBufRefImpl<typename std::add_const<Tchar>::type> ReadBuf(String::ReadWriteMode mode, Tchar (&buf)[size])
|
||||
{
|
||||
return StringModeBufRefImpl<typename std::add_const<Tchar>::type>(buf, size, mode);
|
||||
}
|
||||
template <typename Tchar>
|
||||
inline StringModeBufRefImpl<typename std::add_const<Tchar>::type> ReadBuf(String::ReadWriteMode mode, Tchar * buf, std::size_t size)
|
||||
{
|
||||
return StringModeBufRefImpl<typename std::add_const<Tchar>::type>(buf, size, mode);
|
||||
}
|
||||
template <typename Tchar, std::size_t size>
|
||||
inline StringModeBufRefImpl<Tchar> WriteBuf(String::ReadWriteMode mode, Tchar (&buf)[size])
|
||||
{
|
||||
return StringModeBufRefImpl<Tchar>(buf, size, mode);
|
||||
}
|
||||
template <typename Tchar>
|
||||
inline StringModeBufRefImpl<Tchar> WriteBuf(String::ReadWriteMode mode, Tchar * buf, std::size_t size)
|
||||
{
|
||||
return StringModeBufRefImpl<Tchar>(buf, size, mode);
|
||||
}
|
||||
} // namespace String
|
||||
|
||||
|
||||
#ifdef MODPLUG_TRACKER
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
namespace String {
|
||||
template <typename Tchar, std::size_t size>
|
||||
inline StringBufRefImpl<typename mpt::windows_char_traits<typename std::remove_const<Tchar>::type>::string_type, typename std::add_const<Tchar>::type> ReadWinBuf(Tchar (&buf)[size])
|
||||
{
|
||||
return StringBufRefImpl<typename mpt::windows_char_traits<typename std::remove_const<Tchar>::type>::string_type, typename std::add_const<Tchar>::type>(buf, size);
|
||||
}
|
||||
template <typename Tchar>
|
||||
inline StringBufRefImpl<typename mpt::windows_char_traits<typename std::remove_const<Tchar>::type>::string_type, typename std::add_const<Tchar>::type> ReadWinBuf(Tchar * buf, std::size_t size)
|
||||
{
|
||||
return StringBufRefImpl<typename mpt::windows_char_traits<typename std::remove_const<Tchar>::type>::string_type, typename std::add_const<Tchar>::type>(buf, size);
|
||||
}
|
||||
template <typename Tchar, std::size_t size>
|
||||
inline StringBufRefImpl<typename mpt::windows_char_traits<typename std::remove_const<Tchar>::type>::string_type, Tchar> WriteWinBuf(Tchar (&buf)[size])
|
||||
{
|
||||
return StringBufRefImpl<typename mpt::windows_char_traits<typename std::remove_const<Tchar>::type>::string_type, Tchar>(buf, size);
|
||||
}
|
||||
template <typename Tchar>
|
||||
inline StringBufRefImpl<typename mpt::windows_char_traits<typename std::remove_const<Tchar>::type>::string_type, Tchar> WriteWinBuf(Tchar * buf, std::size_t size)
|
||||
{
|
||||
return StringBufRefImpl<typename mpt::windows_char_traits<typename std::remove_const<Tchar>::type>::string_type, Tchar>(buf, size);
|
||||
}
|
||||
} // namespace String
|
||||
|
||||
#if defined(_MFC_VER)
|
||||
|
||||
template <typename Tchar>
|
||||
class CStringBufRefImpl
|
||||
{
|
||||
private:
|
||||
Tchar * buf;
|
||||
std::size_t size;
|
||||
public:
|
||||
// cppcheck false-positive
|
||||
// cppcheck-suppress uninitMemberVar
|
||||
explicit CStringBufRefImpl(Tchar * buf, std::size_t size)
|
||||
: buf(buf)
|
||||
, size(size)
|
||||
{
|
||||
MPT_ASSERT(size > 0);
|
||||
}
|
||||
CStringBufRefImpl(const CStringBufRefImpl &) = delete;
|
||||
CStringBufRefImpl(CStringBufRefImpl &&) = default;
|
||||
CStringBufRefImpl & operator = (const CStringBufRefImpl &) = delete;
|
||||
CStringBufRefImpl & operator = (CStringBufRefImpl &&) = delete;
|
||||
operator CString () const
|
||||
{
|
||||
std::size_t len = std::find(buf, buf + size, Tchar('\0')) - buf; // terminate at \0
|
||||
return CString(buf, mpt::saturate_cast<int>(len));
|
||||
}
|
||||
CStringBufRefImpl & operator = (const CString & str)
|
||||
{
|
||||
std::fill(buf, buf + size, Tchar('\0'));
|
||||
std::copy(str.GetString(), str.GetString() + std::min(static_cast<std::size_t>(str.GetLength()), size - 1), buf);
|
||||
buf[size - 1] = Tchar('\0');
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Tchar>
|
||||
class CStringBufRefImpl<const Tchar>
|
||||
{
|
||||
private:
|
||||
const Tchar * buf;
|
||||
std::size_t size;
|
||||
public:
|
||||
// cppcheck false-positive
|
||||
// cppcheck-suppress uninitMemberVar
|
||||
explicit CStringBufRefImpl(const Tchar * buf, std::size_t size)
|
||||
: buf(buf)
|
||||
, size(size)
|
||||
{
|
||||
MPT_ASSERT(size > 0);
|
||||
}
|
||||
CStringBufRefImpl(const CStringBufRefImpl &) = delete;
|
||||
CStringBufRefImpl(CStringBufRefImpl &&) = default;
|
||||
CStringBufRefImpl & operator = (const CStringBufRefImpl &) = delete;
|
||||
CStringBufRefImpl & operator = (CStringBufRefImpl &&) = delete;
|
||||
operator CString () const
|
||||
{
|
||||
std::size_t len = std::find(buf, buf + size, Tchar('\0')) - buf; // terminate at \0
|
||||
return CString(buf, mpt::saturate_cast<int>(len));
|
||||
}
|
||||
};
|
||||
|
||||
namespace String {
|
||||
template <typename Tchar, std::size_t size>
|
||||
inline CStringBufRefImpl<typename std::add_const<Tchar>::type> ReadCStringBuf(Tchar (&buf)[size])
|
||||
{
|
||||
return CStringBufRefImpl<typename std::add_const<Tchar>::type>(buf, size);
|
||||
}
|
||||
template <typename Tchar>
|
||||
inline CStringBufRefImpl<typename std::add_const<Tchar>::type> ReadCStringBuf(Tchar * buf, std::size_t size)
|
||||
{
|
||||
return CStringBufRefImpl<typename std::add_const<Tchar>::type>(buf, size);
|
||||
}
|
||||
template <typename Tchar, std::size_t size>
|
||||
inline CStringBufRefImpl<Tchar> WriteCStringBuf(Tchar (&buf)[size])
|
||||
{
|
||||
return CStringBufRefImpl<Tchar>(buf, size);
|
||||
}
|
||||
template <typename Tchar>
|
||||
inline CStringBufRefImpl<Tchar> WriteCStringBuf(Tchar * buf, std::size_t size)
|
||||
{
|
||||
return CStringBufRefImpl<Tchar>(buf, size);
|
||||
}
|
||||
} // namespace String
|
||||
|
||||
#endif // _MFC_VER
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
namespace String
|
||||
{
|
||||
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127) // conditional expression is constant
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
|
||||
|
||||
// Sets last character to null in given char array.
|
||||
// Size of the array must be known at compile time.
|
||||
template <size_t size>
|
||||
void SetNullTerminator(char (&buffer)[size])
|
||||
{
|
||||
STATIC_ASSERT(size > 0);
|
||||
buffer[size - 1] = 0;
|
||||
}
|
||||
|
||||
inline void SetNullTerminator(char *buffer, size_t size)
|
||||
{
|
||||
MPT_ASSERT(size > 0);
|
||||
buffer[size - 1] = 0;
|
||||
}
|
||||
|
||||
template <size_t size>
|
||||
void SetNullTerminator(wchar_t (&buffer)[size])
|
||||
{
|
||||
STATIC_ASSERT(size > 0);
|
||||
buffer[size - 1] = 0;
|
||||
}
|
||||
|
||||
inline void SetNullTerminator(wchar_t *buffer, size_t size)
|
||||
{
|
||||
MPT_ASSERT(size > 0);
|
||||
buffer[size - 1] = 0;
|
||||
}
|
||||
|
||||
|
||||
// Remove any chars after the first null char
|
||||
template <size_t size>
|
||||
void FixNullString(char (&buffer)[size])
|
||||
{
|
||||
STATIC_ASSERT(size > 0);
|
||||
SetNullTerminator(buffer);
|
||||
size_t pos = 0;
|
||||
// Find the first null char.
|
||||
while(pos < size && buffer[pos] != '\0')
|
||||
{
|
||||
pos++;
|
||||
}
|
||||
// Remove everything after the null char.
|
||||
while(pos < size)
|
||||
{
|
||||
buffer[pos++] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
inline void FixNullString(std::string & str)
|
||||
{
|
||||
for(std::size_t i = 0; i < str.length(); ++i)
|
||||
{
|
||||
if(str[i] == '\0')
|
||||
{
|
||||
// if we copied \0 in the middle of the buffer, terminate std::string here
|
||||
str.resize(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Copy a string from srcBuffer to destBuffer using a given read mode.
|
||||
// Used for reading strings from files.
|
||||
// Only use this version of the function if the size of the source buffer is variable.
|
||||
template <ReadWriteMode mode, typename Tbyte>
|
||||
void Read(std::string &dest, const Tbyte *srcBuffer, size_t srcSize)
|
||||
{
|
||||
|
||||
const char *src = mpt::byte_cast<const char*>(srcBuffer);
|
||||
|
||||
dest.clear();
|
||||
|
||||
try
|
||||
{
|
||||
dest = mpt::String::detail::ReadStringBuffer(mode, src, srcSize);
|
||||
} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
|
||||
{
|
||||
MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Copy a charset encoded string from srcBuffer to destBuffer using a given read mode.
|
||||
// Used for reading strings from files.
|
||||
// Only use this version of the function if the size of the source buffer is variable.
|
||||
template <ReadWriteMode mode, typename Tbyte>
|
||||
void Read(mpt::ustring &dest, mpt::Charset charset, const Tbyte *srcBuffer, size_t srcSize)
|
||||
{
|
||||
std::string tmp;
|
||||
Read<mode>(tmp, srcBuffer, srcSize);
|
||||
dest = mpt::ToUnicode(charset, tmp);
|
||||
}
|
||||
|
||||
// Used for reading strings from files.
|
||||
// Preferrably use this version of the function, it is safer.
|
||||
template <ReadWriteMode mode, size_t srcSize, typename Tbyte>
|
||||
void Read(std::string &dest, const Tbyte (&srcBuffer)[srcSize])
|
||||
{
|
||||
STATIC_ASSERT(srcSize > 0);
|
||||
Read<mode>(dest, srcBuffer, srcSize);
|
||||
}
|
||||
|
||||
// Used for reading charset encoded strings from files.
|
||||
// Preferrably use this version of the function, it is safer.
|
||||
template <ReadWriteMode mode, size_t srcSize, typename Tbyte>
|
||||
void Read(mpt::ustring &dest, mpt::Charset charset, const Tbyte(&srcBuffer)[srcSize])
|
||||
{
|
||||
std::string tmp;
|
||||
Read<mode>(tmp, srcBuffer);
|
||||
dest = mpt::ToUnicode(charset, tmp);
|
||||
}
|
||||
|
||||
// Copy a string from srcBuffer to destBuffer using a given read mode.
|
||||
// Used for reading strings from files.
|
||||
// Only use this version of the function if the size of the source buffer is variable.
|
||||
template <ReadWriteMode mode, size_t destSize, typename Tbyte>
|
||||
void Read(char (&destBuffer)[destSize], const Tbyte *srcBuffer, size_t srcSize)
|
||||
{
|
||||
STATIC_ASSERT(destSize > 0);
|
||||
|
||||
char *dst = destBuffer;
|
||||
const char *src = mpt::byte_cast<const char*>(srcBuffer);
|
||||
|
||||
if(mode == nullTerminated || mode == spacePaddedNull)
|
||||
{
|
||||
// We assume that the last character of the source buffer is null.
|
||||
if(srcSize > 0)
|
||||
{
|
||||
srcSize -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(mode == nullTerminated || mode == maybeNullTerminated)
|
||||
{
|
||||
|
||||
// Copy string and leave one character space in the destination buffer for null.
|
||||
dst = std::copy(src, std::find(src, src + std::min(srcSize, destSize - 1), '\0'), dst);
|
||||
|
||||
} else if(mode == spacePadded || mode == spacePaddedNull)
|
||||
{
|
||||
|
||||
// Copy string and leave one character space in the destination buffer for null.
|
||||
// Convert nulls to spaces while copying and counts the length that contains actual characters.
|
||||
std::size_t lengthWithoutNullOrSpace = 0;
|
||||
for(std::size_t pos = 0; pos < srcSize; ++pos)
|
||||
{
|
||||
char c = srcBuffer[pos];
|
||||
if(c != '\0' && c != ' ')
|
||||
{
|
||||
lengthWithoutNullOrSpace = pos + 1;
|
||||
}
|
||||
if(c == '\0')
|
||||
{
|
||||
c = ' ';
|
||||
}
|
||||
if(pos < destSize - 1)
|
||||
{
|
||||
destBuffer[pos] = c;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t destLength = std::min(lengthWithoutNullOrSpace, destSize - 1);
|
||||
|
||||
dst += destLength;
|
||||
|
||||
}
|
||||
|
||||
// Fill rest of string with nulls.
|
||||
std::fill(dst, destBuffer + destSize, '\0');
|
||||
|
||||
}
|
||||
|
||||
// Used for reading strings from files.
|
||||
// Preferrably use this version of the function, it is safer.
|
||||
template <ReadWriteMode mode, size_t destSize, size_t srcSize, typename Tbyte>
|
||||
void Read(char (&destBuffer)[destSize], const Tbyte (&srcBuffer)[srcSize])
|
||||
{
|
||||
STATIC_ASSERT(destSize > 0);
|
||||
STATIC_ASSERT(srcSize > 0);
|
||||
Read<mode, destSize>(destBuffer, srcBuffer, srcSize);
|
||||
}
|
||||
|
||||
|
||||
// Copy a string from srcBuffer to destBuffer using a given write mode.
|
||||
// You should only use this function if src and dest are dynamically sized,
|
||||
// otherwise use one of the safer overloads below.
|
||||
template <ReadWriteMode mode>
|
||||
void Write(char *destBuffer, const size_t destSize, const char *srcBuffer, const size_t srcSize)
|
||||
{
|
||||
MPT_ASSERT(destSize > 0);
|
||||
|
||||
mpt::String::detail::WriteStringBuffer(mode, destBuffer, destSize, srcBuffer, srcSize);
|
||||
|
||||
}
|
||||
|
||||
// Copy a string from srcBuffer to a dynamically sized std::vector destBuffer using a given write mode.
|
||||
// Used for writing strings to files.
|
||||
// Only use this version of the function if the size of the source buffer is variable and the destination buffer also has variable size.
|
||||
template <ReadWriteMode mode>
|
||||
void Write(std::vector<char> &destBuffer, const char *srcBuffer, const size_t srcSize)
|
||||
{
|
||||
MPT_ASSERT(destBuffer.size() > 0);
|
||||
Write<mode>(destBuffer.data(), destBuffer.size(), srcBuffer, srcSize);
|
||||
}
|
||||
|
||||
// Copy a string from srcBuffer to destBuffer using a given write mode.
|
||||
// Used for writing strings to files.
|
||||
// Only use this version of the function if the size of the source buffer is variable.
|
||||
template <ReadWriteMode mode, size_t destSize>
|
||||
void Write(char (&destBuffer)[destSize], const char *srcBuffer, const size_t srcSize)
|
||||
{
|
||||
STATIC_ASSERT(destSize > 0);
|
||||
Write<mode>(destBuffer, destSize, srcBuffer, srcSize);
|
||||
}
|
||||
|
||||
// Copy a string from srcBuffer to destBuffer using a given write mode.
|
||||
// Used for writing strings to files.
|
||||
// Preferrably use this version of the function, it is safer.
|
||||
template <ReadWriteMode mode, size_t destSize, size_t srcSize>
|
||||
void Write(char (&destBuffer)[destSize], const char (&srcBuffer)[srcSize])
|
||||
{
|
||||
STATIC_ASSERT(destSize > 0);
|
||||
STATIC_ASSERT(srcSize > 0);
|
||||
Write<mode, destSize>(destBuffer, srcBuffer, srcSize);
|
||||
}
|
||||
|
||||
template <ReadWriteMode mode>
|
||||
void Write(char *destBuffer, const size_t destSize, const std::string &src)
|
||||
{
|
||||
MPT_ASSERT(destSize > 0);
|
||||
Write<mode>(destBuffer, destSize, src.c_str(), src.length());
|
||||
}
|
||||
|
||||
template <ReadWriteMode mode>
|
||||
void Write(std::vector<char> &destBuffer, const std::string &src)
|
||||
{
|
||||
MPT_ASSERT(destBuffer.size() > 0);
|
||||
Write<mode>(destBuffer, src.c_str(), src.length());
|
||||
}
|
||||
|
||||
template <ReadWriteMode mode, size_t destSize>
|
||||
void Write(char (&destBuffer)[destSize], const std::string &src)
|
||||
{
|
||||
STATIC_ASSERT(destSize > 0);
|
||||
Write<mode, destSize>(destBuffer, src.c_str(), src.length());
|
||||
}
|
||||
|
||||
|
||||
// Copy from a char array to a fixed size char array.
|
||||
template <size_t destSize>
|
||||
void CopyN(char (&destBuffer)[destSize], const char *srcBuffer, const size_t srcSize = std::numeric_limits<size_t>::max())
|
||||
{
|
||||
const size_t copySize = std::min(destSize - 1u, srcSize);
|
||||
std::strncpy(destBuffer, srcBuffer, copySize);
|
||||
destBuffer[copySize] = '\0';
|
||||
}
|
||||
|
||||
// Copy at most srcSize characters from srcBuffer to a std::string.
|
||||
static inline void CopyN(std::string &dest, const char *srcBuffer, const size_t srcSize = std::numeric_limits<size_t>::max())
|
||||
{
|
||||
dest.assign(srcBuffer, srcBuffer + mpt::strnlen(srcBuffer, srcSize));
|
||||
}
|
||||
|
||||
|
||||
// Copy from one fixed size char array to another one.
|
||||
template <size_t destSize, size_t srcSize>
|
||||
void Copy(char (&destBuffer)[destSize], const char (&srcBuffer)[srcSize])
|
||||
{
|
||||
CopyN(destBuffer, srcBuffer, srcSize);
|
||||
}
|
||||
|
||||
// Copy from a std::string to a fixed size char array.
|
||||
template <size_t destSize>
|
||||
void Copy(char (&destBuffer)[destSize], const std::string &src)
|
||||
{
|
||||
CopyN(destBuffer, src.c_str(), src.length());
|
||||
}
|
||||
|
||||
// Copy from a fixed size char array to a std::string.
|
||||
template <size_t srcSize>
|
||||
void Copy(std::string &dest, const char (&srcBuffer)[srcSize])
|
||||
{
|
||||
CopyN(dest, srcBuffer, srcSize);
|
||||
}
|
||||
|
||||
// Copy from a std::string to a std::string.
|
||||
static inline void Copy(std::string &dest, const std::string &src)
|
||||
{
|
||||
dest.assign(src);
|
||||
}
|
||||
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
|
||||
|
||||
} // namespace String
|
||||
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -10,10 +10,22 @@
|
|||
#include "stdafx.h"
|
||||
#include "mptStringFormat.h"
|
||||
|
||||
#if MPT_CXX_AT_LEAST(17) && MPT_COMPILER_MSVC
|
||||
#define MPT_FORMAT_CXX17_INT 1
|
||||
#else
|
||||
#define MPT_FORMAT_CXX17_INT 0
|
||||
#endif
|
||||
|
||||
#if MPT_FORMAT_CXX17_INT
|
||||
#include <charconv>
|
||||
#endif // MPT_FORMAT_CXX17_INT
|
||||
#include <iomanip>
|
||||
#include <locale>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#if MPT_FORMAT_CXX17_INT
|
||||
#include <system_error>
|
||||
#endif // MPT_FORMAT_CXX17_INT
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
@ -24,14 +36,65 @@ namespace mpt
|
|||
{
|
||||
|
||||
|
||||
|
||||
template<typename Tstream, typename T> inline void SaneInsert(Tstream & s, const T & x) { s << x; }
|
||||
// do the right thing for signed/unsigned char and bool
|
||||
template<typename Tstream> void SaneInsert(Tstream & s, const bool & x) { s << static_cast<int>(x); }
|
||||
template<typename Tstream> void SaneInsert(Tstream & s, const signed char & x) { s << static_cast<signed int>(x); }
|
||||
template<typename Tstream> void SaneInsert(Tstream & s, const unsigned char & x) { s << static_cast<unsigned int>(x); }
|
||||
template<typename Tstream> inline void SaneInsert(Tstream & s, const bool & x) { s << static_cast<int>(x); }
|
||||
template<typename Tstream> inline void SaneInsert(Tstream & s, const signed char & x) { s << static_cast<signed int>(x); }
|
||||
template<typename Tstream> inline void SaneInsert(Tstream & s, const unsigned char & x) { s << static_cast<unsigned int>(x); }
|
||||
|
||||
#if MPT_FORMAT_CXX17_INT
|
||||
|
||||
#if MPT_WSTRING_FORMAT
|
||||
std::wstring ToWideSimple(const std::string &nstr)
|
||||
{
|
||||
std::wstring wstr(nstr.size(), L'\0');
|
||||
for(std::size_t i = 0; i < nstr.size(); ++i)
|
||||
{
|
||||
wstr[i] = static_cast<unsigned char>(nstr[i]);
|
||||
}
|
||||
return wstr;
|
||||
}
|
||||
#endif // MPT_WSTRING_FORMAT
|
||||
|
||||
template<typename T>
|
||||
inline std::string ToStringHelper(const T & x)
|
||||
static inline std::string ToChars(const T & x, int base = 10)
|
||||
{
|
||||
std::string str(1, '\0');
|
||||
bool done = false;
|
||||
while(!done)
|
||||
{
|
||||
std::to_chars_result result = std::to_chars(str.data(), str.data() + str.size(), x, base);
|
||||
if(result.ec != std::errc{})
|
||||
{
|
||||
str.resize(Util::ExponentialGrow(str.size()), '\0');
|
||||
} else
|
||||
{
|
||||
str.resize(result.ptr - str.data());
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline std::string ToStringHelperInt(const T & x)
|
||||
{
|
||||
return ToChars(x);
|
||||
}
|
||||
|
||||
#if MPT_WSTRING_FORMAT
|
||||
template<typename T>
|
||||
static inline std::wstring ToWStringHelperInt(const T & x)
|
||||
{
|
||||
return ToWideSimple(ToChars(x));
|
||||
}
|
||||
#endif
|
||||
|
||||
#else // !MPT_FORMAT_CXX17_INT
|
||||
|
||||
template<typename T>
|
||||
static inline std::string ToStringHelperInt(const T & x)
|
||||
{
|
||||
std::ostringstream o;
|
||||
o.imbue(std::locale::classic());
|
||||
|
@ -41,7 +104,29 @@ inline std::string ToStringHelper(const T & x)
|
|||
|
||||
#if MPT_WSTRING_FORMAT
|
||||
template<typename T>
|
||||
inline std::wstring ToWStringHelper(const T & x)
|
||||
static inline std::wstring ToWStringHelperInt(const T & x)
|
||||
{
|
||||
std::wostringstream o;
|
||||
o.imbue(std::locale::classic());
|
||||
SaneInsert(o, x);
|
||||
return o.str();
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // MPT_FORMAT_CXX17_INT
|
||||
|
||||
template<typename T>
|
||||
static inline std::string ToStringHelperFloat(const T & x)
|
||||
{
|
||||
std::ostringstream o;
|
||||
o.imbue(std::locale::classic());
|
||||
SaneInsert(o, x);
|
||||
return o.str();
|
||||
}
|
||||
|
||||
#if MPT_WSTRING_FORMAT
|
||||
template<typename T>
|
||||
static inline std::wstring ToWStringHelperFloat(const T & x)
|
||||
{
|
||||
std::wostringstream o;
|
||||
o.imbue(std::locale::classic());
|
||||
|
@ -61,20 +146,20 @@ std::string ToString(const mpt::ustring & x) { return mpt::ToCharset(mpt::Charse
|
|||
#if defined(_MFC_VER)
|
||||
std::string ToString(const CString & x) { return mpt::ToCharset(mpt::CharsetLocaleOrUTF8, x); }
|
||||
#endif
|
||||
std::string ToString(const bool & x) { return ToStringHelper(x); }
|
||||
std::string ToString(const signed char & x) { return ToStringHelper(x); }
|
||||
std::string ToString(const unsigned char & x) { return ToStringHelper(x); }
|
||||
std::string ToString(const signed short & x) { return ToStringHelper(x); }
|
||||
std::string ToString(const unsigned short & x) { return ToStringHelper(x); }
|
||||
std::string ToString(const signed int & x) { return ToStringHelper(x); }
|
||||
std::string ToString(const unsigned int & x) { return ToStringHelper(x); }
|
||||
std::string ToString(const signed long & x) { return ToStringHelper(x); }
|
||||
std::string ToString(const unsigned long & x) { return ToStringHelper(x); }
|
||||
std::string ToString(const signed long long & x) { return ToStringHelper(x); }
|
||||
std::string ToString(const unsigned long long & x) { return ToStringHelper(x); }
|
||||
std::string ToString(const float & x) { return ToStringHelper(x); }
|
||||
std::string ToString(const double & x) { return ToStringHelper(x); }
|
||||
std::string ToString(const long double & x) { return ToStringHelper(x); }
|
||||
std::string ToString(const bool & x) { return ToStringHelperInt(static_cast<int>(x)); }
|
||||
std::string ToString(const signed char & x) { return ToStringHelperInt(x); }
|
||||
std::string ToString(const unsigned char & x) { return ToStringHelperInt(x); }
|
||||
std::string ToString(const signed short & x) { return ToStringHelperInt(x); }
|
||||
std::string ToString(const unsigned short & x) { return ToStringHelperInt(x); }
|
||||
std::string ToString(const signed int & x) { return ToStringHelperInt(x); }
|
||||
std::string ToString(const unsigned int & x) { return ToStringHelperInt(x); }
|
||||
std::string ToString(const signed long & x) { return ToStringHelperInt(x); }
|
||||
std::string ToString(const unsigned long & x) { return ToStringHelperInt(x); }
|
||||
std::string ToString(const signed long long & x) { return ToStringHelperInt(x); }
|
||||
std::string ToString(const unsigned long long & x) { return ToStringHelperInt(x); }
|
||||
std::string ToString(const float & x) { return ToStringHelperFloat(x); }
|
||||
std::string ToString(const double & x) { return ToStringHelperFloat(x); }
|
||||
std::string ToString(const long double & x) { return ToStringHelperFloat(x); }
|
||||
|
||||
mpt::ustring ToUString(const std::string & x) { return mpt::ToUnicode(mpt::CharsetLocaleOrUTF8, x); }
|
||||
mpt::ustring ToUString(const char * const & x) { return mpt::ToUnicode(mpt::CharsetLocaleOrUTF8, x); }
|
||||
|
@ -90,36 +175,36 @@ mpt::ustring ToUString(const wchar_t & x) { return mpt::ToUnicode(std::wstring(1
|
|||
mpt::ustring ToUString(const CString & x) { return mpt::ToUnicode(x); }
|
||||
#endif
|
||||
#if MPT_USTRING_MODE_WIDE
|
||||
mpt::ustring ToUString(const bool & x) { return ToWStringHelper(x); }
|
||||
mpt::ustring ToUString(const signed char & x) { return ToWStringHelper(x); }
|
||||
mpt::ustring ToUString(const unsigned char & x) { return ToWStringHelper(x); }
|
||||
mpt::ustring ToUString(const signed short & x) { return ToWStringHelper(x); }
|
||||
mpt::ustring ToUString(const unsigned short & x) { return ToWStringHelper(x); }
|
||||
mpt::ustring ToUString(const signed int & x) { return ToWStringHelper(x); }
|
||||
mpt::ustring ToUString(const unsigned int & x) { return ToWStringHelper(x); }
|
||||
mpt::ustring ToUString(const signed long & x) { return ToWStringHelper(x); }
|
||||
mpt::ustring ToUString(const unsigned long & x) { return ToWStringHelper(x); }
|
||||
mpt::ustring ToUString(const signed long long & x) { return ToWStringHelper(x); }
|
||||
mpt::ustring ToUString(const unsigned long long & x) { return ToWStringHelper(x); }
|
||||
mpt::ustring ToUString(const float & x) { return ToWStringHelper(x); }
|
||||
mpt::ustring ToUString(const double & x) { return ToWStringHelper(x); }
|
||||
mpt::ustring ToUString(const long double & x) { return ToWStringHelper(x); }
|
||||
mpt::ustring ToUString(const bool & x) { return ToWStringHelperInt(static_cast<int>(x)); }
|
||||
mpt::ustring ToUString(const signed char & x) { return ToWStringHelperInt(x); }
|
||||
mpt::ustring ToUString(const unsigned char & x) { return ToWStringHelperInt(x); }
|
||||
mpt::ustring ToUString(const signed short & x) { return ToWStringHelperInt(x); }
|
||||
mpt::ustring ToUString(const unsigned short & x) { return ToWStringHelperInt(x); }
|
||||
mpt::ustring ToUString(const signed int & x) { return ToWStringHelperInt(x); }
|
||||
mpt::ustring ToUString(const unsigned int & x) { return ToWStringHelperInt(x); }
|
||||
mpt::ustring ToUString(const signed long & x) { return ToWStringHelperInt(x); }
|
||||
mpt::ustring ToUString(const unsigned long & x) { return ToWStringHelperInt(x); }
|
||||
mpt::ustring ToUString(const signed long long & x) { return ToWStringHelperInt(x); }
|
||||
mpt::ustring ToUString(const unsigned long long & x) { return ToWStringHelperInt(x); }
|
||||
mpt::ustring ToUString(const float & x) { return ToWStringHelperFloat(x); }
|
||||
mpt::ustring ToUString(const double & x) { return ToWStringHelperFloat(x); }
|
||||
mpt::ustring ToUString(const long double & x) { return ToWStringHelperFloat(x); }
|
||||
#endif
|
||||
#if MPT_USTRING_MODE_UTF8
|
||||
mpt::ustring ToUString(const bool & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelper(x)); }
|
||||
mpt::ustring ToUString(const signed char & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelper(x)); }
|
||||
mpt::ustring ToUString(const unsigned char & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelper(x)); }
|
||||
mpt::ustring ToUString(const signed short & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelper(x)); }
|
||||
mpt::ustring ToUString(const unsigned short & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelper(x)); }
|
||||
mpt::ustring ToUString(const signed int & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelper(x)); }
|
||||
mpt::ustring ToUString(const unsigned int & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelper(x)); }
|
||||
mpt::ustring ToUString(const signed long & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelper(x)); }
|
||||
mpt::ustring ToUString(const unsigned long & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelper(x)); }
|
||||
mpt::ustring ToUString(const signed long long & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelper(x)); }
|
||||
mpt::ustring ToUString(const unsigned long long & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelper(x)); }
|
||||
mpt::ustring ToUString(const float & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelper(x)); }
|
||||
mpt::ustring ToUString(const double & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelper(x)); }
|
||||
mpt::ustring ToUString(const long double & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelper(x)); }
|
||||
mpt::ustring ToUString(const bool & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelperInt(static_cast<int>(x))); }
|
||||
mpt::ustring ToUString(const signed char & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelperInt(x)); }
|
||||
mpt::ustring ToUString(const unsigned char & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelperInt(x)); }
|
||||
mpt::ustring ToUString(const signed short & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelperInt(x)); }
|
||||
mpt::ustring ToUString(const unsigned short & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelperInt(x)); }
|
||||
mpt::ustring ToUString(const signed int & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelperInt(x)); }
|
||||
mpt::ustring ToUString(const unsigned int & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelperInt(x)); }
|
||||
mpt::ustring ToUString(const signed long & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelperInt(x)); }
|
||||
mpt::ustring ToUString(const unsigned long & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelperInt(x)); }
|
||||
mpt::ustring ToUString(const signed long long & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelperInt(x)); }
|
||||
mpt::ustring ToUString(const unsigned long long & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelperInt(x)); }
|
||||
mpt::ustring ToUString(const float & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelperFloat(x)); }
|
||||
mpt::ustring ToUString(const double & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelperFloat(x)); }
|
||||
mpt::ustring ToUString(const long double & x) { return mpt::ToUnicode(mpt::CharsetUTF8, ToStringHelperFloat(x)); }
|
||||
#endif
|
||||
|
||||
#if MPT_WSTRING_FORMAT
|
||||
|
@ -132,26 +217,54 @@ std::wstring ToWString(const mpt::ustring & x) { return mpt::ToWide(x); }
|
|||
#if defined(_MFC_VER)
|
||||
std::wstring ToWString(const CString & x) { return mpt::ToWide(x); }
|
||||
#endif
|
||||
std::wstring ToWString(const bool & x) { return ToWStringHelper(x); }
|
||||
std::wstring ToWString(const signed char & x) { return ToWStringHelper(x); }
|
||||
std::wstring ToWString(const unsigned char & x) { return ToWStringHelper(x); }
|
||||
std::wstring ToWString(const signed short & x) { return ToWStringHelper(x); }
|
||||
std::wstring ToWString(const unsigned short & x) { return ToWStringHelper(x); }
|
||||
std::wstring ToWString(const signed int & x) { return ToWStringHelper(x); }
|
||||
std::wstring ToWString(const unsigned int & x) { return ToWStringHelper(x); }
|
||||
std::wstring ToWString(const signed long & x) { return ToWStringHelper(x); }
|
||||
std::wstring ToWString(const unsigned long & x) { return ToWStringHelper(x); }
|
||||
std::wstring ToWString(const signed long long & x) { return ToWStringHelper(x); }
|
||||
std::wstring ToWString(const unsigned long long & x) { return ToWStringHelper(x); }
|
||||
std::wstring ToWString(const float & x) { return ToWStringHelper(x); }
|
||||
std::wstring ToWString(const double & x) { return ToWStringHelper(x); }
|
||||
std::wstring ToWString(const long double & x) { return ToWStringHelper(x); }
|
||||
std::wstring ToWString(const bool & x) { return ToWStringHelperInt(static_cast<int>(x)); }
|
||||
std::wstring ToWString(const signed char & x) { return ToWStringHelperInt(x); }
|
||||
std::wstring ToWString(const unsigned char & x) { return ToWStringHelperInt(x); }
|
||||
std::wstring ToWString(const signed short & x) { return ToWStringHelperInt(x); }
|
||||
std::wstring ToWString(const unsigned short & x) { return ToWStringHelperInt(x); }
|
||||
std::wstring ToWString(const signed int & x) { return ToWStringHelperInt(x); }
|
||||
std::wstring ToWString(const unsigned int & x) { return ToWStringHelperInt(x); }
|
||||
std::wstring ToWString(const signed long & x) { return ToWStringHelperInt(x); }
|
||||
std::wstring ToWString(const unsigned long & x) { return ToWStringHelperInt(x); }
|
||||
std::wstring ToWString(const signed long long & x) { return ToWStringHelperInt(x); }
|
||||
std::wstring ToWString(const unsigned long long & x) { return ToWStringHelperInt(x); }
|
||||
std::wstring ToWString(const float & x) { return ToWStringHelperFloat(x); }
|
||||
std::wstring ToWString(const double & x) { return ToWStringHelperFloat(x); }
|
||||
std::wstring ToWString(const long double & x) { return ToWStringHelperFloat(x); }
|
||||
#endif
|
||||
|
||||
|
||||
template<typename Tostream>
|
||||
inline void ApplyFormat(Tostream & o, const FormatSpec & format)
|
||||
template <typename Tchar>
|
||||
struct NumPunct : std::numpunct<Tchar>
|
||||
{
|
||||
private:
|
||||
unsigned int group;
|
||||
char sep;
|
||||
public:
|
||||
NumPunct(unsigned int g, char s)
|
||||
: group(g)
|
||||
, sep(s)
|
||||
{}
|
||||
std::string do_grouping() const override
|
||||
{
|
||||
return std::string(1, static_cast<char>(group));
|
||||
}
|
||||
Tchar do_thousands_sep() const override
|
||||
{
|
||||
return static_cast<Tchar>(sep);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Tostream, typename T>
|
||||
static inline void ApplyFormat(Tostream & o, const FormatSpec & format, const T &)
|
||||
{
|
||||
MPT_MAYBE_CONSTANT_IF(!std::numeric_limits<T>::is_integer)
|
||||
{
|
||||
if(format.GetGroup() > 0)
|
||||
{
|
||||
o.imbue(std::locale(o.getloc(), new NumPunct<typename Tostream::char_type>(format.GetGroup(), format.GetGroupSep())));
|
||||
}
|
||||
}
|
||||
FormatFlags f = format.GetFlags();
|
||||
std::size_t width = format.GetWidth();
|
||||
int precision = format.GetPrecision();
|
||||
|
@ -170,154 +283,255 @@ inline void ApplyFormat(Tostream & o, const FormatSpec & format)
|
|||
else if(f & fmt_base::NotaSci ) { o << std::setiosflags(std::ios::scientific); }
|
||||
if(f & fmt_base::CaseLow) { o << std::nouppercase; }
|
||||
else if(f & fmt_base::CaseUpp) { o << std::uppercase; }
|
||||
MPT_MAYBE_CONSTANT_IF(!std::numeric_limits<T>::is_integer)
|
||||
{
|
||||
if(f & fmt_base::FillOff) { /* nothing */ }
|
||||
else if(f & fmt_base::FillNul) { o << std::setw(width) << std::setfill(typename Tostream::char_type('0')); }
|
||||
else if(f & fmt_base::FillSpc) { o << std::setw(width) << std::setfill(typename Tostream::char_type(' ')); }
|
||||
}
|
||||
if(precision != -1) { o << std::setprecision(precision); }
|
||||
}
|
||||
|
||||
template<typename Tstring>
|
||||
static inline Tstring PostProcessCase(Tstring str, const FormatSpec & format)
|
||||
{
|
||||
FormatFlags f = format.GetFlags();
|
||||
if(f & fmt_base::CaseUpp)
|
||||
{
|
||||
for(auto & c : str)
|
||||
{
|
||||
if('a' <= c && c <= 'z')
|
||||
{
|
||||
c -= 'a' - 'A';
|
||||
}
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
template<typename Tstring>
|
||||
static inline Tstring PostProcessDigits(Tstring str, const FormatSpec & format)
|
||||
{
|
||||
FormatFlags f = format.GetFlags();
|
||||
std::size_t width = format.GetWidth();
|
||||
if(f & fmt_base::FillNul)
|
||||
{
|
||||
auto pos = str.begin();
|
||||
if(str.length() > 0)
|
||||
{
|
||||
if(str[0] == typename Tstring::value_type('+'))
|
||||
{
|
||||
pos++;
|
||||
width++;
|
||||
} else if(str[0] == typename Tstring::value_type('-'))
|
||||
{
|
||||
pos++;
|
||||
width++;
|
||||
}
|
||||
}
|
||||
if(str.length() < width)
|
||||
{
|
||||
str.insert(pos, width - str.length(), '0');
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
template<typename Tstring>
|
||||
static inline Tstring PostProcessGroup(Tstring str, const FormatSpec & format)
|
||||
{
|
||||
if(format.GetGroup() > 0)
|
||||
{
|
||||
const unsigned int groupSize = format.GetGroup();
|
||||
const char groupSep = format.GetGroupSep();
|
||||
std::size_t len = str.length();
|
||||
for(std::size_t n = 0; n < len; ++n)
|
||||
{
|
||||
if(n > 0 && (n % groupSize) == 0)
|
||||
{
|
||||
if(!(n == (len - 1) && (str[0] == typename Tstring::value_type('+') || str[0] == typename Tstring::value_type('-'))))
|
||||
{
|
||||
str.insert(str.begin() + (len - n), 1, groupSep);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
#if MPT_FORMAT_CXX17_INT
|
||||
|
||||
template<typename T>
|
||||
inline std::string FormatValHelper(const T & x, const FormatSpec & f)
|
||||
static inline std::string FormatValHelperInt(const T & x, const FormatSpec & f)
|
||||
{
|
||||
int base = 10;
|
||||
if(f.GetFlags() & fmt_base::BaseDec) { base = 10; }
|
||||
if(f.GetFlags() & fmt_base::BaseHex) { base = 16; }
|
||||
return PostProcessGroup(PostProcessDigits(PostProcessCase(ToChars(x, base), f), f), f);
|
||||
}
|
||||
|
||||
#if MPT_WSTRING_FORMAT
|
||||
template<typename T>
|
||||
static inline std::wstring FormatValWHelperInt(const T & x, const FormatSpec & f)
|
||||
{
|
||||
int base = 10;
|
||||
if(f.GetFlags() & fmt_base::BaseDec) { base = 10; }
|
||||
if(f.GetFlags() & fmt_base::BaseHex) { base = 16; }
|
||||
return ToWideSimple(PostProcessGroup(PostProcessDigits(PostProcessCase(ToChars(x, base), f), f), f));
|
||||
}
|
||||
#endif
|
||||
|
||||
#else // !MPT_FORMAT_CXX17_INT
|
||||
|
||||
template<typename T>
|
||||
static inline std::string FormatValHelperInt(const T & x, const FormatSpec & f)
|
||||
{
|
||||
MPT_MAYBE_CONSTANT_IF((f.GetFlags() & fmt_base::BaseHex) && std::is_signed<T>::value)
|
||||
{
|
||||
if(x == std::numeric_limits<T>::min())
|
||||
{
|
||||
return std::string(1, '-') + FormatValHelperInt(static_cast<typename std::make_unsigned<T>::type>(x), f);
|
||||
} else MPT_MAYBE_CONSTANT_IF(x < 0)
|
||||
{
|
||||
return std::string(1, '-') + FormatValHelperInt(static_cast<typename std::make_unsigned<T>::type>(0-x), f);
|
||||
} else
|
||||
{
|
||||
return FormatValHelperInt(static_cast<typename std::make_unsigned<T>::type>(x), f);
|
||||
}
|
||||
}
|
||||
std::ostringstream o;
|
||||
o.imbue(std::locale::classic());
|
||||
ApplyFormat(o, f, x);
|
||||
SaneInsert(o, x);
|
||||
return PostProcessGroup(PostProcessDigits(o.str(), f), f);
|
||||
}
|
||||
|
||||
#if MPT_WSTRING_FORMAT
|
||||
template<typename T>
|
||||
static inline std::wstring FormatValWHelperInt(const T & x, const FormatSpec & f)
|
||||
{
|
||||
MPT_MAYBE_CONSTANT_IF((f.GetFlags() & fmt_base::BaseHex) && std::is_signed<T>::value)
|
||||
{
|
||||
if(x == std::numeric_limits<T>::min())
|
||||
{
|
||||
return std::wstring(1, L'-') + FormatValWHelperInt(static_cast<typename std::make_unsigned<T>::type>(x), f);
|
||||
} else MPT_MAYBE_CONSTANT_IF(x < 0)
|
||||
{
|
||||
return std::wstring(1, L'-') + FormatValWHelperInt(static_cast<typename std::make_unsigned<T>::type>(0-x), f);
|
||||
} else
|
||||
{
|
||||
return FormatValWHelperInt(static_cast<typename std::make_unsigned<T>::type>(x), f);
|
||||
}
|
||||
}
|
||||
std::wostringstream o;
|
||||
o.imbue(std::locale::classic());
|
||||
ApplyFormat(o, f, x);
|
||||
SaneInsert(o, x);
|
||||
return PostProcessGroup(PostProcessDigits(o.str(), f), f);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // MPT_FORMAT_CXX17_INT
|
||||
|
||||
template<typename T>
|
||||
static inline std::string FormatValHelperFloat(const T & x, const FormatSpec & f)
|
||||
{
|
||||
std::ostringstream o;
|
||||
o.imbue(std::locale::classic());
|
||||
ApplyFormat(o, f);
|
||||
ApplyFormat(o, f, x);
|
||||
SaneInsert(o, x);
|
||||
return o.str();
|
||||
}
|
||||
|
||||
#if MPT_WSTRING_FORMAT
|
||||
template<typename T>
|
||||
inline std::wstring FormatValWHelper(const T & x, const FormatSpec & f)
|
||||
static inline std::wstring FormatValWHelperFloat(const T & x, const FormatSpec & f)
|
||||
{
|
||||
std::wostringstream o;
|
||||
o.imbue(std::locale::classic());
|
||||
ApplyFormat(o, f);
|
||||
ApplyFormat(o, f, x);
|
||||
SaneInsert(o, x);
|
||||
return o.str();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Parses a useful subset of standard sprintf syntax for specifying floating point formatting.
|
||||
template<typename Tchar>
|
||||
static inline FormatSpec ParseFormatStringFloat(const Tchar * str)
|
||||
{
|
||||
MPT_ASSERT(str);
|
||||
FormatFlags f = FormatFlags();
|
||||
std::size_t width = 0;
|
||||
int precision = -1;
|
||||
if(!str)
|
||||
{
|
||||
return FormatSpec();
|
||||
}
|
||||
const Tchar * p = str;
|
||||
while(*p && *p != Tchar('%'))
|
||||
{
|
||||
++p;
|
||||
}
|
||||
++p;
|
||||
while(*p && (*p == Tchar(' ') || *p == Tchar('0')))
|
||||
{
|
||||
if(*p == Tchar(' ')) f |= mpt::fmt_base::FillSpc;
|
||||
if(*p == Tchar('0')) f |= mpt::fmt_base::FillNul;
|
||||
++p;
|
||||
}
|
||||
if(!(f & mpt::fmt_base::FillSpc) && !(f & mpt::fmt_base::FillNul))
|
||||
{
|
||||
f |= mpt::fmt_base::FillOff;
|
||||
}
|
||||
while(*p && (Tchar('0') <= *p && *p <= Tchar('9')))
|
||||
{
|
||||
if(f & mpt::fmt_base::FillOff)
|
||||
{
|
||||
f &= ~mpt::fmt_base::FillOff;
|
||||
f |= mpt::fmt_base::FillSpc;
|
||||
}
|
||||
width *= 10;
|
||||
width += *p - Tchar('0');
|
||||
++p;
|
||||
}
|
||||
if(*p && *p == Tchar('.'))
|
||||
{
|
||||
++p;
|
||||
precision = 0;
|
||||
while(*p && (Tchar('0') <= *p && *p <= Tchar('9')))
|
||||
{
|
||||
precision *= 10;
|
||||
precision += *p - Tchar('0');
|
||||
++p;
|
||||
}
|
||||
}
|
||||
if(*p && (*p == Tchar('g') || *p == Tchar('G') || *p == Tchar('f') || *p == Tchar('F') || *p == Tchar('e') || *p == Tchar('E')))
|
||||
{
|
||||
if(*p == Tchar('g')) f |= mpt::fmt_base::NotaNrm | mpt::fmt_base::CaseLow;
|
||||
if(*p == Tchar('G')) f |= mpt::fmt_base::NotaNrm | mpt::fmt_base::CaseUpp;
|
||||
if(*p == Tchar('f')) f |= mpt::fmt_base::NotaFix | mpt::fmt_base::CaseLow;
|
||||
if(*p == Tchar('F')) f |= mpt::fmt_base::NotaFix | mpt::fmt_base::CaseUpp;
|
||||
if(*p == Tchar('e')) f |= mpt::fmt_base::NotaSci | mpt::fmt_base::CaseLow;
|
||||
if(*p == Tchar('E')) f |= mpt::fmt_base::NotaSci | mpt::fmt_base::CaseUpp;
|
||||
++p;
|
||||
}
|
||||
return FormatSpec().SetFlags(f).SetWidth(width).SetPrecision(precision);
|
||||
}
|
||||
|
||||
FormatSpec & FormatSpec::ParsePrintf(const char * format)
|
||||
{
|
||||
*this = ParseFormatStringFloat(format);
|
||||
return *this;
|
||||
}
|
||||
FormatSpec & FormatSpec::ParsePrintf(const wchar_t * format)
|
||||
{
|
||||
*this = ParseFormatStringFloat(format);
|
||||
return *this;
|
||||
}
|
||||
FormatSpec & FormatSpec::ParsePrintf(const std::string & format)
|
||||
{
|
||||
*this = ParseFormatStringFloat(format.c_str());
|
||||
return *this;
|
||||
}
|
||||
FormatSpec & FormatSpec::ParsePrintf(const std::wstring & format)
|
||||
{
|
||||
*this = ParseFormatStringFloat(format.c_str());
|
||||
return *this;
|
||||
}
|
||||
std::string FormatVal(const char & x, const FormatSpec & f) { return FormatValHelperInt(x, f); }
|
||||
#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR)
|
||||
std::string FormatVal(const wchar_t & x, const FormatSpec & f) { return FormatValHelperInt(x, f); }
|
||||
#endif // !MPT_COMPILER_QUIRK_NO_WCHAR
|
||||
std::string FormatVal(const bool & x, const FormatSpec & f) { return FormatValHelperInt(static_cast<int>(x), f); }
|
||||
std::string FormatVal(const signed char & x, const FormatSpec & f) { return FormatValHelperInt(x, f); }
|
||||
std::string FormatVal(const unsigned char & x, const FormatSpec & f) { return FormatValHelperInt(x, f); }
|
||||
std::string FormatVal(const signed short & x, const FormatSpec & f) { return FormatValHelperInt(x, f); }
|
||||
std::string FormatVal(const unsigned short & x, const FormatSpec & f) { return FormatValHelperInt(x, f); }
|
||||
std::string FormatVal(const signed int & x, const FormatSpec & f) { return FormatValHelperInt(x, f); }
|
||||
std::string FormatVal(const unsigned int & x, const FormatSpec & f) { return FormatValHelperInt(x, f); }
|
||||
std::string FormatVal(const signed long & x, const FormatSpec & f) { return FormatValHelperInt(x, f); }
|
||||
std::string FormatVal(const unsigned long & x, const FormatSpec & f) { return FormatValHelperInt(x, f); }
|
||||
std::string FormatVal(const signed long long & x, const FormatSpec & f) { return FormatValHelperInt(x, f); }
|
||||
std::string FormatVal(const unsigned long long & x, const FormatSpec & f) { return FormatValHelperInt(x, f); }
|
||||
std::string FormatVal(const float & x, const FormatSpec & f) { return FormatValHelperFloat(x, f); }
|
||||
std::string FormatVal(const double & x, const FormatSpec & f) { return FormatValHelperFloat(x, f); }
|
||||
std::string FormatVal(const long double & x, const FormatSpec & f) { return FormatValHelperFloat(x, f); }
|
||||
|
||||
|
||||
std::string FormatVal(const char & x, const FormatSpec & f) { return FormatValHelper(x, f); }
|
||||
std::string FormatVal(const wchar_t & x, const FormatSpec & f) { return FormatValHelper(x, f); }
|
||||
std::string FormatVal(const bool & x, const FormatSpec & f) { return FormatValHelper(x, f); }
|
||||
std::string FormatVal(const signed char & x, const FormatSpec & f) { return FormatValHelper(x, f); }
|
||||
std::string FormatVal(const unsigned char & x, const FormatSpec & f) { return FormatValHelper(x, f); }
|
||||
std::string FormatVal(const signed short & x, const FormatSpec & f) { return FormatValHelper(x, f); }
|
||||
std::string FormatVal(const unsigned short & x, const FormatSpec & f) { return FormatValHelper(x, f); }
|
||||
std::string FormatVal(const signed int & x, const FormatSpec & f) { return FormatValHelper(x, f); }
|
||||
std::string FormatVal(const unsigned int & x, const FormatSpec & f) { return FormatValHelper(x, f); }
|
||||
std::string FormatVal(const signed long & x, const FormatSpec & f) { return FormatValHelper(x, f); }
|
||||
std::string FormatVal(const unsigned long & x, const FormatSpec & f) { return FormatValHelper(x, f); }
|
||||
std::string FormatVal(const signed long long & x, const FormatSpec & f) { return FormatValHelper(x, f); }
|
||||
std::string FormatVal(const unsigned long long & x, const FormatSpec & f) { return FormatValHelper(x, f); }
|
||||
std::string FormatVal(const float & x, const FormatSpec & f) { return FormatValHelper(x, f); }
|
||||
std::string FormatVal(const double & x, const FormatSpec & f) { return FormatValHelper(x, f); }
|
||||
std::string FormatVal(const long double & x, const FormatSpec & f) { return FormatValHelper(x, f); }
|
||||
#if MPT_USTRING_MODE_WIDE
|
||||
mpt::ustring FormatValU(const char & x, const FormatSpec & f) { return FormatValWHelperInt(x, f); }
|
||||
mpt::ustring FormatValU(const wchar_t & x, const FormatSpec & f) { return FormatValWHelperInt(x, f); }
|
||||
mpt::ustring FormatValU(const bool & x, const FormatSpec & f) { return FormatValWHelperInt(static_cast<int>(x), f); }
|
||||
mpt::ustring FormatValU(const signed char & x, const FormatSpec & f) { return FormatValWHelperInt(x, f); }
|
||||
mpt::ustring FormatValU(const unsigned char & x, const FormatSpec & f) { return FormatValWHelperInt(x, f); }
|
||||
mpt::ustring FormatValU(const signed short & x, const FormatSpec & f) { return FormatValWHelperInt(x, f); }
|
||||
mpt::ustring FormatValU(const unsigned short & x, const FormatSpec & f) { return FormatValWHelperInt(x, f); }
|
||||
mpt::ustring FormatValU(const signed int & x, const FormatSpec & f) { return FormatValWHelperInt(x, f); }
|
||||
mpt::ustring FormatValU(const unsigned int & x, const FormatSpec & f) { return FormatValWHelperInt(x, f); }
|
||||
mpt::ustring FormatValU(const signed long & x, const FormatSpec & f) { return FormatValWHelperInt(x, f); }
|
||||
mpt::ustring FormatValU(const unsigned long & x, const FormatSpec & f) { return FormatValWHelperInt(x, f); }
|
||||
mpt::ustring FormatValU(const signed long long & x, const FormatSpec & f) { return FormatValWHelperInt(x, f); }
|
||||
mpt::ustring FormatValU(const unsigned long long & x, const FormatSpec & f) { return FormatValWHelperInt(x, f); }
|
||||
mpt::ustring FormatValU(const float & x, const FormatSpec & f) { return FormatValWHelperFloat(x, f); }
|
||||
mpt::ustring FormatValU(const double & x, const FormatSpec & f) { return FormatValWHelperFloat(x, f); }
|
||||
mpt::ustring FormatValU(const long double & x, const FormatSpec & f) { return FormatValWHelperFloat(x, f); }
|
||||
#endif
|
||||
#if MPT_USTRING_MODE_UTF8
|
||||
mpt::ustring FormatValU(const char & x, const FormatSpec & f) { return mpt::ToUnicode(mpt::CharsetUTF8, FormatValHelperInt(x, f)); }
|
||||
#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR)
|
||||
mpt::ustring FormatValU(const wchar_t & x, const FormatSpec & f) { return mpt::ToUnicode(mpt::CharsetUTF8, FormatValHelperInt(x, f)); }
|
||||
#endif // !MPT_COMPILER_QUIRK_NO_WCHAR
|
||||
mpt::ustring FormatValU(const bool & x, const FormatSpec & f) { return mpt::ToUnicode(mpt::CharsetUTF8, FormatValHelperInt(static_cast<int>(x), f)); }
|
||||
mpt::ustring FormatValU(const signed char & x, const FormatSpec & f) { return mpt::ToUnicode(mpt::CharsetUTF8, FormatValHelperInt(x, f)); }
|
||||
mpt::ustring FormatValU(const unsigned char & x, const FormatSpec & f) { return mpt::ToUnicode(mpt::CharsetUTF8, FormatValHelperInt(x, f)); }
|
||||
mpt::ustring FormatValU(const signed short & x, const FormatSpec & f) { return mpt::ToUnicode(mpt::CharsetUTF8, FormatValHelperInt(x, f)); }
|
||||
mpt::ustring FormatValU(const unsigned short & x, const FormatSpec & f) { return mpt::ToUnicode(mpt::CharsetUTF8, FormatValHelperInt(x, f)); }
|
||||
mpt::ustring FormatValU(const signed int & x, const FormatSpec & f) { return mpt::ToUnicode(mpt::CharsetUTF8, FormatValHelperInt(x, f)); }
|
||||
mpt::ustring FormatValU(const unsigned int & x, const FormatSpec & f) { return mpt::ToUnicode(mpt::CharsetUTF8, FormatValHelperInt(x, f)); }
|
||||
mpt::ustring FormatValU(const signed long & x, const FormatSpec & f) { return mpt::ToUnicode(mpt::CharsetUTF8, FormatValHelperInt(x, f)); }
|
||||
mpt::ustring FormatValU(const unsigned long & x, const FormatSpec & f) { return mpt::ToUnicode(mpt::CharsetUTF8, FormatValHelperInt(x, f)); }
|
||||
mpt::ustring FormatValU(const signed long long & x, const FormatSpec & f) { return mpt::ToUnicode(mpt::CharsetUTF8, FormatValHelperInt(x, f)); }
|
||||
mpt::ustring FormatValU(const unsigned long long & x, const FormatSpec & f) { return mpt::ToUnicode(mpt::CharsetUTF8, FormatValHelperInt(x, f)); }
|
||||
mpt::ustring FormatValU(const float & x, const FormatSpec & f) { return mpt::ToUnicode(mpt::CharsetUTF8, FormatValHelperFloat(x, f)); }
|
||||
mpt::ustring FormatValU(const double & x, const FormatSpec & f) { return mpt::ToUnicode(mpt::CharsetUTF8, FormatValHelperFloat(x, f)); }
|
||||
mpt::ustring FormatValU(const long double & x, const FormatSpec & f) { return mpt::ToUnicode(mpt::CharsetUTF8, FormatValHelperFloat(x, f)); }
|
||||
#endif
|
||||
|
||||
#if MPT_WSTRING_FORMAT
|
||||
std::wstring FormatValW(const char & x, const FormatSpec & f) { return FormatValWHelper(x, f); }
|
||||
std::wstring FormatValW(const wchar_t & x, const FormatSpec & f) { return FormatValWHelper(x, f); }
|
||||
std::wstring FormatValW(const bool & x, const FormatSpec & f) { return FormatValWHelper(x, f); }
|
||||
std::wstring FormatValW(const signed char & x, const FormatSpec & f) { return FormatValWHelper(x, f); }
|
||||
std::wstring FormatValW(const unsigned char & x, const FormatSpec & f) { return FormatValWHelper(x, f); }
|
||||
std::wstring FormatValW(const signed short & x, const FormatSpec & f) { return FormatValWHelper(x, f); }
|
||||
std::wstring FormatValW(const unsigned short & x, const FormatSpec & f) { return FormatValWHelper(x, f); }
|
||||
std::wstring FormatValW(const signed int & x, const FormatSpec & f) { return FormatValWHelper(x, f); }
|
||||
std::wstring FormatValW(const unsigned int & x, const FormatSpec & f) { return FormatValWHelper(x, f); }
|
||||
std::wstring FormatValW(const signed long & x, const FormatSpec & f) { return FormatValWHelper(x, f); }
|
||||
std::wstring FormatValW(const unsigned long & x, const FormatSpec & f) { return FormatValWHelper(x, f); }
|
||||
std::wstring FormatValW(const signed long long & x, const FormatSpec & f) { return FormatValWHelper(x, f); }
|
||||
std::wstring FormatValW(const unsigned long long & x, const FormatSpec & f) { return FormatValWHelper(x, f); }
|
||||
std::wstring FormatValW(const float & x, const FormatSpec & f) { return FormatValWHelper(x, f); }
|
||||
std::wstring FormatValW(const double & x, const FormatSpec & f) { return FormatValWHelper(x, f); }
|
||||
std::wstring FormatValW(const long double & x, const FormatSpec & f) { return FormatValWHelper(x, f); }
|
||||
std::wstring FormatValW(const char & x, const FormatSpec & f) { return FormatValWHelperInt(x, f); }
|
||||
#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR)
|
||||
std::wstring FormatValW(const wchar_t & x, const FormatSpec & f) { return FormatValWHelperInt(x, f); }
|
||||
#endif // !MPT_COMPILER_QUIRK_NO_WCHAR
|
||||
std::wstring FormatValW(const bool & x, const FormatSpec & f) { return FormatValWHelperInt(static_cast<int>(x), f); }
|
||||
std::wstring FormatValW(const signed char & x, const FormatSpec & f) { return FormatValWHelperInt(x, f); }
|
||||
std::wstring FormatValW(const unsigned char & x, const FormatSpec & f) { return FormatValWHelperInt(x, f); }
|
||||
std::wstring FormatValW(const signed short & x, const FormatSpec & f) { return FormatValWHelperInt(x, f); }
|
||||
std::wstring FormatValW(const unsigned short & x, const FormatSpec & f) { return FormatValWHelperInt(x, f); }
|
||||
std::wstring FormatValW(const signed int & x, const FormatSpec & f) { return FormatValWHelperInt(x, f); }
|
||||
std::wstring FormatValW(const unsigned int & x, const FormatSpec & f) { return FormatValWHelperInt(x, f); }
|
||||
std::wstring FormatValW(const signed long & x, const FormatSpec & f) { return FormatValWHelperInt(x, f); }
|
||||
std::wstring FormatValW(const unsigned long & x, const FormatSpec & f) { return FormatValWHelperInt(x, f); }
|
||||
std::wstring FormatValW(const signed long long & x, const FormatSpec & f) { return FormatValWHelperInt(x, f); }
|
||||
std::wstring FormatValW(const unsigned long long & x, const FormatSpec & f) { return FormatValWHelperInt(x, f); }
|
||||
std::wstring FormatValW(const float & x, const FormatSpec & f) { return FormatValWHelperFloat(x, f); }
|
||||
std::wstring FormatValW(const double & x, const FormatSpec & f) { return FormatValWHelperFloat(x, f); }
|
||||
std::wstring FormatValW(const long double & x, const FormatSpec & f) { return FormatValWHelperFloat(x, f); }
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -340,90 +554,42 @@ Tstring PrintImplTemplate(const Tstring & format
|
|||
, const Tstring & x8
|
||||
)
|
||||
{
|
||||
typedef typename mpt::string_traits<Tstring> traits;
|
||||
Tstring result;
|
||||
const std::size_t len = format.length();
|
||||
result.reserve(len);
|
||||
for(std::size_t pos = 0; pos != len; ++pos)
|
||||
const typename traits::size_type len = traits::length(format);
|
||||
traits::reserve(result, len);
|
||||
for(typename traits::size_type pos = 0; pos != len; ++pos)
|
||||
{
|
||||
typename Tstring::value_type c = format[pos];
|
||||
if(pos + 1 != len && c == '%')
|
||||
typename traits::char_type c = format[pos];
|
||||
if(pos + 1 != len && c == typename traits::char_type('%'))
|
||||
{
|
||||
pos++;
|
||||
c = format[pos];
|
||||
if('1' <= c && c <= '9')
|
||||
if(typename traits::char_type('1') <= c && c <= typename traits::char_type('9'))
|
||||
{
|
||||
const std::size_t n = c - '0';
|
||||
const std::size_t n = c - typename traits::char_type('0');
|
||||
switch(n)
|
||||
{
|
||||
case 1: result.append(x1); break;
|
||||
case 2: result.append(x2); break;
|
||||
case 3: result.append(x3); break;
|
||||
case 4: result.append(x4); break;
|
||||
case 5: result.append(x5); break;
|
||||
case 6: result.append(x6); break;
|
||||
case 7: result.append(x7); break;
|
||||
case 8: result.append(x8); break;
|
||||
case 1: traits::append(result, x1); break;
|
||||
case 2: traits::append(result, x2); break;
|
||||
case 3: traits::append(result, x3); break;
|
||||
case 4: traits::append(result, x4); break;
|
||||
case 5: traits::append(result, x5); break;
|
||||
case 6: traits::append(result, x6); break;
|
||||
case 7: traits::append(result, x7); break;
|
||||
case 8: traits::append(result, x8); break;
|
||||
}
|
||||
continue;
|
||||
} else if(c != '%')
|
||||
} else if(c != typename traits::char_type('%'))
|
||||
{
|
||||
result.append(1, '%');
|
||||
traits::append(result, 1, typename traits::char_type('%'));
|
||||
}
|
||||
}
|
||||
result.append(1, c);
|
||||
traits::append(result, 1, c);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#if defined(_MFC_VER)
|
||||
template<>
|
||||
CString PrintImplTemplate<CString>(const CString & format
|
||||
, const CString & x1
|
||||
, const CString & x2
|
||||
, const CString & x3
|
||||
, const CString & x4
|
||||
, const CString & x5
|
||||
, const CString & x6
|
||||
, const CString & x7
|
||||
, const CString & x8
|
||||
)
|
||||
{
|
||||
CString result;
|
||||
const int len = format.GetLength();
|
||||
result.Preallocate(len);
|
||||
for(int pos = 0; pos != len; ++pos)
|
||||
{
|
||||
CString::XCHAR c = format[pos];
|
||||
if(pos + 1 != len && c == _T('%'))
|
||||
{
|
||||
pos++;
|
||||
c = format[pos];
|
||||
if(_T('1') <= c && c <= _T('9'))
|
||||
{
|
||||
const std::size_t n = c - _T('0');
|
||||
switch(n)
|
||||
{
|
||||
case 1: result += x1; break;
|
||||
case 2: result += x2; break;
|
||||
case 3: result += x3; break;
|
||||
case 4: result += x4; break;
|
||||
case 5: result += x5; break;
|
||||
case 6: result += x6; break;
|
||||
case 7: result += x7; break;
|
||||
case 8: result += x8; break;
|
||||
}
|
||||
continue;
|
||||
} else if(c != _T('%'))
|
||||
{
|
||||
result.AppendChar(_T('%'));
|
||||
}
|
||||
}
|
||||
result.AppendChar(c);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string PrintImpl(const std::string & format
|
||||
, const std::string & x1
|
||||
, const std::string & x2
|
||||
|
@ -470,6 +636,22 @@ mpt::ustring PrintImpl(const mpt::ustring & format
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
mpt::lstring PrintImpl(const mpt::lstring & format
|
||||
, const mpt::lstring & x1
|
||||
, const mpt::lstring & x2
|
||||
, const mpt::lstring & x3
|
||||
, const mpt::lstring & x4
|
||||
, const mpt::lstring & x5
|
||||
, const mpt::lstring & x6
|
||||
, const mpt::lstring & x7
|
||||
, const mpt::lstring & x8
|
||||
)
|
||||
{
|
||||
return PrintImplTemplate<mpt::lstring>(format, x1,x2,x3,x4,x5,x6,x7,x8);
|
||||
}
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
|
||||
#if defined(_MFC_VER)
|
||||
CString PrintImpl(const CString & format
|
||||
, const CString & x1
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
|
||||
#include "mptString.h"
|
||||
|
||||
|
@ -40,14 +42,12 @@ OPENMPT_NAMESPACE_BEGIN
|
|||
// This mimics the behaviour of QString::arg() in QT4/5 or MFC AfxFormatString2(). C printf-like functions offer similar functionality
|
||||
// with a '%n$TYPE' syntax. In .NET, the syntax is '{n}'. This is useful to support localization strings that can change the parameter
|
||||
// ordering.
|
||||
// There are macro verions (MPT_FORMAT and variants) which properly use wide string literals for the format parameter.
|
||||
// 4. Every function is available for std::string, std::wstring and mpt::ustring. std::string makes no assumption about the encoding, which
|
||||
// basically means, it should work for any 7-bit or 8-bit encoding, including for example ASCII, UTF8 or the current locale encoding.
|
||||
// std::string std::wstring mpt::ustring CString
|
||||
// mpt::fmt::val mpt::wfmt::val mpt::ufmt::val mpt::tfmt::val
|
||||
// mpt::FormatVal mpt::FormatValW mpt::FormatValTFunctor<mpt::ustring>() mpt::FormatValTFunctor<Cstring>()
|
||||
// mpt::fmt mpt::wfmt mpt::ufmt mpt::tfmt
|
||||
// mpt::format mpt::format mpt::format mpt::format
|
||||
// std::string std::wstring mpt::ustring mpt::tsrtring CString
|
||||
// mpt::fmt mpt::wfmt mpt::ufmt mpt::tfmt mpt::cfmt
|
||||
// mpt::format("%1") mpt::wformat(L"%1") mpt::uformat(MPT_ULITERAL(%1) mpt::tformat(_T("%1")) mpt::cformat(_T("%1"))
|
||||
// mpt::format("%1") mpt::format(L"%1") mpt::format(MPT_USTRING(%1)) mpt::format(mpt::tstring(_T("%1")) mpt::format(CString(_T("%1"))
|
||||
// 5. All functionality here delegates real work outside of the header file so that <sstream> and <locale> do not need to be included when
|
||||
// using this functionality.
|
||||
// Advantages:
|
||||
|
@ -55,8 +55,8 @@ OPENMPT_NAMESPACE_BEGIN
|
|||
// - Faster compile times because <sstream> and <locale> (2 very complex headers) are not included everywhere.
|
||||
// Disadvantages:
|
||||
// - Slightly more c++ code is required for delegating work.
|
||||
// - As the header does not use iostreams, custom types need to overload mpt::String, mpt::ToWstring and mpt::UString instead of
|
||||
// iostream operator << to allow for custom type formatting.
|
||||
// - As the header does not use iostreams, custom types need to overload mpt::UString instead of iostream operator << to allow for custom type
|
||||
// formatting.
|
||||
// - std::string, std::wstring and mpt::ustring are returned from somewhat deep cascades of helper functions. Where possible, code is
|
||||
// written in such a way that return-value-optimization (RVO) or named-return-value-optimization (NRVO) should be able to eliminate
|
||||
// almost all these copies. This should not be a problem for any decent modern compiler (and even less so for a c++11 compiler where
|
||||
|
@ -65,12 +65,16 @@ OPENMPT_NAMESPACE_BEGIN
|
|||
namespace mpt
|
||||
{
|
||||
|
||||
// ToString() converts various built-in types to a well-defined, locale-independent string representation.
|
||||
// ToUString() converts various built-in types to a well-defined, locale-independent string representation.
|
||||
// This is also used as a type-tunnel pattern for mpt::format.
|
||||
// Custom types that need to be converted to strings are encouraged to overload ToString() and ToWString().
|
||||
// Custom types that need to be converted to strings are encouraged to overload ToUString().
|
||||
|
||||
// fallback to member function ToString()
|
||||
template <typename T> auto ToString(const T & x) -> decltype(x.ToString()) { return x.ToString(); }
|
||||
// fallback to member function ToUString()
|
||||
#if MPT_USTRING_MODE_UTF8
|
||||
template <typename T> auto ToString(const T & x) -> decltype(mpt::ToCharset(mpt::CharsetUTF8, x.ToUString())) { return mpt::ToCharset(mpt::CharsetUTF8, x.ToUString()); }
|
||||
#else
|
||||
template <typename T> auto ToString(const T & x) -> decltype(mpt::ToCharset(mpt::CharsetLocaleOrUTF8, x.ToUString())) { return mpt::ToCharset(mpt::CharsetLocaleOrUTF8, x.ToUString()); }
|
||||
#endif
|
||||
|
||||
static inline std::string ToString(const std::string & x) { return x; }
|
||||
static inline std::string ToString(const char * const & x) { return x; }
|
||||
|
@ -163,22 +167,18 @@ std::wstring ToWString(const unsigned long long & x);
|
|||
std::wstring ToWString(const float & x);
|
||||
std::wstring ToWString(const double & x);
|
||||
std::wstring ToWString(const long double & x);
|
||||
// fallback to member function ToUString()
|
||||
template <typename T> auto ToWString(const T & x) -> decltype(mpt::ToWide(x.ToUString())) { return mpt::ToWide(x.ToUString()); }
|
||||
#endif
|
||||
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
template <typename T> struct ToLocaleHelper { mpt::lstring operator () (const T & v) { return mpt::ToLocale(ToUString(v)); } };
|
||||
template <> struct ToLocaleHelper<mpt::lstring> { mpt::lstring operator () (const mpt::lstring & v) { return v; } };
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
|
||||
#if defined(_MFC_VER)
|
||||
#ifdef UNICODE
|
||||
#if MPT_WSTRING_FORMAT
|
||||
template <typename T> static inline CString ToCStringHelper(const T & x) { return mpt::ToCString(ToWString(x)); }
|
||||
#else
|
||||
template <typename T> static inline CString ToCStringHelper(const T & x) { return mpt::ToCString(ToUString(x)); }
|
||||
#endif
|
||||
#else
|
||||
namespace detail {
|
||||
template <typename T> struct CstringToStdStringImpl { CString operator () (const T & v) { return mpt::ToCString(mpt::CharsetLocale, ToString(v)); } };
|
||||
template <> struct CstringToStdStringImpl<CString> { CString operator () (const CString & v) { return v; } };
|
||||
}
|
||||
template <typename T> static inline CString ToCStringHelper(const T & x) { return mpt::detail::CstringToStdStringImpl<T>()(x); }
|
||||
#endif
|
||||
template <typename T> struct ToCStringHelper { CString operator () (const T & v) { return mpt::ToCString(ToUString(v)); } };
|
||||
template <> struct ToCStringHelper<CString> { CString operator () (const CString & v) { return v; } };
|
||||
#endif
|
||||
|
||||
template <typename Tstring> struct ToStringTFunctor {};
|
||||
|
@ -187,13 +187,17 @@ template <> struct ToStringTFunctor<mpt::ustring> { template <typename T> inline
|
|||
#if MPT_WSTRING_FORMAT && MPT_USTRING_MODE_UTF8
|
||||
template <> struct ToStringTFunctor<std::wstring> { template <typename T> inline std::wstring operator() (const T & x) { return ToWString(x); } };
|
||||
#endif
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
template <> struct ToStringTFunctor<mpt::lstring> { template <typename T> inline mpt::lstring operator() (const T & x) { return mpt::ToLocaleHelper<T>()(x); } };
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
#if defined(_MFC_VER)
|
||||
template <> struct ToStringTFunctor<CString> { template <typename T> inline CString operator() (const T & x) { return mpt::ToCStringHelper(x); } };
|
||||
template <> struct ToStringTFunctor<CString> { template <typename T> inline CString operator() (const T & x) { return mpt::ToCStringHelper<T>()(x); } };
|
||||
#endif
|
||||
|
||||
template<typename Tstring, typename T> inline Tstring ToStringT(const T & x) { return ToStringTFunctor<Tstring>()(x); }
|
||||
|
||||
|
||||
|
||||
struct fmt_base
|
||||
{
|
||||
|
||||
|
@ -204,7 +208,6 @@ enum FormatFlagsEnum
|
|||
CaseLow = 0x0010, // lower case hex digits
|
||||
CaseUpp = 0x0020, // upper case hex digits
|
||||
FillOff = 0x0100, // do not fill up width
|
||||
FillSpc = 0x0200, // fill up width with spaces
|
||||
FillNul = 0x0400, // fill up width with zeros
|
||||
NotaNrm = 0x1000, // float: normal/default notation
|
||||
NotaFix = 0x2000, // float: fixed point notation
|
||||
|
@ -220,7 +223,9 @@ STATIC_ASSERT(sizeof(FormatFlags) >= sizeof(fmt_base::FormatFlagsEnum));
|
|||
class FormatSpec;
|
||||
|
||||
MPT_DEPRECATED std::string FormatVal(const char & x, const FormatSpec & f); // deprecated to catch potential API mis-use, use std::string(1, x) instead
|
||||
#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR)
|
||||
MPT_DEPRECATED std::string FormatVal(const wchar_t & x, const FormatSpec & f); // deprecated to catch potential API mis-use, use std::wstring(1, x) instead
|
||||
#endif // !MPT_COMPILER_QUIRK_NO_WCHAR
|
||||
std::string FormatVal(const bool & x, const FormatSpec & f);
|
||||
std::string FormatVal(const signed char & x, const FormatSpec & f);
|
||||
std::string FormatVal(const unsigned char & x, const FormatSpec & f);
|
||||
|
@ -236,9 +241,30 @@ std::string FormatVal(const float & x, const FormatSpec & f);
|
|||
std::string FormatVal(const double & x, const FormatSpec & f);
|
||||
std::string FormatVal(const long double & x, const FormatSpec & f);
|
||||
|
||||
MPT_DEPRECATED mpt::ustring FormatValU(const char & x, const FormatSpec & f); // deprecated to catch potential API mis-use, use std::string(1, x) instead
|
||||
#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR)
|
||||
MPT_DEPRECATED mpt::ustring FormatValU(const wchar_t & x, const FormatSpec & f); // deprecated to catch potential API mis-use, use std::wstring(1, x) instead
|
||||
#endif // !MPT_COMPILER_QUIRK_NO_WCHAR
|
||||
mpt::ustring FormatValU(const bool & x, const FormatSpec & f);
|
||||
mpt::ustring FormatValU(const signed char & x, const FormatSpec & f);
|
||||
mpt::ustring FormatValU(const unsigned char & x, const FormatSpec & f);
|
||||
mpt::ustring FormatValU(const signed short & x, const FormatSpec & f);
|
||||
mpt::ustring FormatValU(const unsigned short & x, const FormatSpec & f);
|
||||
mpt::ustring FormatValU(const signed int & x, const FormatSpec & f);
|
||||
mpt::ustring FormatValU(const unsigned int & x, const FormatSpec & f);
|
||||
mpt::ustring FormatValU(const signed long & x, const FormatSpec & f);
|
||||
mpt::ustring FormatValU(const unsigned long & x, const FormatSpec & f);
|
||||
mpt::ustring FormatValU(const signed long long & x, const FormatSpec & f);
|
||||
mpt::ustring FormatValU(const unsigned long long & x, const FormatSpec & f);
|
||||
mpt::ustring FormatValU(const float & x, const FormatSpec & f);
|
||||
mpt::ustring FormatValU(const double & x, const FormatSpec & f);
|
||||
mpt::ustring FormatValU(const long double & x, const FormatSpec & f);
|
||||
|
||||
#if MPT_WSTRING_FORMAT
|
||||
MPT_DEPRECATED std::wstring FormatValW(const char & x, const FormatSpec & f); // deprecated to catch potential API mis-use, use std::string(1, x) instead
|
||||
#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR)
|
||||
MPT_DEPRECATED std::wstring FormatValW(const wchar_t & x, const FormatSpec & f); // deprecated to catch potential API mis-use, use std::wstring(1, x) instead
|
||||
#endif // !MPT_COMPILER_QUIRK_NO_WCHAR
|
||||
std::wstring FormatValW(const bool & x, const FormatSpec & f);
|
||||
std::wstring FormatValW(const signed char & x, const FormatSpec & f);
|
||||
std::wstring FormatValW(const unsigned char & x, const FormatSpec & f);
|
||||
|
@ -257,12 +283,13 @@ std::wstring FormatValW(const long double & x, const FormatSpec & f);
|
|||
|
||||
template <typename Tstring> struct FormatValTFunctor {};
|
||||
template <> struct FormatValTFunctor<std::string> { template <typename T> inline std::string operator() (const T & x, const FormatSpec & f) { return FormatVal(x, f); } };
|
||||
#if MPT_WSTRING_FORMAT
|
||||
template <> struct FormatValTFunctor<mpt::ustring> { template <typename T> inline mpt::ustring operator() (const T & x, const FormatSpec & f) { return FormatValU(x, f); } };
|
||||
#if MPT_USTRING_MODE_UTF8 && MPT_WSTRING_FORMAT
|
||||
template <> struct FormatValTFunctor<std::wstring> { template <typename T> inline std::wstring operator() (const T & x, const FormatSpec & f) { return FormatValW(x, f); } };
|
||||
#endif
|
||||
#if MPT_USTRING_MODE_UTF8
|
||||
template <> struct FormatValTFunctor<mpt::ustring> { template <typename T> inline mpt::ustring operator() (const T & x, const FormatSpec & f) { return mpt::ToUnicode(mpt::CharsetUTF8, FormatVal(x, f)); } };
|
||||
#endif
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
template <> struct FormatValTFunctor<mpt::lstring> { template <typename T> inline mpt::lstring operator() (const T & x, const FormatSpec & f) { return mpt::ToLocale(mpt::CharsetLocale, FormatVal(x, f)); } };
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
#if defined(_MFC_VER)
|
||||
#ifdef UNICODE
|
||||
template <> struct FormatValTFunctor<CString> { template <typename T> inline CString operator() (const T & x, const FormatSpec & f) { return mpt::ToCString(FormatValW(x, f)); } };
|
||||
|
@ -278,80 +305,55 @@ private:
|
|||
FormatFlags flags;
|
||||
std::size_t width;
|
||||
int precision;
|
||||
unsigned int group;
|
||||
char group_sep;
|
||||
public:
|
||||
FormatSpec() : flags(0), width(0), precision(-1) {}
|
||||
FormatFlags GetFlags() const { return flags; }
|
||||
std::size_t GetWidth() const { return width; }
|
||||
int GetPrecision() const { return precision; }
|
||||
FormatSpec & SetFlags(FormatFlags f) { flags = f; return *this; }
|
||||
FormatSpec & SetWidth(std::size_t w) { width = w; return *this; }
|
||||
FormatSpec & SetPrecision(int p) { precision = p; return *this; }
|
||||
MPT_CONSTEXPR11_FUN FormatSpec() noexcept : flags(0), width(0), precision(-1), group(0), group_sep(',') {}
|
||||
MPT_CONSTEXPR11_FUN FormatFlags GetFlags() const noexcept { return flags; }
|
||||
MPT_CONSTEXPR11_FUN std::size_t GetWidth() const noexcept { return width; }
|
||||
MPT_CONSTEXPR11_FUN int GetPrecision() const noexcept { return precision; }
|
||||
MPT_CONSTEXPR11_FUN unsigned int GetGroup() const noexcept { return group; }
|
||||
MPT_CONSTEXPR11_FUN char GetGroupSep() const noexcept { return group_sep; }
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & SetFlags(FormatFlags f) noexcept { flags = f; return *this; }
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & SetWidth(std::size_t w) noexcept { width = w; return *this; }
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & SetPrecision(int p) noexcept { precision = p; return *this; }
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & SetGroup(unsigned int g) noexcept { group = g; return *this; }
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & SetGroupSep(char s) noexcept { group_sep = s; return *this; }
|
||||
public:
|
||||
// short-hand construction
|
||||
explicit FormatSpec(FormatFlags f, std::size_t w = 0, int p = -1) : flags(f), width(w), precision(p) {}
|
||||
explicit FormatSpec(const char * format) : flags(0), width(0), precision(-1) { ParsePrintf(format); }
|
||||
explicit FormatSpec(const wchar_t * format) : flags(0), width(0), precision(-1) { ParsePrintf(format); }
|
||||
explicit FormatSpec(const std::string & format) : flags(0), width(0), precision(-1) { ParsePrintf(format); }
|
||||
explicit FormatSpec(const std::wstring & format) : flags(0), width(0), precision(-1) { ParsePrintf(format); }
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & BaseDec() noexcept { flags &= ~(fmt_base::BaseDec|fmt_base::BaseHex); flags |= fmt_base::BaseDec; return *this; }
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & BaseHex() noexcept { flags &= ~(fmt_base::BaseDec|fmt_base::BaseHex); flags |= fmt_base::BaseHex; return *this; }
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & CaseLow() noexcept { flags &= ~(fmt_base::CaseLow|fmt_base::CaseUpp); flags |= fmt_base::CaseLow; return *this; }
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & CaseUpp() noexcept { flags &= ~(fmt_base::CaseLow|fmt_base::CaseUpp); flags |= fmt_base::CaseUpp; return *this; }
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & FillOff() noexcept { flags &= ~(fmt_base::FillOff|fmt_base::FillNul); flags |= fmt_base::FillOff; return *this; }
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & FillNul() noexcept { flags &= ~(fmt_base::FillOff|fmt_base::FillNul); flags |= fmt_base::FillNul; return *this; }
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & NotaNrm() noexcept { flags &= ~(fmt_base::NotaNrm|fmt_base::NotaFix|fmt_base::NotaSci); flags |= fmt_base::NotaNrm; return *this; }
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & NotaFix() noexcept { flags &= ~(fmt_base::NotaNrm|fmt_base::NotaFix|fmt_base::NotaSci); flags |= fmt_base::NotaFix; return *this; }
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & NotaSci() noexcept { flags &= ~(fmt_base::NotaNrm|fmt_base::NotaFix|fmt_base::NotaSci); flags |= fmt_base::NotaSci; return *this; }
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & Width(std::size_t w) noexcept { width = w; return *this; }
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & Prec(int p) noexcept { precision = p; return *this; }
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & Group(unsigned int g) noexcept { group = g; return *this; }
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & GroupSep(char s) noexcept { group_sep = s; return *this; }
|
||||
public:
|
||||
// only for floating point formats
|
||||
FormatSpec & ParsePrintf(const char * format);
|
||||
FormatSpec & ParsePrintf(const wchar_t * format);
|
||||
FormatSpec & ParsePrintf(const std::string & format);
|
||||
FormatSpec & ParsePrintf(const std::wstring & format);
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & Dec() noexcept { return BaseDec(); }
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & Hex() noexcept { return BaseHex(); }
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & Low() noexcept { return CaseLow(); }
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & Upp() noexcept { return CaseUpp(); }
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & Off() noexcept { return FillOff(); }
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & Nul() noexcept { return FillNul(); }
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & Nrm() noexcept { return NotaNrm(); }
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & Fix() noexcept { return NotaFix(); }
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & Sci() noexcept { return NotaSci(); }
|
||||
public:
|
||||
FormatSpec & BaseDec() { flags &= ~(fmt_base::BaseDec|fmt_base::BaseHex); flags |= fmt_base::BaseDec; return *this; }
|
||||
FormatSpec & BaseHex() { flags &= ~(fmt_base::BaseDec|fmt_base::BaseHex); flags |= fmt_base::BaseHex; return *this; }
|
||||
FormatSpec & CaseLow() { flags &= ~(fmt_base::CaseLow|fmt_base::CaseUpp); flags |= fmt_base::CaseLow; return *this; }
|
||||
FormatSpec & CaseUpp() { flags &= ~(fmt_base::CaseLow|fmt_base::CaseUpp); flags |= fmt_base::CaseUpp; return *this; }
|
||||
FormatSpec & FillOff() { flags &= ~(fmt_base::FillOff|fmt_base::FillSpc|fmt_base::FillNul); flags |= fmt_base::FillOff; return *this; }
|
||||
FormatSpec & FillSpc() { flags &= ~(fmt_base::FillOff|fmt_base::FillSpc|fmt_base::FillNul); flags |= fmt_base::FillSpc; return *this; }
|
||||
FormatSpec & FillNul() { flags &= ~(fmt_base::FillOff|fmt_base::FillSpc|fmt_base::FillNul); flags |= fmt_base::FillNul; return *this; }
|
||||
FormatSpec & NotaNrm() { flags &= ~(fmt_base::NotaNrm|fmt_base::NotaFix|fmt_base::NotaSci); flags |= fmt_base::NotaNrm; return *this; }
|
||||
FormatSpec & NotaFix() { flags &= ~(fmt_base::NotaNrm|fmt_base::NotaFix|fmt_base::NotaSci); flags |= fmt_base::NotaFix; return *this; }
|
||||
FormatSpec & NotaSci() { flags &= ~(fmt_base::NotaNrm|fmt_base::NotaFix|fmt_base::NotaSci); flags |= fmt_base::NotaSci; return *this; }
|
||||
FormatSpec & Width(std::size_t w) { width = w; return *this; }
|
||||
FormatSpec & Prec(int p) { precision = p; return *this; }
|
||||
public:
|
||||
FormatSpec & Dec() { return BaseDec(); }
|
||||
FormatSpec & Hex() { return BaseHex(); }
|
||||
FormatSpec & Low() { return CaseLow(); }
|
||||
FormatSpec & Upp() { return CaseUpp(); }
|
||||
FormatSpec & Off() { return FillOff(); }
|
||||
FormatSpec & Spc() { return FillSpc(); }
|
||||
FormatSpec & Nul() { return FillNul(); }
|
||||
FormatSpec & Nrm() { return NotaNrm(); }
|
||||
FormatSpec & Fix() { return NotaFix(); }
|
||||
FormatSpec & Sci() { return NotaSci(); }
|
||||
public:
|
||||
FormatSpec & Decimal() { return BaseDec(); }
|
||||
FormatSpec & Hexadecimal() { return BaseHex(); }
|
||||
FormatSpec & Lower() { return CaseLow(); }
|
||||
FormatSpec & Upper() { return CaseUpp(); }
|
||||
FormatSpec & FillNone() { return FillOff(); }
|
||||
FormatSpec & FillSpace() { return FillSpc(); }
|
||||
FormatSpec & FillZero() { return FillNul(); }
|
||||
FormatSpec & FloatNormal() { return NotaNrm(); }
|
||||
FormatSpec & FloatFixed() { return NotaFix(); }
|
||||
FormatSpec & FloatScientific() { return NotaSci(); }
|
||||
FormatSpec & Precision(int p) { return Prec(p); }
|
||||
template<typename Tstring, typename T>
|
||||
inline Tstring ToStringT(const T & x) const
|
||||
{
|
||||
return FormatValTFunctor<Tstring>()(x, *this);
|
||||
}
|
||||
template<typename T>
|
||||
inline std::string ToString(const T & x) const
|
||||
{
|
||||
return FormatVal(x, *this);
|
||||
}
|
||||
#if MPT_WSTRING_FORMAT
|
||||
template<typename T>
|
||||
inline std::wstring ToWString(const T & x) const
|
||||
{
|
||||
return FormatValW(x, *this);
|
||||
}
|
||||
#endif
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & Decimal() noexcept { return BaseDec(); }
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & Hexadecimal() noexcept { return BaseHex(); }
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & Lower() noexcept { return CaseLow(); }
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & Upper() noexcept { return CaseUpp(); }
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & FillNone() noexcept { return FillOff(); }
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & FillZero() noexcept { return FillNul(); }
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & FloatNormal() noexcept { return NotaNrm(); }
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & FloatFixed() noexcept { return NotaFix(); }
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & FloatScientific() noexcept { return NotaSci(); }
|
||||
MPT_CONSTEXPR14_FUN FormatSpec & Precision(int p) noexcept { return Prec(p); }
|
||||
};
|
||||
|
||||
|
||||
|
@ -365,6 +367,12 @@ static inline Tstring val(const T& x)
|
|||
return ToStringTFunctor<Tstring>()(x);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline Tstring fmt(const T& x, const FormatSpec& f)
|
||||
{
|
||||
return FormatValTFunctor<Tstring>()(x, f);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline Tstring dec(const T& x)
|
||||
{
|
||||
|
@ -372,18 +380,25 @@ static inline Tstring dec(const T& x)
|
|||
return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseDec().FillOff());
|
||||
}
|
||||
template<int width, typename T>
|
||||
static inline Tstring dec(const T& x)
|
||||
{
|
||||
STATIC_ASSERT(std::numeric_limits<T>::is_integer);
|
||||
return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseDec().FillSpc().Width(width));
|
||||
}
|
||||
template<int width, typename T>
|
||||
static inline Tstring dec0(const T& x)
|
||||
{
|
||||
STATIC_ASSERT(std::numeric_limits<T>::is_integer);
|
||||
return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseDec().FillNul().Width(width));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline Tstring dec(unsigned int g, char s, const T& x)
|
||||
{
|
||||
STATIC_ASSERT(std::numeric_limits<T>::is_integer);
|
||||
return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseDec().FillOff().Group(g).GroupSep(s));
|
||||
}
|
||||
template<int width, typename T>
|
||||
static inline Tstring dec0(unsigned int g, char s, const T& x)
|
||||
{
|
||||
STATIC_ASSERT(std::numeric_limits<T>::is_integer);
|
||||
return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseDec().FillNul().Width(width).Group(g).GroupSep(s));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline Tstring hex(const T& x)
|
||||
{
|
||||
|
@ -397,18 +412,6 @@ static inline Tstring HEX(const T& x)
|
|||
return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseHex().CaseUpp().FillOff());
|
||||
}
|
||||
template<int width, typename T>
|
||||
static inline Tstring hex(const T& x)
|
||||
{
|
||||
STATIC_ASSERT(std::numeric_limits<T>::is_integer);
|
||||
return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseHex().CaseLow().FillSpc().Width(width));
|
||||
}
|
||||
template<int width, typename T>
|
||||
static inline Tstring HEX(const T& x)
|
||||
{
|
||||
STATIC_ASSERT(std::numeric_limits<T>::is_integer);
|
||||
return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseHex().CaseUpp().FillSpc().Width(width));
|
||||
}
|
||||
template<int width, typename T>
|
||||
static inline Tstring hex0(const T& x)
|
||||
{
|
||||
STATIC_ASSERT(std::numeric_limits<T>::is_integer);
|
||||
|
@ -422,51 +425,83 @@ static inline Tstring HEX0(const T& x)
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
static inline Tstring flt(const T& x, std::size_t width = 0, int precision = -1)
|
||||
static inline Tstring hex(unsigned int g, char s, const T& x)
|
||||
{
|
||||
STATIC_ASSERT(std::is_floating_point<T>::value);
|
||||
if(width == 0)
|
||||
{
|
||||
return FormatValTFunctor<Tstring>()(x, FormatSpec().NotaNrm().FillOff().Precision(precision));
|
||||
} else
|
||||
{
|
||||
return FormatValTFunctor<Tstring>()(x, FormatSpec().NotaNrm().FillSpc().Width(width).Precision(precision));
|
||||
}
|
||||
STATIC_ASSERT(std::numeric_limits<T>::is_integer);
|
||||
return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseHex().CaseLow().FillOff().Group(g).GroupSep(s));
|
||||
}
|
||||
template<typename T>
|
||||
static inline Tstring fix(const T& x, std::size_t width = 0, int precision = -1)
|
||||
static inline Tstring HEX(unsigned int g, char s, const T& x)
|
||||
{
|
||||
STATIC_ASSERT(std::is_floating_point<T>::value);
|
||||
if(width == 0)
|
||||
{
|
||||
return FormatValTFunctor<Tstring>()(x, FormatSpec().NotaFix().FillOff().Precision(precision));
|
||||
} else
|
||||
{
|
||||
return FormatValTFunctor<Tstring>()(x, FormatSpec().NotaFix().FillSpc().Width(width).Precision(precision));
|
||||
}
|
||||
STATIC_ASSERT(std::numeric_limits<T>::is_integer);
|
||||
return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseHex().CaseUpp().FillOff().Group(g).GroupSep(s));
|
||||
}
|
||||
template<typename T>
|
||||
static inline Tstring sci(const T& x, std::size_t width = 0, int precision = -1)
|
||||
template<int width, typename T>
|
||||
static inline Tstring hex0(unsigned int g, char s, const T& x)
|
||||
{
|
||||
STATIC_ASSERT(std::is_floating_point<T>::value);
|
||||
if(width == 0)
|
||||
{
|
||||
return FormatValTFunctor<Tstring>()(x, FormatSpec().NotaSci().FillOff().Precision(precision));
|
||||
} else
|
||||
{
|
||||
return FormatValTFunctor<Tstring>()(x, FormatSpec().NotaSci().FillSpc().Width(width).Precision(precision));
|
||||
}
|
||||
STATIC_ASSERT(std::numeric_limits<T>::is_integer);
|
||||
return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseHex().CaseLow().FillNul().Width(width).Group(g).GroupSep(s));
|
||||
}
|
||||
template<int width, typename T>
|
||||
static inline Tstring HEX0(unsigned int g, char s, const T& x)
|
||||
{
|
||||
STATIC_ASSERT(std::numeric_limits<T>::is_integer);
|
||||
return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseHex().CaseUpp().FillNul().Width(width).Group(g).GroupSep(s));
|
||||
}
|
||||
|
||||
template <typename T, typename Tformat>
|
||||
static inline Tstring f(const Tformat & format, const T& x)
|
||||
template<typename T>
|
||||
static inline Tstring flt(const T& x, int precision = -1)
|
||||
{
|
||||
STATIC_ASSERT(std::is_floating_point<T>::value);
|
||||
return FormatValTFunctor<Tstring>()(x, FormatSpec().ParsePrintf(format));
|
||||
return FormatValTFunctor<Tstring>()(x, FormatSpec().NotaNrm().FillOff().Precision(precision));
|
||||
}
|
||||
template<typename T>
|
||||
static inline Tstring fix(const T& x, int precision = -1)
|
||||
{
|
||||
STATIC_ASSERT(std::is_floating_point<T>::value);
|
||||
return FormatValTFunctor<Tstring>()(x, FormatSpec().NotaFix().FillOff().Precision(precision));
|
||||
}
|
||||
template<typename T>
|
||||
static inline Tstring sci(const T& x, int precision = -1)
|
||||
{
|
||||
STATIC_ASSERT(std::is_floating_point<T>::value);
|
||||
return FormatValTFunctor<Tstring>()(x, FormatSpec().NotaSci().FillOff().Precision(precision));
|
||||
}
|
||||
|
||||
static inline Tstring pad_left(std::size_t width_, const Tstring &str)
|
||||
{
|
||||
typedef mpt::string_traits<Tstring> traits;
|
||||
typename traits::size_type width = static_cast<typename traits::size_type>(width_);
|
||||
return traits::pad(str, width, 0);
|
||||
}
|
||||
static inline Tstring pad_right(std::size_t width_, const Tstring &str)
|
||||
{
|
||||
typedef mpt::string_traits<Tstring> traits;
|
||||
typename traits::size_type width = static_cast<typename traits::size_type>(width_);
|
||||
return traits::pad(str, 0, width);
|
||||
}
|
||||
static inline Tstring left(std::size_t width_, const Tstring &str)
|
||||
{
|
||||
typedef mpt::string_traits<Tstring> traits;
|
||||
typename traits::size_type width = static_cast<typename traits::size_type>(width_);
|
||||
return (traits::length(str) < width) ? traits::pad(str, 0, width - traits::length(str)) : str;
|
||||
}
|
||||
static inline Tstring right(std::size_t width_, const Tstring &str)
|
||||
{
|
||||
typedef mpt::string_traits<Tstring> traits;
|
||||
typename traits::size_type width = static_cast<typename traits::size_type>(width_);
|
||||
return (traits::length(str) < width) ? traits::pad(str, width - traits::length(str), 0) : str;
|
||||
}
|
||||
static inline Tstring center(std::size_t width_, const Tstring &str)
|
||||
{
|
||||
typedef mpt::string_traits<Tstring> traits;
|
||||
typename traits::size_type width = static_cast<typename traits::size_type>(width_);
|
||||
return (traits::length(str) < width) ? traits::pad(str, (width - traits::length(str)) / 2, (width - traits::length(str) + 1) / 2) : str;
|
||||
}
|
||||
|
||||
}; // struct fmtT
|
||||
|
||||
|
||||
typedef fmtT<std::string> fmt;
|
||||
#if MPT_WSTRING_FORMAT
|
||||
typedef fmtT<std::wstring> wfmt;
|
||||
|
@ -476,8 +511,14 @@ typedef fmtT<std::wstring> ufmt;
|
|||
#else
|
||||
typedef fmtT<mpt::ustring> ufmt;
|
||||
#endif
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
typedef fmtT<mpt::lstring> lfmt;
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
#if MPT_OS_WINDOWS
|
||||
typedef fmtT<mpt::tstring> tfmt;
|
||||
#endif
|
||||
#if defined(_MFC_VER)
|
||||
typedef fmtT<CString> tfmt;
|
||||
typedef fmtT<CString> cfmt;
|
||||
#endif
|
||||
|
||||
} // namespace mpt
|
||||
|
@ -495,14 +536,19 @@ template <> struct to_string_type<char > { typedef std::string type;
|
|||
template <> struct to_string_type<char * > { typedef std::string type; };
|
||||
template <> struct to_string_type<const char > { typedef std::string type; };
|
||||
template <> struct to_string_type<const char * > { typedef std::string type; };
|
||||
#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR)
|
||||
template <> struct to_string_type<std::wstring > { typedef std::wstring type; };
|
||||
template <> struct to_string_type<wchar_t > { typedef std::wstring type; };
|
||||
template <> struct to_string_type<wchar_t * > { typedef std::wstring type; };
|
||||
template <> struct to_string_type<const wchar_t > { typedef std::wstring type; };
|
||||
template <> struct to_string_type<const wchar_t *> { typedef std::wstring type; };
|
||||
#endif // !MPT_COMPILER_QUIRK_NO_WCHAR
|
||||
#if MPT_USTRING_MODE_UTF8
|
||||
template <> struct to_string_type<mpt::ustring > { typedef mpt::ustring type; };
|
||||
#endif
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
template <> struct to_string_type<mpt::lstring > { typedef mpt::lstring type; };
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
#if defined(_MFC_VER)
|
||||
template <> struct to_string_type<CString > { typedef CString type; };
|
||||
#endif
|
||||
|
@ -545,6 +591,19 @@ mpt::ustring PrintImpl(const mpt::ustring & format
|
|||
);
|
||||
#endif
|
||||
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
mpt::lstring PrintImpl(const mpt::lstring & format
|
||||
, const mpt::lstring & x1 = mpt::lstring()
|
||||
, const mpt::lstring & x2 = mpt::lstring()
|
||||
, const mpt::lstring & x3 = mpt::lstring()
|
||||
, const mpt::lstring & x4 = mpt::lstring()
|
||||
, const mpt::lstring & x5 = mpt::lstring()
|
||||
, const mpt::lstring & x6 = mpt::lstring()
|
||||
, const mpt::lstring & x7 = mpt::lstring()
|
||||
, const mpt::lstring & x8 = mpt::lstring()
|
||||
);
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
|
||||
#if defined(_MFC_VER)
|
||||
CString PrintImpl(const CString & format
|
||||
, const CString & x1 = CString()
|
||||
|
@ -769,8 +828,22 @@ static inline message_formatter<mpt::ustring> uformat(const mpt::ustring &format
|
|||
return message_formatter<mpt::ustring>(format);
|
||||
}
|
||||
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
static inline message_formatter<mpt::lstring> lformat(const mpt::lstring &format)
|
||||
{
|
||||
return message_formatter<mpt::lstring>(format);
|
||||
}
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
static inline message_formatter<mpt::tstring> tformat(const mpt::tstring &format)
|
||||
{
|
||||
return message_formatter<mpt::tstring>(format);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_MFC_VER)
|
||||
static inline message_formatter<CString> tformat(const CString &format)
|
||||
static inline message_formatter<CString> cformat(const CString &format)
|
||||
{
|
||||
return message_formatter<CString>(format);
|
||||
}
|
||||
|
@ -779,4 +852,42 @@ static inline message_formatter<CString> tformat(const CString &format)
|
|||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
namespace mpt { namespace String {
|
||||
|
||||
// Combine a vector of values into a string, separated with the given separator.
|
||||
// No escaping is performed.
|
||||
template<typename T>
|
||||
mpt::ustring Combine(const std::vector<T> &vals, const mpt::ustring &sep=U_(","))
|
||||
{
|
||||
mpt::ustring str;
|
||||
for(std::size_t i = 0; i < vals.size(); ++i)
|
||||
{
|
||||
if(i > 0)
|
||||
{
|
||||
str += sep;
|
||||
}
|
||||
str += mpt::ufmt::val(vals[i]);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
template<typename T>
|
||||
std::string Combine(const std::vector<T> &vals, const std::string &sep=std::string(","))
|
||||
{
|
||||
std::string str;
|
||||
for(std::size_t i = 0; i < vals.size(); ++i)
|
||||
{
|
||||
if(i > 0)
|
||||
{
|
||||
str += sep;
|
||||
}
|
||||
str += mpt::fmt::val(vals[i]);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
} } // namespace mpt::String
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
@ -129,6 +131,15 @@ template<> inline std::wstring ConvertStrTo(const mpt::ustring &str) { return mp
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
template<typename T>
|
||||
inline T ConvertStrTo(const mpt::lstring &str)
|
||||
{
|
||||
return ConvertStrTo<T>(mpt::ToCharset(mpt::CharsetLocale, str));
|
||||
}
|
||||
template<> inline mpt::lstring ConvertStrTo(const mpt::lstring &str) { return str; }
|
||||
#endif
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
@ -193,4 +204,47 @@ inline T Hex(const mpt::ustring &str)
|
|||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
namespace mpt { namespace String {
|
||||
|
||||
// Split the given string at separator positions into individual values returned as a vector.
|
||||
// An empty string results in an empty vector.
|
||||
// Leading or trailing separators result in a default-constructed element being inserted before or after the other elements.
|
||||
template<typename T>
|
||||
std::vector<T> Split(const mpt::ustring &str, const mpt::ustring &sep=U_(","))
|
||||
{
|
||||
std::vector<T> vals;
|
||||
std::size_t pos = 0;
|
||||
while(str.find(sep, pos) != std::string::npos)
|
||||
{
|
||||
vals.push_back(ConvertStrTo<T>(str.substr(pos, str.find(sep, pos) - pos)));
|
||||
pos = str.find(sep, pos) + sep.length();
|
||||
}
|
||||
if(!vals.empty() || (str.substr(pos).length() > 0))
|
||||
{
|
||||
vals.push_back(ConvertStrTo<T>(str.substr(pos)));
|
||||
}
|
||||
return vals;
|
||||
}
|
||||
template<typename T>
|
||||
std::vector<T> Split(const std::string &str, const std::string &sep=std::string(","))
|
||||
{
|
||||
std::vector<T> vals;
|
||||
std::size_t pos = 0;
|
||||
while(str.find(sep, pos) != std::string::npos)
|
||||
{
|
||||
vals.push_back(ConvertStrTo<T>(str.substr(pos, str.find(sep, pos) - pos)));
|
||||
pos = str.find(sep, pos) + sep.length();
|
||||
}
|
||||
if(!vals.empty() || (str.substr(pos).length() > 0))
|
||||
{
|
||||
vals.push_back(ConvertStrTo<T>(str.substr(pos)));
|
||||
}
|
||||
return vals;
|
||||
}
|
||||
|
||||
} } // namespace mpt::String
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
||||
|
|
|
@ -9,37 +9,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
#if defined(MPT_ENABLE_THREAD)
|
||||
|
||||
#include <vector> // some C++ header in order to have the C++ standard library version information available
|
||||
|
||||
#if defined(MPT_QUIRK_NO_CPP_THREAD)
|
||||
#define MPT_STD_THREAD 0
|
||||
#elif MPT_COMPILER_GENERIC
|
||||
#define MPT_STD_THREAD 1
|
||||
#elif MPT_COMPILER_MSVC
|
||||
#define MPT_STD_THREAD 1
|
||||
#elif MPT_COMPILER_GCC && !MPT_OS_WINDOWS
|
||||
#define MPT_STD_THREAD 1
|
||||
#elif MPT_COMPILER_CLANG && defined(__GLIBCXX__)
|
||||
#define MPT_STD_THREAD 1
|
||||
#elif (MPT_OS_MACOSX_OR_IOS || MPT_OS_FREEBSD) && MPT_COMPILER_CLANG
|
||||
#define MPT_STD_THREAD 1
|
||||
#elif MPT_CLANG_AT_LEAST(3,6,0) && defined(_LIBCPP_VERSION)
|
||||
#define MPT_STD_THREAD 1
|
||||
#else
|
||||
#define MPT_STD_THREAD 0
|
||||
#endif
|
||||
|
||||
#if MPT_STD_THREAD
|
||||
#include <thread>
|
||||
#else // !MPT_STD_THREAD
|
||||
#if MPT_OS_WINDOWS
|
||||
#include <windows.h>
|
||||
#else // !MPT_OS_WINDOWS
|
||||
#include <pthread.h>
|
||||
#endif // MPT_OS_WINDOWS
|
||||
#endif // MPT_STD_THREAD
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
#if MPT_OS_WINDOWS
|
||||
|
@ -59,303 +33,9 @@ namespace mpt
|
|||
{
|
||||
|
||||
|
||||
|
||||
#if MPT_STD_THREAD
|
||||
|
||||
|
||||
|
||||
typedef std::thread::native_handle_type native_handle_type;
|
||||
typedef std::thread thread;
|
||||
|
||||
|
||||
|
||||
#else // !MPT_STD_THREAD
|
||||
|
||||
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
|
||||
|
||||
typedef HANDLE native_handle_type;
|
||||
|
||||
// std::thread
|
||||
// NOTE: This implementation is not movable and prevents copying.
|
||||
// Therefore, it is not as versatile as a full C++11 std::thread implementation.
|
||||
// It is only a strict subset.
|
||||
class thread
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
thread(const thread &) = delete;
|
||||
thread & operator = (const thread &) = delete;
|
||||
|
||||
private:
|
||||
|
||||
class functor_helper_base {
|
||||
protected:
|
||||
functor_helper_base() {}
|
||||
public:
|
||||
virtual ~functor_helper_base() {}
|
||||
public:
|
||||
virtual void operator () () = 0;
|
||||
};
|
||||
|
||||
template<typename Tfunc>
|
||||
class functor_helper : public functor_helper_base {
|
||||
private:
|
||||
Tfunc func;
|
||||
public:
|
||||
functor_helper(Tfunc func_) : func(func_) { return; }
|
||||
virtual ~functor_helper() { return; }
|
||||
virtual void operator () () { func(); }
|
||||
};
|
||||
|
||||
enum FunctionMode
|
||||
{
|
||||
FunctionModeNone = 0,
|
||||
FunctionModeParamNone = 1,
|
||||
FunctionModeParamPointer = 2,
|
||||
FunctionModeFunctor = 3,
|
||||
};
|
||||
|
||||
native_handle_type threadHandle;
|
||||
|
||||
// Thread startup accesses members of mpt::thread.
|
||||
// If the mpt::thread instanced gets detached and destroyed directly after initialization,
|
||||
// there is a race between thread startup and detach/destroy.
|
||||
// startupDoneEvent protects against this race.
|
||||
HANDLE startupDoneEvent;
|
||||
|
||||
FunctionMode functionMode;
|
||||
union {
|
||||
struct {
|
||||
void (*function)(void);
|
||||
} ModeParamNone;
|
||||
struct {
|
||||
void (*function)(void*);
|
||||
void * userdata;
|
||||
} ModeParamPointer;
|
||||
struct {
|
||||
functor_helper_base * pfunctor;
|
||||
} ModeFunctor;
|
||||
} modeState;
|
||||
|
||||
private:
|
||||
|
||||
uintptr_t ThreadFuntion()
|
||||
{
|
||||
switch(functionMode)
|
||||
{
|
||||
case FunctionModeNone:
|
||||
SetEvent(startupDoneEvent);
|
||||
return 0;
|
||||
break;
|
||||
case FunctionModeParamNone:
|
||||
{
|
||||
void (*f)(void) = modeState.ModeParamNone.function;
|
||||
SetEvent(startupDoneEvent);
|
||||
f();
|
||||
}
|
||||
return 0;
|
||||
break;
|
||||
case FunctionModeParamPointer:
|
||||
{
|
||||
void (*f)(void*) = modeState.ModeParamPointer.function;
|
||||
void * d = modeState.ModeParamPointer.userdata;
|
||||
SetEvent(startupDoneEvent);
|
||||
f(d);
|
||||
}
|
||||
return 0;
|
||||
break;
|
||||
case FunctionModeFunctor:
|
||||
{
|
||||
functor_helper_base * pf = modeState.ModeFunctor.pfunctor;
|
||||
SetEvent(startupDoneEvent);
|
||||
(*pf)();
|
||||
delete pf;
|
||||
}
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
SetEvent(startupDoneEvent);
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
SetEvent(startupDoneEvent);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DWORD WINAPI ThreadFunctionWrapper(LPVOID param)
|
||||
{
|
||||
reinterpret_cast<mpt::thread*>(param)->ThreadFuntion();
|
||||
return 0;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
mpt::native_handle_type native_handle()
|
||||
{
|
||||
return threadHandle;
|
||||
}
|
||||
|
||||
bool joinable() const
|
||||
{
|
||||
return (threadHandle != nullptr);
|
||||
}
|
||||
|
||||
void join()
|
||||
{
|
||||
if(!joinable())
|
||||
{
|
||||
throw std::invalid_argument("thread::joinable() == false");
|
||||
}
|
||||
WaitForSingleObject(threadHandle, INFINITE);
|
||||
CloseHandle(threadHandle);
|
||||
threadHandle = nullptr;
|
||||
}
|
||||
|
||||
void detach()
|
||||
{
|
||||
if(!joinable())
|
||||
{
|
||||
throw std::invalid_argument("thread::joinable() == false");
|
||||
}
|
||||
CloseHandle(threadHandle);
|
||||
threadHandle = nullptr;
|
||||
}
|
||||
|
||||
void swap(thread & other) noexcept
|
||||
{
|
||||
using std::swap;
|
||||
swap(threadHandle, other.threadHandle);
|
||||
swap(startupDoneEvent, other.startupDoneEvent);
|
||||
swap(functionMode, other.functionMode);
|
||||
}
|
||||
|
||||
friend void swap(thread & a, thread & b) noexcept
|
||||
{
|
||||
a.swap(b);
|
||||
}
|
||||
|
||||
thread(thread && other) noexcept
|
||||
: threadHandle(nullptr)
|
||||
, startupDoneEvent(nullptr)
|
||||
, functionMode(FunctionModeNone)
|
||||
{
|
||||
swap(other);
|
||||
}
|
||||
|
||||
thread & operator=(thread && other) noexcept
|
||||
{
|
||||
if(joinable())
|
||||
{
|
||||
std::terminate();
|
||||
}
|
||||
swap(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
thread()
|
||||
: threadHandle(nullptr)
|
||||
, startupDoneEvent(nullptr)
|
||||
, functionMode(FunctionModeNone)
|
||||
{
|
||||
std::memset(&modeState, 0, sizeof(modeState));
|
||||
}
|
||||
|
||||
thread(void (*function)(void))
|
||||
: threadHandle(nullptr)
|
||||
, startupDoneEvent(nullptr)
|
||||
, functionMode(FunctionModeParamNone)
|
||||
{
|
||||
std::memset(&modeState, 0, sizeof(modeState));
|
||||
modeState.ModeParamNone.function = function;
|
||||
startupDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
if(!startupDoneEvent) { throw std::runtime_error("unable to start thread"); }
|
||||
DWORD dummy = 0; // For Win9x
|
||||
threadHandle = CreateThread(NULL, 0, ThreadFunctionWrapper, this, 0, &dummy);
|
||||
if(threadHandle)
|
||||
{
|
||||
WaitForSingleObject(startupDoneEvent, INFINITE);
|
||||
}
|
||||
CloseHandle(startupDoneEvent);
|
||||
startupDoneEvent = nullptr;
|
||||
if(!threadHandle) { throw std::runtime_error("unable to start thread"); }
|
||||
}
|
||||
|
||||
thread(void (*function)(void*), void * userdata)
|
||||
: threadHandle(nullptr)
|
||||
, startupDoneEvent(nullptr)
|
||||
, functionMode(FunctionModeParamPointer)
|
||||
{
|
||||
std::memset(&modeState, 0, sizeof(modeState));
|
||||
modeState.ModeParamPointer.function = function;
|
||||
modeState.ModeParamPointer.userdata = userdata;
|
||||
startupDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
if(!startupDoneEvent) { throw std::runtime_error("unable to start thread"); }
|
||||
DWORD dummy = 0; // For Win9x
|
||||
threadHandle = CreateThread(NULL, 0, ThreadFunctionWrapper, this, 0, &dummy);
|
||||
if(threadHandle)
|
||||
{
|
||||
WaitForSingleObject(startupDoneEvent, INFINITE);
|
||||
}
|
||||
CloseHandle(startupDoneEvent);
|
||||
startupDoneEvent = nullptr;
|
||||
if(!threadHandle) { throw std::runtime_error("unable to start thread"); }
|
||||
}
|
||||
|
||||
template<typename Tfunctor>
|
||||
thread(Tfunctor functor)
|
||||
: threadHandle(nullptr)
|
||||
, startupDoneEvent(nullptr)
|
||||
, functionMode(FunctionModeFunctor)
|
||||
{
|
||||
std::memset(&modeState, 0, sizeof(modeState));
|
||||
modeState.ModeFunctor.pfunctor = new functor_helper<Tfunctor>(functor);
|
||||
startupDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
if(!startupDoneEvent) { throw std::runtime_error("unable to start thread"); }
|
||||
DWORD dummy = 0; // For Win9x
|
||||
threadHandle = CreateThread(NULL, 0, ThreadFunctionWrapper, this, 0, &dummy);
|
||||
if(threadHandle)
|
||||
{
|
||||
WaitForSingleObject(startupDoneEvent, INFINITE);
|
||||
}
|
||||
CloseHandle(startupDoneEvent);
|
||||
startupDoneEvent = nullptr;
|
||||
if(!threadHandle) { throw std::runtime_error("unable to start thread"); }
|
||||
}
|
||||
|
||||
~thread()
|
||||
{
|
||||
MPT_ASSERT(!joinable());
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
static unsigned int hardware_concurrency()
|
||||
{
|
||||
SYSTEM_INFO sysInfo;
|
||||
GetSystemInfo(&sysInfo);
|
||||
return std::max<unsigned int>(sysInfo.dwNumberOfProcessors, 1);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
|
||||
|
||||
#endif // MPT_STD_THREAD
|
||||
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
#if MPT_OS_WINDOWS && (MPT_COMPILER_MSVC || MPT_COMPILER_CLANG)
|
||||
|
||||
enum ThreadPriority
|
||||
{
|
||||
|
@ -366,7 +46,7 @@ enum ThreadPriority
|
|||
ThreadPriorityHighest = THREAD_PRIORITY_HIGHEST
|
||||
};
|
||||
|
||||
inline void SetThreadPriority(mpt::thread &t, mpt::ThreadPriority priority)
|
||||
inline void SetThreadPriority(std::thread &t, mpt::ThreadPriority priority)
|
||||
{
|
||||
::SetThreadPriority(t.native_handle(), priority);
|
||||
}
|
||||
|
@ -387,7 +67,7 @@ enum ThreadPriority
|
|||
ThreadPriorityHighest = 2
|
||||
};
|
||||
|
||||
inline void SetThreadPriority(mpt::thread & /*t*/ , mpt::ThreadPriority /*priority*/ )
|
||||
inline void SetThreadPriority(std::thread & /*t*/ , mpt::ThreadPriority /*priority*/ )
|
||||
{
|
||||
// nothing
|
||||
}
|
||||
|
@ -397,7 +77,7 @@ inline void SetCurrentThreadPriority(mpt::ThreadPriority /*priority*/ )
|
|||
// nothing
|
||||
}
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
#endif // MPT_OS_WINDOWS && (MPT_COMPILER_MSVC || MPT_COMPILER_CLANG)
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#include "stdafx.h"
|
||||
#include "mptTime.h"
|
||||
|
||||
#include "mptStringBuffer.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
@ -43,7 +45,7 @@ uint64 Now()
|
|||
return ((uint64)filetime.dwHighDateTime << 32 | filetime.dwLowDateTime);
|
||||
}
|
||||
|
||||
mpt::ustring ToString(uint64 time100ns)
|
||||
mpt::ustring ToUString(uint64 time100ns)
|
||||
{
|
||||
static const std::size_t bufsize = 256;
|
||||
|
||||
|
@ -55,17 +57,17 @@ mpt::ustring ToString(uint64 time100ns)
|
|||
filetime.dwLowDateTime = (DWORD)((uint64)time100ns);
|
||||
FileTimeToSystemTime(&filetime, &systime);
|
||||
|
||||
WCHAR buf[bufsize];
|
||||
TCHAR buf[bufsize];
|
||||
|
||||
GetDateFormatW(LOCALE_SYSTEM_DEFAULT, 0, &systime, L"yyyy-MM-dd", buf, bufsize);
|
||||
result.append(mpt::ToUnicode(buf));
|
||||
GetDateFormat(LOCALE_SYSTEM_DEFAULT, 0, &systime, TEXT("yyyy-MM-dd"), buf, bufsize);
|
||||
result.append(mpt::ToUnicode(mpt::String::ReadWinBuf(buf)));
|
||||
|
||||
result.append(MPT_USTRING(" "));
|
||||
result.append(U_(" "));
|
||||
|
||||
GetTimeFormatW(LOCALE_SYSTEM_DEFAULT, TIME_FORCE24HOURFORMAT, &systime, L"HH:mm:ss", buf, bufsize);
|
||||
result.append(mpt::ToUnicode(buf));
|
||||
GetTimeFormat(LOCALE_SYSTEM_DEFAULT, TIME_FORCE24HOURFORMAT, &systime, TEXT("HH:mm:ss"), buf, bufsize);
|
||||
result.append(mpt::ToUnicode(mpt::String::ReadWinBuf(buf)));
|
||||
|
||||
result.append(MPT_USTRING("."));
|
||||
result.append(U_("."));
|
||||
|
||||
result.append(mpt::ufmt::dec0<3>((unsigned)systime.wMilliseconds));
|
||||
|
||||
|
@ -159,7 +161,7 @@ mpt::ustring ToShortenedISO8601(tm date)
|
|||
// and strftime does not support reduced precision ISO8601 at all.
|
||||
// Just do the formatting ourselves.
|
||||
mpt::ustring result;
|
||||
mpt::ustring tz = MPT_USTRING("Z");
|
||||
mpt::ustring tz = U_("Z");
|
||||
if(date.tm_year == 0)
|
||||
{
|
||||
return result;
|
||||
|
@ -169,12 +171,12 @@ mpt::ustring ToShortenedISO8601(tm date)
|
|||
{
|
||||
return result;
|
||||
}
|
||||
result += MPT_USTRING("-") + mpt::ufmt::dec0<2>(date.tm_mon + 1);
|
||||
result += U_("-") + mpt::ufmt::dec0<2>(date.tm_mon + 1);
|
||||
if(date.tm_mday < 1 || date.tm_mday > 31)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
result += MPT_USTRING("-") + mpt::ufmt::dec0<2>(date.tm_mday);
|
||||
result += U_("-") + mpt::ufmt::dec0<2>(date.tm_mday);
|
||||
if(date.tm_hour == 0 && date.tm_min == 0 && date.tm_sec == 0)
|
||||
{
|
||||
return result;
|
||||
|
@ -187,17 +189,17 @@ mpt::ustring ToShortenedISO8601(tm date)
|
|||
{
|
||||
return result;
|
||||
}
|
||||
result += MPT_USTRING("T");
|
||||
result += U_("T");
|
||||
if(date.tm_isdst > 0)
|
||||
{
|
||||
tz = MPT_USTRING("+01:00");
|
||||
tz = U_("+01:00");
|
||||
}
|
||||
result += mpt::ufmt::dec0<2>(date.tm_hour) + MPT_USTRING(":") + mpt::ufmt::dec0<2>(date.tm_min);
|
||||
result += mpt::ufmt::dec0<2>(date.tm_hour) + U_(":") + mpt::ufmt::dec0<2>(date.tm_min);
|
||||
if(date.tm_sec < 0 || date.tm_sec > 61)
|
||||
{
|
||||
return result + tz;
|
||||
}
|
||||
result += MPT_USTRING(":") + mpt::ufmt::dec0<2>(date.tm_sec);
|
||||
result += U_(":") + mpt::ufmt::dec0<2>(date.tm_sec);
|
||||
result += tz;
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <time.h>
|
||||
|
@ -34,7 +36,7 @@ namespace ANSI
|
|||
|
||||
uint64 Now();
|
||||
|
||||
mpt::ustring ToString(uint64 time100ns); // i.e. 2015-01-15 18:32:01.718
|
||||
mpt::ustring ToUString(uint64 time100ns); // i.e. 2015-01-15 18:32:01.718
|
||||
|
||||
} // namespacee ANSI
|
||||
|
||||
|
|
|
@ -1,142 +0,0 @@
|
|||
/*
|
||||
* mptTypeTraits.h
|
||||
* ---------------
|
||||
* Purpose: C++11 similar type_traits header plus some OpenMPT specific traits.
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
|
||||
namespace mpt {
|
||||
|
||||
|
||||
|
||||
template <std::size_t size> struct int_of_size { };
|
||||
template <> struct int_of_size<1> { typedef int8 type; };
|
||||
template <> struct int_of_size<2> { typedef int16 type; };
|
||||
template <> struct int_of_size<3> { typedef int32 type; };
|
||||
template <> struct int_of_size<4> { typedef int32 type; };
|
||||
template <> struct int_of_size<5> { typedef int64 type; };
|
||||
template <> struct int_of_size<6> { typedef int64 type; };
|
||||
template <> struct int_of_size<7> { typedef int64 type; };
|
||||
template <> struct int_of_size<8> { typedef int64 type; };
|
||||
|
||||
template <std::size_t size> struct uint_of_size { };
|
||||
template <> struct uint_of_size<1> { typedef uint8 type; };
|
||||
template <> struct uint_of_size<2> { typedef uint16 type; };
|
||||
template <> struct uint_of_size<3> { typedef uint32 type; };
|
||||
template <> struct uint_of_size<4> { typedef uint32 type; };
|
||||
template <> struct uint_of_size<5> { typedef uint64 type; };
|
||||
template <> struct uint_of_size<6> { typedef uint64 type; };
|
||||
template <> struct uint_of_size<7> { typedef uint64 type; };
|
||||
template <> struct uint_of_size<8> { typedef uint64 type; };
|
||||
|
||||
|
||||
// Tell which types are safe for mpt::byte_cast.
|
||||
// signed char is actually not allowed to alias into an object representation,
|
||||
// which means that, if the actual type is not itself signed char but char or
|
||||
// unsigned char instead, dereferencing the signed char pointer is undefined
|
||||
// behaviour.
|
||||
template <typename T> struct is_byte_castable : public std::false_type { };
|
||||
template <> struct is_byte_castable<char> : public std::true_type { };
|
||||
template <> struct is_byte_castable<unsigned char> : public std::true_type { };
|
||||
template <> struct is_byte_castable<const char> : public std::true_type { };
|
||||
template <> struct is_byte_castable<const unsigned char> : public std::true_type { };
|
||||
|
||||
|
||||
// Tell which types are safe to binary write into files.
|
||||
// By default, no types are safe.
|
||||
// When a safe type gets defined,
|
||||
// also specialize this template so that IO functions will work.
|
||||
template <typename T> struct is_binary_safe : public std::false_type { };
|
||||
|
||||
// Specialization for byte types.
|
||||
template <> struct is_binary_safe<char> : public std::true_type { };
|
||||
template <> struct is_binary_safe<uint8> : public std::true_type { };
|
||||
template <> struct is_binary_safe<int8> : public std::true_type { };
|
||||
|
||||
// Generic Specialization for arrays.
|
||||
template <typename T, std::size_t N> struct is_binary_safe<T[N]> : public is_binary_safe<T> { };
|
||||
template <typename T, std::size_t N> struct is_binary_safe<const T[N]> : public is_binary_safe<T> { };
|
||||
|
||||
template <typename T>
|
||||
struct GetRawBytesFunctor
|
||||
{
|
||||
inline const mpt::byte * operator () (const T & v) const
|
||||
{
|
||||
STATIC_ASSERT(mpt::is_binary_safe<typename std::remove_const<T>::type>::value);
|
||||
return reinterpret_cast<const mpt::byte *>(&v);
|
||||
}
|
||||
inline mpt::byte * operator () (T & v) const
|
||||
{
|
||||
STATIC_ASSERT(mpt::is_binary_safe<typename std::remove_const<T>::type>::value);
|
||||
return reinterpret_cast<mpt::byte *>(&v);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
struct GetRawBytesFunctor<T[N]>
|
||||
{
|
||||
inline const mpt::byte * operator () (const T (&v)[N]) const
|
||||
{
|
||||
STATIC_ASSERT(mpt::is_binary_safe<typename std::remove_const<T>::type>::value);
|
||||
return reinterpret_cast<const mpt::byte *>(v);
|
||||
}
|
||||
inline mpt::byte * operator () (T (&v)[N]) const
|
||||
{
|
||||
STATIC_ASSERT(mpt::is_binary_safe<typename std::remove_const<T>::type>::value);
|
||||
return reinterpret_cast<mpt::byte *>(v);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
struct GetRawBytesFunctor<const T[N]>
|
||||
{
|
||||
inline const mpt::byte * operator () (const T (&v)[N]) const
|
||||
{
|
||||
STATIC_ASSERT(mpt::is_binary_safe<typename std::remove_const<T>::type>::value);
|
||||
return reinterpret_cast<const mpt::byte *>(v);
|
||||
}
|
||||
};
|
||||
|
||||
// In order to be able to partially specialize it,
|
||||
// as_raw_memory is implemented via a class template.
|
||||
// Do not overload or specialize as_raw_memory directly.
|
||||
// Using a wrapper (by default just around a cast to const mpt::byte *),
|
||||
// allows for implementing raw memory access
|
||||
// via on-demand generating a cached serialized representation.
|
||||
template <typename T> inline const mpt::byte * as_raw_memory(const T & v)
|
||||
{
|
||||
STATIC_ASSERT(mpt::is_binary_safe<typename std::remove_const<T>::type>::value);
|
||||
return mpt::GetRawBytesFunctor<T>()(v);
|
||||
}
|
||||
template <typename T> inline mpt::byte * as_raw_memory(T & v)
|
||||
{
|
||||
STATIC_ASSERT(mpt::is_binary_safe<typename std::remove_const<T>::type>::value);
|
||||
return mpt::GetRawBytesFunctor<T>()(v);
|
||||
}
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
#define MPT_BINARY_STRUCT(type, size) \
|
||||
MPT_STATIC_ASSERT(sizeof( type ) == (size) ); \
|
||||
MPT_STATIC_ASSERT(alignof( type ) == 1); \
|
||||
MPT_STATIC_ASSERT(std::is_standard_layout< type >::value); \
|
||||
namespace mpt { \
|
||||
template <> struct is_binary_safe< type > : public std::true_type { }; \
|
||||
} \
|
||||
/**/
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -39,7 +39,7 @@ namespace Util
|
|||
#if defined(MODPLUG_TRACKER) || !defined(NO_DMO)
|
||||
|
||||
|
||||
std::wstring CLSIDToString(CLSID clsid)
|
||||
mpt::winstring CLSIDToString(CLSID clsid)
|
||||
{
|
||||
std::wstring str;
|
||||
LPOLESTR tmp = nullptr;
|
||||
|
@ -75,17 +75,17 @@ std::wstring CLSIDToString(CLSID clsid)
|
|||
{
|
||||
::CoTaskMemFree(tmp);
|
||||
tmp = nullptr;
|
||||
MPT_UNUSED_VARIABLE(e);
|
||||
MPT_EXCEPTION_RETHROW_OUT_OF_MEMORY();
|
||||
MPT_EXCEPTION_RETHROW_OUT_OF_MEMORY(e);
|
||||
}
|
||||
::CoTaskMemFree(tmp);
|
||||
tmp = nullptr;
|
||||
return str;
|
||||
return mpt::ToWin(str);
|
||||
}
|
||||
|
||||
|
||||
CLSID StringToCLSID(const std::wstring &str)
|
||||
CLSID StringToCLSID(const mpt::winstring &str_)
|
||||
{
|
||||
const std::wstring str = mpt::ToWide(str_);
|
||||
CLSID clsid = CLSID();
|
||||
std::vector<OLECHAR> tmp(str.c_str(), str.c_str() + str.length() + 1);
|
||||
switch(::CLSIDFromString(tmp.data(), &clsid))
|
||||
|
@ -115,8 +115,9 @@ CLSID StringToCLSID(const std::wstring &str)
|
|||
}
|
||||
|
||||
|
||||
bool VerifyStringToCLSID(const std::wstring &str, CLSID &clsid)
|
||||
bool VerifyStringToCLSID(const mpt::winstring &str_, CLSID &clsid)
|
||||
{
|
||||
const std::wstring str = mpt::ToWide(str_);
|
||||
bool result = false;
|
||||
clsid = CLSID();
|
||||
std::vector<OLECHAR> tmp(str.c_str(), str.c_str() + str.length() + 1);
|
||||
|
@ -145,8 +146,9 @@ bool VerifyStringToCLSID(const std::wstring &str, CLSID &clsid)
|
|||
}
|
||||
|
||||
|
||||
bool IsCLSID(const std::wstring &str)
|
||||
bool IsCLSID(const mpt::winstring &str_)
|
||||
{
|
||||
const std::wstring str = mpt::ToWide(str_);
|
||||
bool result = false;
|
||||
CLSID clsid = CLSID();
|
||||
std::vector<OLECHAR> tmp(str.c_str(), str.c_str() + str.length() + 1);
|
||||
|
@ -177,7 +179,7 @@ bool IsCLSID(const std::wstring &str)
|
|||
}
|
||||
|
||||
|
||||
std::wstring IIDToString(IID iid)
|
||||
mpt::winstring IIDToString(IID iid)
|
||||
{
|
||||
std::wstring str;
|
||||
LPOLESTR tmp = nullptr;
|
||||
|
@ -213,15 +215,15 @@ std::wstring IIDToString(IID iid)
|
|||
{
|
||||
::CoTaskMemFree(tmp);
|
||||
tmp = nullptr;
|
||||
MPT_UNUSED_VARIABLE(e);
|
||||
MPT_EXCEPTION_RETHROW_OUT_OF_MEMORY();
|
||||
MPT_EXCEPTION_RETHROW_OUT_OF_MEMORY(e);
|
||||
}
|
||||
return str;
|
||||
return mpt::ToWin(str);
|
||||
}
|
||||
|
||||
|
||||
IID StringToIID(const std::wstring &str)
|
||||
IID StringToIID(const mpt::winstring &str_)
|
||||
{
|
||||
const std::wstring str = mpt::ToWide(str_);
|
||||
IID iid = IID();
|
||||
std::vector<OLECHAR> tmp(str.c_str(), str.c_str() + str.length() + 1);
|
||||
switch(::IIDFromString(tmp.data(), &iid))
|
||||
|
@ -245,18 +247,18 @@ IID StringToIID(const std::wstring &str)
|
|||
}
|
||||
|
||||
|
||||
std::wstring GUIDToString(GUID guid)
|
||||
mpt::winstring GUIDToString(GUID guid)
|
||||
{
|
||||
std::vector<OLECHAR> tmp(256);
|
||||
if(::StringFromGUID2(guid, tmp.data(), static_cast<int>(tmp.size())) <= 0)
|
||||
{
|
||||
throw std::logic_error("StringFromGUID2() failed.");
|
||||
}
|
||||
return tmp.data();
|
||||
return mpt::ToWin(tmp.data());
|
||||
}
|
||||
|
||||
|
||||
GUID StringToGUID(const std::wstring &str)
|
||||
GUID StringToGUID(const mpt::winstring &str)
|
||||
{
|
||||
return StringToIID(str);
|
||||
}
|
||||
|
@ -278,71 +280,6 @@ GUID CreateGUID()
|
|||
}
|
||||
|
||||
|
||||
#if !MPT_OS_WINDOWS_WINRT
|
||||
|
||||
UUID StringToUUID(const mpt::ustring &str)
|
||||
{
|
||||
UUID uuid = UUID();
|
||||
std::wstring wstr = mpt::ToWide(str);
|
||||
std::vector<wchar_t> tmp(wstr.c_str(), wstr.c_str() + wstr.length() + 1);
|
||||
switch(::UuidFromStringW((RPC_WSTR)(&(tmp[0])), &uuid))
|
||||
{
|
||||
case RPC_S_OK:
|
||||
// nothing
|
||||
break;
|
||||
case RPC_S_INVALID_STRING_UUID:
|
||||
uuid = UUID();
|
||||
break;
|
||||
default:
|
||||
throw std::logic_error("UuidFromStringW() failed.");
|
||||
break;
|
||||
}
|
||||
return uuid;
|
||||
}
|
||||
|
||||
|
||||
mpt::ustring UUIDToString(UUID uuid)
|
||||
{
|
||||
std::wstring wstr;
|
||||
RPC_WSTR tmp = nullptr;
|
||||
switch(::UuidToStringW(&uuid, &tmp))
|
||||
{
|
||||
case RPC_S_OK:
|
||||
// nothing
|
||||
break;
|
||||
case RPC_S_OUT_OF_MEMORY:
|
||||
if(tmp)
|
||||
{
|
||||
::RpcStringFreeW(&tmp);
|
||||
tmp = nullptr;
|
||||
}
|
||||
MPT_EXCEPTION_THROW_OUT_OF_MEMORY();
|
||||
break;
|
||||
default:
|
||||
throw std::logic_error("UuidToStringW() failed.");
|
||||
break;
|
||||
}
|
||||
try
|
||||
{
|
||||
std::size_t len = 0;
|
||||
for(len = 0; tmp[len] != 0; ++len)
|
||||
{
|
||||
// nothing
|
||||
}
|
||||
wstr = std::wstring(tmp, tmp + len);
|
||||
} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
|
||||
{
|
||||
::RpcStringFreeW(&tmp);
|
||||
tmp = nullptr;
|
||||
MPT_UNUSED_VARIABLE(e);
|
||||
MPT_EXCEPTION_RETHROW_OUT_OF_MEMORY();
|
||||
}
|
||||
return mpt::ToUnicode(wstr);
|
||||
}
|
||||
|
||||
#endif // !MPT_OS_WINDOWS_WINRT
|
||||
|
||||
|
||||
bool IsValid(UUID uuid)
|
||||
{
|
||||
return false
|
||||
|
@ -423,17 +360,6 @@ UUID::operator ::UUID () const
|
|||
return UUIDToWin32(*this);
|
||||
}
|
||||
|
||||
mpt::UUID UUID::FromGroups(uint32 group1, uint16 group2, uint16 group3, uint16 group4, uint64 group5)
|
||||
{
|
||||
MPT_ASSERT((group5 & 0xffff000000000000ull) == 0ull);
|
||||
return mpt::UUID
|
||||
( group1
|
||||
, group2
|
||||
, group3
|
||||
, (static_cast<uint64>(group4) << 48) | group5
|
||||
);
|
||||
}
|
||||
|
||||
#endif // MODPLUG_TRACKER || !NO_DMO
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
@ -489,10 +415,6 @@ UUID UUID::GenerateLocalUseOnly()
|
|||
return mpt::UUID::RFC4122Random();
|
||||
#endif
|
||||
#elif MPT_OS_WINDOWS && !MPT_OS_WINDOWS_WINRT
|
||||
#if _WIN32_WINNT >= 0x0501
|
||||
// Available since Win2000, but we check for WinXP in order to not use this
|
||||
// function in Win32old builds. It is not available on some non-fully
|
||||
// patched Win98SE installs in the wild.
|
||||
::UUID uuid = ::UUID();
|
||||
RPC_STATUS status = ::UuidCreateSequential(&uuid);
|
||||
if(status != RPC_S_OK && status != RPC_S_UUID_LOCAL_ONLY)
|
||||
|
@ -509,11 +431,6 @@ UUID UUID::GenerateLocalUseOnly()
|
|||
return mpt::UUID::RFC4122Random();
|
||||
}
|
||||
return mpt::UUIDFromWin32(uuid);
|
||||
#else
|
||||
// Fallback to ::UuidCreate is safe as ::UuidCreateSequential is only a
|
||||
// tiny performance optimization.
|
||||
return Generate();
|
||||
#endif
|
||||
#else
|
||||
return RFC4122Random();
|
||||
#endif
|
||||
|
@ -522,7 +439,7 @@ UUID UUID::GenerateLocalUseOnly()
|
|||
UUID UUID::RFC4122Random()
|
||||
{
|
||||
UUID result;
|
||||
mpt::thread_safe_prng<mpt::best_prng> & prng = mpt::global_prng();
|
||||
mpt::thread_safe_prng<mpt::default_prng> & prng = mpt::global_prng();
|
||||
result.Data1 = mpt::random<uint32>(prng);
|
||||
result.Data2 = mpt::random<uint16>(prng);
|
||||
result.Data3 = mpt::random<uint16>(prng);
|
||||
|
@ -531,62 +448,7 @@ UUID UUID::RFC4122Random()
|
|||
return result;
|
||||
}
|
||||
|
||||
uint32 UUID::GetData1() const
|
||||
{
|
||||
return Data1;
|
||||
}
|
||||
|
||||
uint16 UUID::GetData2() const
|
||||
{
|
||||
return Data2;
|
||||
}
|
||||
|
||||
uint16 UUID::GetData3() const
|
||||
{
|
||||
return Data3;
|
||||
}
|
||||
|
||||
uint64 UUID::GetData4() const
|
||||
{
|
||||
return Data4;
|
||||
}
|
||||
|
||||
bool UUID::IsNil() const
|
||||
{
|
||||
return (Data1 == 0) && (Data2 == 0) && (Data3 == 0) && (Data4 == 0);
|
||||
}
|
||||
|
||||
bool UUID::IsValid() const
|
||||
{
|
||||
return (Data1 != 0) || (Data2 != 0) || (Data3 != 0) || (Data4 != 0);
|
||||
}
|
||||
|
||||
uint8 UUID::Mm() const
|
||||
{
|
||||
return static_cast<uint8>((Data3 >> 8) & 0xffu);
|
||||
}
|
||||
|
||||
uint8 UUID::Nn() const
|
||||
{
|
||||
return static_cast<uint8>((Data4 >> 56) & 0xffu);
|
||||
}
|
||||
|
||||
uint8 UUID::Variant() const
|
||||
{
|
||||
return Nn() >> 4u;
|
||||
}
|
||||
|
||||
uint8 UUID::Version() const
|
||||
{
|
||||
return Mm() >> 4u;
|
||||
}
|
||||
|
||||
bool UUID::IsRFC4122() const
|
||||
{
|
||||
return (Variant() & 0xcu) == 0x8u;
|
||||
}
|
||||
|
||||
void UUID::MakeRFC4122(uint8 version)
|
||||
void UUID::MakeRFC4122(uint8 version) noexcept
|
||||
{
|
||||
// variant
|
||||
uint8 Nn = static_cast<uint8>((Data4 >> 56) & 0xffu);
|
||||
|
@ -603,70 +465,9 @@ void UUID::MakeRFC4122(uint8 version)
|
|||
Data3 |= static_cast<uint16>(Mm) << 8;
|
||||
}
|
||||
|
||||
UUID::UUID()
|
||||
{
|
||||
Data1 = 0;
|
||||
Data2 = 0;
|
||||
Data3 = 0;
|
||||
Data4 = 0;
|
||||
}
|
||||
|
||||
UUID::UUID(uint32 Data1, uint16 Data2, uint16 Data3, uint64 Data4)
|
||||
{
|
||||
this->Data1 = Data1;
|
||||
this->Data2 = Data2;
|
||||
this->Data3 = Data3;
|
||||
this->Data4 = Data4;
|
||||
}
|
||||
|
||||
bool operator==(const mpt::UUID & a, const mpt::UUID & b)
|
||||
{
|
||||
return (a.Data1 == b.Data1) && (a.Data2 == b.Data2) && (a.Data3 == b.Data3) && (a.Data4 == b.Data4);
|
||||
}
|
||||
|
||||
bool operator!=(const mpt::UUID & a, const mpt::UUID & b)
|
||||
{
|
||||
return (a.Data1 != b.Data1) || (a.Data2 != b.Data2) || (a.Data3 != b.Data3) || (a.Data4 != b.Data4);
|
||||
}
|
||||
|
||||
UUID UUID::FromString(const std::string &str)
|
||||
{
|
||||
std::vector<std::string> segments = mpt::String::Split<std::string>(str, std::string("-"));
|
||||
if(segments.size() != 5)
|
||||
{
|
||||
return UUID();
|
||||
}
|
||||
if(segments[0].length() != 8)
|
||||
{
|
||||
return UUID();
|
||||
}
|
||||
if(segments[1].length() != 4)
|
||||
{
|
||||
return UUID();
|
||||
}
|
||||
if(segments[2].length() != 4)
|
||||
{
|
||||
return UUID();
|
||||
}
|
||||
if(segments[3].length() != 4)
|
||||
{
|
||||
return UUID();
|
||||
}
|
||||
if(segments[4].length() != 12)
|
||||
{
|
||||
return UUID();
|
||||
}
|
||||
UUID result;
|
||||
result.Data1 = mpt::String::Parse::Hex<uint32>(segments[0]);
|
||||
result.Data2 = mpt::String::Parse::Hex<uint16>(segments[1]);
|
||||
result.Data3 = mpt::String::Parse::Hex<uint16>(segments[2]);
|
||||
result.Data4 = mpt::String::Parse::Hex<uint64>(segments[3] + segments[4]);
|
||||
return result;
|
||||
}
|
||||
|
||||
UUID UUID::FromString(const mpt::ustring &str)
|
||||
{
|
||||
std::vector<mpt::ustring> segments = mpt::String::Split<mpt::ustring>(str, MPT_USTRING("-"));
|
||||
std::vector<mpt::ustring> segments = mpt::String::Split<mpt::ustring>(str, U_("-"));
|
||||
if(segments.size() != 5)
|
||||
{
|
||||
return UUID();
|
||||
|
@ -699,38 +500,30 @@ UUID UUID::FromString(const mpt::ustring &str)
|
|||
return result;
|
||||
}
|
||||
|
||||
std::string UUID::ToString() const
|
||||
{
|
||||
return std::string()
|
||||
+ mpt::fmt::hex0<8>(GetData1())
|
||||
+ std::string("-")
|
||||
+ mpt::fmt::hex0<4>(GetData2())
|
||||
+ std::string("-")
|
||||
+ mpt::fmt::hex0<4>(GetData3())
|
||||
+ std::string("-")
|
||||
+ mpt::fmt::hex0<4>(static_cast<uint16>(GetData4() >> 48))
|
||||
+ std::string("-")
|
||||
+ mpt::fmt::hex0<4>(static_cast<uint16>(GetData4() >> 32))
|
||||
+ mpt::fmt::hex0<8>(static_cast<uint32>(GetData4() >> 0))
|
||||
;
|
||||
}
|
||||
|
||||
mpt::ustring UUID::ToUString() const
|
||||
{
|
||||
return mpt::ustring()
|
||||
+ mpt::ufmt::hex0<8>(GetData1())
|
||||
+ MPT_USTRING("-")
|
||||
+ U_("-")
|
||||
+ mpt::ufmt::hex0<4>(GetData2())
|
||||
+ MPT_USTRING("-")
|
||||
+ U_("-")
|
||||
+ mpt::ufmt::hex0<4>(GetData3())
|
||||
+ MPT_USTRING("-")
|
||||
+ U_("-")
|
||||
+ mpt::ufmt::hex0<4>(static_cast<uint16>(GetData4() >> 48))
|
||||
+ MPT_USTRING("-")
|
||||
+ U_("-")
|
||||
+ mpt::ufmt::hex0<4>(static_cast<uint16>(GetData4() >> 32))
|
||||
+ mpt::ufmt::hex0<8>(static_cast<uint32>(GetData4() >> 0))
|
||||
;
|
||||
}
|
||||
|
||||
UUID::UUID(UUIDbin uuid)
|
||||
{
|
||||
Data1 = uuid.Data1.get();
|
||||
Data2 = uuid.Data2.get();
|
||||
Data3 = uuid.Data3.get();
|
||||
Data4 = uuid.Data4.get();
|
||||
}
|
||||
|
||||
UUID::UUID(GUIDms guid)
|
||||
{
|
||||
Data1 = guid.Data1.get();
|
||||
|
@ -739,6 +532,16 @@ UUID::UUID(GUIDms guid)
|
|||
Data4 = guid.Data4.get();
|
||||
}
|
||||
|
||||
UUID::operator UUIDbin() const
|
||||
{
|
||||
UUIDbin result;
|
||||
result.Data1 = GetData1();
|
||||
result.Data2 = GetData2();
|
||||
result.Data3 = GetData3();
|
||||
result.Data4 = GetData4();
|
||||
return result;
|
||||
}
|
||||
|
||||
UUID::operator GUIDms() const
|
||||
{
|
||||
GUIDms result;
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
|
||||
#include "Endianness.h"
|
||||
|
||||
|
@ -34,30 +36,23 @@ namespace Util
|
|||
// A CLSID string is not necessarily a standard UUID string,
|
||||
// it might also be a symbolic name for the interface.
|
||||
// (see CLSIDFromString ( http://msdn.microsoft.com/en-us/library/windows/desktop/ms680589%28v=vs.85%29.aspx ))
|
||||
std::wstring CLSIDToString(CLSID clsid);
|
||||
CLSID StringToCLSID(const std::wstring &str);
|
||||
bool VerifyStringToCLSID(const std::wstring &str, CLSID &clsid);
|
||||
bool IsCLSID(const std::wstring &str);
|
||||
mpt::winstring CLSIDToString(CLSID clsid);
|
||||
CLSID StringToCLSID(const mpt::winstring &str);
|
||||
bool VerifyStringToCLSID(const mpt::winstring &str, CLSID &clsid);
|
||||
bool IsCLSID(const mpt::winstring &str);
|
||||
|
||||
// COM IID<->string conversion
|
||||
IID StringToIID(const std::wstring &str);
|
||||
std::wstring IIDToString(IID iid);
|
||||
IID StringToIID(const mpt::winstring &str);
|
||||
mpt::winstring IIDToString(IID iid);
|
||||
|
||||
// General GUID<->string conversion.
|
||||
// The string must/will be in standard GUID format: {4F9A455D-E7EF-4367-B2F0-0C83A38A5C72}
|
||||
GUID StringToGUID(const std::wstring &str);
|
||||
std::wstring GUIDToString(GUID guid);
|
||||
GUID StringToGUID(const mpt::winstring &str);
|
||||
mpt::winstring GUIDToString(GUID guid);
|
||||
|
||||
// Create a COM GUID
|
||||
GUID CreateGUID();
|
||||
|
||||
#if !MPT_OS_WINDOWS_WINRT
|
||||
// General UUID<->string conversion.
|
||||
// The string must/will be in standard UUID format: 4f9a455d-e7ef-4367-b2f0-0c83a38a5c72
|
||||
UUID StringToUUID(const mpt::ustring &str);
|
||||
mpt::ustring UUIDToString(UUID uuid);
|
||||
#endif // !MPT_OS_WINDOWS_WINRT
|
||||
|
||||
// Checks the UUID against the NULL UUID. Returns false if it is NULL, true otherwise.
|
||||
bool IsValid(UUID uuid);
|
||||
|
||||
|
@ -75,49 +70,104 @@ struct GUIDms
|
|||
uint16le Data3;
|
||||
uint64be Data4; // yes, big endian here
|
||||
};
|
||||
STATIC_ASSERT(sizeof(GUIDms) == 16);
|
||||
MPT_BINARY_STRUCT(GUIDms, 16)
|
||||
|
||||
// RFC binary format
|
||||
struct UUIDbin
|
||||
{
|
||||
uint32be Data1;
|
||||
uint16be Data2;
|
||||
uint16be Data3;
|
||||
uint64be Data4;
|
||||
};
|
||||
MPT_BINARY_STRUCT(UUIDbin, 16)
|
||||
|
||||
namespace mpt {
|
||||
|
||||
struct UUID
|
||||
{
|
||||
private:
|
||||
uint32be Data1;
|
||||
uint16be Data2;
|
||||
uint16be Data3;
|
||||
uint64be Data4;
|
||||
uint32 Data1;
|
||||
uint16 Data2;
|
||||
uint16 Data3;
|
||||
uint64 Data4;
|
||||
public:
|
||||
uint32 GetData1() const;
|
||||
uint16 GetData2() const;
|
||||
uint16 GetData3() const;
|
||||
uint64 GetData4() const;
|
||||
MPT_CONSTEXPR11_FUN uint32 GetData1() const noexcept { return Data1; }
|
||||
MPT_CONSTEXPR11_FUN uint16 GetData2() const noexcept { return Data2; }
|
||||
MPT_CONSTEXPR11_FUN uint16 GetData3() const noexcept { return Data3; }
|
||||
MPT_CONSTEXPR11_FUN uint64 GetData4() const noexcept { return Data4; }
|
||||
public:
|
||||
// xxxxxxxx-xxxx-Mmxx-Nnxx-xxxxxxxxxxxx
|
||||
// <--32-->-<16>-<16>-<-------64------>
|
||||
bool IsNil() const;
|
||||
bool IsValid() const;
|
||||
uint8 Variant() const;
|
||||
uint8 Version() const;
|
||||
bool IsRFC4122() const;
|
||||
MPT_CONSTEXPR11_FUN bool IsNil() const noexcept { return (Data1 == 0) && (Data2 == 0) && (Data3 == 0) && (Data4 == 0); }
|
||||
MPT_CONSTEXPR11_FUN bool IsValid() const noexcept { return (Data1 != 0) || (Data2 != 0) || (Data3 != 0) || (Data4 != 0); }
|
||||
MPT_CONSTEXPR11_FUN uint8 Variant() const noexcept { return Nn() >> 4u; }
|
||||
MPT_CONSTEXPR11_FUN uint8 Version() const noexcept { return Mm() >> 4u; }
|
||||
MPT_CONSTEXPR11_FUN bool IsRFC4122() const noexcept { return (Variant() & 0xcu) == 0x8u; }
|
||||
private:
|
||||
uint8 Mm() const;
|
||||
uint8 Nn() const;
|
||||
void MakeRFC4122(uint8 version);
|
||||
MPT_CONSTEXPR11_FUN uint8 Mm() const noexcept { return static_cast<uint8>((Data3 >> 8) & 0xffu); }
|
||||
MPT_CONSTEXPR11_FUN uint8 Nn() const noexcept { return static_cast<uint8>((Data4 >> 56) & 0xffu); }
|
||||
void MakeRFC4122(uint8 version) noexcept;
|
||||
public:
|
||||
#if MPT_OS_WINDOWS && (defined(MODPLUG_TRACKER) || !defined(NO_DMO))
|
||||
explicit UUID(::UUID uuid);
|
||||
operator ::UUID () const;
|
||||
static UUID FromGroups(uint32 group1, uint16 group2, uint16 group3, uint16 group4, uint64 group5);
|
||||
#define MPT_UUID_HELPER( prefix , value , suffix ) ( prefix ## value ## suffix )
|
||||
#define MPT_UUID(group1, group2, group3, group4, group5) mpt::UUID::FromGroups(MPT_UUID_HELPER(0x,group1,u), MPT_UUID_HELPER(0x,group2,u), MPT_UUID_HELPER(0x,group3,u), MPT_UUID_HELPER(0x,group4,u), MPT_UUID_HELPER(0x,group5,ull))
|
||||
#endif // MPT_OS_WINDOWS && (MODPLUG_TRACKER || !NO_DMO)
|
||||
private:
|
||||
static MPT_CONSTEXPR11_FUN uint8 NibbleFromChar(char x)
|
||||
{
|
||||
return
|
||||
('0' <= x && x <= '9') ? static_cast<uint8>(x - '0' + 0) :
|
||||
('a' <= x && x <= 'z') ? static_cast<uint8>(x - 'a' + 10) :
|
||||
('A' <= x && x <= 'Z') ? static_cast<uint8>(x - 'A' + 10) :
|
||||
throw std::domain_error("");
|
||||
}
|
||||
static MPT_CONSTEXPR11_FUN uint8 ByteFromHex(char x, char y)
|
||||
{
|
||||
return static_cast<uint8>(uint8(0)
|
||||
| (NibbleFromChar(x) << 4)
|
||||
| (NibbleFromChar(y) << 0)
|
||||
);
|
||||
}
|
||||
static MPT_CONSTEXPR11_FUN uint16 ParseHex16(const char * str)
|
||||
{
|
||||
return static_cast<uint16>(uint16(0)
|
||||
| (static_cast<uint16>(ByteFromHex(str[0], str[1])) << 8)
|
||||
| (static_cast<uint16>(ByteFromHex(str[2], str[3])) << 0)
|
||||
);
|
||||
}
|
||||
static MPT_CONSTEXPR11_FUN uint32 ParseHex32(const char * str)
|
||||
{
|
||||
return static_cast<uint32>(uint32(0)
|
||||
| (static_cast<uint32>(ByteFromHex(str[0], str[1])) << 24)
|
||||
| (static_cast<uint32>(ByteFromHex(str[2], str[3])) << 16)
|
||||
| (static_cast<uint32>(ByteFromHex(str[4], str[5])) << 8)
|
||||
| (static_cast<uint32>(ByteFromHex(str[6], str[7])) << 0)
|
||||
);
|
||||
}
|
||||
public:
|
||||
UUID();
|
||||
explicit UUID(uint32 Data1, uint16 Data2, uint16 Data3, uint64 Data4);
|
||||
static MPT_CONSTEXPR11_FUN UUID ParseLiteral(const char * str, std::size_t len)
|
||||
{
|
||||
return
|
||||
(len == 36 && str[8] == '-' && str[13] == '-' && str[18] == '-' && str[23] == '-') ?
|
||||
mpt::UUID(
|
||||
ParseHex32(str + 0),
|
||||
ParseHex16(str + 9),
|
||||
ParseHex16(str + 14),
|
||||
uint64(0)
|
||||
| (static_cast<uint64>(ParseHex16(str + 19)) << 48)
|
||||
| (static_cast<uint64>(ParseHex16(str + 24)) << 32)
|
||||
| (static_cast<uint64>(ParseHex32(str + 28)) << 0)
|
||||
)
|
||||
: throw std::domain_error("");
|
||||
}
|
||||
public:
|
||||
MPT_CONSTEXPR11_FUN UUID() noexcept : Data1(0), Data2(0), Data3(0), Data4(0) { }
|
||||
MPT_CONSTEXPR11_FUN explicit UUID(uint32 Data1, uint16 Data2, uint16 Data3, uint64 Data4) noexcept : Data1(Data1), Data2(Data2), Data3(Data3), Data4(Data4) { }
|
||||
explicit UUID(UUIDbin uuid);
|
||||
explicit UUID(GUIDms guid);
|
||||
operator UUIDbin () const;
|
||||
operator GUIDms () const;
|
||||
friend bool operator==(const mpt::UUID & a, const mpt::UUID & b);
|
||||
friend bool operator!=(const mpt::UUID & a, const mpt::UUID & b);
|
||||
public:
|
||||
// Create a UUID
|
||||
static UUID Generate();
|
||||
|
@ -129,18 +179,26 @@ public:
|
|||
public:
|
||||
// General UUID<->string conversion.
|
||||
// The string must/will be in standard UUID format: 4f9a455d-e7ef-4367-b2f0-0c83a38a5c72
|
||||
static UUID FromString(const std::string &str);
|
||||
static UUID FromString(const mpt::ustring &str);
|
||||
std::string ToString() const;
|
||||
mpt::ustring ToUString() const;
|
||||
};
|
||||
|
||||
STATIC_ASSERT(sizeof(mpt::UUID) == 16);
|
||||
|
||||
bool operator==(const mpt::UUID & a, const mpt::UUID & b);
|
||||
bool operator!=(const mpt::UUID & a, const mpt::UUID & b);
|
||||
MPT_CONSTEXPR11_FUN bool operator==(const mpt::UUID & a, const mpt::UUID & b) noexcept
|
||||
{
|
||||
return (a.GetData1() == b.GetData1()) && (a.GetData2() == b.GetData2()) && (a.GetData3() == b.GetData3()) && (a.GetData4() == b.GetData4());
|
||||
}
|
||||
MPT_CONSTEXPR11_FUN bool operator!=(const mpt::UUID & a, const mpt::UUID & b) noexcept
|
||||
{
|
||||
return (a.GetData1() != b.GetData1()) || (a.GetData2() != b.GetData2()) || (a.GetData3() != b.GetData3()) || (a.GetData4() != b.GetData4());
|
||||
}
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
MPT_CONSTEXPR11_FUN mpt::UUID operator "" _uuid (const char * str, std::size_t len)
|
||||
{
|
||||
return mpt::UUID::ParseLiteral(str, len);
|
||||
}
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
||||
|
|
|
@ -48,7 +48,7 @@ Context::Context(mpt::Wine::VersionContext versionContext)
|
|||
{
|
||||
throw mpt::Wine::Exception("Unknown Wine version detected.");
|
||||
}
|
||||
m_Kernel32 = mpt::Library(mpt::LibraryPath::FullPath(MPT_PATHSTRING("kernel32.dll")));
|
||||
m_Kernel32 = mpt::Library(mpt::LibraryPath::FullPath(P_("kernel32.dll")));
|
||||
if(!m_Kernel32.IsValid())
|
||||
{
|
||||
throw mpt::Wine::Exception("Could not load Wine kernel32.dll.");
|
||||
|
@ -136,7 +136,7 @@ std::string Context::PathToPosix(mpt::PathString windowsPath)
|
|||
throw mpt::Wine::Exception("Path too long.");
|
||||
}
|
||||
LPSTR tmp = nullptr;
|
||||
tmp = wine_get_unix_file_name(windowsPath.AsNative().c_str());
|
||||
tmp = wine_get_unix_file_name(windowsPath.ToWide().c_str());
|
||||
if(!tmp)
|
||||
{
|
||||
throw mpt::Wine::Exception("Wine kernel32.dll:wine_get_unix_file_name failed.");
|
||||
|
@ -164,7 +164,7 @@ mpt::PathString Context::PathToWindows(std::string hostPath)
|
|||
{
|
||||
throw mpt::Wine::Exception("Wine kernel32.dll:wine_get_dos_file_name failed.");
|
||||
}
|
||||
result = mpt::PathString::FromNative(tmp);
|
||||
result = mpt::PathString::FromWide(tmp);
|
||||
HeapFree(GetProcessHeap(), 0, tmp);
|
||||
tmp = nullptr;
|
||||
return result;
|
||||
|
@ -213,13 +213,13 @@ std::string Context::EscapePosixShell(std::string line)
|
|||
const char escape_chars [] = { '|', '&', ';', '<', '>', '(', ')', '$', '`', '"', '\'', ' ', '\t' };
|
||||
const char maybe_escape_chars [] = { '*', '?', '[', '#', '~', '=', '%' };
|
||||
line = mpt::String::Replace(line, "\\", "\\\\");
|
||||
for(std::size_t i = 0; i < mpt::size(escape_chars); ++i)
|
||||
for(char c : escape_chars)
|
||||
{
|
||||
line = mpt::String::Replace(line, std::string(1, escape_chars[i]), "\\" + std::string(1, escape_chars[i]));
|
||||
line = mpt::String::Replace(line, std::string(1, c), "\\" + std::string(1, c));
|
||||
}
|
||||
for(std::size_t i = 0; i < mpt::size(maybe_escape_chars); ++i)
|
||||
for(char c : maybe_escape_chars)
|
||||
{
|
||||
line = mpt::String::Replace(line, std::string(1, maybe_escape_chars[i]), "\\" + std::string(1, maybe_escape_chars[i]));
|
||||
line = mpt::String::Replace(line, std::string(1, c), "\\" + std::string(1, c));
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
@ -257,7 +257,7 @@ ExecResult Context::ExecutePosixShellScript(std::string script, FlagSet<ExecFlag
|
|||
progress(userdata);
|
||||
|
||||
// write the script to disk
|
||||
mpt::PathString scriptFilenameWindows = dirWindows + MPT_PATHSTRING("script.sh");
|
||||
mpt::PathString scriptFilenameWindows = dirWindows + P_("script.sh");
|
||||
{
|
||||
mpt::ofstream tempfile(scriptFilenameWindows, std::ios::binary);
|
||||
tempfile << script;
|
||||
|
@ -276,7 +276,7 @@ ExecResult Context::ExecutePosixShellScript(std::string script, FlagSet<ExecFlag
|
|||
progress(userdata);
|
||||
|
||||
// create a wrapper that will call the script and gather result.
|
||||
mpt::PathString wrapperstarterFilenameWindows = dirWindows + MPT_PATHSTRING("wrapperstarter.sh");
|
||||
mpt::PathString wrapperstarterFilenameWindows = dirWindows + P_("wrapperstarter.sh");
|
||||
{
|
||||
mpt::ofstream tempfile(wrapperstarterFilenameWindows, std::ios::binary);
|
||||
std::string wrapperstarterscript;
|
||||
|
@ -289,7 +289,7 @@ ExecResult Context::ExecutePosixShellScript(std::string script, FlagSet<ExecFlag
|
|||
throw mpt::Wine::Exception("Error writing wrapper.sh.");
|
||||
}
|
||||
}
|
||||
mpt::PathString wrapperFilenameWindows = dirWindows + MPT_PATHSTRING("wrapper.sh");
|
||||
mpt::PathString wrapperFilenameWindows = dirWindows + P_("wrapper.sh");
|
||||
std::string cleanupscript;
|
||||
{
|
||||
mpt::ofstream tempfile(wrapperFilenameWindows, std::ios::binary);
|
||||
|
@ -346,11 +346,11 @@ ExecResult Context::ExecutePosixShellScript(std::string script, FlagSet<ExecFlag
|
|||
|
||||
progress(userdata);
|
||||
|
||||
::CreateDirectoryW((dirWindows + MPT_PATHSTRING("filetree")).AsNative().c_str(), NULL);
|
||||
::CreateDirectory((dirWindows + P_("filetree")).AsNative().c_str(), NULL);
|
||||
for(const auto &file : filetree)
|
||||
{
|
||||
std::vector<mpt::ustring> path = mpt::String::Split<mpt::ustring>(mpt::ToUnicode(mpt::CharsetUTF8, file.first), MPT_USTRING("/"));
|
||||
mpt::PathString combinedPath = dirWindows + MPT_PATHSTRING("filetree") + MPT_PATHSTRING("\\");
|
||||
std::vector<mpt::ustring> path = mpt::String::Split<mpt::ustring>(mpt::ToUnicode(mpt::CharsetUTF8, file.first), U_("/"));
|
||||
mpt::PathString combinedPath = dirWindows + P_("filetree") + P_("\\");
|
||||
if(path.size() > 1)
|
||||
{
|
||||
for(std::size_t singlepath = 0; singlepath < path.size() - 1; ++singlepath)
|
||||
|
@ -362,17 +362,17 @@ ExecResult Context::ExecutePosixShellScript(std::string script, FlagSet<ExecFlag
|
|||
combinedPath += mpt::PathString::FromUnicode(path[singlepath]);
|
||||
if(!combinedPath.IsDirectory())
|
||||
{
|
||||
if(::CreateDirectoryW(combinedPath.AsNative().c_str(), NULL) == 0)
|
||||
if(::CreateDirectory(combinedPath.AsNative().c_str(), NULL) == 0)
|
||||
{
|
||||
throw mpt::Wine::Exception("Error writing filetree.");
|
||||
}
|
||||
}
|
||||
combinedPath += MPT_PATHSTRING("\\");
|
||||
combinedPath += P_("\\");
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
mpt::LazyFileRef out(dirWindows + MPT_PATHSTRING("filetree") + MPT_PATHSTRING("\\") + mpt::PathString::FromUTF8(mpt::String::Replace(file.first, "/", "\\")));
|
||||
mpt::LazyFileRef out(dirWindows + P_("filetree") + P_("\\") + mpt::PathString::FromUTF8(mpt::String::Replace(file.first, "/", "\\")));
|
||||
out = file.second;
|
||||
} catch(std::exception &)
|
||||
{
|
||||
|
@ -383,39 +383,32 @@ ExecResult Context::ExecutePosixShellScript(std::string script, FlagSet<ExecFlag
|
|||
progress(userdata);
|
||||
|
||||
// create a wrapper that will find a suitable terminal and run the wrapper script in the terminal window.
|
||||
mpt::PathString terminalWrapperFilenameWindows = dirWindows + MPT_PATHSTRING("terminal.sh");
|
||||
mpt::PathString terminalWrapperFilenameWindows = dirWindows + P_("terminal.sh");
|
||||
{
|
||||
mpt::ofstream tempfile(terminalWrapperFilenameWindows, std::ios::binary);
|
||||
// NOTE:
|
||||
// Modern terminals detach themselves from the invoking shell if another instance is already present.
|
||||
// This means we cannot rely on terminal invocation being syncronous.
|
||||
std::vector<std::string> terminals;
|
||||
terminals.push_back("x-terminal-emulator");
|
||||
terminals.push_back("konsole");
|
||||
terminals.push_back("mate-terminal");
|
||||
terminals.push_back("xfce4-terminal");
|
||||
terminals.push_back("gnome-terminal");
|
||||
terminals.push_back("uxterm");
|
||||
terminals.push_back("xterm");
|
||||
terminals.push_back("rxvt");
|
||||
std::map<std::string, std::string> terminalLanchers;
|
||||
for(std::size_t i = 0; i < terminals.size(); ++i)
|
||||
static constexpr const char * terminals[] =
|
||||
{
|
||||
"x-terminal-emulator",
|
||||
"konsole",
|
||||
"mate-terminal",
|
||||
"xfce4-terminal",
|
||||
"gnome-terminal",
|
||||
"uxterm",
|
||||
"xterm",
|
||||
"rxvt",
|
||||
};
|
||||
std::string terminalscript = "\n";
|
||||
for(const std::string terminal : terminals)
|
||||
{
|
||||
// mate-terminal on Debian 8 cannot execute commands with arguments,
|
||||
// thus we use a separate script that requires no arguments to execute.
|
||||
terminalLanchers[terminals[i]] += std::string() + "if command -v " + terminals[i] + " 2>/dev/null 1>/dev/null ; then" + "\n";
|
||||
terminalLanchers[terminals[i]] += std::string() + " chmod u+x " + EscapePosixShell(dirPosix) + "wrapperstarter.sh" + "\n";
|
||||
terminalLanchers[terminals[i]] += std::string() + " exec `command -v " + terminals[i] + "` -e \"" + EscapePosixShell(dirPosix) + "wrapperstarter.sh\"" + "\n";
|
||||
terminalLanchers[terminals[i]] += std::string() + "fi" + "\n";
|
||||
}
|
||||
|
||||
std::string terminalscript;
|
||||
|
||||
terminalscript += std::string() + "\n";
|
||||
|
||||
for(std::size_t i = 0; i < terminals.size(); ++i)
|
||||
{
|
||||
terminalscript += terminalLanchers[terminals[i]];
|
||||
terminalscript += "if command -v " + terminal + " 2>/dev/null 1>/dev/null ; then" "\n";
|
||||
terminalscript += " chmod u+x " + EscapePosixShell(dirPosix) + "wrapperstarter.sh" "\n";
|
||||
terminalscript += " exec `command -v " + terminal + "` -e \"" + EscapePosixShell(dirPosix) + "wrapperstarter.sh\"" "\n";
|
||||
terminalscript += "fi" "\n";
|
||||
}
|
||||
|
||||
tempfile << terminalscript;
|
||||
|
@ -508,7 +501,8 @@ ExecResult Context::ExecutePosixShellScript(std::string script, FlagSet<ExecFlag
|
|||
if(!createProcessSuccess)
|
||||
{
|
||||
|
||||
if(flags[ExecFlagSilent]) {
|
||||
if(flags[ExecFlagSilent])
|
||||
{
|
||||
unixcommand = "/bin/bash \"" + EscapePosixShell(dirPosix) + "wrapper.sh\"";
|
||||
} else
|
||||
{
|
||||
|
@ -588,7 +582,7 @@ ExecResult Context::ExecutePosixShellScript(std::string script, FlagSet<ExecFlag
|
|||
return result;
|
||||
}
|
||||
|
||||
while(!(dirWindows + MPT_PATHSTRING("done")).IsFile())
|
||||
while(!(dirWindows + P_("done")).IsFile())
|
||||
{ // wait
|
||||
if(progressCancel(userdata) != ExecuteProgressContinueWaiting)
|
||||
{
|
||||
|
@ -600,7 +594,7 @@ ExecResult Context::ExecutePosixShellScript(std::string script, FlagSet<ExecFlag
|
|||
|
||||
int exitCode = 0;
|
||||
{
|
||||
mpt::ifstream exitFile(dirWindows + MPT_PATHSTRING("exit"), std::ios::binary);
|
||||
mpt::ifstream exitFile(dirWindows + P_("exit"), std::ios::binary);
|
||||
if(!exitFile)
|
||||
{
|
||||
throw mpt::Wine::Exception("Script .exit file not found.");
|
||||
|
@ -619,7 +613,7 @@ ExecResult Context::ExecutePosixShellScript(std::string script, FlagSet<ExecFlag
|
|||
std::string outputString;
|
||||
if(!flags[ExecFlagInteractive])
|
||||
{
|
||||
mpt::ifstream outputFile(dirWindows + MPT_PATHSTRING("out"), std::ios::binary);
|
||||
mpt::ifstream outputFile(dirWindows + P_("out"), std::ios::binary);
|
||||
if(outputFile)
|
||||
{
|
||||
outputFile.seekg(0, std::ios::end);
|
||||
|
@ -636,7 +630,7 @@ ExecResult Context::ExecutePosixShellScript(std::string script, FlagSet<ExecFlag
|
|||
std::string errorString;
|
||||
if(flags[ExecFlagSplitOutput])
|
||||
{
|
||||
mpt::ifstream errorFile(dirWindows + MPT_PATHSTRING("err"), std::ios::binary);
|
||||
mpt::ifstream errorFile(dirWindows + P_("err"), std::ios::binary);
|
||||
if(errorFile)
|
||||
{
|
||||
errorFile.seekg(0, std::ios::end);
|
||||
|
@ -656,23 +650,23 @@ ExecResult Context::ExecutePosixShellScript(std::string script, FlagSet<ExecFlag
|
|||
result.error = errorString;
|
||||
|
||||
std::deque<mpt::PathString> paths;
|
||||
paths.push_back(dirWindows + MPT_PATHSTRING("filetree"));
|
||||
mpt::PathString basePath = (dirWindows + MPT_PATHSTRING("filetree")).EnsureTrailingSlash();
|
||||
paths.push_back(dirWindows + P_("filetree"));
|
||||
mpt::PathString basePath = (dirWindows + P_("filetree")).EnsureTrailingSlash();
|
||||
while(!paths.empty())
|
||||
{
|
||||
mpt::PathString path = paths.front();
|
||||
paths.pop_front();
|
||||
path.EnsureTrailingSlash();
|
||||
HANDLE hFind = NULL;
|
||||
WIN32_FIND_DATAW wfd;
|
||||
WIN32_FIND_DATA wfd;
|
||||
MemsetZero(wfd);
|
||||
hFind = FindFirstFileW((path + MPT_PATHSTRING("*.*")).AsNative().c_str(), &wfd);
|
||||
hFind = FindFirstFile((path + P_("*.*")).AsNative().c_str(), &wfd);
|
||||
if(hFind != NULL && hFind != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
do
|
||||
{
|
||||
mpt::PathString filename = mpt::PathString::FromNative(wfd.cFileName);
|
||||
if(filename != MPT_PATHSTRING(".") && filename != MPT_PATHSTRING(".."))
|
||||
if(filename != P_(".") && filename != P_(".."))
|
||||
{
|
||||
filename = path + filename;
|
||||
filetree[filename.ToUTF8()] = std::vector<char>();
|
||||
|
@ -693,7 +687,7 @@ ExecResult Context::ExecutePosixShellScript(std::string script, FlagSet<ExecFlag
|
|||
}
|
||||
}
|
||||
}
|
||||
} while(FindNextFileW(hFind, &wfd));
|
||||
} while(FindNextFile(hFind, &wfd));
|
||||
FindClose(hFind);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
#include "mptOS.h"
|
||||
#include "FlagSet.h"
|
||||
|
||||
|
|
|
@ -133,22 +133,22 @@ const char Ssb::s_EntryID[3] = {'2','2','8'};
|
|||
|
||||
|
||||
#ifdef SSB_LOGGING
|
||||
static const MPT_UCHAR_TYPE tstrWriteHeader[] = MPT_ULITERAL("Write header with ID = %1\n");
|
||||
static const MPT_UCHAR_TYPE tstrWriteProgress[] = MPT_ULITERAL("Wrote entry: {num, id, rpos, size} = {%1, %2, %3, %4}\n");
|
||||
static const MPT_UCHAR_TYPE tstrWritingMap[] = MPT_ULITERAL("Writing map to rpos: %1\n");
|
||||
static const MPT_UCHAR_TYPE tstrMapEntryWrite[] = MPT_ULITERAL("Writing map entry: id=%1, rpos=%2, size=%3\n");
|
||||
static const MPT_UCHAR_TYPE strWriteNote[] = MPT_ULITERAL("Write note: ");
|
||||
static const MPT_UCHAR_TYPE tstrEndOfStream[] = MPT_ULITERAL("End of stream(rpos): %1\n");
|
||||
static const MPT_UCHAR_TYPE tstrWriteHeader[] = UL_("Write header with ID = %1\n");
|
||||
static const MPT_UCHAR_TYPE tstrWriteProgress[] = UL_("Wrote entry: {num, id, rpos, size} = {%1, %2, %3, %4}\n");
|
||||
static const MPT_UCHAR_TYPE tstrWritingMap[] = UL_("Writing map to rpos: %1\n");
|
||||
static const MPT_UCHAR_TYPE tstrMapEntryWrite[] = UL_("Writing map entry: id=%1, rpos=%2, size=%3\n");
|
||||
static const MPT_UCHAR_TYPE strWriteNote[] = UL_("Write note: ");
|
||||
static const MPT_UCHAR_TYPE tstrEndOfStream[] = UL_("End of stream(rpos): %1\n");
|
||||
|
||||
static const MPT_UCHAR_TYPE tstrReadingHeader[] = MPT_ULITERAL("Read header with expected ID = %1\n");
|
||||
static const MPT_UCHAR_TYPE strNoMapInFile[] = MPT_ULITERAL("No map in the file.\n");
|
||||
static const MPT_UCHAR_TYPE strIdMismatch[] = MPT_ULITERAL("ID mismatch, terminating read.\n");
|
||||
static const MPT_UCHAR_TYPE strIdMatch[] = MPT_ULITERAL("ID match, continuing reading.\n");
|
||||
static const MPT_UCHAR_TYPE tstrReadingMap[] = MPT_ULITERAL("Reading map from rpos: %1\n");
|
||||
static const MPT_UCHAR_TYPE tstrEndOfMap[] = MPT_ULITERAL("End of map(rpos): %1\n");
|
||||
static const MPT_UCHAR_TYPE tstrReadProgress[] = MPT_ULITERAL("Read entry: {num, id, rpos, size, desc} = {%1, %2, %3, %4, %5}\n");
|
||||
static const MPT_UCHAR_TYPE tstrNoEntryFound[] = MPT_ULITERAL("No entry with id %1 found.\n");
|
||||
static const MPT_UCHAR_TYPE strReadNote[] = MPT_ULITERAL("Read note: ");
|
||||
static const MPT_UCHAR_TYPE tstrReadingHeader[] = UL_("Read header with expected ID = %1\n");
|
||||
static const MPT_UCHAR_TYPE strNoMapInFile[] = UL_("No map in the file.\n");
|
||||
static const MPT_UCHAR_TYPE strIdMismatch[] = UL_("ID mismatch, terminating read.\n");
|
||||
static const MPT_UCHAR_TYPE strIdMatch[] = UL_("ID match, continuing reading.\n");
|
||||
static const MPT_UCHAR_TYPE tstrReadingMap[] = UL_("Reading map from rpos: %1\n");
|
||||
static const MPT_UCHAR_TYPE tstrEndOfMap[] = UL_("End of map(rpos): %1\n");
|
||||
static const MPT_UCHAR_TYPE tstrReadProgress[] = UL_("Read entry: {num, id, rpos, size, desc} = {%1, %2, %3, %4, %5}\n");
|
||||
static const MPT_UCHAR_TYPE tstrNoEntryFound[] = UL_("No entry with id %1 found.\n");
|
||||
static const MPT_UCHAR_TYPE strReadNote[] = UL_("Read note: ");
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -164,8 +164,8 @@ Ssb::Ssb()
|
|||
}
|
||||
|
||||
|
||||
SsbWrite::SsbWrite(std::ostream& oStrm)
|
||||
: m_pOstrm(&oStrm)
|
||||
SsbWrite::SsbWrite(std::ostream& os)
|
||||
: oStrm(os)
|
||||
, m_posEntrycount(0)
|
||||
, m_posMapPosField(0)
|
||||
{
|
||||
|
@ -173,8 +173,8 @@ SsbWrite::SsbWrite(std::ostream& oStrm)
|
|||
}
|
||||
|
||||
|
||||
SsbRead::SsbRead(std::istream& iStrm)
|
||||
: m_pIstrm(&iStrm)
|
||||
SsbRead::SsbRead(std::istream& is)
|
||||
: iStrm(is)
|
||||
, m_nReadVersion(0)
|
||||
, m_rposMapBegin(0)
|
||||
, m_posMapEnd(0)
|
||||
|
@ -190,13 +190,13 @@ SsbRead::SsbRead(std::istream& iStrm)
|
|||
void SsbWrite::AddWriteNote(const SsbStatus s)
|
||||
{
|
||||
m_Status |= s;
|
||||
SSB_LOG(mpt::format(MPT_USTRING("%1: 0x%2\n"))(strWriteNote, mpt::ufmt::hex(s)));
|
||||
SSB_LOG(mpt::format(U_("%1: 0x%2\n"))(strWriteNote, mpt::ufmt::hex(s)));
|
||||
}
|
||||
|
||||
void SsbRead::AddReadNote(const SsbStatus s)
|
||||
{
|
||||
m_Status |= s;
|
||||
SSB_LOG(mpt::format(MPT_USTRING("%1: 0x%2\n"))(strReadNote, mpt::ufmt::hex(s)));
|
||||
SSB_LOG(mpt::format(U_("%1: 0x%2\n"))(strReadNote, mpt::ufmt::hex(s)));
|
||||
}
|
||||
|
||||
void SsbRead::AddReadNote(const ReadEntry* const pRe, const NumType nNum)
|
||||
|
@ -204,10 +204,10 @@ void SsbRead::AddReadNote(const ReadEntry* const pRe, const NumType nNum)
|
|||
m_Status |= SNT_PROGRESS;
|
||||
SSB_LOG(mpt::format(mpt::ustring(tstrReadProgress))(
|
||||
nNum,
|
||||
(pRe && pRe->nIdLength < 30 && m_Idarray.size() > 0) ? ID(&m_Idarray[pRe->nIdpos], pRe->nIdLength).AsString() : MPT_USTRING(""),
|
||||
(pRe && pRe->nIdLength < 30 && m_Idarray.size() > 0) ? ID(&m_Idarray[pRe->nIdpos], pRe->nIdLength).AsString() : U_(""),
|
||||
(pRe) ? pRe->rposStart : 0,
|
||||
(pRe && pRe->nSize != invalidDatasize) ? mpt::ufmt::val(pRe->nSize) : MPT_USTRING(""),
|
||||
MPT_USTRING("")));
|
||||
(pRe && pRe->nSize != invalidDatasize) ? mpt::ufmt::val(pRe->nSize) : U_(""),
|
||||
U_("")));
|
||||
#ifndef SSB_LOGGING
|
||||
MPT_UNREFERENCED_PARAMETER(pRe);
|
||||
MPT_UNREFERENCED_PARAMETER(nNum);
|
||||
|
@ -242,7 +242,7 @@ void SsbWrite::WriteMapItem(const ID &id,
|
|||
const char* pszDesc)
|
||||
{
|
||||
SSB_LOG(mpt::format(mpt::ustring(tstrMapEntryWrite))(
|
||||
(id.GetSize() > 0) ? id.AsString() : MPT_USTRING(""),
|
||||
(id.GetSize() > 0) ? id.AsString() : U_(""),
|
||||
rposDataStart,
|
||||
nDatasize));
|
||||
|
||||
|
@ -285,8 +285,6 @@ void SsbWrite::IncrementWriteCounter()
|
|||
|
||||
void SsbWrite::BeginWrite(const ID &id, const uint64& nVersion)
|
||||
{
|
||||
std::ostream& oStrm = *m_pOstrm;
|
||||
|
||||
SSB_LOG(mpt::format(mpt::ustring(tstrWriteHeader))(id.AsString()));
|
||||
|
||||
ResetWritestatus();
|
||||
|
@ -368,7 +366,7 @@ SsbRead::ReadRv SsbRead::OnReadEntry(const ReadEntry* pE, const ID &id, const Po
|
|||
{
|
||||
ReadEntry e;
|
||||
e.rposStart = static_cast<RposType>(posReadBegin - m_posStart);
|
||||
e.nSize = static_cast<DataSize>(m_pIstrm->tellg() - posReadBegin);
|
||||
e.nSize = static_cast<DataSize>(iStrm.tellg() - posReadBegin);
|
||||
AddReadNote(&e, m_nCounter);
|
||||
}
|
||||
else // Entry not found.
|
||||
|
@ -386,7 +384,7 @@ SsbRead::ReadRv SsbRead::OnReadEntry(const ReadEntry* pE, const ID &id, const Po
|
|||
|
||||
void SsbWrite::OnWroteItem(const ID &id, const Postype& posBeforeWrite)
|
||||
{
|
||||
const Offtype nRawEntrySize = m_pOstrm->tellp() - posBeforeWrite;
|
||||
const Offtype nRawEntrySize = oStrm.tellp() - posBeforeWrite;
|
||||
|
||||
if (nRawEntrySize < 0 || static_cast<uint64>(nRawEntrySize) > std::numeric_limits<DataSize>::max())
|
||||
{ AddWriteNote(SNW_INSUFFICIENT_DATASIZETYPE); return; }
|
||||
|
@ -402,7 +400,7 @@ void SsbWrite::OnWroteItem(const ID &id, const Postype& posBeforeWrite)
|
|||
if(nEntrySize <= m_nFixedEntrySize)
|
||||
{
|
||||
for(uint32 i = 0; i<m_nFixedEntrySize-nEntrySize; i++)
|
||||
m_pOstrm->put(0);
|
||||
oStrm.put(0);
|
||||
nEntrySize = m_nFixedEntrySize;
|
||||
}
|
||||
else
|
||||
|
@ -418,8 +416,6 @@ void SsbWrite::OnWroteItem(const ID &id, const Postype& posBeforeWrite)
|
|||
|
||||
void SsbRead::BeginRead(const ID &id, const uint64& nVersion)
|
||||
{
|
||||
std::istream& iStrm = *m_pIstrm;
|
||||
|
||||
SSB_LOG(mpt::format(mpt::ustring(tstrReadingHeader))(id.AsString()));
|
||||
|
||||
ResetReadstatus();
|
||||
|
@ -444,7 +440,7 @@ void SsbRead::BeginRead(const ID &id, const uint64& nVersion)
|
|||
uint8 storedIdLen = 0;
|
||||
Binaryread<uint8>(iStrm, storedIdLen);
|
||||
char storedIdBuf[256];
|
||||
MemsetZero(storedIdBuf);
|
||||
Clear(storedIdBuf);
|
||||
if(storedIdLen > 0)
|
||||
{
|
||||
iStrm.read(storedIdBuf, storedIdLen);
|
||||
|
@ -574,7 +570,6 @@ void SsbRead::BeginRead(const ID &id, const uint64& nVersion)
|
|||
|
||||
void SsbRead::CacheMap()
|
||||
{
|
||||
std::istream& iStrm = *m_pIstrm;
|
||||
if(GetFlag(RwfRwHasMap) || m_nFixedEntrySize > 0)
|
||||
{
|
||||
iStrm.seekg(m_posStart + m_rposMapBegin);
|
||||
|
@ -649,7 +644,7 @@ void SsbRead::CacheMap()
|
|||
|
||||
SetFlag(RwfRMapCached, true);
|
||||
m_posDataBegin = (m_rposMapBegin == m_rposEndofHdrData) ? m_posMapEnd : m_posStart + Postype(m_rposEndofHdrData);
|
||||
m_pIstrm->seekg(m_posDataBegin);
|
||||
iStrm.seekg(m_posDataBegin);
|
||||
|
||||
// If there are no positions in the map but there are entry sizes, rposStart will
|
||||
// be relative to data start. Now that posDataBegin is known, make them relative to
|
||||
|
@ -665,12 +660,12 @@ void SsbRead::CacheMap()
|
|||
|
||||
const ReadEntry* SsbRead::Find(const ID &id)
|
||||
{
|
||||
m_pIstrm->clear();
|
||||
iStrm.clear();
|
||||
if (GetFlag(RwfRMapCached) == false)
|
||||
CacheMap();
|
||||
|
||||
if (m_nFixedEntrySize > 0 && GetFlag(RwfRMapHasStartpos) == false && GetFlag(RwfRMapHasSize) == false)
|
||||
m_pIstrm->seekg(m_posDataBegin + Postype(m_nFixedEntrySize * m_nCounter));
|
||||
iStrm.seekg(m_posDataBegin + Postype(m_nFixedEntrySize * m_nCounter));
|
||||
|
||||
if (GetFlag(RwfRMapHasId) == true)
|
||||
{
|
||||
|
@ -682,7 +677,7 @@ const ReadEntry* SsbRead::Find(const ID &id)
|
|||
{
|
||||
m_nNextReadHint = (i + 1) % nEntries;
|
||||
if (mapData[i].rposStart != 0)
|
||||
m_pIstrm->seekg(m_posStart + Postype(mapData[i].rposStart));
|
||||
iStrm.seekg(m_posStart + Postype(mapData[i].rposStart));
|
||||
return &mapData[i];
|
||||
}
|
||||
}
|
||||
|
@ -693,7 +688,6 @@ const ReadEntry* SsbRead::Find(const ID &id)
|
|||
|
||||
void SsbWrite::FinishWrite()
|
||||
{
|
||||
std::ostream& oStrm = *m_pOstrm;
|
||||
const Postype posDataEnd = oStrm.tellp();
|
||||
|
||||
Postype posMapStart = oStrm.tellp();
|
||||
|
@ -711,7 +705,7 @@ void SsbWrite::FinishWrite()
|
|||
oStrm.seekp(m_posEntrycount);
|
||||
|
||||
// Write a fixed size=2 Adaptive64LE because space for this value has already been reserved berforehand.
|
||||
mpt::IO::WriteAdaptiveInt64LE(oStrm, m_nCounter, 2, 2);
|
||||
mpt::IO::WriteAdaptiveInt64LE(oStrm, m_nCounter, 2);
|
||||
|
||||
if (GetFlag(RwfRwHasMap))
|
||||
{ // Write map start position.
|
||||
|
@ -719,7 +713,7 @@ void SsbWrite::FinishWrite()
|
|||
const uint64 rposMap = posMapStart - m_posStart;
|
||||
|
||||
// Write a fixed size=8 Adaptive64LE because space for this value has already been reserved berforehand.
|
||||
mpt::IO::WriteAdaptiveInt64LE(oStrm, rposMap, 8, 8);
|
||||
mpt::IO::WriteAdaptiveInt64LE(oStrm, rposMap, 8);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -10,8 +10,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "../common/typedefs.h"
|
||||
#include "../common/mptTypeTraits.h"
|
||||
#include "BuildSettings.h"
|
||||
|
||||
#include "../common/mptBaseTypes.h"
|
||||
#include "../common/mptIO.h"
|
||||
#include "../common/Endianness.h"
|
||||
|
||||
|
@ -236,7 +237,7 @@ public:
|
|||
STATIC_ASSERT(std::numeric_limits<T>::is_integer);
|
||||
typename mpt::make_le<T>::type valle;
|
||||
valle = val;
|
||||
return ID(std::string(mpt::as_raw_memory(valle), mpt::as_raw_memory(valle) + sizeof(valle)));
|
||||
return ID(std::string(mpt::byte_cast<const char*>(mpt::as_raw_memory(valle).data()), mpt::byte_cast<const char*>(mpt::as_raw_memory(valle).data() + sizeof(valle))));
|
||||
}
|
||||
bool IsPrintable() const;
|
||||
mpt::ustring AsString() const;
|
||||
|
@ -286,7 +287,7 @@ protected:
|
|||
|
||||
protected:
|
||||
|
||||
static const uint8 s_DefaultFlagbyte = 0;
|
||||
enum : uint8 { s_DefaultFlagbyte = 0 };
|
||||
static const char s_EntryID[3];
|
||||
|
||||
};
|
||||
|
@ -374,7 +375,7 @@ private:
|
|||
// immutable when reading, there is no need to ever invalidate the cache and
|
||||
// redo CacheMap().
|
||||
|
||||
std::istream* m_pIstrm; // Read: Pointer to read stream.
|
||||
std::istream& iStrm;
|
||||
|
||||
std::vector<char> m_Idarray; // Read: Holds entry ids.
|
||||
|
||||
|
@ -437,7 +438,7 @@ private:
|
|||
|
||||
private:
|
||||
|
||||
std::ostream* m_pOstrm; // Write: Pointer to write stream.
|
||||
std::ostream& oStrm;
|
||||
|
||||
Postype m_posEntrycount; // Write: Pos of entrycount field.
|
||||
Postype m_posMapPosField; // Write: Pos of map position field.
|
||||
|
@ -449,8 +450,8 @@ private:
|
|||
template <class T, class FuncObj>
|
||||
void SsbWrite::WriteItem(const T& obj, const ID &id, FuncObj Func)
|
||||
{
|
||||
const Postype pos = m_pOstrm->tellp();
|
||||
Func(*m_pOstrm, obj);
|
||||
const Postype pos = oStrm.tellp();
|
||||
Func(oStrm, obj);
|
||||
OnWroteItem(id, pos);
|
||||
}
|
||||
|
||||
|
@ -458,9 +459,9 @@ template <class T, class FuncObj>
|
|||
SsbRead::ReadRv SsbRead::ReadItem(T& obj, const ID &id, FuncObj Func)
|
||||
{
|
||||
const ReadEntry* pE = Find(id);
|
||||
const Postype pos = m_pIstrm->tellg();
|
||||
const Postype pos = iStrm.tellg();
|
||||
if (pE != nullptr || GetFlag(RwfRMapHasId) == false)
|
||||
Func(*m_pIstrm, obj, (pE) ? (pE->nSize) : invalidDatasize);
|
||||
Func(iStrm, obj, (pE) ? (pE->nSize) : invalidDatasize);
|
||||
return OnReadEntry(pE, id, pos);
|
||||
}
|
||||
|
||||
|
@ -468,11 +469,11 @@ SsbRead::ReadRv SsbRead::ReadItem(T& obj, const ID &id, FuncObj Func)
|
|||
template <class T, class FuncObj>
|
||||
SsbRead::ReadRv SsbRead::ReadIterItem(const ReadIterator& iter, T& obj, FuncObj func)
|
||||
{
|
||||
m_pIstrm->clear();
|
||||
iStrm.clear();
|
||||
if (iter->rposStart != 0)
|
||||
m_pIstrm->seekg(m_posStart + Postype(iter->rposStart));
|
||||
const Postype pos = m_pIstrm->tellg();
|
||||
func(*m_pIstrm, obj, iter->nSize);
|
||||
iStrm.seekg(m_posStart + Postype(iter->rposStart));
|
||||
const Postype pos = iStrm.tellg();
|
||||
func(iStrm, obj, iter->nSize);
|
||||
return OnReadEntry(&(*iter), ID(&m_Idarray[iter->nIdpos], iter->nIdLength), pos);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
/*
|
||||
* StdAfx.cpp
|
||||
* ----------
|
||||
* Purpose: Source file that includes just the standard includes
|
||||
* Notes : mptrack.pch will be the pre-compiled header
|
||||
* stdafx.obj will contain the pre-compiled type information
|
||||
* Authors: Olivier Lapicque
|
||||
* OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
MPT_MSVC_WORKAROUND_LNK4221(stdafx)
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -22,12 +22,23 @@
|
|||
|
||||
#if !defined(MPT_BUILD_WINESUPPORT)
|
||||
|
||||
#define _AFX_NO_MFC_CONTROLS_IN_DIALOGS // Do not include support for MFC controls in dialogs (reduces binary bloat; remove this #define if you want to use MFC controls)
|
||||
#include <afxwin.h> // MFC core and standard components
|
||||
// cppcheck-suppress missingInclude
|
||||
#include <afx.h> // MFC core
|
||||
// cppcheck-suppress missingInclude
|
||||
#include <afxwin.h> // MFC standard components
|
||||
// cppcheck-suppress missingInclude
|
||||
#include <afxext.h> // MFC extensions
|
||||
// cppcheck-suppress missingInclude
|
||||
#include <afxcmn.h> // MFC support for Windows Common Controls
|
||||
// cppcheck-suppress missingInclude
|
||||
#include <afxcview.h>
|
||||
// cppcheck-suppress missingInclude
|
||||
#include <afxdlgs.h>
|
||||
#ifdef MPT_MFC_FULL
|
||||
// cppcheck-suppress missingInclude
|
||||
#include <afxlistctrl.h>
|
||||
#endif // MPT_MFC_FULL
|
||||
// cppcheck-suppress missingInclude
|
||||
#include <afxole.h>
|
||||
|
||||
#endif // !MPT_BUILD_WINESUPPORT
|
||||
|
@ -47,27 +58,54 @@
|
|||
#endif
|
||||
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
#if MPT_COMPILER_MSVCCLANGC2
|
||||
// windows.h references IUnknown in a template function without having it even forward-declared.
|
||||
// Clang does not like that. Forward-declaration fixes it.
|
||||
struct IUnknown;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
// this will be available everywhere
|
||||
|
||||
#include "../common/typedefs.h"
|
||||
// <memory>
|
||||
// <new>
|
||||
// <climits>
|
||||
#include "../common/mptBaseMacros.h"
|
||||
// <iterator>
|
||||
// <cstddef>
|
||||
// <cstdint>
|
||||
// <stdint.h>
|
||||
|
||||
#include "../common/mptTypeTraits.h"
|
||||
#include "../common/mptBaseTypes.h"
|
||||
// "mptBaseMacros.h"
|
||||
// <array>
|
||||
// <limits>
|
||||
// <type_traits>
|
||||
// <cstdint>
|
||||
|
||||
#include "../common/mptAssert.h"
|
||||
// "mptBaseMacros.h"
|
||||
|
||||
#include "../common/mptBaseUtils.h"
|
||||
// <algorithm>
|
||||
// <bit>
|
||||
// <limits>
|
||||
// <numeric>
|
||||
// <utility>
|
||||
|
||||
#include "../common/mptException.h"
|
||||
// <exception>
|
||||
// <new>
|
||||
// <afx.h>
|
||||
|
||||
#include "../common/mptSpan.h"
|
||||
// "mptBaseTypes.h"
|
||||
// <array>
|
||||
// <iterator>
|
||||
|
||||
#include "../common/mptMemory.h"
|
||||
// "mptAssert.h"
|
||||
// "mptBaseTypes.h"
|
||||
// "mptSpan.h"
|
||||
// <utility>
|
||||
// <cstring>
|
||||
|
||||
#include "../common/mptAlloc.h"
|
||||
// "mptBaseMacros.h"
|
||||
// "mptMemory.h"
|
||||
// "mptSpan.h"
|
||||
// <memory>
|
||||
// <utility>
|
||||
// <vector>
|
||||
|
||||
#include "../common/mptString.h"
|
||||
// <algorithm>
|
||||
|
@ -76,6 +114,11 @@ struct IUnknown;
|
|||
// <type_traits>
|
||||
// <cstring>
|
||||
|
||||
#include "../common/mptExceptionText.h"
|
||||
// "mptException.h"
|
||||
// "mptString.h"
|
||||
// <exception>
|
||||
|
||||
#include "../common/mptStringFormat.h"
|
||||
|
||||
#include "../common/mptPathString.h"
|
||||
|
@ -83,15 +126,6 @@ struct IUnknown;
|
|||
#include "../common/Logging.h"
|
||||
|
||||
#include "../common/misc_util.h"
|
||||
// <algorithm>
|
||||
// <limits>
|
||||
// <string>
|
||||
// <type_traits>
|
||||
// <vector>
|
||||
// <cmath>
|
||||
// <cstdlib>
|
||||
// <cstring>
|
||||
// <time.h>
|
||||
|
||||
// for std::abs
|
||||
#include <cstdlib>
|
||||
|
@ -99,26 +133,6 @@ struct IUnknown;
|
|||
#include <cmath>
|
||||
#include <math.h>
|
||||
|
||||
#if defined(MPT_ENABLE_FILEIO_STDIO)
|
||||
// for FILE* definition (which cannot be forward-declared in a portable way)
|
||||
#include <cstdio>
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#ifndef NO_VST
|
||||
// VST SDK includes these headers after messing with default compiler structure
|
||||
// packing. No problem in practice as VST SDK sets packing matching the default
|
||||
// packing and we are compiling with default packing and standard headers should
|
||||
// be careful about structure packing anyway, but it is very much unclean
|
||||
// nonetheless. Pre-include the affected headers here as a future-proof
|
||||
// safe-guard and let their own include guards handle the further including by
|
||||
// VST SDK.
|
||||
#include <cstdint>
|
||||
#include <stdint.h>
|
||||
#include <cstring>
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
|
||||
//{{AFX_INSERT_LOCATION}}
|
||||
// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
/*
|
||||
* typedefs.cpp
|
||||
* ------------
|
||||
* Purpose: Basic data type definitions and assorted compiler-related helpers.
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "typedefs.h"
|
||||
|
||||
#include "Endianness.h"
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
#if MPT_PLATFORM_ENDIAN_KNOWN
|
||||
|
||||
MPT_MSVC_WORKAROUND_LNK4221(typedefs)
|
||||
|
||||
#else
|
||||
|
||||
int24::int24(int other)
|
||||
{
|
||||
MPT_MAYBE_CONSTANT_IF(mpt::endian_is_big()) {
|
||||
bytes[0] = (static_cast<unsigned int>(other)>>16)&0xff;
|
||||
bytes[1] = (static_cast<unsigned int>(other)>> 8)&0xff;
|
||||
bytes[2] = (static_cast<unsigned int>(other)>> 0)&0xff;
|
||||
} else {
|
||||
bytes[0] = (static_cast<unsigned int>(other)>> 0)&0xff;
|
||||
bytes[1] = (static_cast<unsigned int>(other)>> 8)&0xff;
|
||||
bytes[2] = (static_cast<unsigned int>(other)>>16)&0xff;
|
||||
}
|
||||
}
|
||||
|
||||
int24::operator int() const
|
||||
{
|
||||
MPT_MAYBE_CONSTANT_IF(mpt::endian_is_big()) {
|
||||
return (static_cast<int8>(bytes[0]) * 65536) + (bytes[1] * 256) + bytes[2];
|
||||
} else {
|
||||
return (static_cast<int8>(bytes[2]) * 65536) + (bytes[1] * 256) + bytes[0];
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,544 +0,0 @@
|
|||
/*
|
||||
* typedefs.h
|
||||
* ----------
|
||||
* Purpose: Basic data type definitions and assorted compiler-related helpers.
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
|
||||
// Advanced inline attributes
|
||||
#if MPT_COMPILER_MSVC
|
||||
#define MPT_FORCEINLINE __forceinline
|
||||
#define MPT_NOINLINE __declspec(noinline)
|
||||
#elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG || MPT_COMPILER_MSVCCLANGC2
|
||||
#define MPT_FORCEINLINE __attribute__((always_inline)) inline
|
||||
#define MPT_NOINLINE __attribute__((noinline))
|
||||
#else
|
||||
#define MPT_FORCEINLINE inline
|
||||
#define MPT_NOINLINE
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// constexpr
|
||||
#define MPT_CONSTEXPR11_FUN constexpr MPT_FORCEINLINE
|
||||
#define MPT_CONSTEXPR11_VAR constexpr
|
||||
#if MPT_CXX_AT_LEAST(14)
|
||||
#define MPT_CONSTEXPR14_FUN constexpr MPT_FORCEINLINE
|
||||
#define MPT_CONSTEXPR14_VAR constexpr
|
||||
#else
|
||||
#define MPT_CONSTEXPR14_FUN MPT_FORCEINLINE
|
||||
#define MPT_CONSTEXPR14_VAR const
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// C++17 std::size
|
||||
OPENMPT_NAMESPACE_END
|
||||
#include <cstddef>
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
namespace mpt {
|
||||
template <typename T>
|
||||
MPT_CONSTEXPR11_FUN auto size(const T & v) -> decltype(v.size())
|
||||
{
|
||||
return v.size();
|
||||
}
|
||||
template <typename T, std::size_t N>
|
||||
MPT_CONSTEXPR11_FUN std::size_t size(const T(&)[N]) noexcept
|
||||
{
|
||||
return N;
|
||||
}
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
// MPT_ARRAY_COUNT macro computes the number of elements in a statically-allocated array.
|
||||
#if MPT_COMPILER_MSVC
|
||||
OPENMPT_NAMESPACE_END
|
||||
#include <cstdlib>
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
#define MPT_ARRAY_COUNT(x) _countof(x)
|
||||
#else
|
||||
#define MPT_ARRAY_COUNT(x) (sizeof((x))/sizeof((x)[0]))
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// Use MPT_RESTRICT to indicate that a pointer is guaranteed to not be aliased.
|
||||
#if MPT_COMPILER_MSVC || MPT_COMPILER_GCC || MPT_COMPILER_CLANG || MPT_COMPILER_MSVCCLANGC2
|
||||
#define MPT_RESTRICT __restrict
|
||||
#else
|
||||
#define MPT_RESTRICT
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// Some functions might be deprecated although they are still in use.
|
||||
// Tag them with "MPT_DEPRECATED".
|
||||
#if MPT_COMPILER_MSVC
|
||||
#define MPT_DEPRECATED __declspec(deprecated)
|
||||
#elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG || MPT_COMPILER_MSVCCLANGC2
|
||||
#define MPT_DEPRECATED __attribute__((deprecated))
|
||||
#else
|
||||
#define MPT_DEPRECATED
|
||||
#endif
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
#define MPT_DEPRECATED_TRACKER MPT_DEPRECATED
|
||||
#define MPT_DEPRECATED_LIBOPENMPT
|
||||
#elif defined(LIBOPENMPT_BUILD)
|
||||
#define MPT_DEPRECATED_TRACKER
|
||||
#define MPT_DEPRECATED_LIBOPENMPT MPT_DEPRECATED
|
||||
#else
|
||||
#define MPT_DEPRECATED_TRACKER MPT_DEPRECATED
|
||||
#define MPT_DEPRECATED_LIBOPENMPT MPT_DEPRECATED
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
|
||||
#if MPT_CXX_AT_LEAST(14)
|
||||
namespace mpt {
|
||||
using std::make_unique;
|
||||
} // namespace mpt
|
||||
#else
|
||||
namespace mpt {
|
||||
template<typename T, typename... Args>
|
||||
std::unique_ptr<T> make_unique(Args&&... args)
|
||||
{
|
||||
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
||||
}
|
||||
} // namespace mpt
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
#define MPT_CONSTANT_IF(x) \
|
||||
__pragma(warning(push)) \
|
||||
__pragma(warning(disable:4127)) \
|
||||
if(x) \
|
||||
__pragma(warning(pop)) \
|
||||
/**/
|
||||
#define MPT_MAYBE_CONSTANT_IF(x) \
|
||||
__pragma(warning(push)) \
|
||||
__pragma(warning(disable:4127)) \
|
||||
if(x) \
|
||||
__pragma(warning(pop)) \
|
||||
/**/
|
||||
#endif
|
||||
|
||||
#if MPT_COMPILER_GCC
|
||||
#define MPT_MAYBE_CONSTANT_IF(x) \
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wtype-limits\"") \
|
||||
if(x) \
|
||||
_Pragma("GCC diagnostic pop") \
|
||||
/**/
|
||||
#endif
|
||||
|
||||
#if MPT_COMPILER_CLANG || MPT_COMPILER_MSVCCLANGC2
|
||||
#define MPT_MAYBE_CONSTANT_IF(x) \
|
||||
_Pragma("clang diagnostic push") \
|
||||
_Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") \
|
||||
_Pragma("clang diagnostic ignored \"-Wtype-limits\"") \
|
||||
_Pragma("clang diagnostic ignored \"-Wtautological-constant-out-of-range-compare\"") \
|
||||
if(x) \
|
||||
_Pragma("clang diagnostic pop") \
|
||||
/**/
|
||||
#endif
|
||||
|
||||
#if !defined(MPT_CONSTANT_IF)
|
||||
// MPT_CONSTANT_IF disables compiler warnings for conditions that are either always true or always false for some reason (dependent on template arguments for example)
|
||||
#define MPT_CONSTANT_IF(x) if(x)
|
||||
#endif
|
||||
|
||||
#if !defined(MPT_MAYBE_CONSTANT_IF)
|
||||
// MPT_MAYBE_CONSTANT_IF disables compiler warnings for conditions that may in some case be either always false or always true (this may turn out to be useful in ASSERTions in some cases).
|
||||
#define MPT_MAYBE_CONSTANT_IF(x) if(x)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
// MSVC warns for the well-known and widespread "do { } while(0)" idiom with warning level 4 ("conditional expression is constant").
|
||||
// It does not warn with "while(0,0)". However this again causes warnings with other compilers.
|
||||
// Solve it with a macro.
|
||||
#define MPT_DO do
|
||||
#define MPT_WHILE_0 while(0,0)
|
||||
#endif
|
||||
|
||||
#ifndef MPT_DO
|
||||
#define MPT_DO do
|
||||
#endif
|
||||
#ifndef MPT_WHILE_0
|
||||
#define MPT_WHILE_0 while(0)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if MPT_COMPILER_MSVC && defined(UNREFERENCED_PARAMETER)
|
||||
#define MPT_UNREFERENCED_PARAMETER(x) UNREFERENCED_PARAMETER(x)
|
||||
#else
|
||||
#define MPT_UNREFERENCED_PARAMETER(x) (void)(x)
|
||||
#endif
|
||||
|
||||
#define MPT_UNUSED_VARIABLE(x) MPT_UNREFERENCED_PARAMETER(x)
|
||||
|
||||
|
||||
|
||||
// Exception handling helpers, because MFC requires explicit deletion of the exception object,
|
||||
// Thus, always call exactly one of MPT_EXCEPTION_RETHROW_OUT_OF_MEMORY() or MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e).
|
||||
|
||||
#if defined(_MFC_VER)
|
||||
|
||||
#define MPT_EXCEPTION_THROW_OUT_OF_MEMORY() MPT_DO { AfxThrowMemoryException(); } MPT_WHILE_0
|
||||
#define MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e) catch ( CMemoryException * e )
|
||||
#define MPT_EXCEPTION_RETHROW_OUT_OF_MEMORY() MPT_DO { throw; } MPT_WHILE_0
|
||||
#define MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e) MPT_DO { if(e) { e->Delete(); e = nullptr; } } MPT_WHILE_0
|
||||
|
||||
#else // !_MFC_VER
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
||||
#include <new>
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
#define MPT_EXCEPTION_THROW_OUT_OF_MEMORY() MPT_DO { throw std::bad_alloc(); } MPT_WHILE_0
|
||||
#define MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e) catch ( const std::bad_alloc & e )
|
||||
#define MPT_EXCEPTION_RETHROW_OUT_OF_MEMORY() MPT_DO { throw; } MPT_WHILE_0
|
||||
#define MPT_EXCEPTION_DELETE_OUT_OF_MEMORY(e) MPT_DO { MPT_UNUSED_VARIABLE(e); } MPT_WHILE_0
|
||||
|
||||
#endif // _MFC_VER
|
||||
|
||||
|
||||
|
||||
// Static code checkers might need to get the knowledge of our assertions transferred to them.
|
||||
#define MPT_CHECKER_ASSUME_ASSERTIONS 1
|
||||
//#define MPT_CHECKER_ASSUME_ASSERTIONS 0
|
||||
|
||||
#ifdef MPT_BUILD_ANALYZED
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
|
||||
#if MPT_CHECKER_ASSUME_ASSERTIONS
|
||||
#define MPT_CHECKER_ASSUME(x) __analysis_assume(!!(x))
|
||||
#endif
|
||||
|
||||
#elif MPT_COMPILER_CLANG || MPT_COMPILER_MSVCCLANGC2
|
||||
|
||||
#if MPT_CHECKER_ASSUME_ASSERTIONS
|
||||
#ifdef NDEBUG
|
||||
#error "Builds for static analyzers depend on std::assert being enabled, but the current build has #define NDEBUG. This makes no sense."
|
||||
#endif
|
||||
OPENMPT_NAMESPACE_END
|
||||
#include <cassert>
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
#define MPT_CHECKER_ASSUME(x) assert(!!(x))
|
||||
#endif
|
||||
|
||||
#endif // MPT_COMPILER
|
||||
|
||||
#endif // MPT_BUILD_ANALYZED
|
||||
|
||||
#ifndef MPT_CHECKER_ASSUME
|
||||
#define MPT_CHECKER_ASSUME(x) MPT_DO { } MPT_WHILE_0
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if defined(_MFC_VER)
|
||||
|
||||
#if !defined(ASSERT)
|
||||
#error "MFC is expected to #define ASSERT"
|
||||
#endif // !defined(ASERRT)
|
||||
#define MPT_FRAMEWORK_ASSERT_IS_DEFINED
|
||||
|
||||
#if defined(_DEBUG)
|
||||
#define MPT_FRAMEWORK_ASSERT_IS_ACTIVE 1
|
||||
#else // !_DEBUG
|
||||
#define MPT_FRAMEWORK_ASSERT_IS_ACTIVE 0
|
||||
#endif // _DEBUG
|
||||
|
||||
// let MFC handle our asserts
|
||||
#define MPT_ASSERT_USE_FRAMEWORK 1
|
||||
|
||||
#else // !_MFC_VER
|
||||
|
||||
#if defined(ASSERT)
|
||||
#define MPT_FRAMEWORK_ASSERT_IS_DEFINED
|
||||
#if defined(_DEBUG)
|
||||
#define MPT_FRAMEWORK_ASSERT_IS_ACTIVE 1
|
||||
#else // !_DEBUG
|
||||
#define MPT_FRAMEWORK_ASSERT_IS_ACTIVE 0
|
||||
#endif // _DEBUG
|
||||
#endif // !defined(ASERRT)
|
||||
|
||||
// handle assert in our own way without relying on some platform-/framework-specific assert implementation
|
||||
#define MPT_ASSERT_USE_FRAMEWORK 0
|
||||
|
||||
#endif // _MFC_VER
|
||||
|
||||
|
||||
#if defined(MPT_FRAMEWORK_ASSERT_IS_DEFINED) && (MPT_ASSERT_USE_FRAMEWORK == 1)
|
||||
|
||||
#define MPT_ASSERT_NOTREACHED() ASSERT(0)
|
||||
#define MPT_ASSERT(expr) ASSERT((expr))
|
||||
#define MPT_ASSERT_MSG(expr, msg) ASSERT((expr) && (msg))
|
||||
#if (MPT_FRAMEWORK_ASSERT_IS_ACTIVE == 1)
|
||||
#define MPT_ASSERT_ALWAYS(expr) ASSERT((expr))
|
||||
#define MPT_ASSERT_ALWAYS_MSG(expr, msg) ASSERT((expr) && (msg))
|
||||
#else
|
||||
#define MPT_ASSERT_ALWAYS(expr) MPT_DO { if(!(expr)) { AssertHandler(__FILE__, __LINE__, __FUNCTION__, #expr); } MPT_CHECKER_ASSUME(expr); } MPT_WHILE_0
|
||||
#define MPT_ASSERT_ALWAYS_MSG(expr, msg) MPT_DO { if(!(expr)) { AssertHandler(__FILE__, __LINE__, __FUNCTION__, #expr, msg); } MPT_CHECKER_ASSUME(expr); } MPT_WHILE_0
|
||||
#ifndef MPT_ASSERT_HANDLER_NEEDED
|
||||
#define MPT_ASSERT_HANDLER_NEEDED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#elif defined(NO_ASSERTS)
|
||||
|
||||
#define MPT_ASSERT_NOTREACHED() MPT_CHECKER_ASSUME(0)
|
||||
#define MPT_ASSERT(expr) MPT_CHECKER_ASSUME(expr)
|
||||
#define MPT_ASSERT_MSG(expr, msg) MPT_CHECKER_ASSUME(expr)
|
||||
#define MPT_ASSERT_ALWAYS(expr) MPT_DO { if(!(expr)) { AssertHandler(__FILE__, __LINE__, __FUNCTION__, #expr); } MPT_CHECKER_ASSUME(expr); } MPT_WHILE_0
|
||||
#define MPT_ASSERT_ALWAYS_MSG(expr, msg) MPT_DO { if(!(expr)) { AssertHandler(__FILE__, __LINE__, __FUNCTION__, #expr, msg); } MPT_CHECKER_ASSUME(expr); } MPT_WHILE_0
|
||||
#ifndef MPT_ASSERT_HANDLER_NEEDED
|
||||
#define MPT_ASSERT_HANDLER_NEEDED
|
||||
#endif
|
||||
|
||||
#else // !NO_ASSERTS
|
||||
|
||||
#define MPT_ASSERT_NOTREACHED() MPT_DO { MPT_CONSTANT_IF(!(0)) { AssertHandler(__FILE__, __LINE__, __FUNCTION__, "0"); } MPT_CHECKER_ASSUME(0); } MPT_WHILE_0
|
||||
#define MPT_ASSERT(expr) MPT_DO { if(!(expr)) { AssertHandler(__FILE__, __LINE__, __FUNCTION__, #expr); } MPT_CHECKER_ASSUME(expr); } MPT_WHILE_0
|
||||
#define MPT_ASSERT_MSG(expr, msg) MPT_DO { if(!(expr)) { AssertHandler(__FILE__, __LINE__, __FUNCTION__, #expr, msg); } MPT_CHECKER_ASSUME(expr); } MPT_WHILE_0
|
||||
#define MPT_ASSERT_ALWAYS(expr) MPT_DO { if(!(expr)) { AssertHandler(__FILE__, __LINE__, __FUNCTION__, #expr); } MPT_CHECKER_ASSUME(expr); } MPT_WHILE_0
|
||||
#define MPT_ASSERT_ALWAYS_MSG(expr, msg) MPT_DO { if(!(expr)) { AssertHandler(__FILE__, __LINE__, __FUNCTION__, #expr, msg); } MPT_CHECKER_ASSUME(expr); } MPT_WHILE_0
|
||||
#ifndef MPT_ASSERT_HANDLER_NEEDED
|
||||
#define MPT_ASSERT_HANDLER_NEEDED
|
||||
#endif
|
||||
|
||||
#endif // NO_ASSERTS
|
||||
|
||||
|
||||
#if defined(MPT_ASSERT_HANDLER_NEEDED)
|
||||
// custom assert handler needed
|
||||
MPT_NOINLINE void AssertHandler(const char *file, int line, const char *function, const char *expr, const char *msg=nullptr);
|
||||
#endif // MPT_ASSERT_HANDLER_NEEDED
|
||||
|
||||
|
||||
|
||||
// Compile time assert.
|
||||
#define MPT_STATIC_ASSERT(expr) static_assert((expr), "compile time assertion failed: " #expr)
|
||||
|
||||
|
||||
|
||||
// Macro for marking intentional fall-throughs in switch statements - can be used for static analysis if supported.
|
||||
#if (MPT_CXX >= 17)
|
||||
#define MPT_FALLTHROUGH [[fallthrough]]
|
||||
#elif MPT_COMPILER_MSVC
|
||||
#define MPT_FALLTHROUGH __fallthrough
|
||||
#elif MPT_COMPILER_CLANG || MPT_COMPILER_MSVCCLANGC2
|
||||
#define MPT_FALLTHROUGH [[clang::fallthrough]]
|
||||
#elif MPT_COMPILER_GCC && MPT_GCC_AT_LEAST(7,1,0)
|
||||
#define MPT_FALLTHROUGH __attribute__((fallthrough))
|
||||
#elif defined(__has_cpp_attribute)
|
||||
#if __has_cpp_attribute(fallthrough)
|
||||
#define MPT_FALLTHROUGH [[fallthrough]]
|
||||
#else
|
||||
#define MPT_FALLTHROUGH MPT_DO { } MPT_WHILE_0
|
||||
#endif
|
||||
#else
|
||||
#define MPT_FALLTHROUGH MPT_DO { } MPT_WHILE_0
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
||||
#include <climits>
|
||||
#include <cstdint>
|
||||
#include <stdint.h>
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
typedef std::int8_t int8;
|
||||
typedef std::int16_t int16;
|
||||
typedef std::int32_t int32;
|
||||
typedef std::int64_t int64;
|
||||
typedef std::uint8_t uint8;
|
||||
typedef std::uint16_t uint16;
|
||||
typedef std::uint32_t uint32;
|
||||
typedef std::uint64_t uint64;
|
||||
|
||||
const int8 int8_min = INT8_MIN;
|
||||
const int16 int16_min = INT16_MIN;
|
||||
const int32 int32_min = INT32_MIN;
|
||||
const int64 int64_min = INT64_MIN;
|
||||
|
||||
const int8 int8_max = INT8_MAX;
|
||||
const int16 int16_max = INT16_MAX;
|
||||
const int32 int32_max = INT32_MAX;
|
||||
const int64 int64_max = INT64_MAX;
|
||||
|
||||
const uint8 uint8_max = UINT8_MAX;
|
||||
const uint16 uint16_max = UINT16_MAX;
|
||||
const uint32 uint32_max = UINT32_MAX;
|
||||
const uint64 uint64_max = UINT64_MAX;
|
||||
|
||||
|
||||
// 24-bit integer wrapper (for 24-bit PCM)
|
||||
struct int24
|
||||
{
|
||||
uint8 bytes[3];
|
||||
int24() { bytes[0] = bytes[1] = bytes[2] = 0; }
|
||||
#if MPT_PLATFORM_ENDIAN_KNOWN
|
||||
explicit int24(int other)
|
||||
{
|
||||
#ifdef MPT_PLATFORM_BIG_ENDIAN
|
||||
bytes[0] = (static_cast<unsigned int>(other)>>16)&0xff;
|
||||
bytes[1] = (static_cast<unsigned int>(other)>> 8)&0xff;
|
||||
bytes[2] = (static_cast<unsigned int>(other)>> 0)&0xff;
|
||||
#else
|
||||
bytes[0] = (static_cast<unsigned int>(other)>> 0)&0xff;
|
||||
bytes[1] = (static_cast<unsigned int>(other)>> 8)&0xff;
|
||||
bytes[2] = (static_cast<unsigned int>(other)>>16)&0xff;
|
||||
#endif
|
||||
}
|
||||
operator int() const
|
||||
{
|
||||
#ifdef MPT_PLATFORM_BIG_ENDIAN
|
||||
return (static_cast<int8>(bytes[0]) * 65536) + (bytes[1] * 256) + bytes[2];
|
||||
#else
|
||||
return (static_cast<int8>(bytes[2]) * 65536) + (bytes[1] * 256) + bytes[0];
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
explicit int24(int other);
|
||||
operator int() const;
|
||||
#endif
|
||||
};
|
||||
MPT_STATIC_ASSERT(sizeof(int24) == 3);
|
||||
#define int24_min (0-0x00800000)
|
||||
#define int24_max (0+0x007fffff)
|
||||
|
||||
|
||||
typedef float float32;
|
||||
MPT_STATIC_ASSERT(sizeof(float32) == 4);
|
||||
|
||||
typedef double float64;
|
||||
MPT_STATIC_ASSERT(sizeof(float64) == 8);
|
||||
|
||||
|
||||
MPT_STATIC_ASSERT(sizeof(std::uintptr_t) == sizeof(void*));
|
||||
|
||||
|
||||
namespace mpt {
|
||||
|
||||
MPT_STATIC_ASSERT(CHAR_BIT == 8);
|
||||
|
||||
MPT_STATIC_ASSERT(sizeof(char) == 1);
|
||||
|
||||
typedef unsigned char byte;
|
||||
MPT_STATIC_ASSERT(sizeof(mpt::byte) == 1);
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
|
||||
#if defined(_M_X64)
|
||||
#define MPT_ARCH_BITS 64
|
||||
#define MPT_ARCH_BITS_32 0
|
||||
#define MPT_ARCH_BITS_64 1
|
||||
#elif defined(_M_IX86)
|
||||
#define MPT_ARCH_BITS 32
|
||||
#define MPT_ARCH_BITS_32 1
|
||||
#define MPT_ARCH_BITS_64 0
|
||||
#endif
|
||||
|
||||
#elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG || MPT_COMPILER_MSVCCLANGC2
|
||||
|
||||
#if defined(__SIZEOF_POINTER__)
|
||||
#if (__SIZEOF_POINTER__ == 8)
|
||||
#define MPT_ARCH_BITS 64
|
||||
#define MPT_ARCH_BITS_32 0
|
||||
#define MPT_ARCH_BITS_64 1
|
||||
#elif (__SIZEOF_POINTER__ == 4)
|
||||
#define MPT_ARCH_BITS 32
|
||||
#define MPT_ARCH_BITS_32 1
|
||||
#define MPT_ARCH_BITS_64 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // MPT_COMPILER
|
||||
|
||||
// fallback
|
||||
|
||||
#if !defined(MPT_ARCH_BITS)
|
||||
#include <cstdint>
|
||||
#include <stdint.h>
|
||||
MPT_STATIC_ASSERT(sizeof(std::uintptr_t) == sizeof(void*));
|
||||
#if defined(UINTPTR_MAX)
|
||||
#if (UINTPTR_MAX == 0xffffffffffffffffull)
|
||||
#define MPT_ARCH_BITS 64
|
||||
#define MPT_ARCH_BITS_32 0
|
||||
#define MPT_ARCH_BITS_64 1
|
||||
#elif (UINTPTR_MAX == 0xffffffffu)
|
||||
#define MPT_ARCH_BITS 32
|
||||
#define MPT_ARCH_BITS_32 1
|
||||
#define MPT_ARCH_BITS_64 0
|
||||
#endif
|
||||
#endif // UINTPTR_MAX
|
||||
#endif // MPT_ARCH_BITS
|
||||
|
||||
|
||||
|
||||
#if MPT_COMPILER_GCC || MPT_COMPILER_CLANG || MPT_COMPILER_MSVCCLANGC2
|
||||
#define MPT_PRINTF_FUNC(formatstringindex,varargsindex) __attribute__((format(printf, formatstringindex, varargsindex)))
|
||||
#else
|
||||
#define MPT_PRINTF_FUNC(formatstringindex,varargsindex)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
// warning LNK4221: no public symbols found; archive member will be inaccessible
|
||||
// There is no way to selectively disable linker warnings.
|
||||
// #pragma warning does not apply and a command line option does not exist.
|
||||
// Some options:
|
||||
// 1. Macro which generates a variable with a unique name for each file (which means we have to pass the filename to the macro)
|
||||
// 2. unnamed namespace containing any symbol (does not work for c++11 compilers because they actually have internal linkage now)
|
||||
// 3. An unused trivial inline function.
|
||||
// Option 3 does not actually solve the problem though, which leaves us with option 1.
|
||||
// In any case, for optimized builds, the linker will just remove the useless symbol.
|
||||
#define MPT_MSVC_WORKAROUND_LNK4221_CONCAT_DETAIL(x,y) x##y
|
||||
#define MPT_MSVC_WORKAROUND_LNK4221_CONCAT(x,y) MPT_MSVC_WORKAROUND_LNK4221_CONCAT_DETAIL(x,y)
|
||||
#define MPT_MSVC_WORKAROUND_LNK4221(x) int MPT_MSVC_WORKAROUND_LNK4221_CONCAT(mpt_msvc_workaround_lnk4221_,x) = 0;
|
||||
#endif
|
||||
|
||||
#ifndef MPT_MSVC_WORKAROUND_LNK4221
|
||||
#define MPT_MSVC_WORKAROUND_LNK4221(x)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// legacy
|
||||
#define CountOf(x) MPT_ARRAY_COUNT(x)
|
||||
#define STATIC_ASSERT(x) MPT_STATIC_ASSERT(x)
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -17,98 +17,86 @@
|
|||
#include "versionNumber.h"
|
||||
#include "svn_version.h"
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
namespace MptVersion {
|
||||
|
||||
static_assert((MPT_VERSION_NUMERIC & 0xffff) != 0x0000, "Version numbers ending in .00.00 shall never exist again, as they make interpreting the version number ambiguous for file formats which can only store the two major parts of the version number (e.g. IT and S3M).");
|
||||
|
||||
const VersionNum num = MPT_VERSION_NUMERIC;
|
||||
static_assert((MPT_VERSION_CURRENT.GetRawVersion() & 0xffffu) != 0x0000u, "Version numbers ending in .00.00 shall never exist again, as they make interpreting the version number ambiguous for file formats which can only store the two major parts of the version number (e.g. IT and S3M).");
|
||||
|
||||
const char * const str = MPT_VERSION_STR;
|
||||
|
||||
std::string GetOpenMPTVersionStr()
|
||||
|
||||
Version Version::Current() noexcept
|
||||
{
|
||||
return std::string("OpenMPT " MPT_VERSION_STR);
|
||||
return MPT_VERSION_CURRENT;
|
||||
}
|
||||
|
||||
VersionNum ToNum(const std::string &s)
|
||||
mpt::ustring Version::GetOpenMPTVersionString() const
|
||||
{
|
||||
VersionNum result = 0;
|
||||
std::vector<std::string> numbers = mpt::String::Split<std::string>(s, std::string("."));
|
||||
for(std::size_t i = 0; i < numbers.size() && i < 4; ++i)
|
||||
return U_("OpenMPT ") + ToUString();
|
||||
}
|
||||
|
||||
Version Version::Parse(const mpt::ustring &s)
|
||||
{
|
||||
uint32 result = 0;
|
||||
std::vector<mpt::ustring> numbers = mpt::String::Split<mpt::ustring>(s, U_("."));
|
||||
for (std::size_t i = 0; i < numbers.size() && i < 4; ++i)
|
||||
{
|
||||
result |= (mpt::String::Parse::Hex<unsigned int>(numbers[i]) & 0xff) << ((3-i)*8);
|
||||
result |= (mpt::String::Parse::Hex<unsigned int>(numbers[i]) & 0xff) << ((3 - i) * 8);
|
||||
}
|
||||
return result;
|
||||
|
||||
return Version(result);
|
||||
}
|
||||
|
||||
std::string ToStr(const VersionNum v)
|
||||
mpt::ustring Version::ToUString() const
|
||||
{
|
||||
uint32 v = m_Version;
|
||||
if(v == 0)
|
||||
{
|
||||
// Unknown version
|
||||
return "Unknown";
|
||||
return U_("Unknown");
|
||||
} else if((v & 0xFFFF) == 0)
|
||||
{
|
||||
// Only parts of the version number are known (e.g. when reading the version from the IT or S3M file header)
|
||||
return mpt::format("%1.%2")(mpt::fmt::HEX((v >> 24) & 0xFF), mpt::fmt::HEX0<2>((v >> 16) & 0xFF));
|
||||
return mpt::format(U_("%1.%2"))(mpt::ufmt::HEX((v >> 24) & 0xFF), mpt::ufmt::HEX0<2>((v >> 16) & 0xFF));
|
||||
} else
|
||||
{
|
||||
// Full version info available
|
||||
return mpt::format("%1.%2.%3.%4")(mpt::fmt::HEX((v >> 24) & 0xFF), mpt::fmt::HEX0<2>((v >> 16) & 0xFF), mpt::fmt::HEX0<2>((v >> 8) & 0xFF), mpt::fmt::HEX0<2>((v) & 0xFF));
|
||||
return mpt::format(U_("%1.%2.%3.%4"))(mpt::ufmt::HEX((v >> 24) & 0xFF), mpt::ufmt::HEX0<2>((v >> 16) & 0xFF), mpt::ufmt::HEX0<2>((v >> 8) & 0xFF), mpt::ufmt::HEX0<2>((v) & 0xFF));
|
||||
}
|
||||
}
|
||||
|
||||
mpt::ustring ToUString(const VersionNum v)
|
||||
Version Version::WithoutTestNumber() const noexcept
|
||||
{
|
||||
if(v == 0)
|
||||
{
|
||||
// Unknown version
|
||||
return MPT_USTRING("Unknown");
|
||||
} else if((v & 0xFFFF) == 0)
|
||||
{
|
||||
// Only parts of the version number are known (e.g. when reading the version from the IT or S3M file header)
|
||||
return mpt::format(MPT_USTRING("%1.%2"))(mpt::ufmt::HEX((v >> 24) & 0xFF), mpt::ufmt::HEX0<2>((v >> 16) & 0xFF));
|
||||
} else
|
||||
{
|
||||
// Full version info available
|
||||
return mpt::format(MPT_USTRING("%1.%2.%3.%4"))(mpt::ufmt::HEX((v >> 24) & 0xFF), mpt::ufmt::HEX0<2>((v >> 16) & 0xFF), mpt::ufmt::HEX0<2>((v >> 8) & 0xFF), mpt::ufmt::HEX0<2>((v) & 0xFF));
|
||||
}
|
||||
return Version(m_Version & 0xFFFFFF00u);
|
||||
}
|
||||
|
||||
VersionNum RemoveBuildNumber(const VersionNum num_)
|
||||
Version Version::WithoutPatchOrTestNumbers() const noexcept
|
||||
{
|
||||
return (num_ & 0xFFFFFF00);
|
||||
return Version(m_Version & 0xFFFF0000u);
|
||||
}
|
||||
|
||||
bool IsTestBuild(const VersionNum num_)
|
||||
bool Version::IsTestVersion() const noexcept
|
||||
{
|
||||
return (
|
||||
// Legacy
|
||||
(num_ > MAKE_VERSION_NUMERIC(1,17,02,54) && num_ < MAKE_VERSION_NUMERIC(1,18,02,00) && num_ != MAKE_VERSION_NUMERIC(1,18,00,00))
|
||||
(*this > MAKE_VERSION_NUMERIC(1,17,02,54) && *this < MAKE_VERSION_NUMERIC(1,18,02,00) && *this != MAKE_VERSION_NUMERIC(1,18,00,00))
|
||||
||
|
||||
// Test builds have non-zero VER_MINORMINOR
|
||||
(num_ > MAKE_VERSION_NUMERIC(1,18,02,00) && RemoveBuildNumber(num_) != num_)
|
||||
(*this > MAKE_VERSION_NUMERIC(1,18,02,00) && ((m_Version & 0xFFFFFF00u) != m_Version))
|
||||
);
|
||||
}
|
||||
|
||||
bool IsDebugBuild()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static std::string GetUrl()
|
||||
|
||||
namespace Source {
|
||||
|
||||
static mpt::ustring GetUrl()
|
||||
{
|
||||
#ifdef OPENMPT_VERSION_URL
|
||||
return OPENMPT_VERSION_URL;
|
||||
return mpt::ToUnicode(mpt::CharsetASCII, OPENMPT_VERSION_URL);
|
||||
#else
|
||||
return "";
|
||||
return mpt::ustring();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -146,7 +134,7 @@ static int GetRevision()
|
|||
#else
|
||||
#if MPT_COMPILER_MSVC
|
||||
#pragma message("SVN revision unknown. Please check your build system.")
|
||||
#elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG || MPT_COMPILER_MSVCCLANGC2
|
||||
#elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG
|
||||
#warning "SVN revision unknown. Please check your build system."
|
||||
#else
|
||||
// There is no portable way to display a warning.
|
||||
|
@ -218,281 +206,302 @@ static bool IsPackage()
|
|||
#endif
|
||||
}
|
||||
|
||||
static std::string GetSourceDate()
|
||||
static mpt::ustring GetSourceDate()
|
||||
{
|
||||
#if defined(OPENMPT_VERSION_DATE)
|
||||
return OPENMPT_VERSION_DATE;
|
||||
return mpt::ToUnicode(mpt::CharsetASCII, OPENMPT_VERSION_DATE);
|
||||
#else
|
||||
return "";
|
||||
return mpt::ustring();
|
||||
#endif
|
||||
}
|
||||
|
||||
SourceInfo GetSourceInfo()
|
||||
} // namespace Source
|
||||
|
||||
SourceInfo::SourceInfo()
|
||||
: m_Url(Source::GetUrl())
|
||||
, m_Revision(Source::GetRevision())
|
||||
, m_IsDirty(Source::IsDirty())
|
||||
, m_HasMixedRevisions(Source::HasMixedRevisions())
|
||||
, m_IsPackage(Source::IsPackage())
|
||||
, m_Date(Source::GetSourceDate())
|
||||
{
|
||||
SourceInfo result;
|
||||
result.Url = GetUrl();
|
||||
result.Revision = GetRevision();
|
||||
result.IsDirty = IsDirty();
|
||||
result.HasMixedRevisions = HasMixedRevisions();
|
||||
result.IsPackage = IsPackage();
|
||||
result.Date = GetSourceDate();
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string SourceInfo::GetStateString() const
|
||||
mpt::ustring SourceInfo::GetUrlWithRevision() const
|
||||
{
|
||||
std::string retval;
|
||||
if(IsDirty)
|
||||
if(m_Url.empty() || (m_Revision == 0))
|
||||
{
|
||||
retval += "+dirty";
|
||||
return mpt::ustring();
|
||||
}
|
||||
if(HasMixedRevisions)
|
||||
return m_Url + UL_("@") + mpt::ufmt::val(m_Revision);
|
||||
}
|
||||
|
||||
mpt::ustring SourceInfo::GetStateString() const
|
||||
{
|
||||
mpt::ustring retval;
|
||||
if(m_IsDirty)
|
||||
{
|
||||
retval += "+mixed";
|
||||
retval += UL_("+dirty");
|
||||
}
|
||||
if(m_HasMixedRevisions)
|
||||
{
|
||||
retval += UL_("+mixed");
|
||||
}
|
||||
if(retval.empty())
|
||||
{
|
||||
retval += "clean";
|
||||
retval += UL_("clean");
|
||||
}
|
||||
if(IsPackage)
|
||||
if(m_IsPackage)
|
||||
{
|
||||
retval += "-pkg";
|
||||
retval += UL_("-pkg");
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
std::string GetBuildDateString()
|
||||
SourceInfo SourceInfo::Current()
|
||||
{
|
||||
#ifdef MODPLUG_TRACKER
|
||||
#if defined(OPENMPT_BUILD_DATE)
|
||||
return OPENMPT_BUILD_DATE;
|
||||
#else
|
||||
return __DATE__ " " __TIME__ ;
|
||||
#endif
|
||||
#else // !MODPLUG_TRACKER
|
||||
return GetSourceInfo().Date;
|
||||
#endif // MODPLUG_TRACKER
|
||||
return SourceInfo();
|
||||
}
|
||||
|
||||
static std::string GetBuildFlagsString()
|
||||
|
||||
|
||||
namespace Build {
|
||||
|
||||
bool IsReleasedBuild()
|
||||
{
|
||||
std::string retval;
|
||||
return !(Version::Current().IsTestVersion() || IsDebugBuild() || Source::IsDirty() || Source::HasMixedRevisions());
|
||||
}
|
||||
|
||||
bool IsDebugBuild()
|
||||
{
|
||||
#if defined(MPT_BUILD_DEBUG) || defined(DEBUG) || defined(_DEBUG)
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
mpt::ustring GetBuildDateString()
|
||||
{
|
||||
mpt::ustring result;
|
||||
#ifdef MODPLUG_TRACKER
|
||||
if(IsTestBuild())
|
||||
#if defined(OPENMPT_BUILD_DATE)
|
||||
result = mpt::ToUnicode(mpt::CharsetASCII, OPENMPT_BUILD_DATE );
|
||||
#else
|
||||
result = mpt::ToUnicode(mpt::CharsetASCII, __DATE__ " " __TIME__ );
|
||||
#endif
|
||||
#else // !MODPLUG_TRACKER
|
||||
result = SourceInfo::Current().Date();
|
||||
#endif // MODPLUG_TRACKER
|
||||
return result;
|
||||
}
|
||||
|
||||
static mpt::ustring GetBuildFlagsString()
|
||||
{
|
||||
mpt::ustring retval;
|
||||
#ifdef MODPLUG_TRACKER
|
||||
if(Version::Current().IsTestVersion())
|
||||
{
|
||||
retval += " TEST";
|
||||
retval += UL_(" TEST");
|
||||
}
|
||||
#endif // MODPLUG_TRACKER
|
||||
if(IsDebugBuild())
|
||||
{
|
||||
retval += " DEBUG";
|
||||
retval += UL_(" DEBUG");
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
std::string GetBuildFeaturesString()
|
||||
mpt::ustring GetBuildFeaturesString()
|
||||
{
|
||||
std::string retval;
|
||||
mpt::ustring retval;
|
||||
#ifdef LIBOPENMPT_BUILD
|
||||
retval = UL_("")
|
||||
#if defined(MPT_CHARSET_WIN32)
|
||||
retval += " +WINAPI";
|
||||
UL_(" +WINAPI")
|
||||
#endif
|
||||
#if defined(MPT_CHARSET_ICONV)
|
||||
retval += " +ICONV";
|
||||
UL_(" +ICONV")
|
||||
#endif
|
||||
#if defined(MPT_CHARSET_CODECVTUTF8)
|
||||
retval += " +CODECVTUTF8";
|
||||
UL_(" +CODECVTUTF8")
|
||||
#endif
|
||||
#if defined(MPT_CHARSET_INTERNAL)
|
||||
retval += " +INTERNALCHARSETS";
|
||||
UL_(" +INTERNALCHARSETS")
|
||||
#endif
|
||||
#if defined(MPT_WITH_ZLIB)
|
||||
retval += " +ZLIB";
|
||||
UL_(" +ZLIB")
|
||||
#endif
|
||||
#if defined(MPT_WITH_MINIZ)
|
||||
retval += " +MINIZ";
|
||||
UL_(" +MINIZ")
|
||||
#endif
|
||||
#if !defined(MPT_WITH_ZLIB) && !defined(MPT_WITH_MINIZ)
|
||||
retval += " -INFLATE";
|
||||
UL_(" -INFLATE")
|
||||
#endif
|
||||
#if defined(MPT_WITH_MPG123)
|
||||
retval += " +MPG123";
|
||||
UL_(" +MPG123")
|
||||
#endif
|
||||
#if defined(MPT_WITH_MINIMP3)
|
||||
retval += " +MINIMP3";
|
||||
UL_(" +MINIMP3")
|
||||
#endif
|
||||
#if defined(MPT_WITH_MEDIAFOUNDATION)
|
||||
retval += " +MF";
|
||||
UL_(" +MF")
|
||||
#endif
|
||||
#if !defined(MPT_WITH_MPG123) && !defined(MPT_WITH_MINIMP3) && !defined(MPT_WITH_MEDIAFOUNDATION)
|
||||
retval += " -MP3";
|
||||
UL_(" -MP3")
|
||||
#endif
|
||||
#if defined(MPT_WITH_OGG) && defined(MPT_WITH_VORBIS) && defined(MPT_WITH_VORBISFILE)
|
||||
retval += " +VORBIS";
|
||||
UL_(" +VORBIS")
|
||||
#endif
|
||||
#if defined(MPT_WITH_STBVORBIS)
|
||||
retval += " +STBVORBIS";
|
||||
UL_(" +STBVORBIS")
|
||||
#endif
|
||||
#if !(defined(MPT_WITH_OGG) && defined(MPT_WITH_VORBIS) && defined(MPT_WITH_VORBISFILE)) && !defined(MPT_WITH_STBVORBIS)
|
||||
retval += " -VORBIS";
|
||||
UL_(" -VORBIS")
|
||||
#endif
|
||||
#if !defined(NO_PLUGINS)
|
||||
retval += " +PLUGINS";
|
||||
UL_(" +PLUGINS")
|
||||
#else
|
||||
retval += " -PLUGINS";
|
||||
UL_(" -PLUGINS")
|
||||
#endif
|
||||
#if !defined(NO_DMO)
|
||||
retval += " +DMO";
|
||||
UL_(" +DMO")
|
||||
#endif
|
||||
;
|
||||
#endif
|
||||
#ifdef MODPLUG_TRACKER
|
||||
#if (MPT_ARCH_BITS == 64)
|
||||
MPT_CONSTANT_IF(mpt::arch_bits == 64)
|
||||
{
|
||||
if (true
|
||||
&& (mpt::Windows::Version::GetMinimumKernelLevel() <= mpt::Windows::Version::WinXP64)
|
||||
&& (mpt::Windows::Version::GetMinimumAPILevel() <= mpt::Windows::Version::WinXP64)
|
||||
) {
|
||||
retval += " WIN64OLD";
|
||||
retval += UL_(" WIN64OLD");
|
||||
}
|
||||
#elif (MPT_ARCH_BITS == 32)
|
||||
} else MPT_CONSTANT_IF(mpt::arch_bits == 32)
|
||||
{
|
||||
if (true
|
||||
&& (mpt::Windows::Version::GetMinimumKernelLevel() <= mpt::Windows::Version::WinXP)
|
||||
&& (mpt::Windows::Version::GetMinimumAPILevel() <= mpt::Windows::Version::WinXP)
|
||||
) {
|
||||
retval += " WIN32OLD";
|
||||
retval += UL_(" WIN32OLD");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
retval += UL_("")
|
||||
#if defined(UNICODE)
|
||||
retval += " UNICODE";
|
||||
UL_(" UNICODE")
|
||||
#else
|
||||
retval += " ANSI";
|
||||
UL_(" ANSI")
|
||||
#endif
|
||||
#ifdef NO_VST
|
||||
retval += " NO_VST";
|
||||
UL_(" NO_VST")
|
||||
#endif
|
||||
#ifdef NO_DMO
|
||||
retval += " NO_DMO";
|
||||
UL_(" NO_DMO")
|
||||
#endif
|
||||
#ifdef NO_PLUGINS
|
||||
retval += " NO_PLUGINS";
|
||||
UL_(" NO_PLUGINS")
|
||||
#endif
|
||||
#ifndef MPT_WITH_ASIO
|
||||
retval += " NO_ASIO";
|
||||
#endif
|
||||
#ifndef MPT_WITH_DSOUND
|
||||
retval += " NO_DSOUND";
|
||||
UL_(" NO_ASIO")
|
||||
#endif
|
||||
;
|
||||
#endif
|
||||
return retval;
|
||||
}
|
||||
|
||||
std::string GetBuildCompilerString()
|
||||
mpt::ustring GetBuildCompilerString()
|
||||
{
|
||||
std::string retval;
|
||||
mpt::ustring retval;
|
||||
#if MPT_COMPILER_GENERIC
|
||||
retval += "*Generic C++11 Compiler";
|
||||
retval += U_("Generic C++11 Compiler");
|
||||
#elif MPT_COMPILER_MSVC
|
||||
#if defined(_MSC_FULL_VER) && defined(_MSC_BUILD) && (_MSC_BUILD > 0)
|
||||
retval += mpt::format("Microsoft Compiler %1.%2.%3.%4")
|
||||
retval += mpt::format(U_("Microsoft Compiler %1.%2.%3.%4"))
|
||||
( _MSC_FULL_VER / 10000000
|
||||
, mpt::fmt::dec0<2>((_MSC_FULL_VER / 100000) % 100)
|
||||
, mpt::fmt::dec0<5>(_MSC_FULL_VER % 100000)
|
||||
, mpt::fmt::dec0<2>(_MSC_BUILD)
|
||||
, mpt::ufmt::dec0<2>((_MSC_FULL_VER / 100000) % 100)
|
||||
, mpt::ufmt::dec0<5>(_MSC_FULL_VER % 100000)
|
||||
, mpt::ufmt::dec0<2>(_MSC_BUILD)
|
||||
);
|
||||
#elif defined(_MSC_FULL_VER)
|
||||
retval += mpt::format("Microsoft Compiler %1.%2.%3")
|
||||
retval += mpt::format(U_("Microsoft Compiler %1.%2.%3"))
|
||||
( _MSC_FULL_VER / 10000000
|
||||
, mpt::fmt::dec0<2>((_MSC_FULL_VER / 100000) % 100)
|
||||
, mpt::fmt::dec0<5>(_MSC_FULL_VER % 100000)
|
||||
, mpt::ufmt::dec0<2>((_MSC_FULL_VER / 100000) % 100)
|
||||
, mpt::ufmt::dec0<5>(_MSC_FULL_VER % 100000)
|
||||
);
|
||||
#else
|
||||
retval += mpt::format("Microsoft Compiler %1.%2")(MPT_COMPILER_MSVC_VERSION / 100, MPT_COMPILER_MSVC_VERSION % 100);
|
||||
retval += mpt::format(U_("Microsoft Compiler %1.%2"))(MPT_COMPILER_MSVC_VERSION / 100, MPT_COMPILER_MSVC_VERSION % 100);
|
||||
#endif
|
||||
#elif MPT_COMPILER_GCC
|
||||
retval += mpt::format("GNU Compiler Collection %1.%2.%3")(MPT_COMPILER_GCC_VERSION / 10000, (MPT_COMPILER_GCC_VERSION / 100) % 100, MPT_COMPILER_GCC_VERSION % 100);
|
||||
retval += mpt::format(U_("GNU Compiler Collection %1.%2.%3"))(MPT_COMPILER_GCC_VERSION / 10000, (MPT_COMPILER_GCC_VERSION / 100) % 100, MPT_COMPILER_GCC_VERSION % 100);
|
||||
#elif MPT_COMPILER_CLANG
|
||||
retval += mpt::format("Clang %1.%2.%3")(MPT_COMPILER_CLANG_VERSION / 10000, (MPT_COMPILER_CLANG_VERSION / 100) % 100, MPT_COMPILER_CLANG_VERSION % 100);
|
||||
#elif MPT_COMPILER_MSVCCLANGC2
|
||||
retval += mpt::format("MSVC-Clang/C2 %1")(MPT_COMPILER_MSVCCLANGC2_VERSION);
|
||||
retval += mpt::format(U_("Clang %1.%2.%3"))(MPT_COMPILER_CLANG_VERSION / 10000, (MPT_COMPILER_CLANG_VERSION / 100) % 100, MPT_COMPILER_CLANG_VERSION % 100);
|
||||
#else
|
||||
retval += "*unknown";
|
||||
retval += U_("unknown");
|
||||
#endif
|
||||
return retval;
|
||||
}
|
||||
|
||||
static std::string GetRevisionString()
|
||||
static mpt::ustring GetRevisionString()
|
||||
{
|
||||
std::string result;
|
||||
if(GetRevision() == 0)
|
||||
mpt::ustring result;
|
||||
if(Source::GetRevision() == 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
result = std::string("-r") + mpt::fmt::val(GetRevision());
|
||||
if(HasMixedRevisions())
|
||||
result = U_("-r") + mpt::ufmt::val(Source::GetRevision());
|
||||
if(Source::HasMixedRevisions())
|
||||
{
|
||||
result += "!";
|
||||
result += UL_("!");
|
||||
}
|
||||
if(IsDirty())
|
||||
if(Source::IsDirty())
|
||||
{
|
||||
result += "+";
|
||||
result += UL_("+");
|
||||
}
|
||||
if(IsPackage())
|
||||
if(Source::IsPackage())
|
||||
{
|
||||
result += "p";
|
||||
result += UL_("p");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
mpt::ustring GetDownloadURL()
|
||||
mpt::ustring GetVersionString(FlagSet<Build::Strings> strings)
|
||||
{
|
||||
#ifdef MODPLUG_TRACKER
|
||||
return (MptVersion::IsDebugBuild() || MptVersion::IsTestBuild() || MptVersion::IsDirty() || MptVersion::HasMixedRevisions())
|
||||
?
|
||||
MPT_USTRING("https://buildbot.openmpt.org/builds/")
|
||||
:
|
||||
MPT_USTRING("https://openmpt.org/download")
|
||||
;
|
||||
#else
|
||||
return MPT_USTRING("https://lib.openmpt.org/");
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string GetVersionString(FlagSet<MptVersion::Strings> strings)
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
std::vector<mpt::ustring> result;
|
||||
if(strings[StringVersion])
|
||||
{
|
||||
result.push_back(MPT_VERSION_STR);
|
||||
result.push_back(mpt::ufmt::val(Version::Current()));
|
||||
}
|
||||
if(strings[StringRevision])
|
||||
{
|
||||
if(IsDebugBuild() || IsTestBuild() || IsDirty() || HasMixedRevisions())
|
||||
if(!IsReleasedBuild())
|
||||
{
|
||||
result.push_back(GetRevisionString());
|
||||
}
|
||||
}
|
||||
if(strings[StringBitness])
|
||||
{
|
||||
result.push_back(mpt::format(" %1 bit")(sizeof(void*)*8));
|
||||
result.push_back(mpt::format(U_(" %1 bit"))(mpt::arch_bits));
|
||||
}
|
||||
if(strings[StringSourceInfo])
|
||||
{
|
||||
const SourceInfo sourceInfo = GetSourceInfo();
|
||||
const SourceInfo sourceInfo = SourceInfo::Current();
|
||||
if(!sourceInfo.GetUrlWithRevision().empty())
|
||||
{
|
||||
result.push_back(mpt::format(" %1")(sourceInfo.GetUrlWithRevision()));
|
||||
result.push_back(mpt::format(U_(" %1"))(sourceInfo.GetUrlWithRevision()));
|
||||
}
|
||||
if(!sourceInfo.Date.empty())
|
||||
if(!sourceInfo.Date().empty())
|
||||
{
|
||||
result.push_back(mpt::format(" (%1)")(sourceInfo.Date));
|
||||
result.push_back(mpt::format(U_(" (%1)"))(sourceInfo.Date()));
|
||||
}
|
||||
if(!sourceInfo.GetStateString().empty())
|
||||
{
|
||||
result.push_back(mpt::format(" %1")(sourceInfo.GetStateString()));
|
||||
result.push_back(mpt::format(U_(" %1"))(sourceInfo.GetStateString()));
|
||||
}
|
||||
}
|
||||
if(strings[StringBuildFlags])
|
||||
{
|
||||
if(IsDebugBuild() || IsTestBuild() || IsDirty() || HasMixedRevisions())
|
||||
if(!IsReleasedBuild())
|
||||
{
|
||||
result.push_back(GetBuildFlagsString());
|
||||
}
|
||||
|
@ -501,81 +510,78 @@ std::string GetVersionString(FlagSet<MptVersion::Strings> strings)
|
|||
{
|
||||
result.push_back(GetBuildFeaturesString());
|
||||
}
|
||||
return mpt::String::Trim(mpt::String::Combine<std::string>(result, std::string("")));
|
||||
return mpt::String::Trim(mpt::String::Combine<mpt::ustring>(result, U_("")));
|
||||
}
|
||||
|
||||
std::string GetVersionStringPure()
|
||||
mpt::ustring GetVersionStringPure()
|
||||
{
|
||||
FlagSet<MptVersion::Strings> strings;
|
||||
strings |= MptVersion::StringVersion;
|
||||
strings |= MptVersion::StringRevision;
|
||||
FlagSet<Build::Strings> strings;
|
||||
strings |= Build::StringVersion;
|
||||
strings |= Build::StringRevision;
|
||||
#ifdef MODPLUG_TRACKER
|
||||
strings |= MptVersion::StringBitness;
|
||||
strings |= Build::StringBitness;
|
||||
#endif
|
||||
return GetVersionString(strings);
|
||||
}
|
||||
|
||||
std::string GetVersionStringSimple()
|
||||
mpt::ustring GetVersionStringSimple()
|
||||
{
|
||||
FlagSet<MptVersion::Strings> strings;
|
||||
strings |= MptVersion::StringVersion;
|
||||
strings |= MptVersion::StringRevision;
|
||||
strings |= MptVersion::StringBuildFlags;
|
||||
FlagSet<Build::Strings> strings;
|
||||
strings |= Build::StringVersion;
|
||||
strings |= Build::StringRevision;
|
||||
strings |= Build::StringBuildFlags;
|
||||
return GetVersionString(strings);
|
||||
}
|
||||
|
||||
std::string GetVersionStringExtended()
|
||||
mpt::ustring GetVersionStringExtended()
|
||||
{
|
||||
FlagSet<MptVersion::Strings> strings;
|
||||
strings |= MptVersion::StringVersion;
|
||||
strings |= MptVersion::StringRevision;
|
||||
FlagSet<Build::Strings> strings;
|
||||
strings |= Build::StringVersion;
|
||||
strings |= Build::StringRevision;
|
||||
#ifdef MODPLUG_TRACKER
|
||||
strings |= MptVersion::StringBitness;
|
||||
strings |= Build::StringBitness;
|
||||
#endif
|
||||
#ifndef MODPLUG_TRACKER
|
||||
strings |= MptVersion::StringSourceInfo;
|
||||
strings |= Build::StringSourceInfo;
|
||||
#endif
|
||||
strings |= MptVersion::StringBuildFlags;
|
||||
strings |= Build::StringBuildFlags;
|
||||
#ifdef MODPLUG_TRACKER
|
||||
strings |= MptVersion::StringBuildFeatures;
|
||||
strings |= Build::StringBuildFeatures;
|
||||
#endif
|
||||
return GetVersionString(strings);
|
||||
}
|
||||
|
||||
std::string SourceInfo::GetUrlWithRevision() const
|
||||
{
|
||||
if(Url.empty() || (Revision == 0))
|
||||
{
|
||||
return std::string();
|
||||
}
|
||||
return Url + "@" + mpt::fmt::val(Revision);
|
||||
}
|
||||
|
||||
mpt::ustring GetURL(std::string key)
|
||||
mpt::ustring GetURL(Build::Url key)
|
||||
{
|
||||
mpt::ustring result;
|
||||
if(key.empty())
|
||||
{
|
||||
result = mpt::ustring();
|
||||
} else if(key == "website")
|
||||
switch(key)
|
||||
{
|
||||
case Url::Website:
|
||||
#ifdef LIBOPENMPT_BUILD
|
||||
result = MPT_USTRING("https://lib.openmpt.org/");
|
||||
result = U_("https://lib.openmpt.org/");
|
||||
#else
|
||||
result = MPT_USTRING("https://openmpt.org/");
|
||||
result = U_("https://openmpt.org/");
|
||||
#endif
|
||||
} else if(key == "forum")
|
||||
{
|
||||
result = MPT_USTRING("https://forum.openmpt.org/");
|
||||
} else if(key == "bugtracker")
|
||||
{
|
||||
result = MPT_USTRING("https://bugs.openmpt.org/");
|
||||
} else if(key == "updates")
|
||||
{
|
||||
result = MPT_USTRING("https://openmpt.org/download");
|
||||
} else if(key == "top_picks")
|
||||
{
|
||||
result = MPT_USTRING("https://openmpt.org/top_picks");
|
||||
break;
|
||||
case Url::Download:
|
||||
#ifdef MODPLUG_TRACKER
|
||||
result = IsReleasedBuild() ? U_("https://openmpt.org/download") : U_("https://builds.openmpt.org/builds/");
|
||||
#else
|
||||
result = U_("https://lib.openmpt.org/libopenmpt/download/");
|
||||
#endif
|
||||
break;
|
||||
case Url::Forum:
|
||||
result = U_("https://forum.openmpt.org/");
|
||||
break;
|
||||
case Url::Bugtracker:
|
||||
result = U_("https://bugs.openmpt.org/");
|
||||
break;
|
||||
case Url::Updates:
|
||||
result = U_("https://openmpt.org/download");
|
||||
break;
|
||||
case Url::TopPicks:
|
||||
result = U_("https://openmpt.org/top_picks");
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -589,12 +595,12 @@ mpt::ustring GetFullCreditsString()
|
|||
"libopenmpt (based on OpenMPT / ModPlug Tracker)\n"
|
||||
#endif
|
||||
"\n"
|
||||
"Copyright \xC2\xA9 2004-2018 Contributors\n"
|
||||
"Copyright \xC2\xA9 2004-2019 Contributors\n"
|
||||
"Copyright \xC2\xA9 1997-2003 Olivier Lapicque\n"
|
||||
"\n"
|
||||
"Contributors:\n"
|
||||
"Johannes Schultz (2008-2018)\n"
|
||||
"J\xC3\xB6rn Heusipp (2012-2018)\n"
|
||||
"Johannes Schultz (2008-2019)\n"
|
||||
"J\xC3\xB6rn Heusipp (2012-2019)\n"
|
||||
"Ahti Lepp\xC3\xA4nen (2005-2011)\n"
|
||||
"Robin Fernandes (2004-2007)\n"
|
||||
"Sergiy Pylypenko (2007)\n"
|
||||
|
@ -603,9 +609,9 @@ mpt::ustring GetFullCreditsString()
|
|||
"Olivier Lapicque (1997-2003)\n"
|
||||
"\n"
|
||||
"Additional patch submitters:\n"
|
||||
"coda (http://coda.s3m.us/)\n"
|
||||
"coda (https://coda.s3m.us/)\n"
|
||||
"kode54 (https://kode54.net/)\n"
|
||||
"Revenant (http://revenant1.net/)\n"
|
||||
"Revenant (https://revenant1.net/)\n"
|
||||
"xaimus (http://xaimus.com/)\n"
|
||||
"\n"
|
||||
"Thanks to:\n"
|
||||
|
@ -621,13 +627,16 @@ mpt::ustring GetFullCreditsString()
|
|||
"https://github.com/avaneev/r8brain-free-src\n"
|
||||
"\n"
|
||||
"Olli Parviainen for SoundTouch Library (time stretching)\n"
|
||||
"http://www.surina.net/soundtouch/\n"
|
||||
"https://www.surina.net/soundtouch/\n"
|
||||
"\n"
|
||||
#endif
|
||||
#ifndef NO_VST
|
||||
"Hermann Seib for his example VST Host implementation\n"
|
||||
"http://www.hermannseib.com/english/vsthost.htm\n"
|
||||
"\n"
|
||||
"Benjamin \"BeRo\" Rosseaux for his independent VST header\n"
|
||||
"https://blog.rosseaux.net/\n"
|
||||
"\n"
|
||||
#endif
|
||||
"Storlek for all the IT compatibility hints and testcases\n"
|
||||
"as well as the IMF, MDL, OKT and ULT loaders\n"
|
||||
|
@ -645,9 +654,12 @@ mpt::ustring GetFullCreditsString()
|
|||
"Antti S. Lankila for Amiga resampler implementation\n"
|
||||
"https://bel.fi/alankila/modguide/interpolate.txt\n"
|
||||
"\n"
|
||||
"Shayde / Reality Productions for Opal OPL3 emulator\n"
|
||||
"https://www.3eality.com/\n"
|
||||
"\n"
|
||||
#ifdef MPT_WITH_ZLIB
|
||||
"Jean-loup Gailly and Mark Adler for zlib\n"
|
||||
"http://zlib.net/\n"
|
||||
"https://zlib.net/\n"
|
||||
"\n"
|
||||
#endif
|
||||
#ifdef MPT_WITH_MINIZ
|
||||
|
@ -662,7 +674,7 @@ mpt::ustring GetFullCreditsString()
|
|||
#endif
|
||||
#ifdef MPT_WITH_UNRAR
|
||||
"Alexander L. Roshal for UnRAR\n"
|
||||
"http://rarlab.com/\n"
|
||||
"https://rarlab.com/\n"
|
||||
"\n"
|
||||
#endif
|
||||
#ifdef MPT_WITH_PORTAUDIO
|
||||
|
@ -670,6 +682,11 @@ mpt::ustring GetFullCreditsString()
|
|||
"http://www.portaudio.com/\n"
|
||||
"\n"
|
||||
#endif
|
||||
#ifdef MPT_WITH_RTAUDIO
|
||||
"Gary P. Scavone, McGill University\n"
|
||||
"https://www.music.mcgill.ca/~gary/rtaudio/\n"
|
||||
"\n"
|
||||
#endif
|
||||
#ifdef MPT_WITH_FLAC
|
||||
"Josh Coalson / Xiph.Org Foundation for libFLAC\n"
|
||||
"https://xiph.org/flac/\n"
|
||||
|
@ -677,13 +694,12 @@ mpt::ustring GetFullCreditsString()
|
|||
#endif
|
||||
#if defined(MPT_WITH_MPG123)
|
||||
"The mpg123 project for libmpg123\n"
|
||||
"http://mpg123.de/\n"
|
||||
"https://mpg123.de/\n"
|
||||
"\n"
|
||||
#endif
|
||||
#ifdef MPT_WITH_MINIMP3
|
||||
"Fabrice Bellard, FFMPEG contributors\n"
|
||||
"and Martin J. Fiedler (KeyJ/kakiarts) for minimp3\n"
|
||||
"http://keyj.emphy.de/minimp3/\n"
|
||||
"Lion (github.com/lieff) for minimp3\n"
|
||||
"https://github.com/lieff/minimp3/\n"
|
||||
"\n"
|
||||
#endif
|
||||
#ifdef MPT_WITH_STBVORBIS
|
||||
|
@ -718,9 +734,13 @@ mpt::ustring GetFullCreditsString()
|
|||
"https://git.xiph.org/?p=libopusenc.git;a=summary\n"
|
||||
"\n"
|
||||
#endif
|
||||
#if defined(MPT_WITH_PICOJSON)
|
||||
"Cybozu Labs Inc. and Kazuho Oku et. al. for picojson\n"
|
||||
"https://github.com/kazuho/picojson\n"
|
||||
#if defined(MPT_WITH_LAME)
|
||||
"The LAME project for LAME\n"
|
||||
"http://lame.sourceforge.net/\n"
|
||||
#endif
|
||||
#if defined(MPT_WITH_NLOHMANNJSON)
|
||||
"Niels Lohmann et al. for nlohmann-json\n"
|
||||
"https://github.com/nlohmann/json\n"
|
||||
"\n"
|
||||
#endif
|
||||
#ifdef MODPLUG_TRACKER
|
||||
|
@ -731,9 +751,12 @@ mpt::ustring GetFullCreditsString()
|
|||
"https://www.music.mcgill.ca/~gary/rtmidi/\n"
|
||||
"\n"
|
||||
"Alexander Uckun for decimal input field\n"
|
||||
"http://www.codeproject.com/Articles/21257/_\n"
|
||||
"https://www.codeproject.com/Articles/21257/_\n"
|
||||
"\n"
|
||||
"Nobuyuki for application and file icon\n"
|
||||
"\xc3\x9alfur Kolka for application icon, splash and about screen\n"
|
||||
"https://www.behance.net/ulfurkolka\n"
|
||||
"\n"
|
||||
"Nobuyuki for file icon\n"
|
||||
"https://twitter.com/nobuyukinyuu\n"
|
||||
"\n"
|
||||
#endif
|
||||
|
@ -746,7 +769,7 @@ mpt::ustring GetFullCreditsString()
|
|||
"33, 8bitbubsy, Anboi, BooT-SectoR-ViruZ, Bvanoudtshoorn\n"
|
||||
"christofori, cubaxd, Diamond, Ganja, Georg, Goor00,\n"
|
||||
"Harbinger, jmkz, KrazyKatz, LPChip, Nofold, Rakib, Sam Zen\n"
|
||||
"Skaven, Skilletaudio, Snu, Squirrel Havoc, Waxhead\n"
|
||||
"Skaven, Skilletaudio, Snu, Squirrel Havoc, Teimoso, Waxhead\n"
|
||||
"\n"
|
||||
#ifndef NO_VST
|
||||
"VST PlugIn Technology by Steinberg Media Technologies GmbH\n"
|
||||
|
@ -762,9 +785,7 @@ mpt::ustring GetFullCreditsString()
|
|||
mpt::ustring GetLicenseString()
|
||||
{
|
||||
return MPT_UTF8(
|
||||
"The OpenMPT code is licensed under the BSD license." "\n"
|
||||
"" "\n"
|
||||
"Copyright (c) 2004-2018, OpenMPT contributors" "\n"
|
||||
"Copyright (c) 2004-2019, OpenMPT contributors" "\n"
|
||||
"Copyright (c) 1997-2003, Olivier Lapicque" "\n"
|
||||
"All rights reserved." "\n"
|
||||
"" "\n"
|
||||
|
@ -792,6 +813,8 @@ mpt::ustring GetLicenseString()
|
|||
);
|
||||
}
|
||||
|
||||
} // namespace MptVersion
|
||||
} // namespace Build
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
||||
|
|
|
@ -10,76 +10,182 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "FlagSet.h"
|
||||
#include "BuildSettings.h"
|
||||
|
||||
#include <string>
|
||||
#include "FlagSet.h"
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
//Creates version number from version parts that appears in version string.
|
||||
//For example MAKE_VERSION_NUMERIC(1,17,02,28) gives version number of
|
||||
//version 1.17.02.28.
|
||||
#define MAKE_VERSION_NUMERIC_HELPER(prefix,v0,v1,v2,v3) ((prefix##v0 << 24) | (prefix##v1<<16) | (prefix##v2<<8) | (prefix##v3))
|
||||
#define MAKE_VERSION_NUMERIC(v0,v1,v2,v3) (MptVersion::VersionNum(MAKE_VERSION_NUMERIC_HELPER(0x,v0,v1,v2,v3)))
|
||||
|
||||
|
||||
namespace MptVersion
|
||||
class Version
|
||||
{
|
||||
|
||||
typedef uint32 VersionNum;
|
||||
private:
|
||||
|
||||
extern const VersionNum num; // e.g. 0x01170208
|
||||
extern const char * const str; // e.g "1.17.02.08"
|
||||
uint32 m_Version; // e.g. 0x01170208
|
||||
|
||||
// Return a OpenMPT version string suitable for file format tags
|
||||
std::string GetOpenMPTVersionStr(); // e.g. "OpenMPT 1.17.02.08"
|
||||
public:
|
||||
|
||||
enum class Field
|
||||
{
|
||||
Major,
|
||||
Minor,
|
||||
Patch,
|
||||
Test,
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
static Version Current() noexcept;
|
||||
|
||||
public:
|
||||
|
||||
MPT_CONSTEXPR11_FUN Version() noexcept
|
||||
: m_Version(0)
|
||||
{}
|
||||
|
||||
explicit MPT_CONSTEXPR11_FUN Version(uint32 version) noexcept
|
||||
: m_Version(version)
|
||||
{}
|
||||
|
||||
explicit MPT_CONSTEXPR11_FUN Version(uint8 v1, uint8 v2, uint8 v3, uint8 v4) noexcept
|
||||
: m_Version((static_cast<uint32>(v1) << 24) | (static_cast<uint32>(v2) << 16) | (static_cast<uint32>(v3) << 8) | (static_cast<uint32>(v4) << 0))
|
||||
{}
|
||||
|
||||
public:
|
||||
|
||||
mpt::ustring ToUString() const; // e.g "1.17.02.08"
|
||||
|
||||
// Returns numerical version value from given version string.
|
||||
VersionNum ToNum(const std::string &s);
|
||||
static Version Parse(const mpt::ustring &s);
|
||||
|
||||
// Returns version string from given numerical version value.
|
||||
std::string ToStr(const VersionNum v);
|
||||
mpt::ustring ToUString(const VersionNum v);
|
||||
public:
|
||||
|
||||
explicit MPT_CONSTEXPR11_FUN operator bool () const noexcept
|
||||
{
|
||||
return m_Version != 0;
|
||||
}
|
||||
MPT_CONSTEXPR11_FUN bool operator ! () const noexcept
|
||||
{
|
||||
return m_Version == 0;
|
||||
}
|
||||
|
||||
MPT_CONSTEXPR11_FUN uint32 GetRawVersion() const noexcept
|
||||
{
|
||||
return m_Version;
|
||||
}
|
||||
|
||||
MPT_FORCEINLINE Version Masked(uint32 mask) const noexcept
|
||||
{
|
||||
return Version(m_Version & mask);
|
||||
}
|
||||
|
||||
MPT_CONSTEXPR11_FUN uint8 GetField(Field field) const noexcept
|
||||
{
|
||||
return
|
||||
(field == Field::Major) ? static_cast<uint8>((m_Version >> 24) & 0xffu) :
|
||||
(field == Field::Minor) ? static_cast<uint8>((m_Version >> 16) & 0xffu) :
|
||||
(field == Field::Patch) ? static_cast<uint8>((m_Version >> 8) & 0xffu) :
|
||||
(field == Field::Test ) ? static_cast<uint8>((m_Version >> 0) & 0xffu) :
|
||||
0u;
|
||||
}
|
||||
|
||||
// Return a version without build number (the last number in the version).
|
||||
// The current versioning scheme uses this number only for test builds, and it should be 00 for official builds,
|
||||
// So sometimes it might be wanted to do comparisons without the build number.
|
||||
VersionNum RemoveBuildNumber(const VersionNum num_);
|
||||
Version WithoutTestNumber() const noexcept;
|
||||
|
||||
Version WithoutPatchOrTestNumbers() const noexcept;
|
||||
|
||||
public:
|
||||
|
||||
// Return a OpenMPT version string suitable for file format tags
|
||||
mpt::ustring GetOpenMPTVersionString() const; // e.g. "OpenMPT 1.17.02.08"
|
||||
|
||||
// Returns true if a given version number is from a test build, false if it's a release build.
|
||||
bool IsTestBuild(const VersionNum num_ = MptVersion::num);
|
||||
bool IsTestVersion() const noexcept;
|
||||
|
||||
};
|
||||
|
||||
MPT_CONSTEXPR11_FUN bool operator == (const Version &a, const Version &b) noexcept
|
||||
{
|
||||
return a.GetRawVersion() == b.GetRawVersion();
|
||||
}
|
||||
MPT_CONSTEXPR11_FUN bool operator != (const Version &a, const Version &b) noexcept
|
||||
{
|
||||
return a.GetRawVersion() != b.GetRawVersion();
|
||||
}
|
||||
MPT_CONSTEXPR11_FUN bool operator <= (const Version &a, const Version &b) noexcept
|
||||
{
|
||||
return a.GetRawVersion() <= b.GetRawVersion();
|
||||
}
|
||||
MPT_CONSTEXPR11_FUN bool operator >= (const Version &a, const Version &b) noexcept
|
||||
{
|
||||
return a.GetRawVersion() >= b.GetRawVersion();
|
||||
}
|
||||
MPT_CONSTEXPR11_FUN bool operator < (const Version &a, const Version &b) noexcept
|
||||
{
|
||||
return a.GetRawVersion() < b.GetRawVersion();
|
||||
}
|
||||
MPT_CONSTEXPR11_FUN bool operator > (const Version &a, const Version &b) noexcept
|
||||
{
|
||||
return a.GetRawVersion() > b.GetRawVersion();
|
||||
}
|
||||
|
||||
|
||||
//Creates version number from version parts that appears in version string.
|
||||
//For example MAKE_VERSION_NUMERIC(1,17,02,28) gives version number of
|
||||
//version 1.17.02.28.
|
||||
#define MPT_MAKE_VERSION_NUMERIC_HELPER(prefix,v0,v1,v2,v3) Version( prefix ## v0 , prefix ## v1 , prefix ## v2 , prefix ## v3 )
|
||||
#define MAKE_VERSION_NUMERIC(v0,v1,v2,v3) MPT_MAKE_VERSION_NUMERIC_HELPER(0x, v0, v1, v2, v3)
|
||||
|
||||
|
||||
|
||||
class SourceInfo
|
||||
{
|
||||
private:
|
||||
mpt::ustring m_Url; // svn repository url (or empty string)
|
||||
int m_Revision; // svn revision (or 0)
|
||||
bool m_IsDirty; // svn working copy is dirty (or false)
|
||||
bool m_HasMixedRevisions; // svn working copy has mixed revisions (or false)
|
||||
bool m_IsPackage; // source code originates from a packaged version of the source code
|
||||
mpt::ustring m_Date; // svn date (or empty string)
|
||||
private:
|
||||
SourceInfo();
|
||||
public:
|
||||
static SourceInfo Current();
|
||||
public:
|
||||
const mpt::ustring & Url() const { return m_Url; }
|
||||
int Revision() const { return m_Revision; }
|
||||
bool IsDirty() const { return m_IsDirty; }
|
||||
bool HasMixedRevisions() const { return m_HasMixedRevisions; }
|
||||
bool IsPackage() const { return m_IsPackage; }
|
||||
const mpt::ustring & Date() const { return m_Date; }
|
||||
public:
|
||||
mpt::ustring GetUrlWithRevision() const; // i.e. "https://source.openmpt.org/svn/openmpt/trunk/OpenMPT@1234" or empty string
|
||||
mpt::ustring GetStateString() const; // i.e. "+dirty" or "clean"
|
||||
};
|
||||
|
||||
|
||||
|
||||
namespace Build
|
||||
{
|
||||
|
||||
// Returns true if all conditions for an official release build are met
|
||||
bool IsReleasedBuild();
|
||||
|
||||
// Return true if this is a debug build with no optimizations
|
||||
bool IsDebugBuild();
|
||||
|
||||
struct SourceInfo
|
||||
{
|
||||
std::string Url; // svn repository url (or empty string)
|
||||
int Revision; // svn revision (or 0)
|
||||
bool IsDirty; // svn working copy is dirty (or false)
|
||||
bool HasMixedRevisions; // svn working copy has mixed revisions (or false)
|
||||
bool IsPackage; // source code originates from a packaged version of the source code
|
||||
std::string Date; // svn date (or empty string)
|
||||
SourceInfo() : Url(std::string()), Revision(0), IsDirty(false), HasMixedRevisions(false), IsPackage(false) { }
|
||||
public:
|
||||
std::string GetUrlWithRevision() const; // i.e. "https://source.openmpt.org/svn/openmpt/trunk/OpenMPT@1234" or empty string
|
||||
std::string GetStateString() const; // i.e. "+dirty" or "clean"
|
||||
};
|
||||
SourceInfo GetSourceInfo();
|
||||
|
||||
// Returns either the URL to download release builds or the URL to download test builds, depending on the current build.
|
||||
mpt::ustring GetDownloadURL();
|
||||
|
||||
// Return a string decribing the time of the build process (if built from a svn working copy and tsvn was available during build, otherwise it returns the time version.cpp was last rebuild which could be unreliable as it does not get rebuild every time without tsvn)
|
||||
std::string GetBuildDateString();
|
||||
mpt::ustring GetBuildDateString();
|
||||
|
||||
// Return a string decribing some of the build features
|
||||
std::string GetBuildFeaturesString(); // e.g. " NO_VST NO_DSOUND"
|
||||
mpt::ustring GetBuildFeaturesString(); // e.g. " NO_VST NO_DSOUND"
|
||||
|
||||
// Return a string describing the compiler version used for building.
|
||||
std::string GetBuildCompilerString(); // e.g. "Microsoft Compiler 15.00.20706.01"
|
||||
mpt::ustring GetBuildCompilerString(); // e.g. "Microsoft Compiler 15.00.20706.01"
|
||||
|
||||
enum Strings
|
||||
{
|
||||
|
@ -94,19 +200,28 @@ namespace MptVersion
|
|||
MPT_DECLARE_ENUM(Strings)
|
||||
|
||||
// Returns a versions string with the fields selected via @strings.
|
||||
std::string GetVersionString(FlagSet<MptVersion::Strings> strings);
|
||||
mpt::ustring GetVersionString(FlagSet<Build::Strings> strings);
|
||||
|
||||
// Returns a pure version string
|
||||
std::string GetVersionStringPure(); // e.g. "1.17.02.08-r1234+ 32 bit"
|
||||
mpt::ustring GetVersionStringPure(); // e.g. "1.17.02.08-r1234+ 32 bit"
|
||||
|
||||
// Returns a simple version string
|
||||
std::string GetVersionStringSimple(); // e.g. "1.17.02.08-r1234+ TEST"
|
||||
mpt::ustring GetVersionStringSimple(); // e.g. "1.17.02.08-r1234+ TEST"
|
||||
|
||||
// Returns MptVersion::str if the build is a clean release build straight from the repository or an extended string otherwise (if built from a svn working copy and tsvn was available during build)
|
||||
std::string GetVersionStringExtended(); // e.g. "1.17.02.08-r1234+ 32 bit DEBUG"
|
||||
// Returns Version::CurrentAsString() if the build is a clean release build straight from the repository or an extended string otherwise (if built from a svn working copy and tsvn was available during build)
|
||||
mpt::ustring GetVersionStringExtended(); // e.g. "1.17.02.08-r1234+ 32 bit DEBUG"
|
||||
|
||||
// Returns a URL for the respective keys. Supported keys: "website", "forum", "bugtracker", "updates", "top_picks"
|
||||
mpt::ustring GetURL(std::string key);
|
||||
enum class Url
|
||||
{
|
||||
Website,
|
||||
Download,
|
||||
Forum,
|
||||
Bugtracker,
|
||||
Updates,
|
||||
TopPicks,
|
||||
};
|
||||
// Returns a URL for the respective key.
|
||||
mpt::ustring GetURL(Build::Url key);
|
||||
|
||||
// Returns a multi-line string containing the full credits for the code base
|
||||
mpt::ustring GetFullCreditsString();
|
||||
|
@ -114,7 +229,8 @@ namespace MptVersion
|
|||
// Returns the OpenMPT license text
|
||||
mpt::ustring GetLicenseString();
|
||||
|
||||
} //namespace MptVersion
|
||||
} //namespace Build
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
#define VER_HELPER_STRINGIZE(x) #x
|
||||
|
@ -17,14 +19,11 @@ OPENMPT_NAMESPACE_BEGIN
|
|||
|
||||
//Version definitions. The only thing that needs to be changed when changing version number.
|
||||
#define VER_MAJORMAJOR 1
|
||||
#define VER_MAJOR 27
|
||||
#define VER_MINOR 10
|
||||
#define VER_MINORMINOR 00
|
||||
|
||||
//Version string. For example "1.17.02.28"
|
||||
#define MPT_VERSION_STR VER_STRINGIZE(VER_MAJORMAJOR) "." VER_STRINGIZE(VER_MAJOR) "." VER_STRINGIZE(VER_MINOR) "." VER_STRINGIZE(VER_MINORMINOR)
|
||||
#define VER_MAJOR 28
|
||||
#define VER_MINOR 02
|
||||
#define VER_MINORMINOR 04
|
||||
|
||||
//Numerical value of the version.
|
||||
#define MPT_VERSION_NUMERIC MAKE_VERSION_NUMERIC(VER_MAJORMAJOR,VER_MAJOR,VER_MINOR,VER_MINORMINOR)
|
||||
#define MPT_VERSION_CURRENT MAKE_VERSION_NUMERIC(VER_MAJORMAJOR,VER_MAJOR,VER_MINOR,VER_MINORMINOR)
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
||||
|
|
|
@ -22,7 +22,7 @@ dbm="DSPE"
|
|||
digi="DIGI Booster module\x00"
|
||||
|
||||
dmf="DDMF"
|
||||
dmf="XTRACKER"
|
||||
#dmf="XTRACKER"
|
||||
dmf="CMSG"
|
||||
dmf="SEQU"
|
||||
dmf="SMPI"
|
||||
|
@ -87,9 +87,8 @@ it="AUTH"
|
|||
|
||||
itp=".pti\x03\x01\x00\x00"
|
||||
|
||||
j2b="MUSE"
|
||||
j2b="\xDE\xAD\xBE\xAF"
|
||||
j2b="\xDE\xAD\xBA\xBE"
|
||||
j2b="MUSE\xDE\xAD\xBE\xAF"
|
||||
j2b="MUSE\xDE\xAD\xBA\xBE"
|
||||
j2b="AMFF"
|
||||
j2b="AM "
|
||||
j2b="MAIN"
|
||||
|
@ -129,7 +128,7 @@ mod="OKTA"
|
|||
mod="CD81"
|
||||
#mod="FA08"
|
||||
mod="FLT8"
|
||||
mod="EXO8"
|
||||
#mod="EXO8"
|
||||
# Depending on the byte offset in the file, we generate either a "xCHN" or "xxCH" magic
|
||||
mod="99CHN"
|
||||
mod="TDZ8"
|
||||
|
@ -194,7 +193,7 @@ psm="MAINSONG"
|
|||
psm="\x00\xFF\x00\x00\x01\x00"
|
||||
psm16="PSM\xFE"
|
||||
psm16="PORD"
|
||||
psm16="PPAN"
|
||||
#psm16="PPAN"
|
||||
psm16="PSAH"
|
||||
psm16="PPAT"
|
||||
|
||||
|
@ -202,7 +201,8 @@ ptm="PTMF"
|
|||
ptm="\x1A\x03\x02"
|
||||
|
||||
s3m="SCRM"
|
||||
s3m="SCRS"
|
||||
#s3m="SCRS"
|
||||
#s3m="SCRI"
|
||||
|
||||
stm="\x1A\x02\x15"
|
||||
|
||||
|
|
|
@ -37,11 +37,7 @@ int main( int argc, char * argv[] ) {
|
|||
throw std::runtime_error( "Usage: libopenmpt_example_cxx SOMEMODULE" );
|
||||
}
|
||||
const std::size_t buffersize = 480;
|
||||
#if defined( LIBOPENMPT_QUIRK_NO_CSTDINT )
|
||||
const openmpt::std::int32_t samplerate = 48000;
|
||||
#else
|
||||
const std::int32_t samplerate = 48000;
|
||||
#endif
|
||||
std::vector<float> left( buffersize );
|
||||
std::vector<float> right( buffersize );
|
||||
const float * const buffers[2] = { left.data(), right.data() };
|
||||
|
|
|
@ -1,504 +0,0 @@
|
|||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
|
||||
|
117
Frameworks/OpenMPT/OpenMPT/include/minimp3/LICENSE
Normal file
117
Frameworks/OpenMPT/OpenMPT/include/minimp3/LICENSE
Normal file
|
@ -0,0 +1,117 @@
|
|||
CC0 1.0 Universal
|
||||
|
||||
Statement of Purpose
|
||||
|
||||
The laws of most jurisdictions throughout the world automatically confer
|
||||
exclusive Copyright and Related Rights (defined below) upon the creator and
|
||||
subsequent owner(s) (each and all, an "owner") of an original work of
|
||||
authorship and/or a database (each, a "Work").
|
||||
|
||||
Certain owners wish to permanently relinquish those rights to a Work for the
|
||||
purpose of contributing to a commons of creative, cultural and scientific
|
||||
works ("Commons") that the public can reliably and without fear of later
|
||||
claims of infringement build upon, modify, incorporate in other works, reuse
|
||||
and redistribute as freely as possible in any form whatsoever and for any
|
||||
purposes, including without limitation commercial purposes. These owners may
|
||||
contribute to the Commons to promote the ideal of a free culture and the
|
||||
further production of creative, cultural and scientific works, or to gain
|
||||
reputation or greater distribution for their Work in part through the use and
|
||||
efforts of others.
|
||||
|
||||
For these and/or other purposes and motivations, and without any expectation
|
||||
of additional consideration or compensation, the person associating CC0 with a
|
||||
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
|
||||
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
|
||||
and publicly distribute the Work under its terms, with knowledge of his or her
|
||||
Copyright and Related Rights in the Work and the meaning and intended legal
|
||||
effect of CC0 on those rights.
|
||||
|
||||
1. Copyright and Related Rights. A Work made available under CC0 may be
|
||||
protected by copyright and related or neighboring rights ("Copyright and
|
||||
Related Rights"). Copyright and Related Rights include, but are not limited
|
||||
to, the following:
|
||||
|
||||
i. the right to reproduce, adapt, distribute, perform, display, communicate,
|
||||
and translate a Work;
|
||||
|
||||
ii. moral rights retained by the original author(s) and/or performer(s);
|
||||
|
||||
iii. publicity and privacy rights pertaining to a person's image or likeness
|
||||
depicted in a Work;
|
||||
|
||||
iv. rights protecting against unfair competition in regards to a Work,
|
||||
subject to the limitations in paragraph 4(a), below;
|
||||
|
||||
v. rights protecting the extraction, dissemination, use and reuse of data in
|
||||
a Work;
|
||||
|
||||
vi. database rights (such as those arising under Directive 96/9/EC of the
|
||||
European Parliament and of the Council of 11 March 1996 on the legal
|
||||
protection of databases, and under any national implementation thereof,
|
||||
including any amended or successor version of such directive); and
|
||||
|
||||
vii. other similar, equivalent or corresponding rights throughout the world
|
||||
based on applicable law or treaty, and any national implementations thereof.
|
||||
|
||||
2. Waiver. To the greatest extent permitted by, but not in contravention of,
|
||||
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
|
||||
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
|
||||
and Related Rights and associated claims and causes of action, whether now
|
||||
known or unknown (including existing as well as future claims and causes of
|
||||
action), in the Work (i) in all territories worldwide, (ii) for the maximum
|
||||
duration provided by applicable law or treaty (including future time
|
||||
extensions), (iii) in any current or future medium and for any number of
|
||||
copies, and (iv) for any purpose whatsoever, including without limitation
|
||||
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
|
||||
the Waiver for the benefit of each member of the public at large and to the
|
||||
detriment of Affirmer's heirs and successors, fully intending that such Waiver
|
||||
shall not be subject to revocation, rescission, cancellation, termination, or
|
||||
any other legal or equitable action to disrupt the quiet enjoyment of the Work
|
||||
by the public as contemplated by Affirmer's express Statement of Purpose.
|
||||
|
||||
3. Public License Fallback. Should any part of the Waiver for any reason be
|
||||
judged legally invalid or ineffective under applicable law, then the Waiver
|
||||
shall be preserved to the maximum extent permitted taking into account
|
||||
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
|
||||
is so judged Affirmer hereby grants to each affected person a royalty-free,
|
||||
non transferable, non sublicensable, non exclusive, irrevocable and
|
||||
unconditional license to exercise Affirmer's Copyright and Related Rights in
|
||||
the Work (i) in all territories worldwide, (ii) for the maximum duration
|
||||
provided by applicable law or treaty (including future time extensions), (iii)
|
||||
in any current or future medium and for any number of copies, and (iv) for any
|
||||
purpose whatsoever, including without limitation commercial, advertising or
|
||||
promotional purposes (the "License"). The License shall be deemed effective as
|
||||
of the date CC0 was applied by Affirmer to the Work. Should any part of the
|
||||
License for any reason be judged legally invalid or ineffective under
|
||||
applicable law, such partial invalidity or ineffectiveness shall not
|
||||
invalidate the remainder of the License, and in such case Affirmer hereby
|
||||
affirms that he or she will not (i) exercise any of his or her remaining
|
||||
Copyright and Related Rights in the Work or (ii) assert any associated claims
|
||||
and causes of action with respect to the Work, in either case contrary to
|
||||
Affirmer's express Statement of Purpose.
|
||||
|
||||
4. Limitations and Disclaimers.
|
||||
|
||||
a. No trademark or patent rights held by Affirmer are waived, abandoned,
|
||||
surrendered, licensed or otherwise affected by this document.
|
||||
|
||||
b. Affirmer offers the Work as-is and makes no representations or warranties
|
||||
of any kind concerning the Work, express, implied, statutory or otherwise,
|
||||
including without limitation warranties of title, merchantability, fitness
|
||||
for a particular purpose, non infringement, or the absence of latent or
|
||||
other defects, accuracy, or the present or absence of errors, whether or not
|
||||
discoverable, all to the greatest extent permissible under applicable law.
|
||||
|
||||
c. Affirmer disclaims responsibility for clearing rights of other persons
|
||||
that may apply to the Work or any use thereof, including without limitation
|
||||
any person's Copyright and Related Rights in the Work. Further, Affirmer
|
||||
disclaims responsibility for obtaining any necessary consents, permissions
|
||||
or other rights required for any use of the Work.
|
||||
|
||||
d. Affirmer understands and acknowledges that Creative Commons is not a
|
||||
party to this document and has no duty or obligation with respect to this
|
||||
CC0 or use of the Work.
|
||||
|
||||
For more information, please see
|
||||
<http://creativecommons.org/publicdomain/zero/1.0/>
|
||||
|
|
@ -1,11 +1,4 @@
|
|||
minimp3 version as of 2017-04-25 from
|
||||
http://keyj.emphy.de/files/projects/minimp3.tar.gz .
|
||||
minimp3 library from https://github.com/lieff/minimp3
|
||||
commit e9df0760e94044caded36a55d70ab4152134adc5 (2018-12-23)
|
||||
The following changes have been made:
|
||||
- mp3_create() declaration has been fixed.
|
||||
- GET_DATA() has been rewritten to avoid unaligned access warnings.
|
||||
- Signed/unsigned comparison warnings have been fixed.
|
||||
- Detection of stdint types has been fixed to work on *BSD.
|
||||
- Modifications have been marked with // OpenMPT
|
||||
- Obviously, unnecessary folders and files have been removed.
|
||||
- For building, premake is used to generate Visual Studio project files.
|
||||
See ../build/premake/ for details.
|
||||
* minimp3.c has been added
|
||||
|
|
|
@ -1,184 +0,0 @@
|
|||
// a libc replacement (more or less) for the Microsoft Visual C compiler
|
||||
// this file is public domain -- do with it whatever you want!
|
||||
#ifndef __LIBC_H_INCLUDED__
|
||||
#define __LIBC_H_INCLUDED__
|
||||
|
||||
// check if minilibc is required
|
||||
#ifndef NEED_MINILIBC
|
||||
#ifndef NOLIBC
|
||||
#define NEED_MINILIBC 0
|
||||
#else
|
||||
#define NEED_MINILIBC 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define INLINE __forceinline
|
||||
#define FASTCALL __fastcall
|
||||
#ifdef NOLIBC
|
||||
#ifdef MAIN_PROGRAM
|
||||
int _fltused=0;
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
#define INLINE inline
|
||||
#define FASTCALL __attribute__((fastcall))
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef WIN32
|
||||
#define WIN32
|
||||
#endif
|
||||
#endif
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#if !NEED_MINILIBC
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
#include <math.h>
|
||||
|
||||
#if !defined(__int8_t_defined) && !defined(_INT8_T_DECLARED) /* OpenMPT */
|
||||
#define __int8_t_defined
|
||||
typedef unsigned char uint8_t;
|
||||
typedef signed char int8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef signed short int16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef signed int int32_t;
|
||||
#ifdef _MSC_VER
|
||||
typedef unsigned __int64 uint64_t;
|
||||
typedef signed __int64 int64_t;
|
||||
#else
|
||||
typedef unsigned long long uint64_t;
|
||||
typedef signed long long int64_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if NEED_MINILIBC
|
||||
|
||||
static INLINE void libc_memset(void *dest, int value, int count) {
|
||||
if (!count) return;
|
||||
__asm {
|
||||
cld
|
||||
mov edi, dest
|
||||
mov eax, value
|
||||
mov ecx, count
|
||||
rep stosb
|
||||
}
|
||||
}
|
||||
|
||||
static INLINE void libc_memcpy(void *dest, const void *src, int count) {
|
||||
if (!count) return;
|
||||
__asm {
|
||||
cld
|
||||
mov esi, src
|
||||
mov edi, dest
|
||||
mov ecx, count
|
||||
rep movsb
|
||||
}
|
||||
}
|
||||
|
||||
#define libc_memmove libc_memcpy
|
||||
|
||||
static INLINE void* libc_malloc(int size) {
|
||||
return (void*) LocalAlloc(LMEM_FIXED, size);
|
||||
}
|
||||
|
||||
static INLINE void* libc_calloc(int size, int nmemb) {
|
||||
return (void*) LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, size * nmemb);
|
||||
}
|
||||
|
||||
static INLINE void* libc_realloc(void* old, int size) {
|
||||
int oldsize = (int) LocalSize((HLOCAL) old);
|
||||
void *mem;
|
||||
if (size <= oldsize) return old;
|
||||
mem = LocalAlloc(LMEM_FIXED, size);
|
||||
libc_memcpy(mem, old, oldsize);
|
||||
LocalFree((HLOCAL) old);
|
||||
return mem;
|
||||
}
|
||||
|
||||
static INLINE void libc_free(void *mem) {
|
||||
LocalFree((HLOCAL) mem);
|
||||
}
|
||||
|
||||
static INLINE double libc_frexp(double x, int *e) {
|
||||
double res = -9999.999;
|
||||
unsigned __int64 i = *(unsigned __int64*)(&x);
|
||||
if (!(i & 0x7F00000000000000UL)) {
|
||||
*e = 0;
|
||||
return x;
|
||||
}
|
||||
*e = ((i << 1) >> 53) - 1022;
|
||||
i &= 0x800FFFFFFFFFFFFFUL;
|
||||
i |= 0x3FF0000000000000UL;
|
||||
return *(double*)(&i) * 0.5;
|
||||
}
|
||||
|
||||
static INLINE double __declspec(naked) libc_exp(double x) { __asm {
|
||||
fldl2e
|
||||
fld qword ptr [esp+4]
|
||||
fmul
|
||||
fst st(1)
|
||||
frndint
|
||||
fxch
|
||||
fsub st(0), st(1)
|
||||
f2xm1
|
||||
fld1
|
||||
fadd
|
||||
fscale
|
||||
ret
|
||||
} }
|
||||
|
||||
|
||||
static INLINE double __declspec(naked) libc_pow(double b, double e) { __asm {
|
||||
fld qword ptr [esp+12]
|
||||
fld qword ptr [esp+4]
|
||||
fyl2x
|
||||
// following is a copy of libc_exp:
|
||||
fst st(1)
|
||||
frndint
|
||||
fxch
|
||||
fsub st(0), st(1)
|
||||
f2xm1
|
||||
fld1
|
||||
fadd
|
||||
fscale
|
||||
ret
|
||||
} }
|
||||
|
||||
|
||||
|
||||
#else // NEED_MINILIBC == 0
|
||||
|
||||
#define libc_malloc malloc
|
||||
#define libc_calloc calloc
|
||||
#define libc_realloc realloc
|
||||
#define libc_free free
|
||||
|
||||
#define libc_memset memset
|
||||
#define libc_memcpy memcpy
|
||||
#define libc_memmove memmove
|
||||
|
||||
#define libc_frexp frexp
|
||||
#define libc_exp exp
|
||||
#define libc_pow pow
|
||||
|
||||
#endif // NEED_MINILIBC
|
||||
|
||||
#endif//__LIBC_H_INCLUDED__
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -14,4 +14,5 @@ Modifications for OpenMPT:
|
|||
alignment from 1 to 4 [-Wcast-align]` has been fixed.
|
||||
* Prototypes of `tdefl_compressor_alloc` and `tinfl_decompressor_alloc`
|
||||
have beeen fixed
|
||||
* Missing #ifndef MINIZ_NO_STDIO has been added to miniz.h.
|
||||
No further changes have been made.
|
||||
|
|
|
@ -1250,7 +1250,9 @@ mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags);
|
|||
|
||||
/* Misc utils/helpers, valid for ZIP reading or writing */
|
||||
mz_bool mz_zip_validate_mem_archive(const void *pMem, size_t size, mz_uint flags, mz_zip_error *pErr);
|
||||
#ifndef MINIZ_NO_STDIO // OpenMPT
|
||||
mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr);
|
||||
#endif // OpenMPT
|
||||
|
||||
/* Universal end function - calls either mz_zip_reader_end() or mz_zip_writer_end(). */
|
||||
mz_bool mz_zip_end(mz_zip_archive *pZip);
|
||||
|
@ -1327,6 +1329,7 @@ mz_bool mz_zip_writer_end(mz_zip_archive *pZip);
|
|||
|
||||
/* -------- Misc. high-level helper functions: */
|
||||
|
||||
#ifndef MINIZ_NO_STDIO // OpenMPT
|
||||
/* mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) appends a memory blob to a ZIP archive. */
|
||||
/* Note this is NOT a fully safe operation. If it crashes or dies in some way your archive can be left in a screwed up state (without a central directory). */
|
||||
/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */
|
||||
|
@ -1339,6 +1342,7 @@ mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, co
|
|||
/* Returns NULL on failure. */
|
||||
void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags);
|
||||
void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr);
|
||||
#endif // OpenMPT
|
||||
|
||||
#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */
|
||||
|
||||
|
|
|
@ -4,13 +4,28 @@
|
|||
* Authors: Kenton Varda <temporal@gauge3d.org> (C interface wrapper)
|
||||
*/
|
||||
|
||||
#ifndef MODPLUG_H__INCLUDED
|
||||
#define MODPLUG_H__INCLUDED
|
||||
#ifndef MODPLUG_MODPLUG_H
|
||||
#define MODPLUG_MODPLUG_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
# if defined(MODPLUG_BUILD) && defined(DLL_EXPORT) /* building libmodplug as a dll for windows */
|
||||
# define MODPLUG_EXPORT __declspec(dllexport)
|
||||
# elif defined(MODPLUG_BUILD) || defined(MODPLUG_STATIC) /* building or using static libmodplug for windows */
|
||||
# define MODPLUG_EXPORT
|
||||
# else
|
||||
# define MODPLUG_EXPORT __declspec(dllimport) /* using libmodplug dll for windows */
|
||||
# endif
|
||||
/* FIXME: USE VISIBILITY ATTRIBUTES HERE */
|
||||
#elif defined(MODPLUG_BUILD)
|
||||
#define MODPLUG_EXPORT
|
||||
#else
|
||||
#define MODPLUG_EXPORT
|
||||
#endif
|
||||
|
||||
struct _ModPlugFile;
|
||||
typedef struct _ModPlugFile ModPlugFile;
|
||||
|
||||
|
@ -29,21 +44,21 @@ typedef void (*ModPlugMixerProc)(int*, unsigned long, unsigned long);
|
|||
/* Load a mod file. [data] should point to a block of memory containing the complete
|
||||
* file, and [size] should be the size of that block.
|
||||
* Return the loaded mod file on success, or NULL on failure. */
|
||||
ModPlugFile* ModPlug_Load(const void* data, int size);
|
||||
MODPLUG_EXPORT ModPlugFile* ModPlug_Load(const void* data, int size);
|
||||
/* Unload a mod file. */
|
||||
void ModPlug_Unload(ModPlugFile* file);
|
||||
MODPLUG_EXPORT void ModPlug_Unload(ModPlugFile* file);
|
||||
|
||||
/* Read sample data into the buffer. Returns the number of bytes read. If the end
|
||||
* of the mod has been reached, zero is returned. */
|
||||
int ModPlug_Read(ModPlugFile* file, void* buffer, int size);
|
||||
MODPLUG_EXPORT int ModPlug_Read(ModPlugFile* file, void* buffer, int size);
|
||||
|
||||
/* Get the name of the mod. The returned buffer is stored within the ModPlugFile
|
||||
* structure and will remain valid until you unload the file. */
|
||||
const char* ModPlug_GetName(ModPlugFile* file);
|
||||
MODPLUG_EXPORT const char* ModPlug_GetName(ModPlugFile* file);
|
||||
|
||||
/* Get the length of the mod, in milliseconds. Note that this result is not always
|
||||
* accurate, especially in the case of mods with loops. */
|
||||
int ModPlug_GetLength(ModPlugFile* file);
|
||||
MODPLUG_EXPORT int ModPlug_GetLength(ModPlugFile* file);
|
||||
|
||||
/* Seek to a particular position in the song. Note that seeking and MODs don't mix very
|
||||
* well. Some mods will be missing instruments for a short time after a seek, as ModPlug
|
||||
|
@ -51,7 +66,7 @@ int ModPlug_GetLength(ModPlugFile* file);
|
|||
* playing at that time. (Doing so would be difficult and not very reliable.) Also,
|
||||
* note that seeking is not very exact in some mods -- especially those for which
|
||||
* ModPlug_GetLength() does not report the full length. */
|
||||
void ModPlug_Seek(ModPlugFile* file, int millisecond);
|
||||
MODPLUG_EXPORT void ModPlug_Seek(ModPlugFile* file, int millisecond);
|
||||
|
||||
enum _ModPlug_Flags
|
||||
{
|
||||
|
@ -97,24 +112,24 @@ typedef struct _ModPlug_Settings
|
|||
/* Get and set the mod decoder settings. All options, except for channels, bits-per-sample,
|
||||
* sampling rate, and loop count, will take effect immediately. Those options which don't
|
||||
* take effect immediately will take effect the next time you load a mod. */
|
||||
void ModPlug_GetSettings(ModPlug_Settings* settings);
|
||||
void ModPlug_SetSettings(const ModPlug_Settings* settings);
|
||||
MODPLUG_EXPORT void ModPlug_GetSettings(ModPlug_Settings* settings);
|
||||
MODPLUG_EXPORT void ModPlug_SetSettings(const ModPlug_Settings* settings);
|
||||
|
||||
/* New ModPlug API Functions */
|
||||
/* NOTE: Master Volume (1-512) */
|
||||
unsigned int ModPlug_GetMasterVolume(ModPlugFile* file) ;
|
||||
void ModPlug_SetMasterVolume(ModPlugFile* file,unsigned int cvol) ;
|
||||
MODPLUG_EXPORT unsigned int ModPlug_GetMasterVolume(ModPlugFile* file) ;
|
||||
MODPLUG_EXPORT void ModPlug_SetMasterVolume(ModPlugFile* file,unsigned int cvol) ;
|
||||
|
||||
int ModPlug_GetCurrentSpeed(ModPlugFile* file);
|
||||
int ModPlug_GetCurrentTempo(ModPlugFile* file);
|
||||
int ModPlug_GetCurrentOrder(ModPlugFile* file);
|
||||
int ModPlug_GetCurrentPattern(ModPlugFile* file);
|
||||
int ModPlug_GetCurrentRow(ModPlugFile* file);
|
||||
int ModPlug_GetPlayingChannels(ModPlugFile* file);
|
||||
MODPLUG_EXPORT int ModPlug_GetCurrentSpeed(ModPlugFile* file);
|
||||
MODPLUG_EXPORT int ModPlug_GetCurrentTempo(ModPlugFile* file);
|
||||
MODPLUG_EXPORT int ModPlug_GetCurrentOrder(ModPlugFile* file);
|
||||
MODPLUG_EXPORT int ModPlug_GetCurrentPattern(ModPlugFile* file);
|
||||
MODPLUG_EXPORT int ModPlug_GetCurrentRow(ModPlugFile* file);
|
||||
MODPLUG_EXPORT int ModPlug_GetPlayingChannels(ModPlugFile* file);
|
||||
|
||||
void ModPlug_SeekOrder(ModPlugFile* file,int order);
|
||||
int ModPlug_GetModuleType(ModPlugFile* file);
|
||||
char* ModPlug_GetMessage(ModPlugFile* file);
|
||||
MODPLUG_EXPORT void ModPlug_SeekOrder(ModPlugFile* file,int order);
|
||||
MODPLUG_EXPORT int ModPlug_GetModuleType(ModPlugFile* file);
|
||||
MODPLUG_EXPORT char* ModPlug_GetMessage(ModPlugFile* file);
|
||||
|
||||
|
||||
#ifndef MODPLUG_NO_FILESAVE
|
||||
|
@ -122,29 +137,29 @@ char* ModPlug_GetMessage(ModPlugFile* file);
|
|||
* EXPERIMENTAL Export Functions
|
||||
*/
|
||||
/*Export to a Scream Tracker 3 S3M module. EXPERIMENTAL (only works on Little-Endian platforms)*/
|
||||
char ModPlug_ExportS3M(ModPlugFile* file, const char* filepath);
|
||||
MODPLUG_EXPORT char ModPlug_ExportS3M(ModPlugFile* file, const char* filepath);
|
||||
|
||||
/*Export to a Extended Module (XM). EXPERIMENTAL (only works on Little-Endian platforms)*/
|
||||
char ModPlug_ExportXM(ModPlugFile* file, const char* filepath);
|
||||
MODPLUG_EXPORT char ModPlug_ExportXM(ModPlugFile* file, const char* filepath);
|
||||
|
||||
/*Export to a Amiga MOD file. EXPERIMENTAL.*/
|
||||
char ModPlug_ExportMOD(ModPlugFile* file, const char* filepath);
|
||||
MODPLUG_EXPORT char ModPlug_ExportMOD(ModPlugFile* file, const char* filepath);
|
||||
|
||||
/*Export to a Impulse Tracker IT file. Should work OK in Little-Endian & Big-Endian platforms :-) */
|
||||
char ModPlug_ExportIT(ModPlugFile* file, const char* filepath);
|
||||
MODPLUG_EXPORT char ModPlug_ExportIT(ModPlugFile* file, const char* filepath);
|
||||
#endif // MODPLUG_NO_FILESAVE
|
||||
|
||||
unsigned int ModPlug_NumInstruments(ModPlugFile* file);
|
||||
unsigned int ModPlug_NumSamples(ModPlugFile* file);
|
||||
unsigned int ModPlug_NumPatterns(ModPlugFile* file);
|
||||
unsigned int ModPlug_NumChannels(ModPlugFile* file);
|
||||
unsigned int ModPlug_SampleName(ModPlugFile* file, unsigned int qual, char* buff);
|
||||
unsigned int ModPlug_InstrumentName(ModPlugFile* file, unsigned int qual, char* buff);
|
||||
MODPLUG_EXPORT unsigned int ModPlug_NumInstruments(ModPlugFile* file);
|
||||
MODPLUG_EXPORT unsigned int ModPlug_NumSamples(ModPlugFile* file);
|
||||
MODPLUG_EXPORT unsigned int ModPlug_NumPatterns(ModPlugFile* file);
|
||||
MODPLUG_EXPORT unsigned int ModPlug_NumChannels(ModPlugFile* file);
|
||||
MODPLUG_EXPORT unsigned int ModPlug_SampleName(ModPlugFile* file, unsigned int qual, char* buff);
|
||||
MODPLUG_EXPORT unsigned int ModPlug_InstrumentName(ModPlugFile* file, unsigned int qual, char* buff);
|
||||
|
||||
/*
|
||||
* Retrieve pattern note-data
|
||||
*/
|
||||
ModPlugNote* ModPlug_GetPattern(ModPlugFile* file, int pattern, unsigned int* numrows);
|
||||
MODPLUG_EXPORT ModPlugNote* ModPlug_GetPattern(ModPlugFile* file, int pattern, unsigned int* numrows);
|
||||
|
||||
/*
|
||||
* =================
|
||||
|
@ -161,8 +176,8 @@ ModPlugNote* ModPlug_GetPattern(ModPlugFile* file, int pattern, unsigned int* nu
|
|||
*
|
||||
* (Samples are signed 32-bit integers)
|
||||
*/
|
||||
void ModPlug_InitMixerCallback(ModPlugFile* file,ModPlugMixerProc proc) ;
|
||||
void ModPlug_UnloadMixerCallback(ModPlugFile* file) ;
|
||||
MODPLUG_EXPORT void ModPlug_InitMixerCallback(ModPlugFile* file,ModPlugMixerProc proc) ;
|
||||
MODPLUG_EXPORT void ModPlug_UnloadMixerCallback(ModPlugFile* file) ;
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
|
|
@ -1,168 +0,0 @@
|
|||
/*
|
||||
* This source code is public domain.
|
||||
*
|
||||
* Authors: Kenton Varda <temporal@gauge3d.org> (C interface wrapper)
|
||||
*/
|
||||
|
||||
#ifndef MODPLUG_H__INCLUDED
|
||||
#define MODPLUG_H__INCLUDED
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct _ModPlugFile;
|
||||
typedef struct _ModPlugFile ModPlugFile;
|
||||
|
||||
struct _ModPlugNote {
|
||||
unsigned char Note;
|
||||
unsigned char Instrument;
|
||||
unsigned char VolumeEffect;
|
||||
unsigned char Effect;
|
||||
unsigned char Volume;
|
||||
unsigned char Parameter;
|
||||
};
|
||||
typedef struct _ModPlugNote ModPlugNote;
|
||||
|
||||
typedef void (*ModPlugMixerProc)(int*, unsigned long, unsigned long);
|
||||
|
||||
/* Load a mod file. [data] should point to a block of memory containing the complete
|
||||
* file, and [size] should be the size of that block.
|
||||
* Return the loaded mod file on success, or NULL on failure. */
|
||||
ModPlugFile* ModPlug_Load(const void* data, int size);
|
||||
/* Unload a mod file. */
|
||||
void ModPlug_Unload(ModPlugFile* file);
|
||||
|
||||
/* Read sample data into the buffer. Returns the number of bytes read. If the end
|
||||
* of the mod has been reached, zero is returned. */
|
||||
int ModPlug_Read(ModPlugFile* file, void* buffer, int size);
|
||||
|
||||
/* Get the name of the mod. The returned buffer is stored within the ModPlugFile
|
||||
* structure and will remain valid until you unload the file. */
|
||||
const char* ModPlug_GetName(ModPlugFile* file);
|
||||
|
||||
/* Get the length of the mod, in milliseconds. Note that this result is not always
|
||||
* accurate, especially in the case of mods with loops. */
|
||||
int ModPlug_GetLength(ModPlugFile* file);
|
||||
|
||||
/* Seek to a particular position in the song. Note that seeking and MODs don't mix very
|
||||
* well. Some mods will be missing instruments for a short time after a seek, as ModPlug
|
||||
* does not scan the sequence backwards to find out which instruments were supposed to be
|
||||
* playing at that time. (Doing so would be difficult and not very reliable.) Also,
|
||||
* note that seeking is not very exact in some mods -- especially those for which
|
||||
* ModPlug_GetLength() does not report the full length. */
|
||||
void ModPlug_Seek(ModPlugFile* file, int millisecond);
|
||||
|
||||
enum _ModPlug_Flags
|
||||
{
|
||||
MODPLUG_ENABLE_OVERSAMPLING = 1 << 0, /* Enable oversampling (*highly* recommended) */
|
||||
MODPLUG_ENABLE_NOISE_REDUCTION = 1 << 1, /* Enable noise reduction */
|
||||
MODPLUG_ENABLE_REVERB = 1 << 2, /* Enable reverb */
|
||||
MODPLUG_ENABLE_MEGABASS = 1 << 3, /* Enable megabass */
|
||||
MODPLUG_ENABLE_SURROUND = 1 << 4 /* Enable surround sound. */
|
||||
};
|
||||
|
||||
enum _ModPlug_ResamplingMode
|
||||
{
|
||||
MODPLUG_RESAMPLE_NEAREST = 0, /* No interpolation (very fast, extremely bad sound quality) */
|
||||
MODPLUG_RESAMPLE_LINEAR = 1, /* Linear interpolation (fast, good quality) */
|
||||
MODPLUG_RESAMPLE_SPLINE = 2, /* Cubic spline interpolation (high quality) */
|
||||
MODPLUG_RESAMPLE_FIR = 3 /* 8-tap fir filter (extremely high quality) */
|
||||
};
|
||||
|
||||
typedef struct _ModPlug_Settings
|
||||
{
|
||||
int mFlags; /* One or more of the MODPLUG_ENABLE_* flags above, bitwise-OR'ed */
|
||||
|
||||
/* Note that ModPlug always decodes sound at 44100kHz, 32 bit, stereo and then
|
||||
* down-mixes to the settings you choose. */
|
||||
int mChannels; /* Number of channels - 1 for mono or 2 for stereo */
|
||||
int mBits; /* Bits per sample - 8, 16, or 32 */
|
||||
int mFrequency; /* Sampling rate - 11025, 22050, or 44100 */
|
||||
int mResamplingMode; /* One of MODPLUG_RESAMPLE_*, above */
|
||||
|
||||
int mReverbDepth; /* Reverb level 0(quiet)-100(loud) */
|
||||
int mReverbDelay; /* Reverb delay in ms, usually 40-200ms */
|
||||
int mBassAmount; /* XBass level 0(quiet)-100(loud) */
|
||||
int mBassRange; /* XBass cutoff in Hz 10-100 */
|
||||
int mSurroundDepth; /* Surround level 0(quiet)-100(heavy) */
|
||||
int mSurroundDelay; /* Surround delay in ms, usually 5-40ms */
|
||||
int mLoopCount; /* Number of times to loop. Zero prevents looping.
|
||||
-1 loops forever. */
|
||||
} ModPlug_Settings;
|
||||
|
||||
/* Get and set the mod decoder settings. All options, except for channels, bits-per-sample,
|
||||
* sampling rate, and loop count, will take effect immediately. Those options which don't
|
||||
* take effect immediately will take effect the next time you load a mod. */
|
||||
void ModPlug_GetSettings(ModPlug_Settings* settings);
|
||||
void ModPlug_SetSettings(const ModPlug_Settings* settings);
|
||||
|
||||
/* New ModPlug API Functions */
|
||||
/* NOTE: Master Volume (1-512) */
|
||||
unsigned int ModPlug_GetMasterVolume(ModPlugFile* file) ;
|
||||
void ModPlug_SetMasterVolume(ModPlugFile* file,unsigned int cvol) ;
|
||||
|
||||
int ModPlug_GetCurrentSpeed(ModPlugFile* file);
|
||||
int ModPlug_GetCurrentTempo(ModPlugFile* file);
|
||||
int ModPlug_GetCurrentOrder(ModPlugFile* file);
|
||||
int ModPlug_GetCurrentPattern(ModPlugFile* file);
|
||||
int ModPlug_GetCurrentRow(ModPlugFile* file);
|
||||
int ModPlug_GetPlayingChannels(ModPlugFile* file);
|
||||
|
||||
void ModPlug_SeekOrder(ModPlugFile* file,int order);
|
||||
int ModPlug_GetModuleType(ModPlugFile* file);
|
||||
char* ModPlug_GetMessage(ModPlugFile* file);
|
||||
|
||||
|
||||
#ifndef MODPLUG_NO_FILESAVE
|
||||
/*
|
||||
* EXPERIMENTAL Export Functions
|
||||
*/
|
||||
/*Export to a Scream Tracker 3 S3M module. EXPERIMENTAL (only works on Little-Endian platforms)*/
|
||||
char ModPlug_ExportS3M(ModPlugFile* file, const char* filepath);
|
||||
|
||||
/*Export to a Extended Module (XM). EXPERIMENTAL (only works on Little-Endian platforms)*/
|
||||
char ModPlug_ExportXM(ModPlugFile* file, const char* filepath);
|
||||
|
||||
/*Export to a Amiga MOD file. EXPERIMENTAL.*/
|
||||
char ModPlug_ExportMOD(ModPlugFile* file, const char* filepath);
|
||||
|
||||
/*Export to a Impulse Tracker IT file. Should work OK in Little-Endian & Big-Endian platforms :-) */
|
||||
char ModPlug_ExportIT(ModPlugFile* file, const char* filepath);
|
||||
#endif // MODPLUG_NO_FILESAVE
|
||||
|
||||
unsigned int ModPlug_NumInstruments(ModPlugFile* file);
|
||||
unsigned int ModPlug_NumSamples(ModPlugFile* file);
|
||||
unsigned int ModPlug_NumPatterns(ModPlugFile* file);
|
||||
unsigned int ModPlug_NumChannels(ModPlugFile* file);
|
||||
unsigned int ModPlug_SampleName(ModPlugFile* file, unsigned int qual, char* buff);
|
||||
unsigned int ModPlug_InstrumentName(ModPlugFile* file, unsigned int qual, char* buff);
|
||||
|
||||
/*
|
||||
* Retrieve pattern note-data
|
||||
*/
|
||||
ModPlugNote* ModPlug_GetPattern(ModPlugFile* file, int pattern, unsigned int* numrows);
|
||||
|
||||
/*
|
||||
* =================
|
||||
* Mixer callback
|
||||
* =================
|
||||
*
|
||||
* Use this callback if you want to 'modify' the mixed data of LibModPlug.
|
||||
*
|
||||
* void proc(int* buffer,unsigned long channels,unsigned long nsamples) ;
|
||||
*
|
||||
* 'buffer': A buffer of mixed samples
|
||||
* 'channels': N. of channels in the buffer
|
||||
* 'nsamples': N. of samples in the buffeer (without taking care of n.channels)
|
||||
*
|
||||
* (Samples are signed 32-bit integers)
|
||||
*/
|
||||
void ModPlug_InitMixerCallback(ModPlugFile* file,ModPlugMixerProc proc) ;
|
||||
void ModPlug_UnloadMixerCallback(ModPlugFile* file) ;
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -10,8 +10,8 @@
|
|||
#define CONFIG_H_INCLUDED 1
|
||||
#endif
|
||||
|
||||
#ifndef __SNDFILE_H
|
||||
#define __SNDFILE_H
|
||||
#ifndef MODPLUG_SNDFILE_H
|
||||
#define MODPLUG_SNDFILE_H
|
||||
|
||||
#ifdef UNDER_CE
|
||||
int _strnicmp(const char *str1,const char *str2, int n);
|
||||
|
@ -456,7 +456,7 @@ typedef struct _MODCOMMAND
|
|||
// Mix Plugins
|
||||
#define MIXPLUG_MIXREADY 0x01 // Set when cleared
|
||||
|
||||
class IMixPlugin
|
||||
class MODPLUG_EXPORT IMixPlugin
|
||||
{
|
||||
public:
|
||||
virtual ~IMixPlugin();
|
||||
|
@ -535,7 +535,7 @@ typedef VOID (* LPSNDMIXHOOKPROC)(int *, unsigned long, unsigned long); // buffe
|
|||
|
||||
|
||||
//==============
|
||||
class CSoundFile
|
||||
class MODPLUG_EXPORT CSoundFile
|
||||
//==============
|
||||
{
|
||||
public: // Static Members
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
* Adam Goode <adam@evdebs.org> (endian and char fixes for PPC)
|
||||
*/
|
||||
|
||||
#ifndef _STDAFX_H_
|
||||
#define _STDAFX_H_
|
||||
#ifndef MODPLUG_STDAFX_H
|
||||
#define MODPLUG_STDAFX_H
|
||||
|
||||
/* Autoconf detection of stdint/inttypes */
|
||||
#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED)
|
||||
|
@ -48,6 +48,10 @@ inline void ProcessPlugins(int n) {}
|
|||
#define strnicmp(a,b,c) strncasecmp(a,b,c)
|
||||
#define HAVE_SINF 1
|
||||
|
||||
#ifndef isblank
|
||||
#define isblank(c) ((c) == ' ' || (c) == '\t')
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#include <stdlib.h>
|
||||
|
@ -121,6 +125,21 @@ inline void ProcessPlugins(int /* n */ ) {}
|
|||
|
||||
#endif // _WIN32
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
# if defined(MODPLUG_BUILD) && defined(DLL_EXPORT) /* building libmodplug as a dll for windows */
|
||||
# define MODPLUG_EXPORT __declspec(dllexport)
|
||||
# elif defined(MODPLUG_BUILD) || defined(MODPLUG_STATIC) /* building or using static libmodplug for windows */
|
||||
# define MODPLUG_EXPORT
|
||||
# else
|
||||
# define MODPLUG_EXPORT __declspec(dllimport) /* using libmodplug dll for windows */
|
||||
# endif
|
||||
/* FIXME: USE VISIBILITY ATTRIBUTES HERE */
|
||||
#elif defined(MODPLUG_BUILD)
|
||||
#define MODPLUG_EXPORT
|
||||
#else
|
||||
#define MODPLUG_EXPORT
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -1037,7 +1037,9 @@ Declare Function openmpt_module_get_metadata_keys_ Alias "openmpt_module_get_met
|
|||
\param key Metadata item key to query. Use openmpt_module_get_metadata_keys to check for available keys.
|
||||
Possible keys are:
|
||||
- type: Module format extension (e.g. it)
|
||||
- type_long: Tracker name associated with the module format (e.g. Impulse Tracker)
|
||||
- type_long: Format name associated with the module format (e.g. Impulse Tracker)
|
||||
- originaltype: Module format extension (e.g. it) of the original module in case the actual type is a converted format (e.g. mo3 or gdm)
|
||||
- originaltype_long: Format name associated with the module format (e.g. Impulse Tracker) of the original module in case the actual type is a converted format (e.g. mo3 or gdm)
|
||||
- container: Container format the module file is embedded in, if any (e.g. umx)
|
||||
- container_long: Full container name if the module is embedded in a container (e.g. Unreal Music)
|
||||
- tracker: Tracker that was (most likely) used to save the module file, if known
|
||||
|
@ -1347,9 +1349,14 @@ Declare Function openmpt_module_highlight_pattern_row_channel_ Alias "openmpt_mo
|
|||
- load.skip_subsongs_init: Set to "1" to avoid pre-initializing sub-songs. Skipping results in faster module loading but slower seeking.
|
||||
- seek.sync_samples: Set to "1" to sync sample playback when using openmpt_module_set_position_seconds or openmpt_module_set_position_order_row.
|
||||
- subsong: The current subsong. Setting it has identical semantics as openmpt_module_select_subsong(), getting it returns the currently selected subsong.
|
||||
- play.at_end: Chooses the behaviour when the end of song is reached:
|
||||
- "fadeout": Fades the module out for a short while. Subsequent reads after the fadeout will return 0 rendered frames.
|
||||
- "continue": Returns 0 rendered frames when the song end is reached. Subsequent reads will continue playing from the song start or loop start.
|
||||
- "stop": Returns 0 rendered frames when the song end is reached. Subsequent reads will return 0 rendered frames.
|
||||
- play.tempo_factor: Set a floating point tempo factor. "1.0" is the default tempo.
|
||||
- play.pitch_factor: Set a floating point pitch factor. "1.0" is the default pitch.
|
||||
- render.resampler.emulate_amiga: Set to "1" to enable the Amiga resampler for Amiga modules. This emulates the sound characteristics of the Paula chip and overrides the selected interpolation filter. Non-Amiga module formats are not affected by this setting.
|
||||
- render.opl.volume_factor: Set volume factor applied to synthesized OPL sounds, relative to the default OPL volume.
|
||||
- dither: Set the dither algorithm that is used for the 16 bit versions of openmpt_module_read. Supported values are:
|
||||
- 0: No dithering.
|
||||
- 1: Default mode. Chosen by OpenMPT code, might change.
|
||||
|
|
|
@ -1 +1,9 @@
|
|||
|
||||
foo_openmpt
|
||||
===========
|
||||
|
||||
foo_openmpt is a module file (https://en.wikipedia.org/wiki/Module_file) decoder
|
||||
component for foobar2000 >= 1.3.0. foo_openmpt is based on libopenmpt.
|
||||
|
||||
|
||||
See https://lib.openmpt.org/ for documentation, FAQ and other details.
|
||||
|
|
|
@ -1 +1,17 @@
|
|||
|
||||
in_openmpt
|
||||
==========
|
||||
|
||||
in_openmpt is a module file (https://en.wikipedia.org/wiki/Module_file) input
|
||||
plugin for Winamp >= 2.0 (or compatible players). in_openmpt is based on
|
||||
libopenmpt.
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
"in_openmpt.dll" and "openmpt-mpg123.dll" must both be placed into the Winamp
|
||||
"Plugins" directory.
|
||||
|
||||
|
||||
See https://lib.openmpt.org/ for documentation, FAQ and other details.
|
||||
|
|
|
@ -1 +1,16 @@
|
|||
|
||||
xmp-openmpt
|
||||
===========
|
||||
|
||||
xmp-openmpt is a module file (https://en.wikipedia.org/wiki/Module_file) input
|
||||
plugin for XMPlay >= 3.8.0.0. xmp-openmpt is based on libopenmpt.
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
"xmp-openmpt.dll" and "openmpt-mpg123.dll" must both be placed into the XMPlay
|
||||
plugins directory.
|
||||
|
||||
|
||||
See https://lib.openmpt.org/ for documentation, FAQ and other details.
|
||||
|
|
|
@ -5,163 +5,161 @@ Changelog {#changelog}
|
|||
For fully detailed change log, please see the source repository directly. This
|
||||
is just a high-level summary.
|
||||
|
||||
### libopenmpt 0.3.12 (2018-09-24)
|
||||
### libopenmpt 0.4.2 (2019-01-22)
|
||||
|
||||
* [**Bug**] openmpt123: Prevent libsdl2 and libsdl from being enabled at the
|
||||
same time because they conflict with each other.
|
||||
* [**Bug**] Make building the JavaScript package work with Emscripten version
|
||||
1.38.1 or later by disabling WebAssembly generation which generates a
|
||||
different set of output files. Emscripten 1.38.1 changed the default to
|
||||
WebAssembly.
|
||||
* [**Bug**] libmodplug: Setting `SNDMIX_NORESAMPLING` in the C++ API always
|
||||
resulted in linear interpolation instead of nearest neighbour.
|
||||
* [**Sec**] DSM: Assertion failure during file parsing with debug STLs
|
||||
(r11209).
|
||||
* [**Sec**] J2B: Assertion failure during file parsing with debug STLs
|
||||
(r11216).
|
||||
|
||||
* [**Change**] The old Emscripten configuration which is compatible with
|
||||
Emscripten before 1.38.0 has been renamed to `CONFIG=emscripten-old`.
|
||||
* S3M: Allow volume change of OPL instruments after Note Cut.
|
||||
|
||||
* libopenmpt now compiles without warnings with GCC 8.
|
||||
### libopenmpt 0.4.1 (2019-01-06)
|
||||
|
||||
* Jump commands on the same row as the end of a pattern loop covering the
|
||||
restart position of the module could cause the module to loop even when
|
||||
looping was disabled.
|
||||
* MO3: Reject overly long MP3 and Vorbis samples.
|
||||
* `play_note` from the libopenmpt_ext interface sometimes silenced the start
|
||||
of a triggered sample.
|
||||
* [**Bug**] Binaries compiled for winold (Windows XP, Vista, 7, for CPUs
|
||||
without SSE2 support) did not actually work on CPUs without SSE2 support.
|
||||
* [**Bug**] libmodplug: Public symbols of the C++ API had `visibility=hidden`
|
||||
set on non-MSVC systems, which made them not publicly accessible.
|
||||
* [**Bug**] Project files for Windows 10 desktop builds on ARM and ARM64
|
||||
(`build/vs2017win10`) were missing from Windows source package.
|
||||
* [**Bug**] MSVC project files in Windows source package lacked additional
|
||||
files required to build DLLs.
|
||||
|
||||
### libopenmpt 0.3.11 (2018-07-28)
|
||||
* MO3: Apply playback changes based on "ModPlug-made" header flag.
|
||||
|
||||
* [**Sec**] Crash with some malformed custom tunings in MPTM files (r10615).
|
||||
* minimp3: Update to commit e9df0760e94044caded36a55d70ab4152134adc5
|
||||
(2018-12-23).
|
||||
|
||||
* Channels whose volume envelope was playing at volume 0 while being moved to
|
||||
a NNA background channel were cut off completely since libopenmpt 0.3.8.
|
||||
* AMF (ASYLUM): Convert 7-bit panning to 8-bit panning for playback.
|
||||
### libopenmpt 0.4.0 (2018-12-23)
|
||||
|
||||
### libopenmpt 0.3.10 (2018-06-17)
|
||||
* [**New**] libopenmpt now includes emulation of the OPL chip and thus plays
|
||||
OPL instruments in S3M, C67 and MPTM files. OPL chip emulation volume can be
|
||||
changed with the new ctl `render.opl.volume_factor`.
|
||||
* [**New**] libopenmpt now supports CDFM / Composer 670 module files.
|
||||
* [**New**] Autotools `configure` and plain `Makefile` now honor the variable
|
||||
`CXXSTDLIB_PCLIBSPRIVATE` which serves the sole purpose of listing the
|
||||
standard library (or libraries) required for static linking. The contents of
|
||||
this variable will be put in `libopenmpt.pc` `Libs.private` and used for
|
||||
nothing else. See \ref libopenmpt_c_staticlinking .
|
||||
* [**New**] foo_openmpt: foo_openmpt now also works on Windows XP.
|
||||
* [**New**] libopenmpt Emscripten builds now ship with MP3 support by
|
||||
default, based on minimp3 by Lion (github.com/lieff).
|
||||
* [**New**] libopenmpt: New ctl `play.at_end` can be used to change what
|
||||
happens when the song end is reached:
|
||||
* "fadeout": Fades the module out for a short while. Subsequent reads
|
||||
after the fadeout will return 0 rendered frames. This is the default and
|
||||
identical to the behaviour in previous libopenmpt versions.
|
||||
* "continue": Returns 0 rendered frames when the song end is reached.
|
||||
Subsequent reads will continue playing from the song start or loop
|
||||
start. This can be used for custom loop logic, such as loop
|
||||
auto-detection and longer fadeouts.
|
||||
* "stop": Returns 0 rendered frames when the song end is reached.
|
||||
Subsequent reads will return 0 rendered frames.
|
||||
* [**New**] Add new metadata fields `"originaltype"` and `"originaltype_long"`
|
||||
which allow more clearly reflecting what is going on with converted formats
|
||||
like MO3 and GDM.
|
||||
* [**New**] `Makefile` `CONFIG=emscripten` now can generate WebAssembly via
|
||||
the additional option `EMSCRIPTEN_TARGET=wasm`.
|
||||
* [**New**] Compiling for DOS is now experimentally supported via DJGPP GCC
|
||||
7.2 or later.
|
||||
|
||||
* [**Change**] minimp3: Instead of the LGPL-2.1-licensed minimp3 by KeyJ,
|
||||
libopenmpt now uses the CC0-1.0-licensed minimp3 by Lion (github.com/lieff)
|
||||
as a fallback if libmpg123 is unavailable. The `USE_MINIMP3` `Makefile`
|
||||
option is gone and minimp3 will be used automatically in the `Makefile`
|
||||
build system if libmpg123 is not available.
|
||||
* [**Change**] openmpt123: openmpt123 now rejects `--output-type` in `--ui`
|
||||
and `--batch` modes and also rejects `--output` in `--render` mode. These
|
||||
combinations of options really made no sense and were rather confusing.
|
||||
* [**Change**] Android NDK build system now uses libc++ (`c++_shared`) instead
|
||||
of GNU libstdc++ (`gnustl_shared`), as recommended by Android NDK r16b.
|
||||
* [**Change**] xmp-openmpt: `openmpt-mpg123.dll` is no longer optional and
|
||||
must be placed into the same directory as `xmp-openmpt.dll`.
|
||||
* [**Change**] in_openmpt: `openmpt-mpg123.dll` is no longer optional and must
|
||||
be placed either into the directory of the player itself or into the same
|
||||
directory as `in_openmpt.dll`. This is dependent on how the player loads its
|
||||
plugins. For WinAMP 5, `openmpt-mpg123.dll` needs to be in the directory
|
||||
which contains `winamp.exe`. `in_openmpt.dll` needs to be in the `Plugins`
|
||||
directory.
|
||||
* [**Change**] foo_openmpt: foo_openmpt is now packaged as a fb2k-component
|
||||
package for easier installation.
|
||||
* [**Change**] When building libopenmpt with MinGW-w64, it is now recommended
|
||||
to use the posix thread model (as opposed to the win32 threading model),
|
||||
because the former does support std::mutex while the latter does not. When
|
||||
building with win32 threading model with the Autotools build system, it is
|
||||
recommended to provide the `mingw-std-threads` package. Building libopenmpt
|
||||
with MinGW-w64 without any `std::thread`/`std::mutex` support is deprecated
|
||||
and support for such configurations will be removed in libopenmpt 0.5.
|
||||
* [**Change**] `Makefile` `CONFIG=emscripten` now has 4 `EMSCRIPTEN_TARGET=`
|
||||
settings: `wasm` generates WebAssembly, `asmjs128m` generates asm.js with a
|
||||
fixed size 128MB heap, `asmjs` generates asm.js with a fixed default size
|
||||
heap (as of Emscripten 1.38.11, this amounts to 16MB), `js` generates
|
||||
JavaScript with dynamic heap growth and with compatibility for older VMs.
|
||||
* [**Change**] libmodplug: Update public headers to libmodplug 0.8.8.5. This
|
||||
adds support for kind-of automatic MODPLUG_EXPORT decoration on Windows.
|
||||
|
||||
* [**Regression**] Support for Clang 3.4, 3.5 has been removed.
|
||||
* [**Regression**] Building with Android NDK older than NDK r16b is not
|
||||
supported any more.
|
||||
* [**Regression**] Support for Emscripten versions older than 1.38.5 has been
|
||||
removed.
|
||||
* [**Regression**] Support for libmpg123 older than 1.14.0 has been removed.
|
||||
* [**Regression**] Using MediaFoundation to decode MP3 samples is no longer
|
||||
supported. Use libmpg123 or minimp3 instead.
|
||||
* [**Regression**] libmodplug: Support for emulating libmodplug 0.8.7 API/ABI
|
||||
has been removed.
|
||||
|
||||
* [**Bug**] xmp-openmpt: Sample rate and number of output channels were not
|
||||
applied correctly when using per-file settings.
|
||||
* [**Bug**] Internal mixer state was not initialized properly when initially
|
||||
rendering in 44100kHz stereo format.
|
||||
* [**Bug**] AMF: Undefined behaviour in loader code could lead to files
|
||||
playing silent.
|
||||
* [**Bug**] openmpt123: Prevent libsdl2 and libsdl from being enabled at the
|
||||
same time because they conflict with each other.
|
||||
* [**Bug**] libmodplug: Setting `SNDMIX_NORESAMPLING` in the C++ API always
|
||||
resulted in linear interpolation instead of nearest neighbour
|
||||
|
||||
* Switching between instruments with portamento did not update the NNA
|
||||
settings for the new instrument.
|
||||
* FAR: Properly import volume commands.
|
||||
|
||||
### libopenmpt 0.3.9 (2018-04-29)
|
||||
|
||||
* [**Sec**] Possible write near address 0 in out-of-memory situations when
|
||||
reading AMS files (r10149).
|
||||
|
||||
* [**Bug**] openmpt123: Fixed build failure in C++17 due to use of removed
|
||||
feature `std::random_shuffle`.
|
||||
|
||||
* STM: Having both Bxx and Cxx commands in a pattern imported the Bxx command
|
||||
incorrectly.
|
||||
* IT: In Compatible Gxx mode, allow sample changes next to a tone portamento
|
||||
effect if a previous sample has already stopped playing.
|
||||
* IT: Fix broken volume envelopes with negative values as found in breakdwn.it
|
||||
by Elysis.
|
||||
* MOD: Slides and delayed notes are executed on every repetition of a row with
|
||||
row delay (fixes "ode to protracker").
|
||||
* XM: If the sustain point of the panning envelope is reached before key-off,
|
||||
it is never released.
|
||||
* XM: Do not default recall volume / panning for delayed instrument-less notes
|
||||
* XM :E60 loop bug was not considered in song length calucation.
|
||||
* S3M: Notes without instrument number use previous note's sample offset.
|
||||
* Tighten M15 and MOD file rejection heuristics.
|
||||
* J2B: Ignore frequency limits from file header. Fixes Medivo.j2b, broken
|
||||
since libopenmpt-0.2.6401-beta17.
|
||||
* STM: More accurate tempo calculation.
|
||||
* STM: Better support for early format revisions (no such files have been
|
||||
found in the wild, though).
|
||||
* STM: Last character of sample name was missing.
|
||||
* Speed up reading of truncated ULT files.
|
||||
* ULT: Portamento import was sometimes broken.
|
||||
* The resonant filter was sometimes unstable when combining low-volume
|
||||
samples, low cutoff and high mixing rates.
|
||||
|
||||
### libopenmpt 0.3.8 (2018-04-08)
|
||||
|
||||
* [**Sec**] Possible out-of-bounds memory read with IT and MO3 files
|
||||
containing many nested pattern loops (r10028).
|
||||
|
||||
* SFX: Work around bad conversions of the "Operation Stealth" soundtrack by
|
||||
turning pattern breaks into note stops.
|
||||
* IMF: Filter cutoff was upside down and the cutoff range was too small.
|
||||
* ParamEq plugin center frequency was not limited correctly.
|
||||
* Keep track of active SFx macro during seeking.
|
||||
* The "note cut" duplicate note action did not volume-ramp the previously
|
||||
playing sample.
|
||||
* A song starting with non-existing patterns could not be played.
|
||||
* DSM: Support restart position and 16-bit samples.
|
||||
* DTM: Import global volume.
|
||||
* MOD: Support notes in octave 2, like in FastTracker 2 (fixes DOPE.MOD).
|
||||
* Do not apply Amiga playback heuristics to MOD files that have clearly been
|
||||
written with a PC tracker.
|
||||
* MPTM: More logical release node behaviour.
|
||||
* Subsong search is now less thorough. It could previously find many subsongs
|
||||
that are technically correct (unplayed rows at the beginning of patterns
|
||||
that have been jumped over due to pattern breaks), but so far no real-world
|
||||
module that would require such a thorough subsong detection was found. The
|
||||
old mechanism caused way more false positives than intended with real-world
|
||||
modules, though.
|
||||
* Restrict the unpacked size of compressed DMF, IT, MDL and MO3 samples to
|
||||
avoid huge allocations with malformed small files.
|
||||
|
||||
### libopenmpt 0.3.7 (2018-03-11)
|
||||
|
||||
* [**Bug**] libopenmpt did not build with NDK r13b on armeabi due to missing
|
||||
`-latomic`.
|
||||
* [**Bug**] xmp-openmpt: Sample rate and number of output channels were not
|
||||
applied correctly when using per-file settings.
|
||||
|
||||
* [**Change**] foo_openmpt: foo_openmpt is now packaged as a fb2k-component
|
||||
package for easier installation.
|
||||
|
||||
* IT: More accurate song length calculation for pattern loops that have no
|
||||
start command and are following another pattern loop.
|
||||
* IMF: Filter cutoff was upside down and the cutoff range was too small.
|
||||
* MED: Correctly import patterns with less channels than the maximum used
|
||||
amount. Import "STP" note stop command.
|
||||
* DBM: Key Off and Set Envelope Position were imported incorrectly.
|
||||
High sample offset (E7x) is now supported.
|
||||
* DIGI / DBM: Arpeggio should not return to base note at end of row.
|
||||
* Some filter changes through MIDI macros were not applied if the note volume
|
||||
was set to 0 on the same row.
|
||||
|
||||
### libopenmpt 0.3.6 (2018-02-03)
|
||||
|
||||
* [**Sec**] Possible out-of-bounds memory read with malformed STP files.
|
||||
(r9576)
|
||||
|
||||
* [**Bug**] Small memory leak with malformed STP files.
|
||||
|
||||
* STM: Accurate emulation of Scream Tracker 2 tempo mode.
|
||||
* STM: Better support for early format revisions (no such files have been
|
||||
found in the wild, though).
|
||||
* Fine volume slides are now supported when seeking with seek.sync_samples=1
|
||||
enabled.
|
||||
|
||||
### libopenmpt 0.3.5 (2018-01-28)
|
||||
|
||||
* [**New**] Support MOD files from the Inconexia demo by Iguana.
|
||||
* [**Bug**] xmp-openmpt: Saved settings were not applied instantly.
|
||||
|
||||
* XM E60 loop bug was not considered in song length calucation.
|
||||
* Tighten M15 and MOD file rejection heuristics.
|
||||
* J2B: Ignore frequency limits from file header. Fixes Medivo.j2b, broken
|
||||
since libopenmpt-0.2.6401-beta17.
|
||||
* ParamEq plugin center frequency was not limited correctly.
|
||||
* libopenmpt_ext C API was not included in the documentation.
|
||||
|
||||
### libopenmpt 0.3.4 (2017-12-17)
|
||||
|
||||
* IT: Fix broken volume envelopes with negative values as found in breakdwn.it
|
||||
by Elysis.
|
||||
|
||||
### libopenmpt 0.3.3 (2017-11-19)
|
||||
|
||||
* [**New**] foo_openmpt: foo_openmpt now also works on Windows XP.
|
||||
|
||||
* [**Bug**] All VS2015 and VS2017 project files targetting Windows XP did not
|
||||
set compiler option `/Zc:threadSafeInit-` which caused at least the player
|
||||
plugins `in_openmpt` and `xmp-openmpt` to fail to load.
|
||||
|
||||
### libopenmpt 0.3.2 (2017-11-04)
|
||||
|
||||
* [**New**] Autotools `configure` and plain `Makefile` now honor the variable
|
||||
`CXXSTDLIB_PCLIBSPRIVATE` which serves the sole purpose of listing the
|
||||
standard library (or libraries) required for static linking. The contents of
|
||||
this variable will be put in `libopenmpt.pc` `Libs.private` and used for
|
||||
nothing else. See \ref libopenmpt_c_staticlinking .
|
||||
|
||||
* [**Change**] Windows bin and dev release packages now use zip archives
|
||||
instead of 7z archives as it had originally been intended for the 0.3.0
|
||||
release.
|
||||
* [**Change**] openmpt123: The following combinations of options are now
|
||||
deprecated because they made no real sense in the first place:
|
||||
`--render --output`, `--ui --output-type`, `--batch --output-type`
|
||||
|
||||
* [**Bug**] libopenmpt did not build on Android NDK 15c (and possibly
|
||||
other versions between 12b and 15c as well).
|
||||
|
||||
* IT: In Compatible Gxx mode, allow sample changes next to a tone portamento
|
||||
effect if a previous sample has already stopped playing.
|
||||
* MOD: Slides and delayed notes are executed on every repetition of a row with
|
||||
row delay (fixes "ode to protracker").
|
||||
|
||||
### libopenmpt 0.3.1 (2017-09-28)
|
||||
|
||||
* [**Bug**] Windows: libopenmpt resource did not compile for release versions.
|
||||
|
||||
### libopenmpt 0.3.0 (2017-09-27, not released)
|
||||
### libopenmpt 0.3 (2017-09-27)
|
||||
|
||||
* [**New**] New error handling functionality in the C API, which in particular
|
||||
allows distinguishing potentially transient out-of-memory errors from parse
|
||||
|
|
|
@ -9,29 +9,33 @@ Dependencies
|
|||
### libopenmpt
|
||||
|
||||
* Supported compilers for building libopenmpt:
|
||||
* **Microsoft Visual Studio 2015** or higher
|
||||
* **Microsoft Visual Studio 2015** or higher, running on a x86-64 build
|
||||
system (other target systems are supported)
|
||||
* **GCC 4.8** or higher
|
||||
* **Clang 3.4** or higher
|
||||
* **MinGW-W64 4.8** or higher
|
||||
* **emscripten 1.31** or higher
|
||||
* **Clang 3.6** or higher
|
||||
* **MinGW-W64 4.8** or higher (it is recommended to preferably use
|
||||
posix threading model as opposed to win32 threading model, or at least
|
||||
have mingw-std-threads available otherwise)
|
||||
* **emscripten 1.38.5** or higher
|
||||
* **DJGPP GCC 7.2** or higher
|
||||
* any other **C++11 compliant** compiler (full standard compliant mode is
|
||||
known to work with GCC >= 5.1 and Clang >= 3.5)
|
||||
known to work with GCC >= 5.1 and Clang)
|
||||
|
||||
libopenmpt makes the following assumptions about the C++ implementation
|
||||
used for building:
|
||||
* `CHAR_BIT == 8` (enforced by static_assert)
|
||||
* `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)
|
||||
* `sizeof(float) == 4` (enforced by static_assert)
|
||||
* `sizeof(double) == 8` (enforced by static_assert)
|
||||
* if `__BYTE_ORDER__` is provided by the compiler and
|
||||
`__STDC_IEC_559__ == 1`, the endianness of integers is the same as
|
||||
the endianness of floats (implicitly assumed)
|
||||
* `wchar_t` encoding is either UTF-16 or UTF-32 (implicitly assumed)
|
||||
* representation of basic source character set is ASCII (implicitly
|
||||
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
|
||||
|
@ -50,13 +54,12 @@ Dependencies
|
|||
* **zlib**
|
||||
* **miniz** can be used internally if no zlib is available.
|
||||
* Built-in **MO3** support requires:
|
||||
* **libmpg123 >= 1.13.0**
|
||||
* **libmpg123 >= 1.14.0**
|
||||
* **libogg**
|
||||
* **libvorbis**
|
||||
* **libvorbisfile**
|
||||
* Alternatively, **Media Foundation** can be used on Windows 7 or later
|
||||
instead of libmpg123 to decode mp3 samples. It's also possible to use
|
||||
**minimp3**.
|
||||
* 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.
|
||||
* Building on Unix-like systems requires:
|
||||
|
@ -70,10 +73,12 @@ Dependencies
|
|||
### openmpt123
|
||||
|
||||
* Supported compilers for building openmpt123:
|
||||
* **Microsoft Visual Studio 2015** or higher
|
||||
* **Microsoft Visual Studio 2015** or higher, running on a x86-64 build
|
||||
system (other target systems are supported)
|
||||
* **GCC 4.8** or higher
|
||||
* **Clang 3.4** or higher
|
||||
* **Clang 3.6** or higher
|
||||
* **MinGW-W64 4.8** or higher
|
||||
* **DJGPP GCC 7.2** or higher
|
||||
* any **C++11 compliant** compiler
|
||||
* Live sound output requires one of:
|
||||
* **PulseAudio**
|
||||
|
@ -81,6 +86,7 @@ Dependencies
|
|||
* **SDL 1.2**
|
||||
* **PortAudio v19**
|
||||
* **Win32**
|
||||
* **liballegro 4.2** on DJGPP/DOS
|
||||
|
||||
|
||||
Optional dependencies
|
||||
|
@ -104,3 +110,19 @@ Optional dependencies
|
|||
* raw PCM has no external dependencies
|
||||
* **help2man** is required to build the documentation.
|
||||
|
||||
|
||||
Source packages
|
||||
---------------
|
||||
|
||||
Building the source packages additionally requires:
|
||||
* 7z (7-zip)
|
||||
* autoconf
|
||||
* autoconf-archive
|
||||
* automake
|
||||
* gzip
|
||||
* help2man
|
||||
* libtool
|
||||
* subversion
|
||||
* tar
|
||||
* xpath (libxml-xpath-perl)
|
||||
* zip
|
||||
|
|
|
@ -7,11 +7,11 @@ Quick Start {#quickstart}
|
|||
|
||||
1. Grab a `libopenmpt-VERSION.autotools.tar.gz` tarball.
|
||||
2. Get dependencies:
|
||||
- **gcc >= 4.8** or **clang >= 3.4**
|
||||
- **gcc >= 4.8** or **clang >= 3.6**
|
||||
- **pkg-config >= 0.24**
|
||||
- **zlib**
|
||||
- **libogg**, **libvorbis**, **libvorbisfile**
|
||||
- **libmpg123 >= 1.13.0**
|
||||
- **libmpg123 >= 1.14.0**
|
||||
- **doxygen >= 1.8**
|
||||
- **libpulse**, **libpulse-simple** (required only by openmpt123)
|
||||
- **portaudio-v19** (required only by openmpt123)
|
||||
|
@ -42,11 +42,11 @@ Quick Start {#quickstart}
|
|||
|
||||
1. Get dependencies:
|
||||
- **GNU make**
|
||||
- **gcc >= 4.8** or **clang >= 3.4**
|
||||
- **gcc >= 4.8** or **clang >= 3.6**
|
||||
- **pkg-config**
|
||||
- **zlib**
|
||||
- **libogg**, **libvorbis**, **libvorbisfile**
|
||||
- **libmpg123 >= 1.13.0**
|
||||
- **libmpg123 >= 1.14.0**
|
||||
- **libpulse**, **libpulse-simple** (required only by openmpt123)
|
||||
- **portaudio-v19** (required only by openmpt123)
|
||||
- **libFLAC** (required only by openmpt123)
|
||||
|
|
|
@ -3,8 +3,15 @@
|
|||
#pragma warning(disable:4091)
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4996)
|
||||
#endif
|
||||
#include "foobar2000/SDK/foobar2000.h"
|
||||
#include "foobar2000/helpers/helpers.h"
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include "libopenmpt.hpp"
|
||||
|
||||
|
@ -136,24 +143,10 @@ struct foo_openmpt_settings {
|
|||
|
||||
|
||||
|
||||
// Sample initquit implementation. See also: initquit class documentation in relevant header.
|
||||
|
||||
class myinitquit : public initquit {
|
||||
public:
|
||||
void on_init() {
|
||||
// console::print("Sample component: on_init()");
|
||||
}
|
||||
void on_quit() {
|
||||
// console::print("Sample component: on_quit()");
|
||||
}
|
||||
};
|
||||
|
||||
static initquit_factory_t<myinitquit> g_myinitquit_factory;
|
||||
|
||||
|
||||
|
||||
// No inheritance. Our methods get called over input framework templates. See input_singletrack_impl for descriptions of what each method does.
|
||||
class input_openmpt {
|
||||
// Note that input class does *not* implement virtual methods or derive from interface classes.
|
||||
// Our methods get called over input framework templates. See input_singletrack_impl for descriptions of what each method does.
|
||||
// input_stubs just provides stub implementations of mundane methods that are irrelevant for most implementations.
|
||||
class input_openmpt : public input_stubs {
|
||||
public:
|
||||
void open(service_ptr_t<file> p_filehint,const char * p_path,t_input_open_reason p_reason,abort_callback & p_abort) {
|
||||
if ( p_reason == input_open_info_write ) {
|
||||
|
@ -276,7 +269,15 @@ public:
|
|||
std::transform( ext.begin(), ext.end(), ext.begin(), tolower );
|
||||
return std::find( extensions.begin(), extensions.end(), ext ) != extensions.end();
|
||||
}
|
||||
public:
|
||||
static GUID g_get_guid() {
|
||||
// {B0B7CCC3-4520-44D3-B5F9-22EB9EBA7575}
|
||||
static const GUID foo_openmpt_guid = { 0xb0b7ccc3, 0x4520, 0x44d3, { 0xb5, 0xf9, 0x22, 0xeb, 0x9e, 0xba, 0x75, 0x75 } };
|
||||
return foo_openmpt_guid;
|
||||
}
|
||||
static const char * g_get_name() {
|
||||
return "OpenMPT Module Decoder";
|
||||
}
|
||||
private:
|
||||
service_ptr_t<file> m_file;
|
||||
static const std::size_t buffersize = 1024;
|
||||
foo_openmpt_settings settings;
|
||||
|
@ -286,6 +287,7 @@ public:
|
|||
std::vector<float> rear_left;
|
||||
std::vector<float> rear_right;
|
||||
std::vector<float> buffer;
|
||||
public:
|
||||
input_openmpt() : mod(0), left(buffersize), right(buffersize), rear_left(buffersize), rear_right(buffersize), buffer(4*buffersize) {}
|
||||
~input_openmpt() { delete mod; mod = 0; }
|
||||
};
|
||||
|
@ -293,53 +295,29 @@ public:
|
|||
static input_singletrack_factory_t<input_openmpt> g_input_openmpt_factory;
|
||||
|
||||
|
||||
class input_file_type_v2_impl_openmpt : public input_file_type_v2 {
|
||||
public:
|
||||
input_file_type_v2_impl_openmpt()
|
||||
: extensions( openmpt::get_supported_extensions() )
|
||||
{ }
|
||||
unsigned get_count() {
|
||||
return static_cast<unsigned>( extensions.size() );
|
||||
}
|
||||
bool is_associatable( unsigned idx ) {
|
||||
return true;
|
||||
}
|
||||
void get_format_name( unsigned idx, pfc::string_base & out, bool isPlural ) {
|
||||
if ( isPlural ) {
|
||||
out = "OpenMPT compatible module files";
|
||||
} else {
|
||||
out = "OpenMPT compatible module file";
|
||||
}
|
||||
}
|
||||
void get_extensions( unsigned idx, pfc::string_base & out ) {
|
||||
out = extensions[idx].c_str();
|
||||
}
|
||||
private:
|
||||
std::vector<std::string> extensions;
|
||||
};
|
||||
|
||||
// copied table from soundlib/Tables.cpp
|
||||
// the foobar2000 interface is stupid demanding to declare those statically
|
||||
|
||||
DECLARE_FILE_TYPE("OpenMPT compatible module files",
|
||||
"*.mod" ";"
|
||||
"*.s3m" ";"
|
||||
"*.xm" ";"
|
||||
"*.it" ";"
|
||||
"*.mptm" ";"
|
||||
"*.stm" ";"
|
||||
"*.nst" ";"
|
||||
"*.m15" ";"
|
||||
"*.stk" ";"
|
||||
"*.st26" ";"
|
||||
"*.pt36" ";"
|
||||
"*.ice" ";"
|
||||
"*.wow" ";"
|
||||
"*.ult" ";"
|
||||
"*.669" ";"
|
||||
"*.mtm" ";"
|
||||
"*.med" ";"
|
||||
"*.far" ";"
|
||||
"*.mdl" ";"
|
||||
"*.ams" ";"
|
||||
"*.ams" ";"
|
||||
"*.dsm" ";"
|
||||
"*.dtm" ";"
|
||||
"*.amf" ";"
|
||||
"*.amf" ";"
|
||||
"*.okt" ";"
|
||||
"*.dmf" ";"
|
||||
"*.ptm" ";"
|
||||
"*.psm" ";"
|
||||
"*.mt2" ";"
|
||||
"*.dbm" ";"
|
||||
"*.digi" ";"
|
||||
"*.imf" ";"
|
||||
"*.j2b" ";"
|
||||
"*.plm" ";"
|
||||
"*.stp" ";"
|
||||
"*.sfx" ";"
|
||||
"*.sfx2" ";"
|
||||
"*.mms" ";"
|
||||
"*.gdm" ";"
|
||||
"*.umx" ";"
|
||||
"*.mo3" ";"
|
||||
"*.xpk" ";"
|
||||
"*.ppm" ";"
|
||||
"*.mmcmp" );
|
||||
namespace { static service_factory_single_t<input_file_type_v2_impl_openmpt> g_filetypes; }
|
||||
|
|
|
@ -37,27 +37,14 @@
|
|||
#endif // _MSC_VER
|
||||
|
||||
#include "libopenmpt.hpp"
|
||||
#ifdef LIBOPENMPT_QUIRK_NO_CSTDINT
|
||||
#include <stdint.h>
|
||||
namespace std {
|
||||
typedef ::int8_t int8_t;
|
||||
typedef ::int16_t int16_t;
|
||||
typedef ::int32_t int32_t;
|
||||
typedef ::int64_t int64_t;
|
||||
typedef ::uint8_t uint8_t;
|
||||
typedef ::uint16_t uint16_t;
|
||||
typedef ::uint32_t uint32_t;
|
||||
typedef ::uint64_t uint64_t;
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "libopenmpt_plugin_gui.hpp"
|
||||
|
||||
#include "svn_version.h"
|
||||
#if defined(OPENMPT_VERSION_REVISION)
|
||||
static char * in_openmpt_string = "in_openmpt " OPENMPT_API_VERSION_STRING "." OPENMPT_API_VERSION_STRINGIZE(OPENMPT_VERSION_REVISION);
|
||||
static const char * in_openmpt_string = "in_openmpt " OPENMPT_API_VERSION_STRING "." OPENMPT_API_VERSION_STRINGIZE(OPENMPT_VERSION_REVISION);
|
||||
#else
|
||||
static char * in_openmpt_string = "in_openmpt " OPENMPT_API_VERSION_STRING;
|
||||
static const char * in_openmpt_string = "in_openmpt " OPENMPT_API_VERSION_STRING;
|
||||
#endif
|
||||
|
||||
#ifndef NOMINMAX
|
||||
|
@ -209,7 +196,7 @@ static void config( HWND hwndParent ) {
|
|||
static void about( HWND hwndParent ) {
|
||||
std::ostringstream about;
|
||||
about << SHORT_TITLE << " version " << openmpt::string::get( "library_version" ) << " " << "(built " << openmpt::string::get( "build" ) << ")" << std::endl;
|
||||
about << " Copyright (c) 2013-2018 OpenMPT developers (https://lib.openmpt.org/)" << std::endl;
|
||||
about << " Copyright (c) 2013-2019 OpenMPT developers (https://lib.openmpt.org/)" << std::endl;
|
||||
about << " OpenMPT version " << openmpt::string::get( "core_version" ) << std::endl;
|
||||
about << std::endl;
|
||||
about << openmpt::string::get( "contact" ) << std::endl;
|
||||
|
@ -452,7 +439,7 @@ static DWORD WINAPI DecodeThread( LPVOID ) {
|
|||
|
||||
In_Module inmod = {
|
||||
IN_VER,
|
||||
in_openmpt_string, // SHORT_TITLE,
|
||||
const_cast< char * >( in_openmpt_string ), // SHORT_TITLE,
|
||||
0, // hMainWindow
|
||||
0, // hDllInstance
|
||||
NULL, // filled later in Init() "mptm\0ModPlug Tracker Module (*.mptm)\0",
|
||||
|
|
|
@ -167,8 +167,8 @@
|
|||
/*! \defgroup libopenmpt_c libopenmpt C */
|
||||
|
||||
/*! \addtogroup libopenmpt_c
|
||||
@{
|
||||
*/
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@ -293,6 +293,9 @@ typedef int64_t (*openmpt_stream_tell_func)( void * stream );
|
|||
/*! \brief Stream callbacks
|
||||
*
|
||||
* Stream callbacks used by libopenmpt for stream operations.
|
||||
* \sa openmpt_stream_get_file_callbacks
|
||||
* \sa openmpt_stream_get_fd_callbacks
|
||||
* \sa openmpt_stream_get_buffer_callbacks
|
||||
*/
|
||||
typedef struct openmpt_stream_callbacks {
|
||||
|
||||
|
@ -1120,7 +1123,9 @@ LIBOPENMPT_API const char * openmpt_module_get_metadata_keys( openmpt_module * m
|
|||
* \param key Metadata item key to query. Use openmpt_module_get_metadata_keys to check for available keys.
|
||||
* Possible keys are:
|
||||
* - type: Module format extension (e.g. it)
|
||||
* - type_long: Tracker name associated with the module format (e.g. Impulse Tracker)
|
||||
* - type_long: Format name associated with the module format (e.g. Impulse Tracker)
|
||||
* - originaltype: Module format extension (e.g. it) of the original module in case the actual type is a converted format (e.g. mo3 or gdm)
|
||||
* - originaltype_long: Format name associated with the module format (e.g. Impulse Tracker) of the original module in case the actual type is a converted format (e.g. mo3 or gdm)
|
||||
* - container: Container format the module file is embedded in, if any (e.g. umx)
|
||||
* - container_long: Full container name if the module is embedded in a container (e.g. Unreal Music)
|
||||
* - tracker: Tracker that was (most likely) used to save the module file, if known
|
||||
|
@ -1397,9 +1402,14 @@ LIBOPENMPT_API const char * openmpt_module_highlight_pattern_row_channel( openmp
|
|||
* - load.skip_subsongs_init: Set to "1" to avoid pre-initializing sub-songs. Skipping results in faster module loading but slower seeking.
|
||||
* - seek.sync_samples: Set to "1" to sync sample playback when using openmpt_module_set_position_seconds or openmpt_module_set_position_order_row.
|
||||
* - subsong: The current subsong. Setting it has identical semantics as openmpt_module_select_subsong(), getting it returns the currently selected subsong.
|
||||
* - play.at_end: Chooses the behaviour when the end of song is reached:
|
||||
* - "fadeout": Fades the module out for a short while. Subsequent reads after the fadeout will return 0 rendered frames.
|
||||
* - "continue": Returns 0 rendered frames when the song end is reached. Subsequent reads will continue playing from the song start or loop start.
|
||||
* - "stop": Returns 0 rendered frames when the song end is reached. Subsequent reads will return 0 rendered frames.
|
||||
* - play.tempo_factor: Set a floating point tempo factor. "1.0" is the default tempo.
|
||||
* - play.pitch_factor: Set a floating point pitch factor. "1.0" is the default pitch.
|
||||
* - render.resampler.emulate_amiga: Set to "1" to enable the Amiga resampler for Amiga modules. This emulates the sound characteristics of the Paula chip and overrides the selected interpolation filter. Non-Amiga module formats are not affected by this setting.
|
||||
* - render.opl.volume_factor: Set volume factor applied to synthesized OPL sounds, relative to the default OPL volume.
|
||||
* - dither: Set the dither algorithm that is used for the 16 bit versions of openmpt_module_read. Supported values are:
|
||||
* - 0: No dithering.
|
||||
* - 1: Default mode. Chosen by OpenMPT code, might change.
|
||||
|
@ -1432,8 +1442,8 @@ LIBOPENMPT_API int openmpt_module_ctl_set( openmpt_module * mod, const char * ct
|
|||
#endif
|
||||
|
||||
/*!
|
||||
@}
|
||||
*/
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* LIBOPENMPT_H */
|
||||
|
||||
|
|
|
@ -150,7 +150,7 @@ public:
|
|||
exception & operator = ( const exception & other ) noexcept;
|
||||
exception & operator = ( exception && other ) noexcept;
|
||||
virtual ~exception() noexcept;
|
||||
virtual const char * what() const noexcept;
|
||||
const char * what() const noexcept override;
|
||||
}; // class exception
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
|
@ -724,7 +724,9 @@ public:
|
|||
\param key Metadata item key to query. Use openmpt::module::get_metadata_keys to check for available keys.
|
||||
Possible keys are:
|
||||
- type: Module format extension (e.g. it)
|
||||
- type_long: Tracker name associated with the module format (e.g. Impulse Tracker)
|
||||
- type_long: Format name associated with the module format (e.g. Impulse Tracker)
|
||||
- originaltype: Module format extension (e.g. it) of the original module in case the actual type is a converted format (e.g. mo3 or gdm)
|
||||
- originaltype_long: Format name associated with the module format (e.g. Impulse Tracker) of the original module in case the actual type is a converted format (e.g. mo3 or gdm)
|
||||
- container: Container format the module file is embedded in, if any (e.g. umx)
|
||||
- container_long: Full container name if the module is embedded in a container (e.g. Unreal Music)
|
||||
- tracker: Tracker that was (most likely) used to save the module file, if known
|
||||
|
@ -966,9 +968,14 @@ public:
|
|||
- load.skip_subsongs_init: Set to "1" to avoid pre-initializing sub-songs. Skipping results in faster module loading but slower seeking.
|
||||
- seek.sync_samples: Set to "1" to sync sample playback when using openmpt::module::set_position_seconds or openmpt::module::set_position_order_row.
|
||||
- subsong: The current subsong. Setting it has identical semantics as openmpt::module::select_subsong(), getting it returns the currently selected subsong.
|
||||
- play.at_end: Chooses the behaviour when the end of song is reached:
|
||||
- "fadeout": Fades the module out for a short while. Subsequent reads after the fadeout will return 0 rendered frames.
|
||||
- "continue": Returns 0 rendered frames when the song end is reached. Subsequent reads will continue playing from the song start or loop start.
|
||||
- "stop": Returns 0 rendered frames when the song end is reached. Subsequent reads will return 0 rendered frames.
|
||||
- play.tempo_factor: Set a floating point tempo factor. "1.0" is the default tempo.
|
||||
- play.pitch_factor: Set a floating point pitch factor. "1.0" is the default pitch.
|
||||
- render.resampler.emulate_amiga: Set to "1" to enable the Amiga resampler for Amiga modules. This emulates the sound characteristics of the Paula chip and overrides the selected interpolation filter. Non-Amiga module formats are not affected by this setting.
|
||||
- render.opl.volume_factor: Set volume factor applied to synthesized OPL sounds, relative to the default OPL volume.
|
||||
- dither: Set the dither algorithm that is used for the 16 bit versions of openmpt::module::read. Supported values are:
|
||||
- 0: No dithering.
|
||||
- 1: Default mode. Chosen by OpenMPT code, might change.
|
||||
|
|
|
@ -50,10 +50,7 @@ public:
|
|||
logfunc_logger( openmpt_log_func func, void * user ) : m_logfunc(func), m_user(user) {
|
||||
return;
|
||||
}
|
||||
virtual ~logfunc_logger() {
|
||||
return;
|
||||
}
|
||||
virtual void log( const std::string & message ) const {
|
||||
void log( const std::string & message ) const override {
|
||||
if ( m_logfunc ) {
|
||||
m_logfunc( message.c_str(), m_user );
|
||||
} else {
|
||||
|
@ -71,9 +68,8 @@ public:
|
|||
{
|
||||
return;
|
||||
}
|
||||
virtual ~invalid_module_pointer() throw() {
|
||||
return;
|
||||
}
|
||||
invalid_module_pointer(const invalid_module_pointer&) = default;
|
||||
virtual ~invalid_module_pointer() noexcept = default;
|
||||
};
|
||||
|
||||
class argument_null_pointer : public openmpt::exception {
|
||||
|
@ -83,9 +79,8 @@ public:
|
|||
{
|
||||
return;
|
||||
}
|
||||
virtual ~argument_null_pointer() throw() {
|
||||
return;
|
||||
}
|
||||
argument_null_pointer(const argument_null_pointer&) = default;
|
||||
virtual ~argument_null_pointer() noexcept = default;
|
||||
};
|
||||
|
||||
} // namespace interface
|
||||
|
@ -100,6 +95,12 @@ static std::string format_exception( const char * const function ) {
|
|||
err += "ERROR: ";
|
||||
const char * what = e.what();
|
||||
err += what ? what : "";
|
||||
} catch ( const std::bad_alloc & e ) {
|
||||
err += function;
|
||||
err += ": ";
|
||||
err += "OUT OF MEMORY: ";
|
||||
const char * what = e.what();
|
||||
err += what ? what : "";
|
||||
} catch ( const std::exception & e ) {
|
||||
err += function;
|
||||
err += ": ";
|
||||
|
|
|
@ -152,10 +152,11 @@ int probe_file_header( std::uint64_t flags, std::istream & stream ) {
|
|||
#pragma warning(disable:4702) // unreachable code
|
||||
#endif // _MSC_VER
|
||||
|
||||
module::module( const module & ) {
|
||||
module::module( const module & ) : impl(nullptr) {
|
||||
throw exception("openmpt::module is non-copyable");
|
||||
}
|
||||
|
||||
// cppcheck-suppress operatorEqVarError
|
||||
void module::operator = ( const module & ) {
|
||||
throw exception("openmpt::module is non-copyable");
|
||||
}
|
||||
|
@ -417,9 +418,10 @@ module_ext::~module_ext() {
|
|||
#pragma warning(push)
|
||||
#pragma warning(disable:4702) // unreachable code
|
||||
#endif // _MSC_VER
|
||||
module_ext::module_ext( const module_ext & other ) : module(other) {
|
||||
module_ext::module_ext( const module_ext & other ) : module(other), ext_impl(nullptr) {
|
||||
throw std::runtime_error("openmpt::module_ext is non-copyable");
|
||||
}
|
||||
// cppcheck-suppress operatorEqVarError
|
||||
void module_ext::operator = ( const module_ext & ) {
|
||||
throw std::runtime_error("openmpt::module_ext is non-copyable");
|
||||
}
|
||||
|
|
|
@ -135,7 +135,7 @@ namespace openmpt {
|
|||
if ( factor <= 0.0 || factor > 4.0 ) {
|
||||
throw openmpt::exception("invalid tempo factor");
|
||||
}
|
||||
m_sndFile->m_nTempoFactor = Util::Round<uint32_t>( 65536.0 / factor );
|
||||
m_sndFile->m_nTempoFactor = mpt::saturate_round<uint32_t>( 65536.0 / factor );
|
||||
m_sndFile->RecalculateSamplesPerTick();
|
||||
}
|
||||
|
||||
|
@ -147,7 +147,7 @@ namespace openmpt {
|
|||
if ( factor <= 0.0 || factor > 4.0 ) {
|
||||
throw openmpt::exception("invalid pitch factor");
|
||||
}
|
||||
m_sndFile->m_nFreqFactor = Util::Round<uint32_t>( 65536.0 * factor );
|
||||
m_sndFile->m_nFreqFactor = mpt::saturate_round<uint32_t>( 65536.0 * factor );
|
||||
m_sndFile->RecalculateSamplesPerTick();
|
||||
}
|
||||
|
||||
|
@ -159,7 +159,7 @@ namespace openmpt {
|
|||
if ( volume < 0.0 || volume > 1.0 ) {
|
||||
throw openmpt::exception("invalid global volume");
|
||||
}
|
||||
m_sndFile->m_PlayState.m_nGlobalVolume = Util::Round<uint32_t>( volume * MAX_GLOBAL_VOLUME );
|
||||
m_sndFile->m_PlayState.m_nGlobalVolume = mpt::saturate_round<uint32_t>( volume * MAX_GLOBAL_VOLUME );
|
||||
}
|
||||
|
||||
double module_ext_impl::get_global_volume( ) const {
|
||||
|
@ -173,7 +173,7 @@ namespace openmpt {
|
|||
if ( volume < 0.0 || volume > 1.0 ) {
|
||||
throw openmpt::exception("invalid global volume");
|
||||
}
|
||||
m_sndFile->m_PlayState.Chn[channel].nGlobalVol = Util::Round<std::int32_t>(volume * 64.0);
|
||||
m_sndFile->m_PlayState.Chn[channel].nGlobalVol = mpt::saturate_round<std::int32_t>(volume * 64.0);
|
||||
}
|
||||
|
||||
double module_ext_impl::get_channel_volume( std::int32_t channel ) const {
|
||||
|
@ -269,11 +269,11 @@ namespace openmpt {
|
|||
chn.nMasterChn = 0; // remove NNA association
|
||||
chn.nNewNote = chn.nLastNote = static_cast<uint8>(note);
|
||||
chn.ResetEnvelopes();
|
||||
m_sndFile->InstrumentChange(&chn, instrument + 1);
|
||||
m_sndFile->InstrumentChange(chn, instrument + 1);
|
||||
chn.nFadeOutVol = 0x10000;
|
||||
m_sndFile->NoteChange(&chn, note, false, true, true);
|
||||
chn.nPan = Util::Round<int32_t>( Clamp( panning * 128.0, -128.0, 128.0 ) + 128.0 );
|
||||
chn.nVolume = Util::Round<int32_t>( Clamp( volume * 256.0, 0.0, 256.0 ) );
|
||||
m_sndFile->NoteChange(chn, note, false, true, true);
|
||||
chn.nPan = mpt::saturate_round<int32_t>( Clamp( panning * 128.0, -128.0, 128.0 ) + 128.0 );
|
||||
chn.nVolume = mpt::saturate_round<int32_t>( Clamp( volume * 256.0, 0.0, 256.0 ) );
|
||||
|
||||
// Remove channel from list of mixed channels to fix https://bugs.openmpt.org/view.php?id=209
|
||||
// This is required because a previous note on the same channel might have just stopped playing,
|
||||
|
|
|
@ -61,43 +61,43 @@ public:
|
|||
|
||||
// pattern_vis
|
||||
|
||||
virtual effect_type get_pattern_row_channel_volume_effect_type( std::int32_t pattern, std::int32_t row, std::int32_t channel ) const;
|
||||
effect_type get_pattern_row_channel_volume_effect_type( std::int32_t pattern, std::int32_t row, std::int32_t channel ) const override;
|
||||
|
||||
virtual effect_type get_pattern_row_channel_effect_type( std::int32_t pattern, std::int32_t row, std::int32_t channel ) const;
|
||||
effect_type get_pattern_row_channel_effect_type( std::int32_t pattern, std::int32_t row, std::int32_t channel ) const override;
|
||||
|
||||
// interactive
|
||||
|
||||
virtual void set_current_speed( std::int32_t speed );
|
||||
void set_current_speed( std::int32_t speed ) override;
|
||||
|
||||
virtual void set_current_tempo( std::int32_t tempo );
|
||||
void set_current_tempo( std::int32_t tempo ) override;
|
||||
|
||||
virtual void set_tempo_factor( double factor );
|
||||
void set_tempo_factor( double factor ) override;
|
||||
|
||||
virtual double get_tempo_factor( ) const;
|
||||
double get_tempo_factor( ) const override;
|
||||
|
||||
virtual void set_pitch_factor( double factor );
|
||||
void set_pitch_factor( double factor ) override;
|
||||
|
||||
virtual double get_pitch_factor( ) const;
|
||||
double get_pitch_factor( ) const override;
|
||||
|
||||
virtual void set_global_volume( double volume );
|
||||
void set_global_volume( double volume ) override;
|
||||
|
||||
virtual double get_global_volume( ) const;
|
||||
double get_global_volume( ) const override;
|
||||
|
||||
virtual void set_channel_volume( std::int32_t channel, double volume );
|
||||
void set_channel_volume( std::int32_t channel, double volume ) override;
|
||||
|
||||
virtual double get_channel_volume( std::int32_t channel ) const;
|
||||
double get_channel_volume( std::int32_t channel ) const override;
|
||||
|
||||
virtual void set_channel_mute_status( std::int32_t channel, bool mute );
|
||||
void set_channel_mute_status( std::int32_t channel, bool mute ) override;
|
||||
|
||||
virtual bool get_channel_mute_status( std::int32_t channel ) const;
|
||||
bool get_channel_mute_status( std::int32_t channel ) const override;
|
||||
|
||||
virtual void set_instrument_mute_status( std::int32_t instrument, bool mute );
|
||||
void set_instrument_mute_status( std::int32_t instrument, bool mute ) override;
|
||||
|
||||
virtual bool get_instrument_mute_status( std::int32_t instrument ) const;
|
||||
bool get_instrument_mute_status( std::int32_t instrument ) const override;
|
||||
|
||||
virtual std::int32_t play_note( std::int32_t instrument, std::int32_t note, double volume, double panning );
|
||||
std::int32_t play_note( std::int32_t instrument, std::int32_t note, double volume, double panning ) override;
|
||||
|
||||
virtual void stop_note( std::int32_t channel );
|
||||
void stop_note( std::int32_t channel ) override;
|
||||
|
||||
|
||||
/* add stuff here */
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue