Updated libOpenMPT to version 0.6.5-pre.1+r17609
This allows us to eliminate the requirement to continue bundling version 0.5.x of libOpenMPT for compatibility with macOS 10.13 through 10.14.x. Signed-off-by: Christopher Snowhill <kode54@gmail.com>
This commit is contained in:
parent
0832a8ea34
commit
919497148a
992 changed files with 8 additions and 370115 deletions
|
@ -107,7 +107,6 @@
|
|||
83256B68286661FC0036D9C0 /* libmpg123.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 83256B672866617F0036D9C0 /* libmpg123.0.dylib */; };
|
||||
83256B69286661FC0036D9C0 /* libmpg123.0.dylib in CopyFiles */ = {isa = PBXBuildFile; fileRef = 83256B672866617F0036D9C0 /* libmpg123.0.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||
832923AF279FAC400048201E /* Cog.q1.json in Resources */ = {isa = PBXBuildFile; fileRef = 832923AE279FAC400048201E /* Cog.q1.json */; };
|
||||
83293070277886250010C07E /* OpenMPTOld.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8329306D277885790010C07E /* OpenMPTOld.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
832C1253180BD1E2005507C1 /* Cog.help in Resources */ = {isa = PBXBuildFile; fileRef = 832C1252180BD1E2005507C1 /* Cog.help */; };
|
||||
832CFC4F2851AA1A002AC26F /* NSView+Visibility.m in Sources */ = {isa = PBXBuildFile; fileRef = 832CFC4E2851AA1A002AC26F /* NSView+Visibility.m */; };
|
||||
832CFC562851AA8B002AC26F /* SpectrumViewCG.m in Sources */ = {isa = PBXBuildFile; fileRef = 832CFC552851AA8B002AC26F /* SpectrumViewCG.m */; };
|
||||
|
@ -402,20 +401,6 @@
|
|||
remoteGlobalIDString = 8314D6311A354DFE00EEE8E6;
|
||||
remoteInfo = sidplay;
|
||||
};
|
||||
8329306C277885790010C07E /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 83293065277885790010C07E /* OpenMPTOld.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 83E5EFA31FFEF78100659F0F;
|
||||
remoteInfo = OpenMPTOld;
|
||||
};
|
||||
8329306E2778860C0010C07E /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 83293065277885790010C07E /* OpenMPTOld.xcodeproj */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 83E5EFA21FFEF78100659F0F;
|
||||
remoteInfo = OpenMPTOld;
|
||||
};
|
||||
834068BC20E4E40200A01561 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 17C808C00C3BD1DD005707C4 /* WavPack.xcodeproj */;
|
||||
|
@ -703,7 +688,6 @@
|
|||
files = (
|
||||
8372C93D27C7895300E250C9 /* MAD.bundle in CopyFiles */,
|
||||
83489C6B2782F78700BDCEA2 /* libvgmPlayer.bundle in CopyFiles */,
|
||||
83293070277886250010C07E /* OpenMPTOld.bundle in CopyFiles */,
|
||||
834D794020E4EFEF00C4A5CC /* VorbisPlugin.bundle in CopyFiles */,
|
||||
834D793F20E4EFEA00C4A5CC /* OpusPlugin.bundle in CopyFiles */,
|
||||
83A360B220E4E81D00192DAB /* Flac.bundle in CopyFiles */,
|
||||
|
@ -928,7 +912,6 @@
|
|||
83229C9E283B0095004626A8 /* SpectrumWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SpectrumWindow.xib; sourceTree = "<group>"; };
|
||||
83256B672866617F0036D9C0 /* libmpg123.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libmpg123.0.dylib; path = ThirdParty/mpg123/lib/libmpg123.0.dylib; sourceTree = "<group>"; };
|
||||
832923AE279FAC400048201E /* Cog.q1.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = Cog.q1.json; sourceTree = "<group>"; };
|
||||
83293065277885790010C07E /* OpenMPTOld.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = OpenMPTOld.xcodeproj; path = Plugins/OpenMPT.old/OpenMPTOld.xcodeproj; sourceTree = "<group>"; };
|
||||
832C1252180BD1E2005507C1 /* Cog.help */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Cog.help; sourceTree = "<group>"; };
|
||||
832CFC4E2851AA1A002AC26F /* NSView+Visibility.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSView+Visibility.m"; sourceTree = "<group>"; };
|
||||
832CFC532851AA37002AC26F /* NSView+Visibility.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSView+Visibility.h"; sourceTree = "<group>"; };
|
||||
|
@ -1338,7 +1321,6 @@
|
|||
83B0669C180D5668008E3612 /* MIDI.xcodeproj */,
|
||||
17C8089E0C3BD1AB005707C4 /* Musepack.xcodeproj */,
|
||||
83E5EFAC1FFEF78100659F0F /* OpenMPT.xcodeproj */,
|
||||
83293065277885790010C07E /* OpenMPTOld.xcodeproj */,
|
||||
8375B05117FFEA400092A79F /* OpusPlugin.xcodeproj */,
|
||||
8E8D41C20CBB0DA000135C1B /* Pls.xcodeproj */,
|
||||
17C808A70C3BD1BA005707C4 /* Shorten.xcodeproj */,
|
||||
|
@ -1710,14 +1692,6 @@
|
|||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
83293066277885790010C07E /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8329306D277885790010C07E /* OpenMPTOld.bundle */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
834068A720E4E40200A01561 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -2185,10 +2159,6 @@
|
|||
ProductGroup = 83CA5AF820E4E394003E463A /* Products */;
|
||||
ProjectRef = 83E5EFAC1FFEF78100659F0F /* OpenMPT.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = 83293066277885790010C07E /* Products */;
|
||||
ProjectRef = 83293065277885790010C07E /* OpenMPTOld.xcodeproj */;
|
||||
},
|
||||
{
|
||||
ProductGroup = 830B62AF20E4EF89004A74B2 /* Products */;
|
||||
ProjectRef = 8375B05117FFEA400092A79F /* OpusPlugin.xcodeproj */;
|
||||
|
@ -2350,13 +2320,6 @@
|
|||
remoteRef = 8314D6401A354DFF00EEE8E6 /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
8329306D277885790010C07E /* OpenMPTOld.bundle */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.cfbundle;
|
||||
path = OpenMPTOld.bundle;
|
||||
remoteRef = 8329306C277885790010C07E /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
834068BD20E4E40200A01561 /* WavPack.bundle */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.cfbundle;
|
||||
|
@ -2742,11 +2705,6 @@
|
|||
name = Preferences;
|
||||
targetProxy = 17F5623A0C3BD9280019975C /* PBXContainerItemProxy */;
|
||||
};
|
||||
8329306F2778860C0010C07E /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
name = OpenMPTOld;
|
||||
targetProxy = 8329306E2778860C0010C07E /* PBXContainerItemProxy */;
|
||||
};
|
||||
83489C6A2782F76900BDCEA2 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
name = "libvgmPlayer Plugin";
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2021-2022 Christopher Snowhill. All rights reserved.</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
|
@ -1,26 +0,0 @@
|
|||
Copyright (c) 2004-2022, OpenMPT contributors
|
||||
Copyright (c) 1997-2003, Olivier Lapicque
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the OpenMPT project nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
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.
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -1,260 +0,0 @@
|
|||
|
||||
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
|
||||
--------------
|
||||
|
||||
|
||||
### OpenMPT
|
||||
|
||||
- Supported Visual Studio versions:
|
||||
|
||||
- Visual Studio 2017 and 2019 Community/Professional/Enterprise
|
||||
|
||||
To compile the project, open `build/vsVERSIONwin7/OpenMPT.sln` (VERSION
|
||||
being 2017 or 2019) and hit the compile button. Other target systems can
|
||||
be found in the `vs2017*` and `vs2019*` sibling folders.
|
||||
|
||||
- OpenMPT requires the compile host system to be 64bit x86-64.
|
||||
|
||||
- The Windows 8.1 SDK is required to build OpenMPT with Visual Studio 2017
|
||||
(this is included with Visual Studio, however may need to be selected
|
||||
explicitly during setup).
|
||||
|
||||
- Microsoft Foundation Classes (MFC) are required to build OpenMPT.
|
||||
|
||||
|
||||
### libopenmpt and openmpt123
|
||||
|
||||
For detailed requirements, see `libopenmpt/dox/quickstart.md`.
|
||||
|
||||
- Autotools
|
||||
|
||||
Grab a `libopenmpt-VERSION-autotools.tar.gz` tarball.
|
||||
|
||||
./configure
|
||||
make
|
||||
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 2017 and 2019 in the
|
||||
corresponding `build/vsVERSIONwin7/` folder.
|
||||
Projects that target Windows 10 Desktop (including ARM and ARM64) are
|
||||
available in `build/vsVERSIONwin10/` (Visual Studio 2017 requires SDK
|
||||
version 10.0.16299).
|
||||
Minimal projects that target Windows 10 UWP are available in
|
||||
`build/vsVERSIONuwp/`.
|
||||
Most projects are supported with any of the mentioned Visual Studio
|
||||
verions, with the following exceptions:
|
||||
|
||||
- in_openmpt: Requires Visual Studio with MFC.
|
||||
|
||||
- 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 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:
|
||||
|
||||
- Winamp 5 SDK:
|
||||
|
||||
To build libopenmpt as a winamp input plugin, copy the contents of
|
||||
`WA5.55_SDK.exe` to include/winamp/.
|
||||
|
||||
Please visit
|
||||
[winamp.com](http://wiki.winamp.com/wiki/Plug-in_Developer) to
|
||||
download the SDK.
|
||||
You can disable in_openmpt in the solution configuration.
|
||||
|
||||
- XMPlay SDK:
|
||||
|
||||
To build libopenmpt with XMPlay input plugin support, copy the
|
||||
contents of xmp-sdk.zip into include/xmplay/.
|
||||
|
||||
Please visit [un4seen.com](https://www.un4seen.com/xmplay.html) to
|
||||
download the SDK.
|
||||
You can disable xmp-openmpt in the solution configuration.
|
||||
|
||||
- Makefile
|
||||
|
||||
The makefile supports different build environments and targets via the
|
||||
`CONFIG=` parameter directly to the make invocation.
|
||||
Use `make CONFIG=$newconfig clean` when switching between different configs
|
||||
because the makefile cleans only intermediates and target that are active
|
||||
for the current config and no configuration state is kept around across
|
||||
invocations.
|
||||
|
||||
- mingw-w64:
|
||||
|
||||
The required compiler version is at least GCC 7.
|
||||
|
||||
make CONFIG=mingw64-win32 # for win32
|
||||
|
||||
make CONFIG=mingw64-win64 # for win64
|
||||
|
||||
- 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 7
|
||||
|
||||
- clang 5
|
||||
|
||||
The Makefile requires pkg-config for native builds.
|
||||
For sound output in openmpt123, PortAudio or SDL is required.
|
||||
openmpt123 can optionally use libflac and libsndfile to render PCM
|
||||
files to disk.
|
||||
|
||||
When using gcc, run:
|
||||
|
||||
make CONFIG=gcc
|
||||
|
||||
When using clang, it is recommended to do:
|
||||
|
||||
make CONFIG=clang
|
||||
|
||||
Otherwise, simply run
|
||||
|
||||
make
|
||||
|
||||
which will try to guess the compiler based on your operating system.
|
||||
|
||||
- emscripten (on Unix-like systems):
|
||||
|
||||
Run:
|
||||
|
||||
# generates WebAssembly with JavaScript fallback
|
||||
make CONFIG=emscripten EMSCRIPTEN_TARGET=all
|
||||
|
||||
or
|
||||
|
||||
# generates WebAssembly
|
||||
make CONFIG=emscripten EMSCRIPTEN_TARGET=wasm
|
||||
|
||||
or
|
||||
|
||||
# generates JavaScript 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. Depending on how your distribution calls the `node.js` binary,
|
||||
you might have to edit `build/make/config-emscripten.mk`.
|
||||
|
||||
- DJGPP / DOS
|
||||
|
||||
Cross-compilation from Linux systems is supported with DJGPP GCC 7.2 or
|
||||
later via
|
||||
|
||||
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:
|
||||
|
||||
To compile libopenmpt with fuzzing instrumentation for afl-fuzz, run:
|
||||
|
||||
make CONFIG=afl
|
||||
|
||||
For more detailed instructions, read `contrib/fuzzing/readme.md`.
|
||||
|
||||
- other compilers:
|
||||
|
||||
To compile libopenmpt with other C++17 compliant compilers, run:
|
||||
|
||||
make CONFIG=generic
|
||||
|
||||
|
||||
The `Makefile` supports some customizations. You might want to read the top
|
||||
which should get you some possible make settings, like e.g.
|
||||
`make DYNLINK=0` or similar. Cross compiling or different compiler would
|
||||
best be implemented via new `config-*.mk` files.
|
||||
|
||||
The `Makefile` also supports building doxygen documentation by using
|
||||
|
||||
make doc
|
||||
|
||||
Binaries and documentation can be installed systen-wide with
|
||||
|
||||
make PREFIX=/yourprefix install
|
||||
make PREFIX=/yourprefix install-doc
|
||||
|
||||
Some systems (i.e. Linux) require running
|
||||
|
||||
sudo ldconfig
|
||||
|
||||
in order for the system linker to be able to pick up newly installed
|
||||
libraries.
|
||||
|
||||
`PREFIX` defaults to `/usr/local`. A `DESTDIR=` parameter is also
|
||||
supported.
|
||||
|
||||
- Android NDK
|
||||
|
||||
See `build/android_ndk/README.AndroidNDK.txt`.
|
||||
|
||||
|
||||
|
||||
Contributing to OpenMPT/libopenmpt
|
||||
----------------------------------
|
||||
|
||||
|
||||
See [contributing](doc/contributing.md).
|
||||
|
|
@ -1,226 +0,0 @@
|
|||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := openmpt
|
||||
|
||||
LOCAL_CFLAGS +=#-std=c99
|
||||
LOCAL_CPPFLAGS += -std=c++17 -fexceptions -frtti
|
||||
|
||||
LOCAL_CPP_FEATURES += exceptions rtti
|
||||
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH) $(LOCAL_PATH)/common $(LOCAL_PATH)/build/svn_version
|
||||
|
||||
LOCAL_CFLAGS += -fvisibility=hidden -Wall -DLIBOPENMPT_BUILD -DMPT_WITH_ZLIB
|
||||
LOCAL_CPPFLAGS +=#-fvisibility=hidden -Wall -DLIBOPENMPT_BUILD -DMPT_WITH_ZLIB
|
||||
LOCAL_LDLIBS += -lz
|
||||
|
||||
MPT_SVNURL?=
|
||||
MPT_SVNVERSION?=
|
||||
MPT_SVNDATE?=
|
||||
ifneq ($(MPT_SVNURL),)
|
||||
LOCAL_CFLAGS += -D MPT_SVNURL=\"$(MPT_SVNURL)\"
|
||||
LOCAL_CPPFLAGS +=#-D MPT_SVNURL=\"$(MPT_SVNURL)\"
|
||||
endif
|
||||
ifneq ($(MPT_SVNVERSION),)
|
||||
LOCAL_CFLAGS += -D MPT_SVNVERSION=\"$(MPT_SVNVERSION)\"
|
||||
LOCAL_CPPFLAGS +=#-D MPT_SVNVERSION=\"$(MPT_SVNVERSION)\"
|
||||
endif
|
||||
ifneq ($(MPT_SVNDATE),)
|
||||
LOCAL_CFLAGS += -D MPT_SVNDATE=\"$(MPT_SVNDATE)\"
|
||||
LOCAL_CPPFLAGS +=#-D MPT_SVNDATE=\"$(MPT_SVNDATE)\"
|
||||
endif
|
||||
|
||||
|
||||
LOCAL_SRC_FILES :=
|
||||
|
||||
ifeq ($(MPT_WITH_MINIMP3),1)
|
||||
LOCAL_CFLAGS += -DMPT_WITH_MINIMP3
|
||||
LOCAL_CPPFLAGS +=#-DMPT_WITH_MINIMP3
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
|
||||
LOCAL_SRC_FILES += include/minimp3/minimp3.c
|
||||
LOCAL_LDLIBS +=
|
||||
endif
|
||||
|
||||
ifeq ($(MPT_WITH_MPG123),1)
|
||||
LOCAL_CFLAGS += -DMPT_WITH_MPG123
|
||||
LOCAL_CPPFLAGS +=#-DMPT_WITH_MPG123
|
||||
LOCAL_C_INCLUDES +=
|
||||
LOCAL_SRC_FILES +=
|
||||
LOCAL_LDLIBS += -lmpg123
|
||||
endif
|
||||
|
||||
ifeq ($(MPT_WITH_OGG),1)
|
||||
LOCAL_CFLAGS += -DMPT_WITH_OGG
|
||||
LOCAL_CPPFLAGS +=#-DMPT_WITH_OGG
|
||||
LOCAL_C_INCLUDES +=
|
||||
LOCAL_SRC_FILES +=
|
||||
LOCAL_LDLIBS += -logg
|
||||
endif
|
||||
|
||||
ifeq ($(MPT_WITH_STBVORBIS),1)
|
||||
LOCAL_CFLAGS += -DMPT_WITH_STBVORBIS
|
||||
LOCAL_CPPFLAGS +=#-DMPT_WITH_STBVORBIS
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
|
||||
LOCAL_SRC_FILES += include/stb_vorbis/stb_vorbis.c
|
||||
LOCAL_LDLIBS +=
|
||||
endif
|
||||
|
||||
ifeq ($(MPT_WITH_VORBIS),1)
|
||||
LOCAL_CFLAGS += -DMPT_WITH_VORBIS
|
||||
LOCAL_CPPFLAGS +=#-DMPT_WITH_VORBIS
|
||||
LOCAL_C_INCLUDES +=
|
||||
LOCAL_SRC_FILES +=
|
||||
LOCAL_LDLIBS += -lvorbis
|
||||
endif
|
||||
|
||||
ifeq ($(MPT_WITH_VORBISFILE),1)
|
||||
LOCAL_CFLAGS += -DMPT_WITH_VORBISFILE
|
||||
LOCAL_CPPFLAGS +=#-DMPT_WITH_VORBISFILE
|
||||
LOCAL_C_INCLUDES +=
|
||||
LOCAL_SRC_FILES +=
|
||||
LOCAL_LDLIBS += -lvorbisfile
|
||||
endif
|
||||
|
||||
LOCAL_SRC_FILES += \
|
||||
common/ComponentManager.cpp \
|
||||
common/FileReader.cpp \
|
||||
common/Logging.cpp \
|
||||
common/misc_util.cpp \
|
||||
common/mptAlloc.cpp \
|
||||
common/mptCPU.cpp \
|
||||
common/mptFileIO.cpp \
|
||||
common/mptIO.cpp \
|
||||
common/mptLibrary.cpp \
|
||||
common/mptOS.cpp \
|
||||
common/mptPathString.cpp \
|
||||
common/mptRandom.cpp \
|
||||
common/mptString.cpp \
|
||||
common/mptStringBuffer.cpp \
|
||||
common/mptStringFormat.cpp \
|
||||
common/mptStringParse.cpp \
|
||||
common/mptTime.cpp \
|
||||
common/mptUUID.cpp \
|
||||
common/mptWine.cpp \
|
||||
common/Profiler.cpp \
|
||||
common/serialization_utils.cpp \
|
||||
common/version.cpp \
|
||||
libopenmpt/libopenmpt_c.cpp \
|
||||
libopenmpt/libopenmpt_cxx.cpp \
|
||||
libopenmpt/libopenmpt_impl.cpp \
|
||||
libopenmpt/libopenmpt_ext_impl.cpp \
|
||||
soundbase/Dither.cpp \
|
||||
soundlib/AudioCriticalSection.cpp \
|
||||
soundlib/ContainerMMCMP.cpp \
|
||||
soundlib/ContainerPP20.cpp \
|
||||
soundlib/ContainerUMX.cpp \
|
||||
soundlib/ContainerXPK.cpp \
|
||||
soundlib/Dlsbank.cpp \
|
||||
soundlib/Fastmix.cpp \
|
||||
soundlib/InstrumentExtensions.cpp \
|
||||
soundlib/ITCompression.cpp \
|
||||
soundlib/ITTools.cpp \
|
||||
soundlib/Load_669.cpp \
|
||||
soundlib/Load_amf.cpp \
|
||||
soundlib/Load_ams.cpp \
|
||||
soundlib/Load_c67.cpp \
|
||||
soundlib/Load_dbm.cpp \
|
||||
soundlib/Load_digi.cpp \
|
||||
soundlib/Load_dmf.cpp \
|
||||
soundlib/Load_dsm.cpp \
|
||||
soundlib/Load_dtm.cpp \
|
||||
soundlib/Load_far.cpp \
|
||||
soundlib/Load_gdm.cpp \
|
||||
soundlib/Load_imf.cpp \
|
||||
soundlib/Load_it.cpp \
|
||||
soundlib/Load_itp.cpp \
|
||||
soundlib/load_j2b.cpp \
|
||||
soundlib/Load_mdl.cpp \
|
||||
soundlib/Load_med.cpp \
|
||||
soundlib/Load_mid.cpp \
|
||||
soundlib/Load_mo3.cpp \
|
||||
soundlib/Load_mod.cpp \
|
||||
soundlib/Load_mt2.cpp \
|
||||
soundlib/Load_mtm.cpp \
|
||||
soundlib/Load_okt.cpp \
|
||||
soundlib/Load_plm.cpp \
|
||||
soundlib/Load_psm.cpp \
|
||||
soundlib/Load_ptm.cpp \
|
||||
soundlib/Load_s3m.cpp \
|
||||
soundlib/Load_sfx.cpp \
|
||||
soundlib/Load_stm.cpp \
|
||||
soundlib/Load_stp.cpp \
|
||||
soundlib/Load_ult.cpp \
|
||||
soundlib/Load_uax.cpp \
|
||||
soundlib/Load_wav.cpp \
|
||||
soundlib/Load_xm.cpp \
|
||||
soundlib/Message.cpp \
|
||||
soundlib/MIDIEvents.cpp \
|
||||
soundlib/MIDIMacros.cpp \
|
||||
soundlib/MixerLoops.cpp \
|
||||
soundlib/MixerSettings.cpp \
|
||||
soundlib/MixFuncTable.cpp \
|
||||
soundlib/ModChannel.cpp \
|
||||
soundlib/modcommand.cpp \
|
||||
soundlib/ModInstrument.cpp \
|
||||
soundlib/ModSample.cpp \
|
||||
soundlib/ModSequence.cpp \
|
||||
soundlib/modsmp_ctrl.cpp \
|
||||
soundlib/mod_specifications.cpp \
|
||||
soundlib/MPEGFrame.cpp \
|
||||
soundlib/OggStream.cpp \
|
||||
soundlib/OPL.cpp \
|
||||
soundlib/Paula.cpp \
|
||||
soundlib/patternContainer.cpp \
|
||||
soundlib/pattern.cpp \
|
||||
soundlib/RowVisitor.cpp \
|
||||
soundlib/S3MTools.cpp \
|
||||
soundlib/SampleFormats.cpp \
|
||||
soundlib/SampleFormatBRR.cpp \
|
||||
soundlib/SampleFormatFLAC.cpp \
|
||||
soundlib/SampleFormatMediaFoundation.cpp \
|
||||
soundlib/SampleFormatMP3.cpp \
|
||||
soundlib/SampleFormatOpus.cpp \
|
||||
soundlib/SampleFormatSFZ.cpp \
|
||||
soundlib/SampleFormatVorbis.cpp \
|
||||
soundlib/SampleIO.cpp \
|
||||
soundlib/Sndfile.cpp \
|
||||
soundlib/Snd_flt.cpp \
|
||||
soundlib/Snd_fx.cpp \
|
||||
soundlib/Sndmix.cpp \
|
||||
soundlib/SoundFilePlayConfig.cpp \
|
||||
soundlib/UMXTools.cpp \
|
||||
soundlib/UpgradeModule.cpp \
|
||||
soundlib/Tables.cpp \
|
||||
soundlib/Tagging.cpp \
|
||||
soundlib/TinyFFT.cpp \
|
||||
soundlib/tuningCollection.cpp \
|
||||
soundlib/tuning.cpp \
|
||||
soundlib/WAVTools.cpp \
|
||||
soundlib/WindowedFIR.cpp \
|
||||
soundlib/XMTools.cpp \
|
||||
soundlib/plugins/DigiBoosterEcho.cpp \
|
||||
soundlib/plugins/dmo/DMOPlugin.cpp \
|
||||
soundlib/plugins/dmo/Chorus.cpp \
|
||||
soundlib/plugins/dmo/Compressor.cpp \
|
||||
soundlib/plugins/dmo/Distortion.cpp \
|
||||
soundlib/plugins/dmo/Echo.cpp \
|
||||
soundlib/plugins/dmo/Flanger.cpp \
|
||||
soundlib/plugins/dmo/Gargle.cpp \
|
||||
soundlib/plugins/dmo/I3DL2Reverb.cpp \
|
||||
soundlib/plugins/dmo/ParamEq.cpp \
|
||||
soundlib/plugins/dmo/WavesReverb.cpp \
|
||||
soundlib/plugins/LFOPlugin.cpp \
|
||||
soundlib/plugins/PluginManager.cpp \
|
||||
soundlib/plugins/PlugInterface.cpp \
|
||||
sounddsp/AGC.cpp \
|
||||
sounddsp/DSP.cpp \
|
||||
sounddsp/EQ.cpp \
|
||||
sounddsp/Reverb.cpp \
|
||||
test/TestToolsLib.cpp \
|
||||
test/test.cpp
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
|
||||
APP_CFLAGS :=#-std=c99
|
||||
APP_CPPFLAGS := -std=c++17 -fexceptions -frtti
|
||||
APP_LDFLAGS :=
|
||||
APP_STL := c++_shared
|
|
@ -1,21 +0,0 @@
|
|||
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
This is preliminary documentation.
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
0. The minimum required Android NDK version is r18b.
|
||||
1. Copy the whole libopenmpt source tree below your jni directory.
|
||||
2. Copy build/android_ndk/* into the root of libopenmpt, i.e. also into the
|
||||
jni directory and adjust as needed.
|
||||
3. If you want to support MO3 decoding, you have to either make libmpg123,
|
||||
libogg, libvorbis and libvorbisfile available (recommended) OR build
|
||||
libopenmpt with minimp3 and stb_vorbis support (not recommended).
|
||||
Pass the appropriate options to ndk-build:
|
||||
MPT_WITH_MINIMP3=1 : Build minimp3 into libopenmpt
|
||||
MPT_WITH_MPG123=1 : Link against libmpg123 compiled externally
|
||||
MPT_WITH_OGG=1 : Link against libogg compiled externally
|
||||
MPT_WITH_STBVORBIS=1 : Build stb_vorbis into libopenmpt
|
||||
MPT_WITH_VORBIS=1 : Link against libvorbis compiled externally
|
||||
MPT_WITH_VORBISFILE=1 : Link against libvorbisfile compiled externally
|
||||
4. Use ndk-build as usual.
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
|
||||
MPT_SVNVERSION=17278
|
||||
MPT_SVNURL=https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.18
|
||||
MPT_SVNDATE=2022-04-24T13:19:56.339906Z
|
|
@ -1,46 +0,0 @@
|
|||
|
||||
CC = contrib/fuzzing/afl/afl-clang-lto
|
||||
CXX = contrib/fuzzing/afl/afl-clang-lto++
|
||||
LD = contrib/fuzzing/afl/afl-clang-lto++
|
||||
AR = ar
|
||||
|
||||
ifneq ($(STDCXX),)
|
||||
CXXFLAGS_STDCXX = -std=$(STDCXX)
|
||||
else
|
||||
ifeq ($(shell printf '\n' > bin/empty.cpp ; if $(CXX) -std=c++17 -c bin/empty.cpp -o bin/empty.out > /dev/null 2>&1 ; then echo 'c++17' ; fi ), c++17)
|
||||
CXXFLAGS_STDCXX = -std=c++17
|
||||
endif
|
||||
endif
|
||||
CFLAGS_STDC = -std=c99
|
||||
CXXFLAGS += $(CXXFLAGS_STDCXX)
|
||||
CFLAGS += $(CFLAGS_STDC)
|
||||
|
||||
DYNLINK=0
|
||||
SHARED_LIB=0
|
||||
STATIC_LIB=1
|
||||
|
||||
CPPFLAGS +=
|
||||
CXXFLAGS += -fPIC -fno-strict-aliasing
|
||||
CFLAGS += -fPIC -fno-strict-aliasing
|
||||
LDFLAGS +=
|
||||
LDLIBS += -lm
|
||||
ARFLAGS := rcs
|
||||
|
||||
CXXFLAGS_WARNINGS += -Wmissing-declarations
|
||||
CFLAGS_WARNINGS += -Wmissing-prototypes
|
||||
|
||||
ifeq ($(CHECKED_ADDRESS),1)
|
||||
CXXFLAGS += -fsanitize=address
|
||||
CFLAGS += -fsanitize=address
|
||||
endif
|
||||
|
||||
ifeq ($(CHECKED_UNDEFINED),1)
|
||||
CXXFLAGS += -fsanitize=undefined
|
||||
CFLAGS += -fsanitize=undefined
|
||||
endif
|
||||
|
||||
EXESUFFIX=
|
||||
|
||||
FUZZ=1
|
||||
CPPFLAGS += -DMPT_BUILD_FUZZER -DMPT_BUILD_FATAL_ASSERTS
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
|
||||
CC = clang$(TOOLCHAIN_SUFFIX)
|
||||
CXX = clang++$(TOOLCHAIN_SUFFIX)
|
||||
LD = clang++$(TOOLCHAIN_SUFFIX)
|
||||
AR = ar$(TOOLCHAIN_SUFFIX)
|
||||
|
||||
ifneq ($(STDCXX),)
|
||||
CXXFLAGS_STDCXX = -std=$(STDCXX)
|
||||
else
|
||||
ifeq ($(shell printf '\n' > bin/empty.cpp ; if $(CXX) -std=c++17 -c bin/empty.cpp -o bin/empty.out > /dev/null 2>&1 ; then echo 'c++17' ; fi ), c++17)
|
||||
CXXFLAGS_STDCXX = -std=c++17
|
||||
else
|
||||
ifeq ($(shell printf '\n' > bin/empty.cpp ; if $(CXX) -std=c++14 -c bin/empty.cpp -o bin/empty.out > /dev/null 2>&1 ; then echo 'c++14' ; fi ), c++14)
|
||||
CXXFLAGS_STDCXX = -std=c++14
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
CFLAGS_STDC = -std=c99
|
||||
CXXFLAGS += $(CXXFLAGS_STDCXX)
|
||||
CFLAGS += $(CFLAGS_STDC)
|
||||
|
||||
CPPFLAGS +=
|
||||
CXXFLAGS += -fPIC
|
||||
CFLAGS += -fPIC
|
||||
LDFLAGS +=
|
||||
LDLIBS += -lm
|
||||
ARFLAGS := rcs
|
||||
|
||||
ifeq ($(CHECKED_ADDRESS),1)
|
||||
CXXFLAGS += -fsanitize=address
|
||||
CFLAGS += -fsanitize=address
|
||||
endif
|
||||
|
||||
ifeq ($(CHECKED_UNDEFINED),1)
|
||||
CXXFLAGS += -fsanitize=undefined
|
||||
CFLAGS += -fsanitize=undefined
|
||||
endif
|
||||
|
||||
CXXFLAGS_WARNINGS += -Wmissing-declarations -Wshift-count-negative -Wshift-count-overflow -Wshift-overflow -Wshift-sign-overflow -Wshift-op-parentheses
|
||||
CFLAGS_WARNINGS += -Wmissing-prototypes -Wshift-count-negative -Wshift-count-overflow -Wshift-overflow -Wshift-sign-overflow -Wshift-op-parentheses
|
||||
|
||||
CXXFLAGS_WARNINGS += -Wdeprecated -Wextra-semi -Wnon-virtual-dtor -Wreserved-id-macro -Wglobal-constructors -Wimplicit-fallthrough
|
||||
|
||||
#CXXFLAGS_WARNINGS += -Wdocumentation
|
||||
#CXXFLAGS_WARNINGS += -Wconversion
|
||||
#CXXFLAGS_WARNINGS += -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded -Wno-shadow -Wno-sign-conversion -Wno-weak-vtables
|
||||
|
||||
ifeq ($(MODERN),1)
|
||||
LDFLAGS += -fuse-ld=lld
|
||||
CXXFLAGS_WARNINGS += -Wpedantic -Wframe-larger-than=16000
|
||||
CFLAGS_WARNINGS += -Wpedantic -Wframe-larger-than=4000
|
||||
LDFLAGS_WARNINGS += -Wl,-no-undefined -Wl,--detect-odr-violations
|
||||
# re-renable after 1.29 branch
|
||||
#CXXFLAGS_WARNINGS += -Wdouble-promotion
|
||||
#CFLAGS_WARNINGS += -Wdouble-promotion
|
||||
endif
|
||||
|
||||
CFLAGS_SILENT += -Wno-cast-align
|
||||
CFLAGS_SILENT += -Wno-cast-qual
|
||||
CFLAGS_SILENT += -Wno-missing-prototypes
|
||||
CFLAGS_SILENT += -Wno-sign-compare
|
||||
CFLAGS_SILENT += -Wno-unused-function
|
||||
CFLAGS_SILENT += -Wno-unused-parameter
|
||||
|
||||
EXESUFFIX=
|
|
@ -1,42 +0,0 @@
|
|||
|
||||
ifeq ($(HOST),unix)
|
||||
|
||||
ifeq ($(HOST_FLAVOUR),MACOSX)
|
||||
|
||||
include build/make/config-clang.mk
|
||||
# Mac OS X overrides
|
||||
DYNLINK=0
|
||||
SHARED_SONAME=0
|
||||
|
||||
else ifeq ($(HOST_FLAVOUR),LINUX)
|
||||
|
||||
include build/make/config-gcc.mk
|
||||
|
||||
else ifeq ($(HOST_FLAVOUR),FREEBSD)
|
||||
|
||||
include build/make/config-clang.mk
|
||||
NO_LTDL?=1
|
||||
NO_PORTAUDIOCPP?=1
|
||||
|
||||
else ifeq ($(HOST_FLAVOUR),HAIKU)
|
||||
|
||||
# In Haiku x86 32bit (but not 64bit),
|
||||
# modern compilers need a -x86 suffix.
|
||||
UNAME_P:=$(shell uname -p)
|
||||
ifeq ($(UNAME_P),x86)
|
||||
TOOLCHAIN_SUFFIX=-x86
|
||||
endif
|
||||
include build/make/config-gcc.mk
|
||||
|
||||
else
|
||||
|
||||
include build/make/config-generic.mk
|
||||
|
||||
endif
|
||||
|
||||
else
|
||||
|
||||
include build/make/config-generic.mk
|
||||
|
||||
endif
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
|
||||
CC = i386-pc-msdosdjgpp-gcc
|
||||
CXX = i386-pc-msdosdjgpp-g++
|
||||
LD = i386-pc-msdosdjgpp-g++
|
||||
AR = i386-pc-msdosdjgpp-ar
|
||||
|
||||
# Note that we are using GNU extensions instead of 100% standards-compliant
|
||||
# mode, because otherwise DJGPP-specific headers/functions are unavailable.
|
||||
CXXFLAGS_STDCXX = -std=gnu++17
|
||||
CFLAGS_STDC = -std=gnu99
|
||||
CXXFLAGS += $(CXXFLAGS_STDCXX)
|
||||
CFLAGS += $(CFLAGS_STDC)
|
||||
|
||||
CPPFLAGS +=
|
||||
CXXFLAGS += -march=i386 -m80387 -mtune=pentium
|
||||
CFLAGS += -march=i386 -m80387 -mtune=pentium
|
||||
LDFLAGS +=
|
||||
LDLIBS += -lm
|
||||
ARFLAGS := rcs
|
||||
|
||||
ifeq ($(BUNDLED_ALLEGRO42),1)
|
||||
CPPFLAGS_ALLEGRO42 := -Iinclude/allegro42/include -DALLEGRO_HAVE_STDINT_H -DLONG_LONG="long long"
|
||||
LDFLAGS_ALLEGRO42 :=
|
||||
LDLIBS_ALLEGRO42 := include/allegro42/lib/liballeg.a
|
||||
endif
|
||||
|
||||
CFLAGS_SILENT += -Wno-unused-parameter -Wno-unused-function -Wno-cast-qual -Wno-old-style-declaration -Wno-type-limits -Wno-unused-but-set-variable
|
||||
|
||||
EXESUFFIX=.exe
|
||||
|
||||
DYNLINK=0
|
||||
SHARED_LIB=0
|
||||
STATIC_LIB=1
|
||||
SHARED_SONAME=0
|
||||
|
||||
DEBUG=0
|
||||
OPTIMIZE=0
|
||||
OPTIMIZE_SIZE=1
|
||||
|
||||
IS_CROSS=1
|
||||
|
||||
# generates warnings
|
||||
MPT_COMPILER_NOVISIBILITY=1
|
||||
|
||||
# causes crashes on process shutdown
|
||||
MPT_COMPILER_NOGCSECTIONS=1
|
||||
|
||||
NO_ZLIB=1
|
||||
NO_LTDL=1
|
||||
NO_DL=1
|
||||
NO_MPG123=1
|
||||
NO_OGG=1
|
||||
NO_VORBIS=1
|
||||
NO_VORBISFILE=1
|
||||
NO_PORTAUDIO=1
|
||||
NO_PORTAUDIOCPP=1
|
||||
NO_PULSEAUDIO=1
|
||||
NO_SDL=1
|
||||
NO_SDL2=1
|
||||
NO_SNDFILE=1
|
||||
NO_FLAC=1
|
||||
|
|
@ -1,133 +0,0 @@
|
|||
|
||||
CC = emcc -c
|
||||
CXX = em++ -c
|
||||
LD = em++
|
||||
AR = emar
|
||||
LINK.cc = em++ $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
|
||||
|
||||
EMSCRIPTEN_TARGET?=default
|
||||
|
||||
ifneq ($(STDCXX),)
|
||||
CXXFLAGS_STDCXX = -std=$(STDCXX)
|
||||
else
|
||||
ifeq ($(shell printf '\n' > bin/empty.cpp ; if $(CXX) -std=c++17 -c bin/empty.cpp -o bin/empty.out > /dev/null 2>&1 ; then echo 'c++17' ; fi ), c++17)
|
||||
CXXFLAGS_STDCXX = -std=c++17
|
||||
endif
|
||||
endif
|
||||
CFLAGS_STDC = -std=c99
|
||||
CXXFLAGS += $(CXXFLAGS_STDCXX)
|
||||
CFLAGS += $(CFLAGS_STDC)
|
||||
|
||||
CPPFLAGS +=
|
||||
CXXFLAGS += -fPIC
|
||||
CFLAGS += -fPIC
|
||||
LDFLAGS +=
|
||||
LDLIBS +=
|
||||
ARFLAGS := rcs
|
||||
|
||||
CXXFLAGS += -Os
|
||||
CFLAGS += -Os
|
||||
LDFLAGS += -Os
|
||||
|
||||
ifeq ($(EMSCRIPTEN_TARGET),default)
|
||||
# emits whatever is emscripten's default, currently (1.38.8) this is the same as "wasm" below.
|
||||
CPPFLAGS += -DMPT_BUILD_WASM
|
||||
CXXFLAGS +=
|
||||
CFLAGS +=
|
||||
LDFLAGS +=
|
||||
|
||||
LDFLAGS += -s ALLOW_MEMORY_GROWTH=1
|
||||
|
||||
else ifeq ($(EMSCRIPTEN_TARGET),all)
|
||||
# emits native wasm AND javascript with full wasm optimizations.
|
||||
CPPFLAGS += -DMPT_BUILD_WASM
|
||||
CXXFLAGS +=
|
||||
CFLAGS +=
|
||||
LDFLAGS += -s WASM=2 -s LEGACY_VM_SUPPORT=1 -Wno-transpile
|
||||
|
||||
LDFLAGS += -s ALLOW_MEMORY_GROWTH=1
|
||||
|
||||
else ifeq ($(EMSCRIPTEN_TARGET),audioworkletprocessor)
|
||||
# emits an es6 module in a single file suitable for use in an AudioWorkletProcessor
|
||||
CPPFLAGS += -DMPT_BUILD_WASM -DMPT_BUILD_AUDIOWORKLETPROCESSOR
|
||||
CXXFLAGS +=
|
||||
CFLAGS +=
|
||||
LDFLAGS += -s WASM=1 -s WASM_ASYNC_COMPILATION=0 -s MODULARIZE=1 -s EXPORT_ES6=1 -s SINGLE_FILE=1
|
||||
|
||||
LDFLAGS += -s ALLOW_MEMORY_GROWTH=1
|
||||
|
||||
else ifeq ($(EMSCRIPTEN_TARGET),wasm)
|
||||
# emits native wasm.
|
||||
CPPFLAGS += -DMPT_BUILD_WASM
|
||||
CXXFLAGS +=
|
||||
CFLAGS +=
|
||||
LDFLAGS += -s WASM=1
|
||||
|
||||
LDFLAGS += -s ALLOW_MEMORY_GROWTH=1
|
||||
|
||||
else ifeq ($(EMSCRIPTEN_TARGET),js)
|
||||
# emits only plain javascript with plain javascript focused optimizations.
|
||||
CPPFLAGS += -DMPT_BUILD_ASMJS
|
||||
CXXFLAGS +=
|
||||
CFLAGS +=
|
||||
LDFLAGS += -s WASM=0 -s LEGACY_VM_SUPPORT=1 -Wno-transpile
|
||||
|
||||
LDFLAGS += -s ALLOW_MEMORY_GROWTH=1
|
||||
|
||||
endif
|
||||
|
||||
CXXFLAGS += -s DISABLE_EXCEPTION_CATCHING=0 -ffast-math
|
||||
CFLAGS += -s DISABLE_EXCEPTION_CATCHING=0 -ffast-math -fno-strict-aliasing
|
||||
LDFLAGS += -s DISABLE_EXCEPTION_CATCHING=0 -s ERROR_ON_UNDEFINED_SYMBOLS=1 -s ERROR_ON_MISSING_LIBRARIES=1 -s EXPORT_NAME="'libopenmpt'"
|
||||
|
||||
CFLAGS_SILENT += -Wno-\#warnings
|
||||
CFLAGS_SILENT += -Wno-cast-align
|
||||
CFLAGS_SILENT += -Wno-cast-qual
|
||||
CFLAGS_SILENT += -Wno-format
|
||||
CFLAGS_SILENT += -Wno-missing-prototypes
|
||||
CFLAGS_SILENT += -Wno-sign-compare
|
||||
CFLAGS_SILENT += -Wno-unused-function
|
||||
CFLAGS_SILENT += -Wno-unused-parameter
|
||||
CFLAGS_SILENT += -Wno-unused-variable
|
||||
|
||||
CXXFLAGS_WARNINGS += -Wmissing-declarations
|
||||
CFLAGS_WARNINGS += -Wmissing-prototypes
|
||||
|
||||
REQUIRES_RUNPREFIX=1
|
||||
|
||||
EXESUFFIX=.js
|
||||
SOSUFFIX=.js
|
||||
RUNPREFIX=node
|
||||
TEST_LDFLAGS= --pre-js build/make/test-pre.js -lnodefs.js
|
||||
|
||||
DYNLINK=0
|
||||
SHARED_LIB=1
|
||||
STATIC_LIB=0
|
||||
EXAMPLES=1
|
||||
OPENMPT123=0
|
||||
SHARED_SONAME=0
|
||||
NO_SHARED_LINKER_FLAG=1
|
||||
|
||||
# Disable the generic compiler optimization flags as emscripten is sufficiently different.
|
||||
# Optimization flags are hard-coded for emscripten in this file.
|
||||
DEBUG=0
|
||||
OPTIMIZE=0
|
||||
OPTIMIZE_SIZE=0
|
||||
|
||||
IS_CROSS=1
|
||||
|
||||
NO_ZLIB=1
|
||||
NO_LTDL=1
|
||||
NO_DL=1
|
||||
NO_MPG123=1
|
||||
NO_OGG=1
|
||||
NO_VORBIS=1
|
||||
NO_VORBISFILE=1
|
||||
NO_PORTAUDIO=1
|
||||
NO_PORTAUDIOCPP=1
|
||||
NO_PULSEAUDIO=1
|
||||
NO_SDL=1
|
||||
NO_SDL2=1
|
||||
NO_FLAC=1
|
||||
NO_SNDFILE=1
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
|
||||
CC = gcc$(TOOLCHAIN_SUFFIX)
|
||||
CXX = g++$(TOOLCHAIN_SUFFIX)
|
||||
LD = g++($TOOLCHAIN_SUFFIX)
|
||||
AR = ar$(TOOLCHAIN_SUFFIX)
|
||||
|
||||
ifneq ($(STDCXX),)
|
||||
CXXFLAGS_STDCXX = -std=$(STDCXX)
|
||||
else
|
||||
ifeq ($(shell printf '\n' > bin/empty.cpp ; if $(CXX) -std=c++17 -c bin/empty.cpp -o bin/empty.out > /dev/null 2>&1 ; then echo 'c++17' ; fi ), c++17)
|
||||
CXXFLAGS_STDCXX = -std=c++17
|
||||
endif
|
||||
endif
|
||||
CFLAGS_STDC = -std=c99
|
||||
CXXFLAGS += $(CXXFLAGS_STDCXX)
|
||||
CFLAGS += $(CFLAGS_STDC)
|
||||
|
||||
CPPFLAGS +=
|
||||
CXXFLAGS += -fPIC
|
||||
CFLAGS += -fPIC
|
||||
LDFLAGS +=
|
||||
LDLIBS += -lm
|
||||
ARFLAGS := rcs
|
||||
|
||||
ifeq ($(CHECKED_ADDRESS),1)
|
||||
CXXFLAGS += -fsanitize=address
|
||||
CFLAGS += -fsanitize=address
|
||||
endif
|
||||
|
||||
ifeq ($(CHECKED_UNDEFINED),1)
|
||||
CXXFLAGS += -fsanitize=undefined
|
||||
CFLAGS += -fsanitize=undefined
|
||||
endif
|
||||
|
||||
CXXFLAGS_WARNINGS += -Wsuggest-override -Wno-psabi
|
||||
|
||||
ifeq ($(MODERN),1)
|
||||
LDFLAGS += -fuse-ld=gold
|
||||
CXXFLAGS_WARNINGS += -Wpedantic -Wlogical-op -Wframe-larger-than=16000
|
||||
CFLAGS_WARNINGS += -Wpedantic -Wlogical-op -Wframe-larger-than=4000
|
||||
LDFLAGS_WARNINGS += -Wl,-no-undefined -Wl,--detect-odr-violations
|
||||
# re-renable after 1.29 branch
|
||||
#CXXFLAGS_WARNINGS += -Wdouble-promotion
|
||||
#CFLAGS_WARNINGS += -Wdouble-promotion
|
||||
endif
|
||||
|
||||
CFLAGS_SILENT += -Wno-cast-qual
|
||||
CFLAGS_SILENT += -Wno-empty-body
|
||||
CFLAGS_SILENT += -Wno-implicit-fallthrough
|
||||
CFLAGS_SILENT += -Wno-old-style-declaration
|
||||
CFLAGS_SILENT += -Wno-sign-compare
|
||||
CFLAGS_SILENT += -Wno-type-limits
|
||||
CFLAGS_SILENT += -Wno-unused-but-set-variable
|
||||
CFLAGS_SILENT += -Wno-unused-function
|
||||
CFLAGS_SILENT += -Wno-unused-parameter
|
||||
|
||||
EXESUFFIX=
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
|
||||
CC ?= cc
|
||||
CXX ?= c++
|
||||
LD ?= c++
|
||||
AR = ar
|
||||
|
||||
CXXFLAGS_STDCXX = -std=c++17
|
||||
CFLAGS_STDC = -std=c99
|
||||
CXXFLAGS += $(CXXFLAGS_STDCXX)
|
||||
CFLAGS += $(CFLAGS_STDC)
|
||||
|
||||
CPPFLAGS +=
|
||||
CXXFLAGS +=
|
||||
CFLAGS +=
|
||||
LDFLAGS +=
|
||||
LDLIBS +=
|
||||
ARFLAGS := rcs
|
||||
|
||||
MPT_COMPILER_GENERIC=1
|
||||
SHARED_LIB=0
|
||||
DYNLINK=0
|
||||
|
||||
EXESUFFIX=
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
|
||||
include config-defaults.mk
|
|
@ -1,2 +0,0 @@
|
|||
|
||||
include config-defaults.mk
|
|
@ -1,47 +0,0 @@
|
|||
|
||||
CC = i686-w64-mingw32-gcc$(MINGW_FLAVOUR)
|
||||
CXX = i686-w64-mingw32-g++$(MINGW_FLAVOUR)
|
||||
LD = i686-w64-mingw32-g++$(MINGW_FLAVOUR)
|
||||
AR = i686-w64-mingw32-ar$(MINGW_FLAVOUR)
|
||||
|
||||
CXXFLAGS_STDCXX = -std=c++17
|
||||
CFLAGS_STDC = -std=c99
|
||||
CXXFLAGS += $(CXXFLAGS_STDCXX)
|
||||
CFLAGS += $(CFLAGS_STDC)
|
||||
|
||||
CPPFLAGS += -DWIN32 -D_WIN32
|
||||
CXXFLAGS += -municode -mconsole
|
||||
CFLAGS += -municode -mconsole
|
||||
LDFLAGS +=
|
||||
LDLIBS += -lm -lole32 -lrpcrt4 -lwinmm
|
||||
ARFLAGS := rcs
|
||||
|
||||
PC_LIBS_PRIVATE += -lole32 -lrpcrt4
|
||||
|
||||
CFLAGS_SILENT += -Wno-unused-parameter -Wno-unused-function -Wno-cast-qual -Wno-old-style-declaration -Wno-type-limits -Wno-unused-but-set-variable
|
||||
|
||||
EXESUFFIX=.exe
|
||||
SOSUFFIX=.dll
|
||||
SOSUFFIXWINDOWS=1
|
||||
|
||||
DYNLINK=0
|
||||
SHARED_LIB=1
|
||||
STATIC_LIB=0
|
||||
SHARED_SONAME=0
|
||||
|
||||
IS_CROSS=1
|
||||
|
||||
NO_ZLIB=1
|
||||
NO_LTDL=1
|
||||
NO_DL=1
|
||||
NO_MPG123=1
|
||||
NO_OGG=1
|
||||
NO_VORBIS=1
|
||||
NO_VORBISFILE=1
|
||||
NO_PORTAUDIO=1
|
||||
NO_PORTAUDIOCPP=1
|
||||
NO_PULSEAUDIO=1
|
||||
NO_SDL=1
|
||||
NO_SDL2=1
|
||||
NO_SNDFILE=1
|
||||
NO_FLAC=1
|
|
@ -1,47 +0,0 @@
|
|||
|
||||
CC = x86_64-w64-mingw32-gcc$(MINGW_FLAVOUR)
|
||||
CXX = x86_64-w64-mingw32-g++$(MINGW_FLAVOUR)
|
||||
LD = x86_64-w64-mingw32-g++$(MINGW_FLAVOUR)
|
||||
AR = x86_64-w64-mingw32-ar$(MINGW_FLAVOUR)
|
||||
|
||||
CXXFLAGS_STDCXX = -std=c++17
|
||||
CFLAGS_STDC = -std=c99
|
||||
CXXFLAGS += $(CXXFLAGS_STDCXX)
|
||||
CFLAGS += $(CFLAGS_STDC)
|
||||
|
||||
CPPFLAGS += -DWIN32 -D_WIN32 -DWIN64 -D_WIN64
|
||||
CXXFLAGS += -municode -mconsole
|
||||
CFLAGS += -municode -mconsole
|
||||
LDFLAGS +=
|
||||
LDLIBS += -lm -lole32 -lrpcrt4 -lwinmm
|
||||
ARFLAGS := rcs
|
||||
|
||||
PC_LIBS_PRIVATE += -lole32 -lrpcrt4
|
||||
|
||||
CFLAGS_SILENT += -Wno-unused-parameter -Wno-unused-function -Wno-cast-qual -Wno-old-style-declaration -Wno-type-limits -Wno-unused-but-set-variable
|
||||
|
||||
EXESUFFIX=.exe
|
||||
SOSUFFIX=.dll
|
||||
SOSUFFIXWINDOWS=1
|
||||
|
||||
DYNLINK=0
|
||||
SHARED_LIB=1
|
||||
STATIC_LIB=0
|
||||
SHARED_SONAME=0
|
||||
|
||||
IS_CROSS=1
|
||||
|
||||
NO_ZLIB=1
|
||||
NO_LTDL=1
|
||||
NO_DL=1
|
||||
NO_MPG123=1
|
||||
NO_OGG=1
|
||||
NO_VORBIS=1
|
||||
NO_VORBISFILE=1
|
||||
NO_PORTAUDIO=1
|
||||
NO_PORTAUDIOCPP=1
|
||||
NO_PULSEAUDIO=1
|
||||
NO_SDL=1
|
||||
NO_SDL2=1
|
||||
NO_SNDFILE=1
|
||||
NO_FLAC=1
|
|
@ -1,49 +0,0 @@
|
|||
|
||||
CC = x86_64-w64-mingw32-gcc$(MINGW_FLAVOUR)
|
||||
CXX = x86_64-w64-mingw32-g++$(MINGW_FLAVOUR)
|
||||
LD = x86_64-w64-mingw32-g++$(MINGW_FLAVOUR)
|
||||
AR = x86_64-w64-mingw32-ar$(MINGW_FLAVOUR)
|
||||
|
||||
CXXFLAGS_STDCXX = -std=c++17
|
||||
CFLAGS_STDC = -std=c99
|
||||
CXXFLAGS += $(CXXFLAGS_STDCXX)
|
||||
CFLAGS += $(CFLAGS_STDC)
|
||||
|
||||
CPPFLAGS += -DWIN32 -D_WIN32 -DWIN64 -D_WIN64 -DWINAPI_FAMILY=0x2 -D_WIN32_WINNT=0x0602
|
||||
CXXFLAGS += -municode -mconsole
|
||||
CFLAGS += -municode -mconsole
|
||||
LDFLAGS +=
|
||||
LDLIBS += -lm -lole32 -lwinmm
|
||||
ARFLAGS := rcs
|
||||
|
||||
PC_LIBS_PRIVATE += -lole32 -lrpcrt4
|
||||
|
||||
CFLAGS_SILENT += -Wno-unused-parameter -Wno-unused-function -Wno-cast-qual -Wno-old-style-declaration -Wno-type-limits -Wno-unused-but-set-variable
|
||||
|
||||
EXESUFFIX=.exe
|
||||
SOSUFFIX=.dll
|
||||
SOSUFFIXWINDOWS=1
|
||||
|
||||
DYNLINK=0
|
||||
SHARED_LIB=1
|
||||
STATIC_LIB=0
|
||||
SHARED_SONAME=0
|
||||
|
||||
IS_CROSS=1
|
||||
|
||||
OPENMPT123=0
|
||||
|
||||
NO_ZLIB=1
|
||||
NO_LTDL=1
|
||||
NO_DL=1
|
||||
NO_MPG123=1
|
||||
NO_OGG=1
|
||||
NO_VORBIS=1
|
||||
NO_VORBISFILE=1
|
||||
NO_PORTAUDIO=1
|
||||
NO_PORTAUDIOCPP=1
|
||||
NO_PULSEAUDIO=1
|
||||
NO_SDL=1
|
||||
NO_SDL2=1
|
||||
NO_SNDFILE=1
|
||||
NO_FLAC=1
|
|
@ -1,49 +0,0 @@
|
|||
|
||||
CC = i686-w64-mingw32-gcc$(MINGW_FLAVOUR)
|
||||
CXX = i686-w64-mingw32-g++$(MINGW_FLAVOUR)
|
||||
LD = i686-w64-mingw32-g++$(MINGW_FLAVOUR)
|
||||
AR = i686-w64-mingw32-ar$(MINGW_FLAVOUR)
|
||||
|
||||
CXXFLAGS_STDCXX = -std=c++17
|
||||
CFLAGS_STDC = -std=c99
|
||||
CXXFLAGS += $(CXXFLAGS_STDCXX)
|
||||
CFLAGS += $(CFLAGS_STDC)
|
||||
|
||||
CPPFLAGS += -DWIN32 -D_WIN32 -DWINAPI_FAMILY=0x2 -D_WIN32_WINNT=0x0602
|
||||
CXXFLAGS += -municode -mconsole
|
||||
CFLAGS += -municode -mconsole
|
||||
LDFLAGS +=
|
||||
LDLIBS += -lm -lole32 -lrpcrt4 -lwinmm
|
||||
ARFLAGS := rcs
|
||||
|
||||
PC_LIBS_PRIVATE += -lole32 -lrpcrt4
|
||||
|
||||
CFLAGS_SILENT += -Wno-unused-parameter -Wno-unused-function -Wno-cast-qual -Wno-old-style-declaration -Wno-type-limits -Wno-unused-but-set-variable
|
||||
|
||||
EXESUFFIX=.exe
|
||||
SOSUFFIX=.dll
|
||||
SOSUFFIXWINDOWS=1
|
||||
|
||||
DYNLINK=0
|
||||
SHARED_LIB=1
|
||||
STATIC_LIB=0
|
||||
SHARED_SONAME=0
|
||||
|
||||
IS_CROSS=1
|
||||
|
||||
OPENMPT123=0
|
||||
|
||||
NO_ZLIB=1
|
||||
NO_LTDL=1
|
||||
NO_DL=1
|
||||
NO_MPG123=1
|
||||
NO_OGG=1
|
||||
NO_VORBIS=1
|
||||
NO_VORBISFILE=1
|
||||
NO_PORTAUDIO=1
|
||||
NO_PORTAUDIOCPP=1
|
||||
NO_PULSEAUDIO=1
|
||||
NO_SDL=1
|
||||
NO_SDL2=1
|
||||
NO_SNDFILE=1
|
||||
NO_FLAC=1
|
|
@ -1,24 +0,0 @@
|
|||
|
||||
CC ?= cc
|
||||
CXX ?= c++
|
||||
LD ?= c++
|
||||
AR = ar
|
||||
|
||||
CXXFLAGS_STDCXX = -std=c++17
|
||||
CFLAGS_STDC = -std=c99
|
||||
CXXFLAGS += $(CXXFLAGS_STDCXX)
|
||||
CFLAGS += $(CFLAGS_STDC)
|
||||
|
||||
CPPFLAGS += -DMPT_COMPILER_GENERIC
|
||||
CXXFLAGS +=
|
||||
CFLAGS +=
|
||||
LDFLAGS +=
|
||||
LDLIBS +=
|
||||
ARFLAGS := rcs
|
||||
|
||||
MPT_COMPILER_GENERIC=1
|
||||
SHARED_LIB=0
|
||||
DYNLINK=0
|
||||
|
||||
EXESUFFIX=
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
|
||||
var Module = {
|
||||
'preInit': function(text) {
|
||||
FS.mkdir('/test');
|
||||
FS.mount(NODEFS, {'root': '../test/'}, '/test');
|
||||
FS.mkdir('/libopenmpt');
|
||||
FS.mount(NODEFS, {'root': '../libopenmpt/'}, '/libopenmpt');
|
||||
}
|
||||
};
|
|
@ -1,10 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
#define OPENMPT_VERSION_SVNVERSION "17278"
|
||||
#define OPENMPT_VERSION_REVISION 17278
|
||||
#define OPENMPT_VERSION_DIRTY 0
|
||||
#define OPENMPT_VERSION_MIXEDREVISIONS 0
|
||||
#define OPENMPT_VERSION_URL "https://source.openmpt.org/svn/openmpt/tags/libopenmpt-0.5.18"
|
||||
#define OPENMPT_VERSION_DATE "2022-04-24T13:19:56.339906Z"
|
||||
#define OPENMPT_VERSION_IS_PACKAGE 1
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#define OPENMPT_VERSION_URL "$WCURL$"
|
||||
#define OPENMPT_VERSION_SVNVERSION "$WCRANGE$$WCMODS?M:$"
|
||||
#define OPENMPT_VERSION_DATE "$WCDATEUTC=%Y-%m-%dT%H:%M:%S$Z"
|
||||
|
||||
#define OPENMPT_VERSION_REVISION $WCREV$
|
||||
#define OPENMPT_VERSION_DIRTY $WCMODS?1:0$
|
||||
#define OPENMPT_VERSION_MIXEDREVISIONS $WCMIXED?1:0$
|
||||
|
||||
#define OPENMPT_VERSION_IS_PACKAGE 0
|
||||
|
||||
#define OPENMPT_BUILD_DATE "$WCNOW=%Y-%m-%d %H:%M:%S$"
|
|
@ -1,6 +0,0 @@
|
|||
@echo off
|
||||
set INTDIR=%1%
|
||||
if not exist %INTDIR% mkdir %INTDIR%
|
||||
if not exist %INTDIR%\svn_version mkdir %INTDIR%\svn_version
|
||||
subwcrev ..\.. ..\..\build\svn_version\svn_version.template.subwcrev.h %INTDIR%\svn_version\svn_version.h || del %INTDIR%\svn_version\svn_version.h || exit 0
|
||||
exit 0
|
|
@ -1,730 +0,0 @@
|
|||
/*
|
||||
* BuildSettings.h
|
||||
* ---------------
|
||||
* Purpose: Global, user settable compile time flags (and some global system header configuration)
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
#include "CompilerDetect.h"
|
||||
|
||||
|
||||
|
||||
// set windows version early so that we can deduce dependencies from SDK version
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0601 // _WIN32_WINNT_WIN7
|
||||
#endif
|
||||
|
||||
#ifndef WINVER
|
||||
#define WINVER _WIN32_WINNT
|
||||
#endif
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER) && defined(LIBOPENMPT_BUILD)
|
||||
#error "either MODPLUG_TRACKER or LIBOPENMPT_BUILD has to be defined"
|
||||
#elif defined(MODPLUG_TRACKER)
|
||||
// nothing
|
||||
#elif defined(LIBOPENMPT_BUILD)
|
||||
// nothing
|
||||
#else
|
||||
#error "either MODPLUG_TRACKER or LIBOPENMPT_BUILD has to be defined"
|
||||
#endif // MODPLUG_TRACKER || LIBOPENMPT_BUILD
|
||||
|
||||
|
||||
|
||||
// wrapper for autoconf macros
|
||||
|
||||
#if defined(HAVE_CONFIG_H)
|
||||
|
||||
#include "config.h"
|
||||
|
||||
// Fixup dependencies which are currently not used in libopenmpt itself
|
||||
#ifdef MPT_WITH_FLAC
|
||||
#undef MPT_WITH_FLAC
|
||||
#endif
|
||||
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
|
||||
|
||||
// Dependencies from the MSVC build system
|
||||
#if defined(MPT_BUILD_MSVC)
|
||||
|
||||
// This section defines which dependencies are available when building with
|
||||
// MSVC. Other build systems provide MPT_WITH_* macros via command-line or other
|
||||
// means.
|
||||
// OpenMPT and libopenmpt should compile and run successfully (albeit with
|
||||
// reduced functionality) with any or all dependencies missing/disabled.
|
||||
// The defaults match the bundled third-party libraries with the addition of
|
||||
// ASIO and VST SDKs.
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
#if !defined(MPT_BUILD_WINESUPPORT)
|
||||
#define MPT_WITH_MFC
|
||||
#endif // !MPT_BUILD_WINESUPPORT
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
// OpenMPT-only dependencies
|
||||
#if !MPT_MSVC_BEFORE(2019,0)
|
||||
// disabled for VS2017 because of multiple initialization of inline variables
|
||||
// https://developercommunity.visualstudio.com/t/static-inline-variable-gets-destroyed-multiple-tim/297876
|
||||
#define MPT_WITH_ASIO
|
||||
#endif
|
||||
#define MPT_WITH_DMO
|
||||
#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_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
|
||||
|
||||
// OpenMPT and libopenmpt dependencies (not for openmp123, player plugins or examples)
|
||||
//#define MPT_WITH_DL
|
||||
#define MPT_WITH_FLAC
|
||||
//#define MPT_WITH_LTDL
|
||||
#if MPT_OS_WINDOWS
|
||||
#define MPT_WITH_MEDIAFOUNDATION
|
||||
#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
|
||||
#if MPT_OS_WINDOWS
|
||||
#if (_WIN32_WINNT >= 0x0A00)
|
||||
#define MPT_WITH_WINDOWS10
|
||||
#endif
|
||||
#endif
|
||||
#define MPT_WITH_ZLIB
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
#if defined(LIBOPENMPT_BUILD)
|
||||
|
||||
// OpenMPT and libopenmpt dependencies (not for openmp123, player plugins or examples)
|
||||
#if defined(LIBOPENMPT_BUILD_FULL) && defined(LIBOPENMPT_BUILD_SMALL)
|
||||
#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_SMALL)
|
||||
|
||||
//#define MPT_WITH_DL
|
||||
//#define MPT_WITH_FLAC
|
||||
//#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
|
||||
|
||||
#else // !LIBOPENMPT_BUILD_SMALL
|
||||
|
||||
//#define MPT_WITH_DL
|
||||
//#define MPT_WITH_FLAC
|
||||
//#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_SMALL
|
||||
|
||||
#endif // LIBOPENMPT_BUILD
|
||||
|
||||
#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_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.
|
||||
#if defined(MPT_BUILD_DEBUG) || defined(MPT_BUILD_CHECKED)
|
||||
#define ENABLE_TESTS
|
||||
#endif
|
||||
|
||||
// Disable any file saving functionality (not really useful except for the player library)
|
||||
//#define MODPLUG_NO_FILESAVE
|
||||
|
||||
// Disable any debug logging
|
||||
//#define NO_LOGGING
|
||||
#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
|
||||
|
||||
// Enable all individual logging macros and MPT_LOG calls
|
||||
//#define MPT_ALL_LOGGING
|
||||
|
||||
// Disable all runtime asserts
|
||||
#if !defined(MPT_BUILD_DEBUG) && !defined(MPT_BUILD_CHECKED) && !defined(MPT_BUILD_WINESUPPORT)
|
||||
#define NO_ASSERTS
|
||||
#endif
|
||||
|
||||
// Enable callback stream wrapper for FileReader (required by libopenmpt C API).
|
||||
//#define MPT_FILEREADER_CALLBACK_STREAM
|
||||
|
||||
// Support for externally linked samples e.g. in MPTM files
|
||||
#define MPT_EXTERNAL_SAMPLES
|
||||
|
||||
// Support mpt::ChartsetLocale
|
||||
#define MPT_ENABLE_CHARSET_LOCALE
|
||||
|
||||
// Use inline assembly
|
||||
#define ENABLE_ASM
|
||||
|
||||
// Disable unarchiving support
|
||||
//#define NO_ARCHIVE_SUPPORT
|
||||
|
||||
// Disable the built-in reverb effect
|
||||
//#define NO_REVERB
|
||||
|
||||
// Disable built-in miscellaneous DSP effects (surround, mega bass, noise reduction)
|
||||
//#define NO_DSP
|
||||
|
||||
// Disable the built-in equalizer.
|
||||
//#define NO_EQ
|
||||
|
||||
// Disable the built-in automatic gain control
|
||||
//#define NO_AGC
|
||||
|
||||
// Define to build without VST plugin support; makes build possible without VST SDK.
|
||||
//#define NO_VST
|
||||
|
||||
// (HACK) Define to build without any plugin support
|
||||
//#define NO_PLUGINS
|
||||
|
||||
// Do not build libopenmpt C api
|
||||
#define NO_LIBOPENMPT_C
|
||||
|
||||
// Do not build libopenmpt C++ api
|
||||
#define NO_LIBOPENMPT_CXX
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
|
||||
#if defined(LIBOPENMPT_BUILD)
|
||||
|
||||
#if (defined(_DEBUG) || defined(DEBUG)) && !defined(MPT_BUILD_DEBUG)
|
||||
#define MPT_BUILD_DEBUG
|
||||
#endif
|
||||
|
||||
#if defined(LIBOPENMPT_BUILD_TEST)
|
||||
#define ENABLE_TESTS
|
||||
#else
|
||||
#define MODPLUG_NO_FILESAVE
|
||||
#endif
|
||||
#if defined(MPT_BUILD_ANALZYED) || defined(MPT_BUILD_DEBUG) || defined(MPT_BUILD_CHECKED) || defined(ENABLE_TESTS)
|
||||
// enable asserts
|
||||
#else
|
||||
#define NO_ASSERTS
|
||||
#endif
|
||||
//#define NO_LOGGING
|
||||
//#define MPT_ALL_LOGGING
|
||||
#define MPT_FILEREADER_CALLBACK_STREAM
|
||||
//#define MPT_EXTERNAL_SAMPLES
|
||||
#if defined(ENABLE_TESTS) || defined(MPT_BUILD_HACK_ARCHIVE_SUPPORT)
|
||||
#define MPT_ENABLE_CHARSET_LOCALE
|
||||
#else
|
||||
//#define MPT_ENABLE_CHARSET_LOCALE
|
||||
#endif
|
||||
// Do not use inline asm in library builds. There is just about no codepath which would use it anyway.
|
||||
//#define ENABLE_ASM
|
||||
#if defined(MPT_BUILD_HACK_ARCHIVE_SUPPORT)
|
||||
//#define NO_ARCHIVE_SUPPORT
|
||||
#else
|
||||
#define NO_ARCHIVE_SUPPORT
|
||||
#endif
|
||||
//#define NO_REVERB
|
||||
#define NO_DSP
|
||||
#define NO_EQ
|
||||
#define NO_AGC
|
||||
#define NO_VST
|
||||
//#define NO_PLUGINS
|
||||
//#define NO_LIBOPENMPT_C
|
||||
//#define NO_LIBOPENMPT_CXX
|
||||
|
||||
#endif // LIBOPENMPT_BUILD
|
||||
|
||||
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
#ifndef MPT_ENABLE_CHARSET_LOCALE
|
||||
#define MPT_ENABLE_CHARSET_LOCALE
|
||||
#endif
|
||||
|
||||
#elif MPT_OS_LINUX
|
||||
|
||||
#elif MPT_OS_ANDROID
|
||||
|
||||
#elif MPT_OS_EMSCRIPTEN
|
||||
|
||||
#ifndef MPT_LOCALE_ASSUME_CHARSET
|
||||
#define MPT_LOCALE_ASSUME_CHARSET Charset::UTF8
|
||||
#endif
|
||||
|
||||
#elif MPT_OS_MACOSX_OR_IOS
|
||||
|
||||
#elif MPT_OS_DJGPP
|
||||
|
||||
#ifndef MPT_LOCALE_ASSUME_CHARSET
|
||||
#define MPT_LOCALE_ASSUME_CHARSET Charset::CP437
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if MPT_COMPILER_MSVC && !defined(MPT_USTRING_MODE_UTF8_FORCE)
|
||||
|
||||
// Use wide strings for MSVC because this is the native encoding on
|
||||
// microsoft platforms.
|
||||
#define MPT_USTRING_MODE_WIDE 1
|
||||
#define MPT_USTRING_MODE_UTF8 0
|
||||
|
||||
#else // !MPT_COMPILER_MSVC
|
||||
|
||||
#define MPT_USTRING_MODE_WIDE 0
|
||||
#define MPT_USTRING_MODE_UTF8 1
|
||||
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
|
||||
#if MPT_USTRING_MODE_UTF8
|
||||
|
||||
// MPT_USTRING_MODE_UTF8 mpt::ustring is implemented via mpt::u8string
|
||||
#define MPT_ENABLE_U8STRING 1
|
||||
|
||||
#else
|
||||
|
||||
#define MPT_ENABLE_U8STRING 0
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(MODPLUG_TRACKER) || MPT_USTRING_MODE_WIDE
|
||||
|
||||
// mpt::ToWString, mpt::wfmt, ConvertStrTo<std::wstring>
|
||||
// Required by the tracker to ease interfacing with WinAPI.
|
||||
// Required by MPT_USTRING_MODE_WIDE to ease type tunneling in mpt::format.
|
||||
#define MPT_WSTRING_FORMAT 1
|
||||
|
||||
#else
|
||||
|
||||
#define MPT_WSTRING_FORMAT 0
|
||||
|
||||
#endif
|
||||
|
||||
#if MPT_OS_WINDOWS || MPT_USTRING_MODE_WIDE || MPT_WSTRING_FORMAT
|
||||
|
||||
// mpt::ToWide
|
||||
// Required on Windows by mpt::PathString.
|
||||
// Required by MPT_USTRING_MODE_WIDE as they share the conversion functions.
|
||||
// Required by MPT_WSTRING_FORMAT because of std::string<->std::wstring conversion in mpt::ToString and mpt::ToWString.
|
||||
#define MPT_WSTRING_CONVERT 1
|
||||
|
||||
#else
|
||||
|
||||
#define MPT_WSTRING_CONVERT 0
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// fixing stuff up
|
||||
|
||||
#if defined(MPT_BUILD_ANALYZED) || defined(MPT_BUILD_CHECKED)
|
||||
#ifdef NO_ASSERTS
|
||||
#undef NO_ASSERTS // static or dynamic analyzers want assertions on
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(MPT_BUILD_FUZZER)
|
||||
#ifndef MPT_FUZZ_TRACKER
|
||||
#define MPT_FUZZ_TRACKER
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !MPT_COMPILER_MSVC && defined(ENABLE_ASM)
|
||||
#undef ENABLE_ASM // inline assembly requires MSVC compiler
|
||||
#endif
|
||||
|
||||
#if defined(ENABLE_ASM)
|
||||
#if MPT_COMPILER_MSVC && defined(_M_IX86)
|
||||
|
||||
#define ENABLE_CPUID
|
||||
// Generate general x86 inline assembly and intrinsics.
|
||||
#define ENABLE_X86
|
||||
// Generate MMX instructions (only used when the CPU supports it).
|
||||
#define ENABLE_MMX
|
||||
// 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 SSE3 instructions (only used when the CPU supports it).
|
||||
#define ENABLE_SSE3
|
||||
// Generate SSE4 instructions (only used when the CPU supports it).
|
||||
#define ENABLE_SSE4
|
||||
// Generate AVX instructions (only used when the CPU supports it).
|
||||
#define ENABLE_AVX
|
||||
// Generate AVX2 instructions (only used when the CPU supports it).
|
||||
#define ENABLE_AVX2
|
||||
|
||||
#elif MPT_COMPILER_MSVC && defined(_M_X64)
|
||||
|
||||
#define ENABLE_CPUID
|
||||
// Generate general x64 intrinsics.
|
||||
#define ENABLE_X64
|
||||
// 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 SSE3 instructions (only used when the CPU supports it).
|
||||
#define ENABLE_SSE3
|
||||
// Generate SSE4 instructions (only used when the CPU supports it).
|
||||
#define ENABLE_SSE4
|
||||
// Generate AVX instructions (only used when the CPU supports it).
|
||||
#define ENABLE_AVX
|
||||
// Generate AVX2 instructions (only used when the CPU supports it).
|
||||
#define ENABLE_AVX2
|
||||
|
||||
#endif // arch
|
||||
#endif // ENABLE_ASM
|
||||
|
||||
#if defined(ENABLE_TESTS) && defined(MODPLUG_NO_FILESAVE)
|
||||
#undef MODPLUG_NO_FILESAVE // tests recommend file saving
|
||||
#endif
|
||||
|
||||
#if defined(MPT_WITH_ZLIB) && defined(MPT_WITH_MINIZ)
|
||||
// Only one deflate implementation should be used. Prefer zlib.
|
||||
#undef MPT_WITH_MINIZ
|
||||
#endif
|
||||
|
||||
#if !MPT_OS_WINDOWS && defined(MPT_WITH_MEDIAFOUNDATION)
|
||||
#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
|
||||
|
||||
#if defined(MODPLUG_TRACKER) && !defined(MPT_ENABLE_TEMPFILE)
|
||||
#define MPT_ENABLE_TEMPFILE
|
||||
#endif
|
||||
|
||||
#if defined(MODPLUG_TRACKER) && !defined(MPT_ENABLE_DYNBIND)
|
||||
#define MPT_ENABLE_DYNBIND // Tracker requires dynamic library loading for export codecs
|
||||
#endif
|
||||
|
||||
#if defined(MPT_WITH_MEDIAFOUNDATION) && !defined(MPT_ENABLE_DYNBIND)
|
||||
#define MPT_ENABLE_DYNBIND // MediaFoundation needs dynamic loading in order to test availability of delay loaded libs
|
||||
#endif
|
||||
|
||||
#if (defined(MPT_WITH_MPG123) || defined(MPT_WITH_MINIMP3)) && !defined(MPT_ENABLE_MP3_SAMPLES)
|
||||
#define MPT_ENABLE_MP3_SAMPLES
|
||||
#endif
|
||||
|
||||
#if defined(ENABLE_TESTS)
|
||||
#define MPT_ENABLE_FILEIO // Test suite requires PathString for file loading.
|
||||
#endif
|
||||
|
||||
#if defined(MODPLUG_TRACKER) && !defined(MPT_ENABLE_FILEIO)
|
||||
#define MPT_ENABLE_FILEIO // Tracker requires disk file io
|
||||
#endif
|
||||
|
||||
#if defined(MODPLUG_TRACKER) && !defined(MPT_ENABLE_THREAD)
|
||||
#define MPT_ENABLE_THREAD // Tracker requires threads
|
||||
#endif
|
||||
|
||||
#if defined(MPT_EXTERNAL_SAMPLES) && !defined(MPT_ENABLE_FILEIO)
|
||||
#define MPT_ENABLE_FILEIO // External samples require disk file io
|
||||
#endif
|
||||
|
||||
#if defined(NO_PLUGINS)
|
||||
// Any plugin type requires NO_PLUGINS to not be defined.
|
||||
#define NO_VST
|
||||
#endif
|
||||
|
||||
#if defined(ENABLE_ASM) || !defined(NO_VST)
|
||||
#define MPT_ENABLE_ALIGNED_ALLOC
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER) && !defined(MPT_BUILD_WINESUPPORT) && !defined(MPT_BUILD_WINESUPPORT_WRAPPER)
|
||||
#ifndef MPT_NO_NAMESPACE
|
||||
#define MPT_NO_NAMESPACE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(MPT_NO_NAMESPACE)
|
||||
|
||||
#ifdef OPENMPT_NAMESPACE
|
||||
#undef OPENMPT_NAMESPACE
|
||||
#endif
|
||||
#define OPENMPT_NAMESPACE
|
||||
|
||||
#ifdef OPENMPT_NAMESPACE_BEGIN
|
||||
#undef OPENMPT_NAMESPACE_BEGIN
|
||||
#endif
|
||||
#define OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
#ifdef OPENMPT_NAMESPACE_END
|
||||
#undef OPENMPT_NAMESPACE_END
|
||||
#endif
|
||||
#define OPENMPT_NAMESPACE_END
|
||||
|
||||
#else
|
||||
|
||||
#ifndef OPENMPT_NAMESPACE
|
||||
#define OPENMPT_NAMESPACE OpenMPT
|
||||
#endif
|
||||
|
||||
#ifndef OPENMPT_NAMESPACE_BEGIN
|
||||
#define OPENMPT_NAMESPACE_BEGIN namespace OPENMPT_NAMESPACE {
|
||||
#endif
|
||||
#ifndef OPENMPT_NAMESPACE_END
|
||||
#define OPENMPT_NAMESPACE_END }
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// platform configuration
|
||||
|
||||
#ifdef MPT_WITH_MFC
|
||||
//#define MPT_MFC_FULL // use full MFC, including MFC controls
|
||||
#endif // MPT_WITH_MFC
|
||||
|
||||
#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
|
||||
|
||||
// windows.h excludes
|
||||
#define NOMEMMGR // GMEM_*, LMEM_*, GHND, LHND, associated routines
|
||||
#define NOMINMAX // Macros min(a,b) and max(a,b)
|
||||
#define NOSERVICE // All Service Controller routines, SERVICE_ equates, etc.
|
||||
#define NOCOMM // COMM driver routines
|
||||
#define NOKANJI // Kanji support stuff.
|
||||
#define NOPROFILER // Profiler interface.
|
||||
#define NOMCX // Modem Configuration Extensions
|
||||
|
||||
// mmsystem.h excludes
|
||||
#define MMNODRV
|
||||
//#define MMNOSOUND
|
||||
//#define MMNOWAVE
|
||||
//#define MMNOMIDI
|
||||
#define MMNOAUX
|
||||
#define MMNOMIXER
|
||||
//#define MMNOTIMER
|
||||
#define MMNOJOY
|
||||
#define MMNOMCI
|
||||
//#define MMNOMMIO
|
||||
//#define MMNOMMSYSTEM
|
||||
|
||||
// mmreg.h excludes
|
||||
#define NOMMIDS
|
||||
//#define NONEWWAVE
|
||||
#define NONEWRIFF
|
||||
#define NOJPEGDIB
|
||||
#define NONEWIC
|
||||
#define NOBITMAP
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
|
||||
|
||||
// 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
|
||||
|
||||
#ifndef _FILE_OFFSET_BITS
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#endif
|
||||
|
||||
#if MPT_COMPILER_CLANG
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// compiler configuration
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
|
||||
#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
|
||||
|
||||
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_WARNINGS // Define to disable the "This function or variable may be unsafe" warnings.
|
||||
#endif
|
||||
#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1
|
||||
#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT 1
|
||||
#ifndef _SCL_SECURE_NO_WARNINGS
|
||||
#define _SCL_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#ifndef NO_WARN_MBCS_MFC_DEPRECATION
|
||||
#define NO_WARN_MBCS_MFC_DEPRECATION
|
||||
#endif
|
||||
|
||||
#pragma warning(disable:4355) // 'this' : used in base member initializer list
|
||||
|
||||
// happens for immutable classes (i.e. classes containing const members)
|
||||
#pragma warning(disable:4512) // assignment operator could not be generated
|
||||
|
||||
#pragma warning(error:4309) // Treat "truncation of constant value"-warning as error.
|
||||
#pragma warning(error:4463) // Treat overflow; assigning value to bit-field that can only hold values from low_value to high_value"-warning as error.
|
||||
|
||||
#ifdef MPT_BUILD_ANALYZED
|
||||
// Disable Visual Studio static analyzer warnings that generate too many false positives in VS2010.
|
||||
//#pragma warning(disable:6246)
|
||||
//#pragma warning(disable:6262)
|
||||
#pragma warning(disable:6297) // 32-bit value is shifted, then cast to 64-bit value. Results might not be an expected value.
|
||||
#pragma warning(disable:6326) // Potential comparison of a constant with another constant
|
||||
//#pragma warning(disable:6385)
|
||||
//#pragma warning(disable:6386)
|
||||
#endif // MPT_BUILD_ANALYZED
|
||||
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
|
||||
#if MPT_COMPILER_CLANG
|
||||
|
||||
#if defined(MPT_BUILD_MSVC)
|
||||
#pragma clang diagnostic warning "-Wimplicit-fallthrough"
|
||||
#endif // MPT_BUILD_MSVC
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
#pragma clang diagnostic ignored "-Wunused-local-typedef"
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
#endif // MPT_COMPILER_CLANG
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// standard library quirks
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// third-party library configuration
|
||||
|
||||
#ifdef MPT_WITH_FLAC
|
||||
#ifdef MPT_BUILD_MSVC_STATIC
|
||||
#define FLAC__NO_DLL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef MPT_WITH_SMBPITCHSHIFT
|
||||
#ifdef MPT_BUILD_MSVC_SHARED
|
||||
#define SMBPITCHSHIFT_USE_DLL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef MPT_WITH_STBVORBIS
|
||||
#define STB_VORBIS_HEADER_ONLY
|
||||
#ifndef STB_VORBIS_NO_PULLDATA_API
|
||||
#define STB_VORBIS_NO_PULLDATA_API
|
||||
#endif
|
||||
#ifndef STB_VORBIS_NO_STDIO
|
||||
#define STB_VORBIS_NO_STDIO
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef MPT_WITH_VORBISFILE
|
||||
#ifndef OV_EXCLUDE_STATIC_CALLBACKS
|
||||
#define OV_EXCLUDE_STATIC_CALLBACKS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef MPT_WITH_ZLIB
|
||||
#ifdef MPT_BUILD_MSVC_SHARED
|
||||
#define ZLIB_DLL
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -1,372 +0,0 @@
|
|||
/*
|
||||
* CompilerDetect.h
|
||||
* ----------------
|
||||
* Purpose: Detect current compiler and provide readable version test macros.
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
#define MPT_COMPILER_MAKE_VERSION2(version,sp) ((version) * 100 + (sp))
|
||||
#define MPT_COMPILER_MAKE_VERSION3(major,minor,patch) ((major) * 10000 + (minor) * 100 + (patch))
|
||||
#define MPT_COMPILER_MAKE_VERSION3_BUILD(major,minor,build) ((major) * 10000000 + (minor) * 100000 + (patch))
|
||||
|
||||
|
||||
|
||||
#if defined(MPT_COMPILER_GENERIC)
|
||||
|
||||
#undef MPT_COMPILER_GENERIC
|
||||
#define MPT_COMPILER_GENERIC 1
|
||||
|
||||
#elif defined(__clang__) && defined(_MSC_VER) && defined(__c2__)
|
||||
|
||||
#error "Clang/C2 is not supported. Please use Clang/LLVM for Windows instead."
|
||||
|
||||
#elif defined(__clang__)
|
||||
|
||||
#define MPT_COMPILER_CLANG 1
|
||||
#define MPT_COMPILER_CLANG_VERSION MPT_COMPILER_MAKE_VERSION3(__clang_major__,__clang_minor__,__clang_patchlevel__)
|
||||
#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(5,0,0)
|
||||
#error "clang version 5 required"
|
||||
#endif
|
||||
|
||||
#if defined(__clang_analyzer__)
|
||||
#ifndef MPT_BUILD_ANALYZED
|
||||
#define MPT_BUILD_ANALYZED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#elif defined(__GNUC__)
|
||||
|
||||
#define MPT_COMPILER_GCC 1
|
||||
#define MPT_COMPILER_GCC_VERSION MPT_COMPILER_MAKE_VERSION3(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__)
|
||||
#define MPT_GCC_AT_LEAST(major,minor,patch) (MPT_COMPILER_GCC_VERSION >= MPT_COMPILER_MAKE_VERSION3((major),(minor),(patch)))
|
||||
#define MPT_GCC_BEFORE(major,minor,patch) (MPT_COMPILER_GCC_VERSION < MPT_COMPILER_MAKE_VERSION3((major),(minor),(patch)))
|
||||
|
||||
#if MPT_GCC_BEFORE(7,1,0)
|
||||
#error "GCC version 7.1 required"
|
||||
#endif
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
|
||||
#define MPT_COMPILER_MSVC 1
|
||||
#if (_MSC_VER >= 1926)
|
||||
#define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2019,6)
|
||||
#elif (_MSC_VER >= 1925)
|
||||
#define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2019,5)
|
||||
#elif (_MSC_VER >= 1924)
|
||||
#define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2019,4)
|
||||
#elif (_MSC_VER >= 1923)
|
||||
#define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2019,3)
|
||||
#elif (_MSC_VER >= 1922)
|
||||
#define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2019,2)
|
||||
#elif (_MSC_VER >= 1921)
|
||||
#define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2019,1)
|
||||
#elif (_MSC_VER >= 1920)
|
||||
#define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2019,0)
|
||||
#elif (_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)
|
||||
#elif (_MSC_VER >= 1913)
|
||||
#define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2017,6)
|
||||
#elif (_MSC_VER >= 1912)
|
||||
#define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2017,5)
|
||||
#elif (_MSC_VER >= 1911)
|
||||
#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)
|
||||
#define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2013,0)
|
||||
#elif (_MSC_VER >= 1700)
|
||||
#define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2012,0)
|
||||
#elif (_MSC_VER >= 1600)
|
||||
#define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2010,0)
|
||||
#elif (_MSC_VER >= 1500)
|
||||
#define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2008,0)
|
||||
#else
|
||||
#define MPT_COMPILER_MSVC_VERSION MPT_COMPILER_MAKE_VERSION2(2005,0)
|
||||
#endif
|
||||
#define MPT_MSVC_AT_LEAST(version,sp) (MPT_COMPILER_MSVC_VERSION >= MPT_COMPILER_MAKE_VERSION2((version),(sp)))
|
||||
#define MPT_MSVC_BEFORE(version,sp) (MPT_COMPILER_MSVC_VERSION < MPT_COMPILER_MAKE_VERSION2((version),(sp)))
|
||||
|
||||
#if MPT_MSVC_BEFORE(2017,9)
|
||||
#error "MSVC version 2017 15.9 required"
|
||||
#endif
|
||||
|
||||
#if defined(_PREFAST_)
|
||||
#ifndef MPT_BUILD_ANALYZED
|
||||
#define MPT_BUILD_ANALYZED
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#define MPT_COMPILER_GENERIC 1
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifndef MPT_COMPILER_GENERIC
|
||||
#define MPT_COMPILER_GENERIC 0
|
||||
#endif
|
||||
#ifndef MPT_COMPILER_CLANG
|
||||
#define MPT_COMPILER_CLANG 0
|
||||
#define MPT_CLANG_AT_LEAST(major,minor,patch) 0
|
||||
#define MPT_CLANG_BEFORE(major,minor,patch) 0
|
||||
#endif
|
||||
#ifndef MPT_COMPILER_GCC
|
||||
#define MPT_COMPILER_GCC 0
|
||||
#define MPT_GCC_AT_LEAST(major,minor,patch) 0
|
||||
#define MPT_GCC_BEFORE(major,minor,patch) 0
|
||||
#endif
|
||||
#ifndef MPT_COMPILER_MSVC
|
||||
#define MPT_COMPILER_MSVC 0
|
||||
#define MPT_MSVC_AT_LEAST(version,sp) 0
|
||||
#define MPT_MSVC_BEFORE(version,sp) 0
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if MPT_COMPILER_GENERIC || MPT_COMPILER_GCC || MPT_COMPILER_CLANG
|
||||
|
||||
#if (__cplusplus >= 201703)
|
||||
#define MPT_CXX 17
|
||||
#else
|
||||
#define MPT_CXX 17
|
||||
#endif
|
||||
|
||||
#elif MPT_COMPILER_MSVC
|
||||
|
||||
#if (_MSVC_LANG >= 201703)
|
||||
#define MPT_CXX 17
|
||||
#else
|
||||
#define MPT_CXX 17
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#define MPT_CXX 17
|
||||
|
||||
#endif
|
||||
|
||||
// MPT_CXX is stricter than just using __cplusplus directly.
|
||||
// We will only claim a language version as supported IFF all core language and
|
||||
// library fatures that we need are actually supported AND working correctly
|
||||
// (to our needs).
|
||||
|
||||
#define MPT_CXX_AT_LEAST(version) (MPT_CXX >= (version))
|
||||
#define MPT_CXX_BEFORE(version) (MPT_CXX < (version))
|
||||
|
||||
|
||||
|
||||
// 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
|
||||
// singlethreaded later on.
|
||||
#define MPT_PLATFORM_MULTITHREADED 1
|
||||
|
||||
|
||||
|
||||
// specific C++ features
|
||||
|
||||
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
// Compiler has multiplication/division semantics when shifting signed integers.
|
||||
#define MPT_COMPILER_SHIFT_SIGNED 1
|
||||
#endif
|
||||
|
||||
#ifndef MPT_COMPILER_SHIFT_SIGNED
|
||||
#define MPT_COMPILER_SHIFT_SIGNED 0
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// The order of the checks matters!
|
||||
#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)
|
||||
// ok
|
||||
#elif (__EMSCRIPTEN_major__ == 1) && (__EMSCRIPTEN_minor__ > 39)
|
||||
// ok
|
||||
#elif (__EMSCRIPTEN_major__ == 1) && (__EMSCRIPTEN_minor__ == 39) && (__EMSCRIPTEN_tiny__ >= 7)
|
||||
// ok
|
||||
#else
|
||||
#error "Emscripten >= 1.39.7 is required."
|
||||
#endif
|
||||
#endif
|
||||
#elif defined(_WIN32)
|
||||
#define MPT_OS_WINDOWS 1
|
||||
#if defined(WINAPI_FAMILY)
|
||||
#include <winapifamily.h>
|
||||
#if (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)
|
||||
#define MPT_OS_WINDOWS_WINRT 0
|
||||
#else
|
||||
#define MPT_OS_WINDOWS_WINRT 1
|
||||
#endif
|
||||
#else // !WINAPI_FAMILY
|
||||
#define MPT_OS_WINDOWS_WINRT 0
|
||||
#endif // WINAPI_FAMILY
|
||||
#elif defined(__APPLE__)
|
||||
#define MPT_OS_MACOSX_OR_IOS 1
|
||||
//#include "TargetConditionals.h"
|
||||
//#if TARGET_IPHONE_SIMULATOR
|
||||
//#elif TARGET_OS_IPHONE
|
||||
//#elif TARGET_OS_MAC
|
||||
//#else
|
||||
//#endif
|
||||
#elif defined(__HAIKU__)
|
||||
#define MPT_OS_HAIKU 1
|
||||
#elif defined(__ANDROID__) || defined(ANDROID)
|
||||
#define MPT_OS_ANDROID 1
|
||||
#elif defined(__linux__)
|
||||
#define MPT_OS_LINUX 1
|
||||
#elif defined(__DragonFly__)
|
||||
#define MPT_OS_DRAGONFLYBSD 1
|
||||
#elif defined(__FreeBSD__)
|
||||
#define MPT_OS_FREEBSD 1
|
||||
#elif defined(__OpenBSD__)
|
||||
#define MPT_OS_OPENBSD 1
|
||||
#elif defined(__NetBSD__)
|
||||
#define MPT_OS_NETBSD 1
|
||||
#elif defined(__unix__)
|
||||
#define MPT_OS_GENERIC_UNIX 1
|
||||
#else
|
||||
#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
|
||||
#ifndef MPT_OS_WINDOWS
|
||||
#define MPT_OS_WINDOWS 0
|
||||
#endif
|
||||
#ifndef MPT_OS_WINDOWS_WINRT
|
||||
#define MPT_OS_WINDOWS_WINRT 0
|
||||
#endif
|
||||
#ifndef MPT_OS_MACOSX_OR_IOS
|
||||
#define MPT_OS_MACOSX_OR_IOS 0
|
||||
#endif
|
||||
#ifndef MPT_OS_HAIKU
|
||||
#define MPT_OS_HAIKU 0
|
||||
#endif
|
||||
#ifndef MPT_OS_ANDROID
|
||||
#define MPT_OS_ANDROID 0
|
||||
#endif
|
||||
#ifndef MPT_OS_LINUX
|
||||
#define MPT_OS_LINUX 0
|
||||
#endif
|
||||
#ifndef MPT_OS_DRAGONFLYBSD
|
||||
#define MPT_OS_DRAGONFLYBSD 0
|
||||
#endif
|
||||
#ifndef MPT_OS_FREEBSD
|
||||
#define MPT_OS_FREEBSD 0
|
||||
#endif
|
||||
#ifndef MPT_OS_OPENBSD
|
||||
#define MPT_OS_OPENBSD 0
|
||||
#endif
|
||||
#ifndef MPT_OS_NETBSD
|
||||
#define MPT_OS_NETBSD 0
|
||||
#endif
|
||||
#ifndef MPT_OS_GENERIC_UNIX
|
||||
#define MPT_OS_GENERIC_UNIX 0
|
||||
#endif
|
||||
#ifndef MPT_OS_UNKNOWN
|
||||
#define MPT_OS_UNKNOWN 0
|
||||
#endif
|
||||
|
||||
#ifndef MPT_OS_EMSCRIPTEN_ANCIENT
|
||||
#define MPT_OS_EMSCRIPTEN_ANCIENT 0
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if (MPT_OS_DJGPP || MPT_OS_EMSCRIPTEN)
|
||||
#undef MPT_PLATFORM_MULTITHREADED
|
||||
#define MPT_PLATFORM_MULTITHREADED 0
|
||||
#endif
|
||||
|
||||
|
||||
#if MPT_OS_EMSCRIPTEN && defined(MPT_BUILD_AUDIOWORKLETPROCESSOR)
|
||||
#define MPT_COMPILER_QUIRK_CHRONO_NO_HIGH_RESOLUTION_CLOCK
|
||||
#define MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE
|
||||
#endif
|
||||
|
||||
|
||||
#if MPT_OS_DJGPP
|
||||
#define MPT_COMPILER_QUIRK_NO_WCHAR
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__arm__)
|
||||
|
||||
#if defined(__SOFTFP__)
|
||||
#define MPT_COMPILER_QUIRK_FLOAT_EMULATED 1
|
||||
#else
|
||||
#define MPT_COMPILER_QUIRK_FLOAT_EMULATED 0
|
||||
#endif
|
||||
#if defined(__VFP_FP__)
|
||||
// native-endian IEEE754
|
||||
#define MPT_COMPILER_QUIRK_FLOAT_NOTNATIVEENDIAN 0
|
||||
#define MPT_COMPILER_QUIRK_FLOAT_NOTIEEE754 0
|
||||
#elif defined(__MAVERICK__)
|
||||
// little-endian IEEE754, we assume native-endian though
|
||||
#define MPT_COMPILER_QUIRK_FLOAT_NOTNATIVEENDIAN 1
|
||||
#define MPT_COMPILER_QUIRK_FLOAT_NOTIEEE754 0
|
||||
#else
|
||||
// not IEEE754
|
||||
#define MPT_COMPILER_QUIRK_FLOAT_NOTNATIVEENDIAN 1
|
||||
#define MPT_COMPILER_QUIRK_FLOAT_NOTIEEE754 1
|
||||
#endif
|
||||
|
||||
#elif defined(__mips__)
|
||||
|
||||
#if defined(__mips_soft_float)
|
||||
#define MPT_COMPILER_QUIRK_FLOAT_EMULATED 1
|
||||
#else
|
||||
#define MPT_COMPILER_QUIRK_FLOAT_EMULATED 0
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if MPT_OS_EMSCRIPTEN
|
||||
#define MPT_COMPILER_QUIRK_FLOAT_PREFER64 1
|
||||
#endif
|
||||
|
||||
#ifndef MPT_COMPILER_QUIRK_FLOAT_PREFER32
|
||||
#define MPT_COMPILER_QUIRK_FLOAT_PREFER32 0
|
||||
#endif
|
||||
#ifndef MPT_COMPILER_QUIRK_FLOAT_PREFER64
|
||||
#define MPT_COMPILER_QUIRK_FLOAT_PREFER64 0
|
||||
#endif
|
||||
#ifndef MPT_COMPILER_QUIRK_FLOAT_EMULATED
|
||||
#define MPT_COMPILER_QUIRK_FLOAT_EMULATED 0
|
||||
#endif
|
||||
#ifndef MPT_COMPILER_QUIRK_FLOAT_NOTNATIVEENDIAN
|
||||
#define MPT_COMPILER_QUIRK_FLOAT_NOTNATIVEENDIAN 0
|
||||
#endif
|
||||
#ifndef MPT_COMPILER_QUIRK_FLOAT_NOTIEEE754
|
||||
#define MPT_COMPILER_QUIRK_FLOAT_NOTIEEE754 0
|
||||
#endif
|
|
@ -1,469 +0,0 @@
|
|||
/*
|
||||
* ComponentManager.cpp
|
||||
* --------------------
|
||||
* Purpose: Manages loading of optional components.
|
||||
* Notes : (currently none)
|
||||
* Authors: Joern Heusipp
|
||||
* OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "ComponentManager.h"
|
||||
|
||||
#include "Logging.h"
|
||||
|
||||
#include "mptMutex.h"
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
#if defined(MPT_ENABLE_COMPONENTS)
|
||||
|
||||
|
||||
ComponentBase::ComponentBase(ComponentType type)
|
||||
: m_Type(type)
|
||||
, m_Initialized(false)
|
||||
, m_Available(false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ComponentBase::~ComponentBase()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void ComponentBase::SetInitialized()
|
||||
{
|
||||
m_Initialized = true;
|
||||
}
|
||||
|
||||
|
||||
void ComponentBase::SetAvailable()
|
||||
{
|
||||
m_Available = true;
|
||||
}
|
||||
|
||||
|
||||
ComponentType ComponentBase::GetType() const
|
||||
{
|
||||
return m_Type;
|
||||
}
|
||||
|
||||
|
||||
bool ComponentBase::IsInitialized() const
|
||||
{
|
||||
return m_Initialized;
|
||||
}
|
||||
|
||||
|
||||
bool ComponentBase::IsAvailable() const
|
||||
{
|
||||
return m_Initialized && m_Available;
|
||||
}
|
||||
|
||||
|
||||
mpt::ustring ComponentBase::GetVersion() const
|
||||
{
|
||||
return mpt::ustring();
|
||||
}
|
||||
|
||||
|
||||
void ComponentBase::Initialize()
|
||||
{
|
||||
if(IsInitialized())
|
||||
{
|
||||
return;
|
||||
}
|
||||
if(DoInitialize())
|
||||
{
|
||||
SetAvailable();
|
||||
}
|
||||
SetInitialized();
|
||||
}
|
||||
|
||||
|
||||
#if defined(MPT_ENABLE_DYNBIND)
|
||||
|
||||
|
||||
ComponentLibrary::ComponentLibrary(ComponentType type)
|
||||
: ComponentBase(type)
|
||||
, m_BindFailed(false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ComponentLibrary::~ComponentLibrary()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
bool ComponentLibrary::AddLibrary(const std::string &libName, const mpt::LibraryPath &libPath)
|
||||
{
|
||||
if(m_Libraries[libName].IsValid())
|
||||
{
|
||||
// prefer previous
|
||||
return true;
|
||||
}
|
||||
mpt::Library lib(libPath);
|
||||
if(!lib.IsValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
m_Libraries[libName] = lib;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void ComponentLibrary::ClearLibraries()
|
||||
{
|
||||
m_Libraries.clear();
|
||||
}
|
||||
|
||||
|
||||
void ComponentLibrary::SetBindFailed()
|
||||
{
|
||||
m_BindFailed = true;
|
||||
}
|
||||
|
||||
|
||||
void ComponentLibrary::ClearBindFailed()
|
||||
{
|
||||
m_BindFailed = false;
|
||||
}
|
||||
|
||||
|
||||
bool ComponentLibrary::HasBindFailed() const
|
||||
{
|
||||
return m_BindFailed;
|
||||
}
|
||||
|
||||
|
||||
mpt::Library ComponentLibrary::GetLibrary(const std::string &libName) const
|
||||
{
|
||||
const auto it = m_Libraries.find(libName);
|
||||
if(it == m_Libraries.end())
|
||||
{
|
||||
return mpt::Library();
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
|
||||
#endif // MPT_ENABLE_DYNBIND
|
||||
|
||||
|
||||
#if MPT_COMPONENT_MANAGER
|
||||
|
||||
|
||||
ComponentFactoryBase::ComponentFactoryBase(const std::string &id, const std::string &settingsKey)
|
||||
: m_ID(id)
|
||||
, m_SettingsKey(settingsKey)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ComponentFactoryBase::~ComponentFactoryBase()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
std::string ComponentFactoryBase::GetID() const
|
||||
{
|
||||
return m_ID;
|
||||
}
|
||||
|
||||
|
||||
std::string ComponentFactoryBase::GetSettingsKey() const
|
||||
{
|
||||
return m_SettingsKey;
|
||||
}
|
||||
|
||||
|
||||
void ComponentFactoryBase::PreConstruct() const
|
||||
{
|
||||
MPT_LOG(LogInformation, "Components",
|
||||
mpt::format(U_("Constructing Component %1"))
|
||||
( mpt::ToUnicode(mpt::Charset::ASCII, m_ID)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
void ComponentFactoryBase::Initialize(ComponentManager &componentManager, std::shared_ptr<IComponent> component) const
|
||||
{
|
||||
if(componentManager.IsComponentBlocked(GetSettingsKey()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
componentManager.InitializeComponent(component);
|
||||
}
|
||||
|
||||
|
||||
// Global list of component register functions.
|
||||
// We do not use a global scope static list head because the corresponding
|
||||
// mutex would be no POD type and would thus not be safe to be usable in
|
||||
// zero-initialized state.
|
||||
// Function scope static initialization is guaranteed to be thread safe
|
||||
// in C++11.
|
||||
// We use this implementation to be future-proof.
|
||||
// MSVC currently does not exploit the possibility of using multiple threads
|
||||
// for global lifetime object's initialization.
|
||||
// An implementation with a simple global list head and no mutex at all would
|
||||
// thus work fine for MSVC (currently).
|
||||
|
||||
static mpt::mutex & ComponentListMutex()
|
||||
{
|
||||
static mpt::mutex g_ComponentListMutex;
|
||||
return g_ComponentListMutex;
|
||||
}
|
||||
|
||||
static ComponentListEntry * & ComponentListHead()
|
||||
{
|
||||
static ComponentListEntry *g_ComponentListHead = nullptr;
|
||||
return g_ComponentListHead;
|
||||
}
|
||||
|
||||
bool ComponentListPush(ComponentListEntry *entry)
|
||||
{
|
||||
mpt::lock_guard<mpt::mutex> guard(ComponentListMutex());
|
||||
entry->next = ComponentListHead();
|
||||
ComponentListHead() = entry;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static std::shared_ptr<ComponentManager> g_ComponentManager;
|
||||
|
||||
|
||||
void ComponentManager::Init(const IComponentManagerSettings &settings)
|
||||
{
|
||||
MPT_LOG(LogInformation, "Components", U_("Init"));
|
||||
// cannot use make_shared because the constructor is private
|
||||
g_ComponentManager = std::shared_ptr<ComponentManager>(new ComponentManager(settings));
|
||||
}
|
||||
|
||||
|
||||
void ComponentManager::Release()
|
||||
{
|
||||
MPT_LOG(LogInformation, "Components", U_("Release"));
|
||||
g_ComponentManager = nullptr;
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<ComponentManager> ComponentManager::Instance()
|
||||
{
|
||||
return g_ComponentManager;
|
||||
}
|
||||
|
||||
|
||||
ComponentManager::ComponentManager(const IComponentManagerSettings &settings)
|
||||
: m_Settings(settings)
|
||||
{
|
||||
mpt::lock_guard<mpt::mutex> guard(ComponentListMutex());
|
||||
for(ComponentListEntry *entry = ComponentListHead(); entry; entry = entry->next)
|
||||
{
|
||||
entry->reg(*this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ComponentManager::Register(const IComponentFactory &componentFactory)
|
||||
{
|
||||
if(m_Components.find(componentFactory.GetID()) != m_Components.end())
|
||||
{
|
||||
return;
|
||||
}
|
||||
RegisteredComponent registeredComponent;
|
||||
registeredComponent.settingsKey = componentFactory.GetSettingsKey();
|
||||
registeredComponent.factoryMethod = componentFactory.GetStaticConstructor();
|
||||
registeredComponent.instance = nullptr;
|
||||
registeredComponent.weakInstance = std::weak_ptr<IComponent>();
|
||||
m_Components.insert(std::make_pair(componentFactory.GetID(), registeredComponent));
|
||||
}
|
||||
|
||||
|
||||
void ComponentManager::Startup()
|
||||
{
|
||||
MPT_LOG(LogDebug, "Components", U_("Startup"));
|
||||
if(m_Settings.LoadOnStartup())
|
||||
{
|
||||
for(auto &it : m_Components)
|
||||
{
|
||||
it.second.instance = it.second.factoryMethod(*this);
|
||||
it.second.weakInstance = it.second.instance;
|
||||
}
|
||||
}
|
||||
if(!m_Settings.KeepLoaded())
|
||||
{
|
||||
for(auto &it : m_Components)
|
||||
{
|
||||
it.second.instance = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ComponentManager::IsComponentBlocked(const std::string &settingsKey) const
|
||||
{
|
||||
if(settingsKey.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return m_Settings.IsBlocked(settingsKey);
|
||||
}
|
||||
|
||||
|
||||
void ComponentManager::InitializeComponent(std::shared_ptr<IComponent> component) const
|
||||
{
|
||||
if(!component)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if(component->IsInitialized())
|
||||
{
|
||||
return;
|
||||
}
|
||||
component->Initialize();
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<const IComponent> ComponentManager::GetComponent(const IComponentFactory &componentFactory)
|
||||
{
|
||||
std::shared_ptr<IComponent> component = nullptr;
|
||||
auto it = m_Components.find(componentFactory.GetID());
|
||||
if(it != m_Components.end())
|
||||
{ // registered component
|
||||
if((*it).second.instance)
|
||||
{ // loaded
|
||||
component = (*it).second.instance;
|
||||
} else
|
||||
{ // not loaded
|
||||
component = (*it).second.weakInstance.lock();
|
||||
if(!component)
|
||||
{
|
||||
component = (*it).second.factoryMethod(*this);
|
||||
}
|
||||
if(m_Settings.KeepLoaded())
|
||||
{ // keep the component loaded
|
||||
(*it).second.instance = component;
|
||||
}
|
||||
(*it).second.weakInstance = component;
|
||||
}
|
||||
} else
|
||||
{ // unregistered component
|
||||
component = componentFactory.Construct(*this);
|
||||
}
|
||||
MPT_ASSERT(component);
|
||||
return component;
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<const IComponent> ComponentManager::ReloadComponent(const IComponentFactory &componentFactory)
|
||||
{
|
||||
std::shared_ptr<IComponent> component = nullptr;
|
||||
auto it = m_Components.find(componentFactory.GetID());
|
||||
if(it != m_Components.end())
|
||||
{ // registered component
|
||||
if((*it).second.instance)
|
||||
{ // loaded
|
||||
(*it).second.instance = nullptr;
|
||||
if(!(*it).second.weakInstance.expired())
|
||||
{
|
||||
throw std::runtime_error("Component not completely unloaded. Cannot reload.");
|
||||
}
|
||||
(*it).second.weakInstance = std::weak_ptr<IComponent>();
|
||||
}
|
||||
// not loaded
|
||||
component = (*it).second.factoryMethod(*this);
|
||||
if(m_Settings.KeepLoaded())
|
||||
{ // keep the component loaded
|
||||
(*it).second.instance = component;
|
||||
}
|
||||
(*it).second.weakInstance = component;
|
||||
} else
|
||||
{ // unregistered component
|
||||
component = componentFactory.Construct(*this);
|
||||
}
|
||||
MPT_ASSERT(component);
|
||||
return component;
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::string> ComponentManager::GetRegisteredComponents() const
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
result.reserve(m_Components.size());
|
||||
for(const auto &it : m_Components)
|
||||
{
|
||||
result.push_back(it.first);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
ComponentInfo ComponentManager::GetComponentInfo(std::string name) const
|
||||
{
|
||||
ComponentInfo result;
|
||||
result.name = name;
|
||||
result.state = ComponentStateUnregistered;
|
||||
result.settingsKey = "";
|
||||
result.type = ComponentTypeUnknown;
|
||||
const auto it = m_Components.find(name);
|
||||
if(it == m_Components.end())
|
||||
{
|
||||
result.state = ComponentStateUnregistered;
|
||||
return result;
|
||||
}
|
||||
result.settingsKey = it->second.settingsKey;
|
||||
if(IsComponentBlocked(it->second.settingsKey))
|
||||
{
|
||||
result.state = ComponentStateBlocked;
|
||||
return result;
|
||||
}
|
||||
std::shared_ptr<IComponent> component = it->second.instance;
|
||||
if(!component)
|
||||
{
|
||||
component = it->second.weakInstance.lock();
|
||||
}
|
||||
if(!component)
|
||||
{
|
||||
result.state = ComponentStateUnintialized;
|
||||
return result;
|
||||
}
|
||||
result.type = component->GetType();
|
||||
if(!component->IsInitialized())
|
||||
{
|
||||
result.state = ComponentStateUnintialized;
|
||||
return result;
|
||||
}
|
||||
if(!component->IsAvailable())
|
||||
{
|
||||
result.state = ComponentStateUnavailable;
|
||||
return result;
|
||||
}
|
||||
result.state = ComponentStateAvailable;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
mpt::PathString ComponentManager::GetComponentPath() const
|
||||
{
|
||||
return m_Settings.Path();
|
||||
}
|
||||
|
||||
|
||||
#endif // MPT_COMPONENT_MANAGER
|
||||
|
||||
|
||||
#endif // MPT_ENABLE_COMPONENTS
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,519 +0,0 @@
|
|||
/*
|
||||
* ComponentManager.h
|
||||
* ------------------
|
||||
* Purpose: Manages loading of optional components.
|
||||
* Notes : (currently none)
|
||||
* Authors: Joern Heusipp
|
||||
* OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "../common/misc_util.h"
|
||||
#include "../common/mptMutex.h"
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
#define MPT_ENABLE_COMPONENTS
|
||||
|
||||
|
||||
#if defined(MPT_ENABLE_COMPONENTS)
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
#define MPT_COMPONENT_MANAGER 1
|
||||
#else
|
||||
#define MPT_COMPONENT_MANAGER 0
|
||||
#endif
|
||||
|
||||
|
||||
enum ComponentType
|
||||
{
|
||||
ComponentTypeUnknown = 0,
|
||||
ComponentTypeBuiltin, // PortAudio
|
||||
ComponentTypeSystem, // mf.dll
|
||||
ComponentTypeSystemInstallable, // acm mp3 codec
|
||||
ComponentTypeBundled, // libsoundtouch
|
||||
ComponentTypeForeign, // libmp3lame
|
||||
};
|
||||
|
||||
|
||||
class ComponentFactoryBase;
|
||||
|
||||
|
||||
class IComponent
|
||||
{
|
||||
|
||||
friend class ComponentFactoryBase;
|
||||
|
||||
protected:
|
||||
|
||||
IComponent() = default;
|
||||
|
||||
public:
|
||||
|
||||
virtual ~IComponent() = default;
|
||||
|
||||
public:
|
||||
|
||||
virtual ComponentType GetType() const = 0;
|
||||
|
||||
virtual bool IsInitialized() const = 0; // Initialize() has been called
|
||||
virtual bool IsAvailable() const = 0; // Initialize() has been successfull
|
||||
virtual mpt::ustring GetVersion() const = 0;
|
||||
|
||||
virtual void Initialize() = 0; // try to load the component
|
||||
|
||||
};
|
||||
|
||||
|
||||
class ComponentBase
|
||||
: public IComponent
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
ComponentType m_Type;
|
||||
|
||||
bool m_Initialized;
|
||||
bool m_Available;
|
||||
|
||||
protected:
|
||||
|
||||
ComponentBase(ComponentType type);
|
||||
|
||||
public:
|
||||
|
||||
virtual ~ComponentBase();
|
||||
|
||||
protected:
|
||||
|
||||
void SetInitialized();
|
||||
void SetAvailable();
|
||||
|
||||
public:
|
||||
|
||||
ComponentType GetType() const override;
|
||||
bool IsInitialized() const override;
|
||||
bool IsAvailable() const override;
|
||||
|
||||
mpt::ustring GetVersion() const override;
|
||||
|
||||
public:
|
||||
|
||||
void Initialize() override;
|
||||
|
||||
protected:
|
||||
|
||||
virtual bool DoInitialize() = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
class ComponentBuiltin : public ComponentBase
|
||||
{
|
||||
public:
|
||||
ComponentBuiltin()
|
||||
: ComponentBase(ComponentTypeBuiltin)
|
||||
{
|
||||
return;
|
||||
}
|
||||
bool DoInitialize() override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#define MPT_GLOBAL_BIND(lib, name) name = &::name;
|
||||
|
||||
|
||||
#if defined(MPT_ENABLE_DYNBIND)
|
||||
|
||||
|
||||
class ComponentLibrary
|
||||
: public ComponentBase
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
typedef std::map<std::string, mpt::Library> TLibraryMap;
|
||||
TLibraryMap m_Libraries;
|
||||
|
||||
bool m_BindFailed;
|
||||
|
||||
protected:
|
||||
|
||||
ComponentLibrary(ComponentType type);
|
||||
|
||||
public:
|
||||
|
||||
virtual ~ComponentLibrary();
|
||||
|
||||
protected:
|
||||
|
||||
bool AddLibrary(const std::string &libName, const mpt::LibraryPath &libPath);
|
||||
void ClearLibraries();
|
||||
void SetBindFailed();
|
||||
void ClearBindFailed();
|
||||
bool HasBindFailed() const;
|
||||
|
||||
public:
|
||||
|
||||
virtual mpt::Library GetLibrary(const std::string &libName) const;
|
||||
|
||||
template <typename Tfunc>
|
||||
bool Bind(Tfunc * & f, const std::string &libName, const std::string &symbol) const
|
||||
{
|
||||
return GetLibrary(libName).Bind(f, symbol);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
bool DoInitialize() override = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#define MPT_COMPONENT_BIND(libName, func) MPT_DO { if(!Bind( func , libName , #func )) { SetBindFailed(); } } MPT_WHILE_0
|
||||
#define MPT_COMPONENT_BIND_OPTIONAL(libName, func) Bind( func , libName , #func )
|
||||
#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
|
||||
{
|
||||
private:
|
||||
mpt::PathString m_BaseName;
|
||||
public:
|
||||
ComponentSystemDLL(const mpt::PathString &baseName)
|
||||
: ComponentLibrary(ComponentTypeSystem)
|
||||
, m_BaseName(baseName)
|
||||
{
|
||||
return;
|
||||
}
|
||||
bool DoInitialize() override
|
||||
{
|
||||
AddLibrary(m_BaseName.ToUTF8(), mpt::LibraryPath::System(m_BaseName));
|
||||
return GetLibrary(m_BaseName.ToUTF8()).IsValid();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class ComponentBundledDLL : public ComponentLibrary
|
||||
{
|
||||
private:
|
||||
mpt::PathString m_FullName;
|
||||
public:
|
||||
ComponentBundledDLL(const mpt::PathString &fullName)
|
||||
: ComponentLibrary(ComponentTypeBundled)
|
||||
, m_FullName(fullName)
|
||||
{
|
||||
return;
|
||||
}
|
||||
bool DoInitialize() override
|
||||
{
|
||||
AddLibrary(m_FullName.ToUTF8(), mpt::LibraryPath::AppFullName(m_FullName));
|
||||
return GetLibrary(m_FullName.ToUTF8()).IsValid();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif // MPT_ENABLE_DYNBIND
|
||||
|
||||
|
||||
#if MPT_COMPONENT_MANAGER
|
||||
|
||||
|
||||
class ComponentManager;
|
||||
|
||||
typedef std::shared_ptr<IComponent> (*ComponentFactoryMethod)(ComponentManager &componentManager);
|
||||
|
||||
|
||||
class IComponentFactory
|
||||
{
|
||||
protected:
|
||||
IComponentFactory() = default;
|
||||
public:
|
||||
virtual ~IComponentFactory() = default;
|
||||
public:
|
||||
virtual std::string GetID() const = 0;
|
||||
virtual std::string GetSettingsKey() const = 0;
|
||||
virtual std::shared_ptr<IComponent> Construct(ComponentManager &componentManager) const = 0;
|
||||
virtual ComponentFactoryMethod GetStaticConstructor() const = 0;
|
||||
};
|
||||
|
||||
|
||||
class ComponentFactoryBase
|
||||
: public IComponentFactory
|
||||
{
|
||||
private:
|
||||
std::string m_ID;
|
||||
std::string m_SettingsKey;
|
||||
protected:
|
||||
ComponentFactoryBase(const std::string &id, const std::string &settingsKey);
|
||||
void PreConstruct() const;
|
||||
void Initialize(ComponentManager &componentManager, std::shared_ptr<IComponent> component) const;
|
||||
public:
|
||||
virtual ~ComponentFactoryBase();
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
class ComponentFactory
|
||||
: public ComponentFactoryBase
|
||||
{
|
||||
public:
|
||||
ComponentFactory()
|
||||
: ComponentFactoryBase(T::g_ID, T::g_SettingsKey)
|
||||
{
|
||||
return;
|
||||
}
|
||||
public:
|
||||
std::shared_ptr<IComponent> Construct(ComponentManager &componentManager) const override
|
||||
{
|
||||
PreConstruct();
|
||||
std::shared_ptr<IComponent> component = std::make_shared<T>();
|
||||
Initialize(componentManager, component);
|
||||
return component;
|
||||
}
|
||||
static std::shared_ptr<IComponent> StaticConstruct(ComponentManager &componentManager)
|
||||
{
|
||||
return ComponentFactory().Construct(componentManager);
|
||||
}
|
||||
virtual ComponentFactoryMethod GetStaticConstructor() const override
|
||||
{
|
||||
return &StaticConstruct;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class IComponentManagerSettings
|
||||
{
|
||||
public:
|
||||
virtual bool LoadOnStartup() const = 0;
|
||||
virtual bool KeepLoaded() const = 0;
|
||||
virtual bool IsBlocked(const std::string &key) const = 0;
|
||||
virtual mpt::PathString Path() const = 0;
|
||||
protected:
|
||||
virtual ~IComponentManagerSettings() = default;
|
||||
};
|
||||
|
||||
|
||||
class ComponentManagerSettingsDefault
|
||||
: public IComponentManagerSettings
|
||||
{
|
||||
public:
|
||||
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(); }
|
||||
};
|
||||
|
||||
|
||||
enum ComponentState
|
||||
{
|
||||
ComponentStateUnregistered,
|
||||
ComponentStateBlocked,
|
||||
ComponentStateUnintialized,
|
||||
ComponentStateUnavailable,
|
||||
ComponentStateAvailable,
|
||||
};
|
||||
|
||||
|
||||
struct ComponentInfo
|
||||
{
|
||||
std::string name;
|
||||
ComponentState state;
|
||||
std::string settingsKey;
|
||||
ComponentType type;
|
||||
};
|
||||
|
||||
|
||||
class ComponentManager
|
||||
{
|
||||
friend class ComponentFactoryBase;
|
||||
public:
|
||||
static void Init(const IComponentManagerSettings &settings);
|
||||
static void Release();
|
||||
static std::shared_ptr<ComponentManager> Instance();
|
||||
private:
|
||||
ComponentManager(const IComponentManagerSettings &settings);
|
||||
private:
|
||||
struct RegisteredComponent
|
||||
{
|
||||
std::string settingsKey;
|
||||
ComponentFactoryMethod factoryMethod;
|
||||
std::shared_ptr<IComponent> instance;
|
||||
std::weak_ptr<IComponent> weakInstance;
|
||||
};
|
||||
typedef std::map<std::string, RegisteredComponent> TComponentMap;
|
||||
const IComponentManagerSettings &m_Settings;
|
||||
TComponentMap m_Components;
|
||||
private:
|
||||
bool IsComponentBlocked(const std::string &settingsKey) const;
|
||||
void InitializeComponent(std::shared_ptr<IComponent> component) const;
|
||||
public:
|
||||
void Register(const IComponentFactory &componentFactory);
|
||||
void Startup();
|
||||
std::shared_ptr<const IComponent> GetComponent(const IComponentFactory &componentFactory);
|
||||
std::shared_ptr<const IComponent> ReloadComponent(const IComponentFactory &componentFactory);
|
||||
std::vector<std::string> GetRegisteredComponents() const;
|
||||
ComponentInfo GetComponentInfo(std::string name) const;
|
||||
mpt::PathString GetComponentPath() const;
|
||||
};
|
||||
|
||||
|
||||
struct ComponentListEntry
|
||||
{
|
||||
ComponentListEntry *next;
|
||||
void (*reg)(ComponentManager &componentManager);
|
||||
};
|
||||
|
||||
bool ComponentListPush(ComponentListEntry *entry);
|
||||
|
||||
#define MPT_DECLARE_COMPONENT_MEMBERS public: static const char * const g_ID; static const char * const g_SettingsKey;
|
||||
|
||||
#define MPT_REGISTERED_COMPONENT(name, settingsKey) \
|
||||
static void RegisterComponent ## name (ComponentManager &componentManager) \
|
||||
{ \
|
||||
componentManager.Register(ComponentFactory< name >()); \
|
||||
} \
|
||||
static ComponentListEntry Component ## name ## ListEntry = { nullptr, & RegisterComponent ## name }; \
|
||||
bool Component ## name ## Registered = ComponentListPush(& Component ## name ## ListEntry ); \
|
||||
const char * const name :: g_ID = #name ; \
|
||||
const char * const name :: g_SettingsKey = settingsKey ; \
|
||||
/**/
|
||||
|
||||
|
||||
template <typename type>
|
||||
std::shared_ptr<const type> GetComponent()
|
||||
{
|
||||
return std::dynamic_pointer_cast<const type>(ComponentManager::Instance()->GetComponent(ComponentFactory<type>()));
|
||||
}
|
||||
|
||||
|
||||
template <typename type>
|
||||
std::shared_ptr<const type> ReloadComponent()
|
||||
{
|
||||
return std::dynamic_pointer_cast<const type>(ComponentManager::Instance()->ReloadComponent(ComponentFactory<type>()));
|
||||
}
|
||||
|
||||
|
||||
inline mpt::PathString GetComponentPath()
|
||||
{
|
||||
return ComponentManager::Instance()->GetComponentPath();
|
||||
}
|
||||
|
||||
|
||||
#else // !MPT_COMPONENT_MANAGER
|
||||
|
||||
|
||||
#define MPT_DECLARE_COMPONENT_MEMBERS
|
||||
|
||||
#define MPT_REGISTERED_COMPONENT(name, settingsKey)
|
||||
|
||||
|
||||
template <typename type>
|
||||
std::shared_ptr<const type> GetComponent()
|
||||
{
|
||||
static std::weak_ptr<type> cache;
|
||||
static mpt::mutex m;
|
||||
mpt::lock_guard<mpt::mutex> l(m);
|
||||
std::shared_ptr<type> component = cache.lock();
|
||||
if(!component)
|
||||
{
|
||||
component = std::make_shared<type>();
|
||||
component->Initialize();
|
||||
cache = component;
|
||||
}
|
||||
return component;
|
||||
}
|
||||
|
||||
|
||||
inline mpt::PathString GetComponentPath()
|
||||
{
|
||||
return mpt::PathString();
|
||||
}
|
||||
|
||||
|
||||
#endif // MPT_COMPONENT_MANAGER
|
||||
|
||||
|
||||
// Simple wrapper around std::shared_ptr<ComponentType> which automatically
|
||||
// gets a reference to the component (or constructs it) on initialization.
|
||||
template <typename T>
|
||||
class ComponentHandle
|
||||
{
|
||||
private:
|
||||
std::shared_ptr<const T> component;
|
||||
public:
|
||||
ComponentHandle()
|
||||
: component(GetComponent<T>())
|
||||
{
|
||||
return;
|
||||
}
|
||||
~ComponentHandle()
|
||||
{
|
||||
return;
|
||||
}
|
||||
bool IsAvailable() const
|
||||
{
|
||||
return component && component->IsAvailable();
|
||||
}
|
||||
const T *get() const
|
||||
{
|
||||
return component.get();
|
||||
}
|
||||
const T &operator*() const
|
||||
{
|
||||
return *component;
|
||||
}
|
||||
const T *operator->() const
|
||||
{
|
||||
return &*component;
|
||||
}
|
||||
#if MPT_COMPONENT_MANAGER
|
||||
void Reload()
|
||||
{
|
||||
component = nullptr;
|
||||
component = ReloadComponent<T>();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
bool IsComponentAvailable(const ComponentHandle<T> &handle)
|
||||
{
|
||||
return handle.IsAvailable();
|
||||
}
|
||||
|
||||
|
||||
#endif // MPT_ENABLE_COMPONENTS
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
File diff suppressed because it is too large
Load diff
|
@ -1,153 +0,0 @@
|
|||
/*
|
||||
* FileReader.cpp
|
||||
* --------------
|
||||
* Purpose: A basic class for transparent reading of memory-based files.
|
||||
* 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 "FileReader.h"
|
||||
|
||||
#if defined(MPT_ENABLE_TEMPFILE) && MPT_OS_WINDOWS
|
||||
#include <windows.h>
|
||||
#include "mptFileIO.h"
|
||||
#include <stdexcept>
|
||||
#endif // MPT_ENABLE_TEMPFILE && MPT_OS_WINDOWS
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
#if defined(MPT_ENABLE_TEMPFILE) && MPT_OS_WINDOWS
|
||||
|
||||
|
||||
OnDiskFileWrapper::OnDiskFileWrapper(FileReader &file, const mpt::PathString &fileNameExtension)
|
||||
: m_IsTempFile(false)
|
||||
{
|
||||
try
|
||||
{
|
||||
file.Rewind();
|
||||
if(file.GetFileName().empty())
|
||||
{
|
||||
const mpt::PathString tempName = mpt::CreateTempFileName(P_("OpenMPT"), fileNameExtension);
|
||||
|
||||
#if MPT_OS_WINDOWS && MPT_OS_WINDOWS_WINRT
|
||||
#if (_WIN32_WINNT < 0x0602)
|
||||
#define MPT_ONDISKFILEWRAPPER_NO_CREATEFILE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef MPT_ONDISKFILEWRAPPER_NO_CREATEFILE
|
||||
|
||||
mpt::ofstream f(tempName, std::ios::binary);
|
||||
if(!f)
|
||||
{
|
||||
throw std::runtime_error("");
|
||||
}
|
||||
while(!file.EndOfFile())
|
||||
{
|
||||
FileReader::PinnedRawDataView view = file.ReadPinnedRawDataView(mpt::IO::BUFFERSIZE_NORMAL);
|
||||
std::size_t towrite = view.size();
|
||||
std::size_t written = 0;
|
||||
do
|
||||
{
|
||||
std::size_t chunkSize = mpt::saturate_cast<std::size_t>(towrite);
|
||||
bool chunkOk = false;
|
||||
chunkOk = mpt::IO::WriteRaw(f, mpt::const_byte_span(view.data() + written, chunkSize));
|
||||
if(!chunkOk)
|
||||
{
|
||||
throw std::runtime_error("");
|
||||
}
|
||||
towrite -= chunkSize;
|
||||
written += chunkSize;
|
||||
} while(towrite > 0);
|
||||
}
|
||||
f.close();
|
||||
|
||||
#else // !MPT_ONDISKFILEWRAPPER_NO_CREATEFILE
|
||||
|
||||
HANDLE hFile = NULL;
|
||||
#if MPT_OS_WINDOWS_WINRT
|
||||
hFile = CreateFile2(tempName.AsNative().c_str(), GENERIC_WRITE, FILE_SHARE_READ, CREATE_ALWAYS, NULL);
|
||||
#else
|
||||
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)
|
||||
{
|
||||
throw std::runtime_error("");
|
||||
}
|
||||
while(!file.EndOfFile())
|
||||
{
|
||||
FileReader::PinnedRawDataView view = file.ReadPinnedRawDataView(mpt::IO::BUFFERSIZE_NORMAL);
|
||||
std::size_t towrite = view.size();
|
||||
std::size_t written = 0;
|
||||
do
|
||||
{
|
||||
DWORD chunkSize = mpt::saturate_cast<DWORD>(towrite);
|
||||
DWORD chunkDone = 0;
|
||||
WriteFile(hFile, view.data() + written, chunkSize, &chunkDone, NULL);
|
||||
if(chunkDone != chunkSize)
|
||||
{
|
||||
CloseHandle(hFile);
|
||||
hFile = NULL;
|
||||
throw std::runtime_error("");
|
||||
}
|
||||
towrite -= chunkDone;
|
||||
written += chunkDone;
|
||||
} while(towrite > 0);
|
||||
}
|
||||
CloseHandle(hFile);
|
||||
hFile = NULL;
|
||||
|
||||
#endif // MPT_ONDISKFILEWRAPPER_NO_CREATEFILE
|
||||
|
||||
m_Filename = tempName;
|
||||
m_IsTempFile = true;
|
||||
} else
|
||||
{
|
||||
m_Filename = file.GetFileName();
|
||||
}
|
||||
} catch (const std::runtime_error &)
|
||||
{
|
||||
m_IsTempFile = false;
|
||||
m_Filename = mpt::PathString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
OnDiskFileWrapper::~OnDiskFileWrapper()
|
||||
{
|
||||
if(m_IsTempFile)
|
||||
{
|
||||
DeleteFile(m_Filename.AsNative().c_str());
|
||||
m_IsTempFile = false;
|
||||
}
|
||||
m_Filename = mpt::PathString();
|
||||
}
|
||||
|
||||
|
||||
bool OnDiskFileWrapper::IsValid() const
|
||||
{
|
||||
return !m_Filename.empty();
|
||||
}
|
||||
|
||||
|
||||
mpt::PathString OnDiskFileWrapper::GetFilename() const
|
||||
{
|
||||
return m_Filename;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
|
||||
MPT_MSVC_WORKAROUND_LNK4221(FileReader)
|
||||
|
||||
|
||||
#endif // MPT_ENABLE_TEMPFILE && MPT_OS_WINDOWS
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
File diff suppressed because it is too large
Load diff
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
* FileReaderFwd.h
|
||||
* ---------------
|
||||
* Purpose: Forward declaration for class FileReader.
|
||||
* 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"
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
class FileReaderTraitsMemory;
|
||||
|
||||
class FileReaderTraitsStdStream;
|
||||
|
||||
using FileReaderTraitsDefault = FileReaderTraitsStdStream;
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename Ttraits>
|
||||
class FileReader;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
using FileReader = detail::FileReader<FileReaderTraitsDefault>;
|
||||
|
||||
using MemoryFileReader = detail::FileReader<FileReaderTraitsMemory>;
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
||||
|
|
@ -1,415 +0,0 @@
|
|||
/*
|
||||
* FlagSet.h
|
||||
* ---------
|
||||
* Purpose: A flexible and typesafe flag set class.
|
||||
* Notes : Originally based on http://stackoverflow.com/questions/4226960/type-safer-bitflags-in-c .
|
||||
* Rewritten to be standard-conforming.
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
// Be aware of the required size when specializing this.
|
||||
// We cannot assert the minimum size because some compilers always allocate an 'int',
|
||||
// even for enums that would fit in smaller integral types.
|
||||
template <typename Tenum>
|
||||
struct enum_traits
|
||||
{
|
||||
using store_type = typename std::make_unsigned<Tenum>::type;
|
||||
};
|
||||
|
||||
|
||||
// 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:
|
||||
using enum_type = enum_t;
|
||||
using value_type = enum_value_type;
|
||||
using store_type = typename enum_traits<enum_t>::store_type;
|
||||
private:
|
||||
store_type bits;
|
||||
public:
|
||||
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) 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) 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 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 noexcept { return enum_value_type(~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) 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) 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) 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) 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) 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) 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) 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; }
|
||||
|
||||
};
|
||||
|
||||
|
||||
// Type-safe enum wrapper that allows type-safe bitwise testing.
|
||||
template <typename enum_t>
|
||||
class Enum
|
||||
{
|
||||
public:
|
||||
using self_type = Enum;
|
||||
using enum_type = enum_t;
|
||||
using value_type = enum_value_type<enum_t>;
|
||||
using store_type = typename value_type::store_type;
|
||||
private:
|
||||
enum_type value;
|
||||
public:
|
||||
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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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:
|
||||
using self_type = FlagSet;
|
||||
using enum_type = enum_t;
|
||||
using value_type = enum_value_type<enum_t>;
|
||||
using store_type = store_t;
|
||||
|
||||
private:
|
||||
|
||||
// support truncated store_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) 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() 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) noexcept : bits_(store_from_value(value_type(flags)))
|
||||
{
|
||||
}
|
||||
|
||||
MPT_CONSTEXPR11_FUN FlagSet(enum_type flag) noexcept : bits_(store_from_value(value_type(flag)))
|
||||
{
|
||||
}
|
||||
|
||||
explicit MPT_CONSTEXPR11_FUN FlagSet(store_type flags) noexcept : bits_(store_from_value(value_type::from_bits(flags)))
|
||||
{
|
||||
}
|
||||
|
||||
MPT_CONSTEXPR11_FUN explicit operator bool () const noexcept
|
||||
{
|
||||
return load();
|
||||
}
|
||||
MPT_CONSTEXPR11_FUN explicit operator store_type () const noexcept
|
||||
{
|
||||
return load().as_bits();
|
||||
}
|
||||
|
||||
MPT_CONSTEXPR11_FUN value_type value() const noexcept
|
||||
{
|
||||
return load();
|
||||
}
|
||||
|
||||
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 noexcept
|
||||
{
|
||||
return test(flags);
|
||||
}
|
||||
|
||||
// String representation of flag set
|
||||
std::string to_string() const noexcept
|
||||
{
|
||||
std::string str(size_bits(), '0');
|
||||
|
||||
for(size_t x = 0; x < size_bits(); ++x)
|
||||
{
|
||||
str[size_bits() - x - 1] = (load() & (1 << x) ? '1' : '0');
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
// Set one or more 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) noexcept
|
||||
{
|
||||
return store((val ? (load() | flags) : (load() & ~flags)));
|
||||
}
|
||||
|
||||
// Clear or flags.
|
||||
MPT_CONSTEXPR14_FUN FlagSet &reset() noexcept
|
||||
{
|
||||
return store(value_type());
|
||||
}
|
||||
|
||||
// Clear one or more flags.
|
||||
MPT_CONSTEXPR14_FUN FlagSet &reset(value_type flags) noexcept
|
||||
{
|
||||
return store(load() & ~flags);
|
||||
}
|
||||
|
||||
// Toggle all flags.
|
||||
MPT_CONSTEXPR14_FUN FlagSet &flip() noexcept
|
||||
{
|
||||
return store(~load());
|
||||
}
|
||||
|
||||
// Toggle one or more 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 noexcept
|
||||
{
|
||||
return sizeof(store_type);
|
||||
}
|
||||
|
||||
// Returns the size of the flag set in bits
|
||||
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 noexcept
|
||||
{
|
||||
return (load() & flags);
|
||||
}
|
||||
|
||||
// Test if all specified flags are set.
|
||||
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 noexcept
|
||||
{
|
||||
return (load() & ~flags);
|
||||
}
|
||||
|
||||
// Test if any flag is set.
|
||||
MPT_CONSTEXPR11_FUN bool any() const noexcept
|
||||
{
|
||||
return load();
|
||||
}
|
||||
|
||||
// Test if no flags are set.
|
||||
MPT_CONSTEXPR11_FUN bool none() const noexcept
|
||||
{
|
||||
return !load();
|
||||
}
|
||||
|
||||
MPT_CONSTEXPR11_FUN store_type GetRaw() const noexcept
|
||||
{
|
||||
return bits_;
|
||||
}
|
||||
|
||||
MPT_CONSTEXPR14_FUN FlagSet & SetRaw(store_type flags) noexcept
|
||||
{
|
||||
bits_ = flags;
|
||||
return *this;
|
||||
}
|
||||
|
||||
MPT_CONSTEXPR14_FUN FlagSet &operator = (value_type flags) noexcept
|
||||
{
|
||||
return store(flags);
|
||||
}
|
||||
|
||||
MPT_CONSTEXPR14_FUN FlagSet &operator = (enum_type flag) noexcept
|
||||
{
|
||||
return store(flag);
|
||||
}
|
||||
|
||||
MPT_CONSTEXPR14_FUN FlagSet &operator = (FlagSet flags) noexcept
|
||||
{
|
||||
return store(flags.load());
|
||||
}
|
||||
|
||||
MPT_CONSTEXPR14_FUN FlagSet &operator &= (value_type flags) noexcept
|
||||
{
|
||||
return store(load() & flags);
|
||||
}
|
||||
|
||||
MPT_CONSTEXPR14_FUN FlagSet &operator |= (value_type flags) noexcept
|
||||
{
|
||||
return store(load() | 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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
|
||||
#define DECLARE_FLAGSET MPT_DECLARE_ENUM
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,433 +0,0 @@
|
|||
/*
|
||||
* Logging.cpp
|
||||
* -----------
|
||||
* Purpose: General logging
|
||||
* 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 "Logging.h"
|
||||
#include "mptFileIO.h"
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
#include <atomic>
|
||||
#endif
|
||||
#include "version.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <cstdarg>
|
||||
#include <cstring>
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
namespace log
|
||||
{
|
||||
|
||||
|
||||
#ifndef NO_LOGGING
|
||||
|
||||
|
||||
|
||||
#if !defined(MPT_LOG_GLOBAL_LEVEL_STATIC)
|
||||
#if defined(MPT_LOG_GLOBAL_LEVEL)
|
||||
int GlobalLogLevel = static_cast<int>(MPT_LOG_GLOBAL_LEVEL);
|
||||
#else
|
||||
int GlobalLogLevel = static_cast<int>(LogDebug);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER) && !defined(MPT_LOG_IS_DISABLED)
|
||||
|
||||
bool FileEnabled = false;
|
||||
bool DebuggerEnabled = true;
|
||||
bool ConsoleEnabled = false;
|
||||
|
||||
static char g_FacilitySolo[1024] = {0};
|
||||
static char g_FacilityBlocked[1024] = {0};
|
||||
|
||||
void SetFacilities(const std::string &solo, const std::string &blocked)
|
||||
{
|
||||
std::strcpy(g_FacilitySolo, solo.c_str());
|
||||
std::strcpy(g_FacilityBlocked, blocked.c_str());
|
||||
}
|
||||
|
||||
bool IsFacilityActive(const char *facility)
|
||||
{
|
||||
if(facility)
|
||||
{
|
||||
if(std::strlen(g_FacilitySolo) > 0)
|
||||
{
|
||||
if(std::strcmp(facility, g_FacilitySolo) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(std::strlen(g_FacilityBlocked) > 0)
|
||||
{
|
||||
if(std::strcmp(facility, g_FacilitySolo) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
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(loc);
|
||||
MPT_UNREFERENCED_PARAMETER(level);
|
||||
MPT_UNREFERENCED_PARAMETER(facility);
|
||||
MPT_UNREFERENCED_PARAMETER(text);
|
||||
#else // !MPT_LOG_IS_DISABLED
|
||||
MPT_MAYBE_CONSTANT_IF(mpt::log::GlobalLogLevel < level)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
if(!IsFacilityActive(facility))
|
||||
{
|
||||
return;
|
||||
}
|
||||
#else // !MODPLUG_TRACKER
|
||||
MPT_UNREFERENCED_PARAMETER(facility);
|
||||
#endif // MODPLUG_TRACKER
|
||||
// remove eol if already present and add log level prefix
|
||||
const mpt::ustring message = LogLevelToString(level) + U_(": ") + mpt::String::RTrim(text, U_("\r\n"));
|
||||
const mpt::ustring file = mpt::ToUnicode(mpt::CharsetSource, loc.file_name() ? loc.file_name() : "");
|
||||
const mpt::ustring function = mpt::ToUnicode(mpt::CharsetSource, 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;
|
||||
uint64 cur = mpt::Date::ANSI::Now();
|
||||
uint64 diff = cur/10000 - s_lastlogtime;
|
||||
s_lastlogtime = cur/10000;
|
||||
#else
|
||||
uint64 cur = 0;
|
||||
uint64 diff = 0;
|
||||
#endif
|
||||
if(mpt::log::FileEnabled)
|
||||
{
|
||||
static mpt::ofstream s_logfile;
|
||||
if(!s_logfile)
|
||||
{
|
||||
s_logfile.open(P_("mptrack.log"), std::ios::app);
|
||||
}
|
||||
if(s_logfile)
|
||||
{
|
||||
mpt::IO::WriteText(s_logfile, mpt::ToCharset(mpt::CharsetLogfile, 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
|
||||
)));
|
||||
mpt::IO::Flush(s_logfile);
|
||||
}
|
||||
}
|
||||
if(mpt::log::DebuggerEnabled)
|
||||
{
|
||||
OutputDebugStringW(mpt::ToWide(mpt::format(U_("%1(%2): +%3 %4 [%5]\n"))
|
||||
( file
|
||||
, line
|
||||
, mpt::ufmt::right(6, mpt::ufmt::dec(diff))
|
||||
, message
|
||||
, function
|
||||
)).c_str());
|
||||
}
|
||||
if(mpt::log::ConsoleEnabled)
|
||||
{
|
||||
static bool consoleInited = false;
|
||||
if(!consoleInited)
|
||||
{
|
||||
AllocConsole();
|
||||
consoleInited = true;
|
||||
}
|
||||
std::wstring consoletext = mpt::ToWide(message) + L"\r\n";
|
||||
DWORD dummy = 0;
|
||||
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
|
||||
<< "NativeSupport: "
|
||||
<< mpt::ToCharset(mpt::CharsetStdIO, file) << "(" << mpt::ToCharset(mpt::CharsetStdIO, line) << ")" << ": "
|
||||
<< mpt::ToCharset(mpt::CharsetStdIO, message)
|
||||
<< " [" << mpt::ToCharset(mpt::CharsetStdIO, function) << "]"
|
||||
<< std::endl;
|
||||
#else // !MODPLUG_TRACKER
|
||||
std::clog
|
||||
<< "libopenmpt: "
|
||||
<< mpt::ToCharset(mpt::CharsetStdIO, file) << "(" << mpt::ToCharset(mpt::CharsetStdIO, line) << ")" << ": "
|
||||
<< mpt::ToCharset(mpt::CharsetStdIO, message)
|
||||
<< " [" << mpt::ToCharset(mpt::CharsetStdIO, function) << "]"
|
||||
<< std::endl;
|
||||
#endif // MODPLUG_TRACKER
|
||||
#endif // MPT_LOG_IS_DISABLED
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // !NO_LOGGING
|
||||
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
|
||||
namespace Trace {
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
// Debugging functionality will use simple globals.
|
||||
|
||||
std::atomic<bool> g_Enabled = ATOMIC_VAR_INIT(false);
|
||||
|
||||
static bool g_Sealed = false;
|
||||
|
||||
struct Entry {
|
||||
uint32 Index;
|
||||
uint32 ThreadId;
|
||||
uint64 Timestamp;
|
||||
const char * Function;
|
||||
const char * File;
|
||||
int Line;
|
||||
Direction Direction;
|
||||
};
|
||||
|
||||
static MPT_FORCEINLINE bool operator < (const Entry &a, const Entry &b) noexcept
|
||||
{
|
||||
/*
|
||||
return false
|
||||
|| (a.Timestamp < b.Timestamp)
|
||||
|| (a.ThreadID < b.ThreadID)
|
||||
|| (a.File < b.File)
|
||||
|| (a.Line < b.Line)
|
||||
|| (a.Function < b.Function)
|
||||
;
|
||||
*/
|
||||
return false
|
||||
|| (a.Index < b.Index)
|
||||
;
|
||||
}
|
||||
|
||||
static std::vector<mpt::log::Trace::Entry> Entries;
|
||||
|
||||
static std::atomic<uint32> NextIndex(0);
|
||||
|
||||
static uint32 ThreadIdGUI = 0;
|
||||
static uint32 ThreadIdAudio = 0;
|
||||
static uint32 ThreadIdNotify = 0;
|
||||
static uint32 ThreadIdWatchdir = 0;
|
||||
|
||||
void Enable(std::size_t numEntries)
|
||||
{
|
||||
if(g_Sealed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Entries.clear();
|
||||
Entries.resize(numEntries);
|
||||
NextIndex.store(0);
|
||||
g_Enabled = (numEntries > 0);
|
||||
}
|
||||
|
||||
void Disable()
|
||||
{
|
||||
if(g_Sealed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
g_Enabled = false;
|
||||
}
|
||||
|
||||
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;
|
||||
QueryPerformanceCounter(&time);
|
||||
const uint64 timestamp = time.QuadPart;
|
||||
#else
|
||||
FILETIME time = FILETIME();
|
||||
GetSystemTimeAsFileTime(&time);
|
||||
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 % numEntries];
|
||||
entry.Index = index;
|
||||
entry.ThreadId = threadid;
|
||||
entry.Timestamp = timestamp;
|
||||
entry.Function = loc.function_name();
|
||||
entry.File = loc.file_name();
|
||||
entry.Line = loc.line();
|
||||
entry.Direction = direction;
|
||||
}
|
||||
|
||||
void Seal()
|
||||
{
|
||||
if(!g_Enabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
g_Enabled = false;
|
||||
g_Sealed = true;
|
||||
uint32 count = NextIndex.fetch_add(0);
|
||||
if(count < Entries.size())
|
||||
{
|
||||
Entries.resize(count);
|
||||
}
|
||||
}
|
||||
|
||||
bool Dump(const mpt::PathString &filename)
|
||||
{
|
||||
if(!g_Sealed)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
LARGE_INTEGER qpcNow;
|
||||
qpcNow.QuadPart = 0;
|
||||
QueryPerformanceCounter(&qpcNow);
|
||||
uint64 ftNow = mpt::Date::ANSI::Now();
|
||||
|
||||
// sort according to index in case of overflows
|
||||
std::stable_sort(Entries.begin(), Entries.end());
|
||||
|
||||
mpt::ofstream f(filename);
|
||||
|
||||
f << "Build: OpenMPT " << mpt::ToCharset(mpt::CharsetLogfile, Build::GetVersionStringExtended()) << std::endl;
|
||||
|
||||
bool qpcValid = false;
|
||||
|
||||
LARGE_INTEGER qpcFreq;
|
||||
qpcFreq.QuadPart = 0;
|
||||
QueryPerformanceFrequency(&qpcFreq);
|
||||
if(qpcFreq.QuadPart > 0)
|
||||
{
|
||||
qpcValid = true;
|
||||
}
|
||||
|
||||
f << "Dump: " << mpt::ToCharset(mpt::CharsetLogfile, mpt::Date::ANSI::ToUString(ftNow)) << std::endl;
|
||||
f << "Captured events: " << Entries.size() << std::endl;
|
||||
if(qpcValid && (Entries.size() > 0))
|
||||
{
|
||||
double period = static_cast<double>(Entries[Entries.size() - 1].Timestamp - Entries[0].Timestamp) / static_cast<double>(qpcFreq.QuadPart);
|
||||
double eventsPerSecond = Entries.size() / period;
|
||||
f << "Period [s]: " << mpt::fmt::fix(period) << std::endl;
|
||||
f << "Events/second: " << mpt::fmt::fix(eventsPerSecond) << std::endl;
|
||||
}
|
||||
|
||||
for(auto &entry : Entries)
|
||||
{
|
||||
if(!entry.Function) entry.Function = "";
|
||||
if(!entry.File) entry.File = "";
|
||||
std::string time;
|
||||
if(qpcValid)
|
||||
{
|
||||
time = mpt::ToCharset(mpt::CharsetLogfile, 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));
|
||||
}
|
||||
f << time;
|
||||
if(entry.ThreadId == ThreadIdGUI)
|
||||
{
|
||||
f << " -----GUI ";
|
||||
} else if(entry.ThreadId == ThreadIdAudio)
|
||||
{
|
||||
f << " ---Audio ";
|
||||
} else if(entry.ThreadId == ThreadIdNotify)
|
||||
{
|
||||
f << " --Notify ";
|
||||
} else if(entry.ThreadId == ThreadIdWatchdir)
|
||||
{
|
||||
f << " WatchDir ";
|
||||
} else
|
||||
{
|
||||
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;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SetThreadId(mpt::log::Trace::ThreadKind kind, uint32 id)
|
||||
{
|
||||
if(id == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
switch(kind)
|
||||
{
|
||||
case ThreadKindGUI:
|
||||
ThreadIdGUI = id;
|
||||
break;
|
||||
case ThreadKindAudio:
|
||||
ThreadIdAudio = id;
|
||||
break;
|
||||
case ThreadKindNotify:
|
||||
ThreadIdNotify = id;
|
||||
break;
|
||||
case ThreadKindWatchdir:
|
||||
ThreadIdWatchdir = id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 GetThreadId(mpt::log::Trace::ThreadKind kind)
|
||||
{
|
||||
uint32 result = 0;
|
||||
switch(kind)
|
||||
{
|
||||
case ThreadKindGUI:
|
||||
result = ThreadIdGUI;
|
||||
break;
|
||||
case ThreadKindAudio:
|
||||
result = ThreadIdAudio;
|
||||
break;
|
||||
case ThreadKindNotify:
|
||||
result = ThreadIdNotify;
|
||||
break;
|
||||
case ThreadKindWatchdir:
|
||||
result = ThreadIdWatchdir;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
} // namespace Trace
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
} // namespace log
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,254 +0,0 @@
|
|||
/*
|
||||
* Logging.h
|
||||
* ---------
|
||||
* Purpose: General logging
|
||||
* 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"
|
||||
|
||||
#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
|
||||
#include <atomic>
|
||||
#endif
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
/*
|
||||
|
||||
|
||||
Build time logging configuration (in BuildSettings.h):
|
||||
|
||||
* #define NO_LOGGING
|
||||
Disables all logging completely.
|
||||
MPT_LOG calls are not even compiled but instead completely removed via the
|
||||
preprocessor.
|
||||
|
||||
* #define MPT_LOG_GLOBAL_LEVEL_STATIC
|
||||
#define MPT_LOG_GLOBAL_LEVEL #
|
||||
Define the former (to anything) and the latter (to one of the log levels
|
||||
below) in order to statically select the verbosity of logging at build time.
|
||||
MPT_LOG calls that exceed the specified logging level will get dead-code
|
||||
eliminated at compile time.
|
||||
This especially means that, when setting MPT_LOG_GLOBAL_LEVEL to 0, no
|
||||
MPT_LOG call (with a constant level parameter) remains in the resulting
|
||||
binary, however, they still do get parsed and properly type checked by the
|
||||
compiler.
|
||||
|
||||
|
||||
Logging:
|
||||
|
||||
If the context is related to a particular CSoundfile instance, use
|
||||
CSoundfile::AddToLog.
|
||||
|
||||
Logging a simple message:
|
||||
MPT_LOG(LogWarning, "sounddev", "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(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
|
||||
single conditional in case the verbosity does not require logging the respective
|
||||
message. Even the expression "text" is not evaluated.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
enum LogLevel
|
||||
{
|
||||
LogDebug = 5,
|
||||
LogInformation = 4,
|
||||
LogNotification = 3,
|
||||
LogWarning = 2,
|
||||
LogError = 1
|
||||
};
|
||||
|
||||
|
||||
inline mpt::ustring LogLevelToString(LogLevel level)
|
||||
{
|
||||
switch(level)
|
||||
{
|
||||
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 U_("unknown");
|
||||
}
|
||||
|
||||
|
||||
class ILog
|
||||
{
|
||||
protected:
|
||||
virtual ~ILog() { }
|
||||
public:
|
||||
virtual void AddToLog(LogLevel level, const mpt::ustring &text) const = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
namespace log
|
||||
{
|
||||
|
||||
|
||||
|
||||
#ifndef NO_LOGGING
|
||||
|
||||
|
||||
#if defined(MPT_LOG_GLOBAL_LEVEL_STATIC)
|
||||
#if (MPT_LOG_GLOBAL_LEVEL <= 0)
|
||||
// Logging framework is enabled (!NO_LOGGING) but all logging has beeen statically disabled.
|
||||
// All logging code gets compiled and immediately dead-code eliminated.
|
||||
#define MPT_LOG_IS_DISABLED
|
||||
#endif
|
||||
static constexpr int GlobalLogLevel = MPT_LOG_GLOBAL_LEVEL ;
|
||||
#else
|
||||
extern int GlobalLogLevel;
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER) && !defined(MPT_LOG_IS_DISABLED)
|
||||
extern bool FileEnabled;
|
||||
extern bool DebuggerEnabled;
|
||||
extern bool ConsoleEnabled;
|
||||
void SetFacilities(const std::string &solo, const std::string &blocked);
|
||||
bool IsFacilityActive(const char *facility);
|
||||
#else
|
||||
MPT_FORCEINLINE bool IsFacilityActive(const char * /*facility*/ ) { return true; }
|
||||
#endif
|
||||
|
||||
|
||||
#endif // !NO_LOGGING
|
||||
|
||||
|
||||
|
||||
#ifndef NO_LOGGING
|
||||
|
||||
|
||||
class Logger
|
||||
{
|
||||
public:
|
||||
// facility:ASCII
|
||||
void SendLogMessage(const mpt::source_location &loc, LogLevel level, const char *facility, const mpt::ustring &text);
|
||||
};
|
||||
|
||||
#define MPT_LOG(level, facility, text) \
|
||||
MPT_DO \
|
||||
{ \
|
||||
MPT_MAYBE_CONSTANT_IF(mpt::log::GlobalLogLevel >= ( level )) \
|
||||
{ \
|
||||
MPT_MAYBE_CONSTANT_IF(mpt::log::IsFacilityActive(( facility ))) \
|
||||
{ \
|
||||
mpt::log::Logger().SendLogMessage( MPT_SOURCE_LOCATION_CURRENT() , ( level ), ( facility ), ( text )); \
|
||||
} \
|
||||
} \
|
||||
} MPT_WHILE_0 \
|
||||
/**/
|
||||
|
||||
|
||||
#else // !NO_LOGGING
|
||||
|
||||
|
||||
#define MPT_LOG(level, facility, text) MPT_DO { } MPT_WHILE_0
|
||||
|
||||
|
||||
#endif // NO_LOGGING
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
|
||||
|
||||
namespace Trace {
|
||||
|
||||
// This is not strictly thread safe in all corner cases because of missing barriers.
|
||||
// We do not care in order to not harm the fast path with additional barriers.
|
||||
// Enabled tracing incurs a runtime overhead with multiple threads as a global atomic variable
|
||||
// gets modified.
|
||||
// This cacheline bouncing does not matter at all
|
||||
// if there are not multiple thread adding trace points at high frequency (way greater than 1000Hz),
|
||||
// which, in OpenMPT, is only ever the case for just a single thread (the audio thread), if at all.
|
||||
extern std::atomic<bool> g_Enabled;
|
||||
inline bool IsEnabled() { return g_Enabled; }
|
||||
|
||||
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,
|
||||
ThreadKindAudio,
|
||||
ThreadKindNotify,
|
||||
ThreadKindWatchdir,
|
||||
};
|
||||
|
||||
void Enable(std::size_t numEntries);
|
||||
void Disable();
|
||||
|
||||
void SetThreadId(mpt::log::Trace::ThreadKind kind, uint32 id);
|
||||
uint32 GetThreadId(mpt::log::Trace::ThreadKind kind);
|
||||
|
||||
void Seal();
|
||||
bool Dump(const mpt::PathString &filename);
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
||||
} // namespace log
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,221 +0,0 @@
|
|||
/*
|
||||
* Profiler.cpp
|
||||
* ------------
|
||||
* Purpose: Performance measuring
|
||||
* 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 "Profiler.h"
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
#ifdef USE_PROFILER
|
||||
|
||||
|
||||
class Statistics
|
||||
{
|
||||
public:
|
||||
Profile &profile;
|
||||
Profile::Data data;
|
||||
double usage;
|
||||
Statistics(Profile &p) : profile(p)
|
||||
{
|
||||
usage = 0.0;
|
||||
Update();
|
||||
}
|
||||
void Update()
|
||||
{
|
||||
data = profile.GetAndResetData();
|
||||
uint64 now = profile.GetTime();
|
||||
uint64 timewindow = now - data.Start;
|
||||
if(data.Calls > 0 && timewindow > 0)
|
||||
{
|
||||
usage = (double)data.Sum / (double)timewindow;
|
||||
} else
|
||||
{
|
||||
usage = 0.0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct ProfileBlock
|
||||
{
|
||||
class Profile * profile;
|
||||
const char * name;
|
||||
class Statistics * stats;
|
||||
};
|
||||
|
||||
static constexpr std::size_t MAX_PROFILES = 1024;
|
||||
|
||||
static ProfileBlock Profiles[ MAX_PROFILES ];
|
||||
|
||||
static std::size_t NextProfile = 0;
|
||||
|
||||
|
||||
static void RegisterProfile(Profile *newprofile)
|
||||
{
|
||||
if(NextProfile < MAX_PROFILES)
|
||||
{
|
||||
Profiles[NextProfile].profile = newprofile;
|
||||
Profiles[NextProfile].stats = 0;
|
||||
NextProfile++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void UnregisterProfile(Profile *oldprofile)
|
||||
{
|
||||
for(std::size_t i=0; i<NextProfile; i++) {
|
||||
if(Profiles[i].profile == oldprofile) {
|
||||
Profiles[i].profile = 0;
|
||||
delete Profiles[i].stats;
|
||||
Profiles[i].stats = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Profiler::Update()
|
||||
{
|
||||
for(std::size_t i=0; i<NextProfile; i++)
|
||||
{
|
||||
if(!Profiles[i].stats)
|
||||
{
|
||||
Profiles[i].stats = new Statistics(*Profiles[i].profile);
|
||||
} else
|
||||
{
|
||||
Profiles[i].stats->Update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string Profiler::DumpProfiles()
|
||||
{
|
||||
std::string ret;
|
||||
for(std::size_t i=0; i<NextProfile; i++)
|
||||
{
|
||||
if(Profiles[i].stats)
|
||||
{
|
||||
Statistics &stats = *Profiles[i].stats;
|
||||
std::string cat;
|
||||
switch(stats.profile.Category)
|
||||
{
|
||||
case Profiler::GUI: cat = "GUI"; break;
|
||||
case Profiler::Audio: cat = "Audio"; break;
|
||||
case Profiler::Notify: cat = "Notify"; break;
|
||||
}
|
||||
ret += cat + " " + std::string(stats.profile.Name) + ": " + mpt::fmt::right(6, mpt::fmt::fix(stats.usage * 100.0, 3)) + "%\r\n";
|
||||
}
|
||||
}
|
||||
ret += "\r\n";
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
std::vector<double> Profiler::DumpCategories()
|
||||
{
|
||||
std::vector<double> ret;
|
||||
ret.resize(Profiler::CategoriesCount);
|
||||
for(std::size_t i=0; i<NextProfile; i++)
|
||||
{
|
||||
if(Profiles[i].stats)
|
||||
{
|
||||
ret[Profiles[i].profile->Category] += Profiles[i].stats->usage;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
uint64 Profile::GetTime() const
|
||||
{
|
||||
LARGE_INTEGER ret;
|
||||
ret.QuadPart = 0;
|
||||
QueryPerformanceCounter(&ret);
|
||||
return ret.QuadPart;
|
||||
}
|
||||
|
||||
|
||||
uint64 Profile::GetFrequency() const
|
||||
{
|
||||
LARGE_INTEGER ret;
|
||||
ret.QuadPart = 0;
|
||||
QueryPerformanceFrequency(&ret);
|
||||
return ret.QuadPart;
|
||||
}
|
||||
|
||||
|
||||
Profile::Profile(Profiler::Category category, const char *name) : Category(category), Name(name)
|
||||
{
|
||||
data.Calls = 0;
|
||||
data.Sum = 0;
|
||||
data.Overhead = 0;
|
||||
data.Start = GetTime();
|
||||
EnterTime = 0;
|
||||
RegisterProfile(this);
|
||||
}
|
||||
|
||||
|
||||
Profile::~Profile()
|
||||
{
|
||||
UnregisterProfile(this);
|
||||
}
|
||||
|
||||
|
||||
Profile::Data Profile::GetAndResetData()
|
||||
{
|
||||
Profile::Data ret;
|
||||
datamutex.lock();
|
||||
ret = data;
|
||||
data.Calls = 0;
|
||||
data.Sum = 0;
|
||||
data.Overhead = 0;
|
||||
data.Start = GetTime();
|
||||
datamutex.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void Profile::Reset()
|
||||
{
|
||||
datamutex.lock();
|
||||
data.Calls = 0;
|
||||
data.Sum = 0;
|
||||
data.Overhead = 0;
|
||||
data.Start = GetTime();
|
||||
datamutex.unlock();
|
||||
}
|
||||
|
||||
|
||||
void Profile::Enter()
|
||||
{
|
||||
EnterTime = GetTime();
|
||||
}
|
||||
|
||||
|
||||
void Profile::Leave()
|
||||
{
|
||||
uint64 LeaveTime = GetTime();
|
||||
datamutex.lock();
|
||||
data.Calls += 1;
|
||||
data.Sum += LeaveTime - EnterTime;
|
||||
datamutex.unlock();
|
||||
}
|
||||
|
||||
|
||||
#else // !USE_PROFILER
|
||||
|
||||
MPT_MSVC_WORKAROUND_LNK4221(Profiler)
|
||||
|
||||
#endif // USE_PROFILER
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,127 +0,0 @@
|
|||
/*
|
||||
* Profiler.h
|
||||
* ----------
|
||||
* Purpose: Performance measuring
|
||||
* 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 "../common/mptMutex.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
|
||||
//#define USE_PROFILER
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef USE_PROFILER
|
||||
|
||||
class Profiler
|
||||
{
|
||||
public:
|
||||
enum Category
|
||||
{
|
||||
GUI,
|
||||
Audio,
|
||||
Notify,
|
||||
CategoriesCount
|
||||
};
|
||||
static std::vector<std::string> GetCategoryNames()
|
||||
{
|
||||
std::vector<std::string> ret;
|
||||
ret.push_back("GUI");
|
||||
ret.push_back("Audio");
|
||||
ret.push_back("Notify");
|
||||
return ret;
|
||||
}
|
||||
public:
|
||||
static void Update();
|
||||
static std::string DumpProfiles();
|
||||
static std::vector<double> DumpCategories();
|
||||
};
|
||||
|
||||
|
||||
class Profile
|
||||
{
|
||||
private:
|
||||
mutable mpt::mutex datamutex;
|
||||
public:
|
||||
struct Data
|
||||
{
|
||||
uint64 Calls;
|
||||
uint64 Sum;
|
||||
int64 Overhead;
|
||||
uint64 Start;
|
||||
};
|
||||
public:
|
||||
Data data;
|
||||
uint64 EnterTime;
|
||||
Profiler::Category Category;
|
||||
const char * const Name;
|
||||
uint64 GetTime() const;
|
||||
uint64 GetFrequency() const;
|
||||
public:
|
||||
Profile(Profiler::Category category, const char *name);
|
||||
~Profile();
|
||||
void Reset();
|
||||
void Enter();
|
||||
void Leave();
|
||||
class Scope
|
||||
{
|
||||
private:
|
||||
Profile &profile;
|
||||
public:
|
||||
Scope(Profile &p) : profile(p) { profile.Enter(); }
|
||||
~Scope() { profile.Leave(); }
|
||||
};
|
||||
public:
|
||||
Data GetAndResetData();
|
||||
};
|
||||
|
||||
|
||||
#define OPENMPT_PROFILE_SCOPE(cat, name) \
|
||||
static Profile OPENMPT_PROFILE_VAR(cat, name);\
|
||||
Profile::Scope OPENMPT_PROFILE_SCOPE_VAR(OPENMPT_PROFILE_VAR); \
|
||||
/**/
|
||||
|
||||
|
||||
#define OPENMPT_PROFILE_FUNCTION(cat) OPENMPT_PROFILE_SCOPE(cat, __func__)
|
||||
|
||||
|
||||
#else // !USE_PROFILER
|
||||
|
||||
|
||||
class Profiler
|
||||
{
|
||||
public:
|
||||
enum Category
|
||||
{
|
||||
CategoriesCount
|
||||
};
|
||||
static std::vector<std::string> GetCategoryNames() { return std::vector<std::string>(); }
|
||||
public:
|
||||
static void Update() { }
|
||||
static std::string DumpProfiles() { return std::string(); }
|
||||
static std::vector<double> DumpCategories() { return std::vector<double>(); }
|
||||
};
|
||||
#define OPENMPT_PROFILE_SCOPE(cat, name) MPT_DO { } MPT_WHILE_0
|
||||
#define OPENMPT_PROFILE_FUNCTION(cat) MPT_DO { } MPT_WHILE_0
|
||||
|
||||
|
||||
#endif // USE_PROFILER
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,118 +0,0 @@
|
|||
/*
|
||||
* misc_util.cpp
|
||||
* -------------
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "misc_util.h"
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
|
||||
namespace Util
|
||||
{
|
||||
|
||||
|
||||
static constexpr mpt::uchar EncodeNibble[16] = {
|
||||
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 c1, mpt::uchar c2)
|
||||
{
|
||||
byte = 0;
|
||||
if(UC_('0') <= c1 && c1 <= UC_('9'))
|
||||
{
|
||||
byte += static_cast<uint8>((c1 - UC_('0')) << 4);
|
||||
} else if(UC_('A') <= c1 && c1 <= UC_('F'))
|
||||
{
|
||||
byte += static_cast<uint8>((c1 - UC_('A') + 10) << 4);
|
||||
} else if(UC_('a') <= c1 && c1 <= UC_('f'))
|
||||
{
|
||||
byte += static_cast<uint8>((c1 - UC_('a') + 10) << 4);
|
||||
} else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(UC_('0') <= c2 && c2 <= UC_('9'))
|
||||
{
|
||||
byte += static_cast<uint8>(c2 - UC_('0'));
|
||||
} else if(UC_('A') <= c2 && c2 <= UC_('F'))
|
||||
{
|
||||
byte += static_cast<uint8>(c2 - UC_('A') + 10);
|
||||
} else if(UC_('a') <= c2 && c2 <= UC_('f'))
|
||||
{
|
||||
byte += static_cast<uint8>(c2 - UC_('a') + 10);
|
||||
} else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
mpt::ustring BinToHex(mpt::const_byte_span src)
|
||||
{
|
||||
mpt::ustring result;
|
||||
result.reserve(src.size() * 2);
|
||||
for(std::byte byte : src)
|
||||
{
|
||||
result.push_back(EncodeNibble[(mpt::byte_cast<uint8>(byte) & 0xf0) >> 4]);
|
||||
result.push_back(EncodeNibble[mpt::byte_cast<uint8>(byte) & 0x0f]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::byte> HexToBin(const mpt::ustring &src)
|
||||
{
|
||||
std::vector<std::byte> result;
|
||||
result.reserve(src.size() / 2);
|
||||
for(std::size_t i = 0; (i + 1) < src.size(); i += 2)
|
||||
{
|
||||
uint8 byte = 0;
|
||||
if(!DecodeByte(byte, src[i], src[i + 1]))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
result.push_back(mpt::byte_cast<std::byte>(byte));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
} // namespace Util
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER) || (defined(LIBOPENMPT_BUILD) && defined(LIBOPENMPT_BUILD_TEST))
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
std::string getenv(const std::string &env_var, const std::string &def)
|
||||
{
|
||||
#if MPT_OS_WINDOWS && MPT_OS_WINDOWS_WINRT
|
||||
MPT_UNREFERENCED_PARAMETER(env_var);
|
||||
return def;
|
||||
#else
|
||||
const char *val = std::getenv(env_var.c_str());
|
||||
if(!val)
|
||||
{
|
||||
return def;
|
||||
}
|
||||
return val;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
#endif // MODPLUG_TRACKER || (LIBOPENMPT_BUILD && LIBOPENMPT_BUILD_TEST)
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,247 +0,0 @@
|
|||
/*
|
||||
* misc_util.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 "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 <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
namespace Util
|
||||
{
|
||||
|
||||
// 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)
|
||||
{
|
||||
MPT_ASSERT(insEnd >= insStart);
|
||||
if(fix >= insStart)
|
||||
{
|
||||
fix += (insEnd - insStart + 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Insert a range of items [insStart, insEnd], and possibly shift items in range [fixStart, fixEnd] to the right.
|
||||
template<typename T>
|
||||
void InsertRange(const T insStart, const T insEnd, T &fixStart, T &fixEnd)
|
||||
{
|
||||
MPT_ASSERT(insEnd >= insStart);
|
||||
const T insLength = insEnd - insStart + 1;
|
||||
if(fixStart >= insEnd)
|
||||
{
|
||||
fixStart += insLength;
|
||||
}
|
||||
if(fixEnd >= insEnd)
|
||||
{
|
||||
fixEnd += insLength;
|
||||
}
|
||||
}
|
||||
|
||||
// Delete a range of items [delStart, delEnd], and possibly shift item fix to the left.
|
||||
template<typename T>
|
||||
void DeleteItem(const T delStart, const T delEnd, T &fix)
|
||||
{
|
||||
MPT_ASSERT(delEnd >= delStart);
|
||||
if(fix > delEnd)
|
||||
{
|
||||
fix -= (delEnd - delStart + 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Delete a range of items [delStart, delEnd], and possibly shift items in range [fixStart, fixEnd] to the left.
|
||||
template<typename T>
|
||||
void DeleteRange(const T delStart, const T delEnd, T &fixStart, T &fixEnd)
|
||||
{
|
||||
MPT_ASSERT(delEnd >= delStart);
|
||||
const T delLength = delEnd - delStart + 1;
|
||||
if(delStart < fixStart && delEnd < fixStart)
|
||||
{
|
||||
// cut part is before loop start
|
||||
fixStart -= delLength;
|
||||
fixEnd -= delLength;
|
||||
} else if(delStart < fixStart && delEnd < fixEnd)
|
||||
{
|
||||
// cut part is partly before loop start
|
||||
fixStart = delStart;
|
||||
fixEnd -= delLength;
|
||||
} else if(delStart >= fixStart && delEnd < fixEnd)
|
||||
{
|
||||
// cut part is in the loop
|
||||
fixEnd -= delLength;
|
||||
} else if(delStart >= fixStart && delStart < fixEnd && delEnd > fixEnd)
|
||||
{
|
||||
// cut part is partly before loop end
|
||||
fixEnd = delStart;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Util
|
||||
|
||||
|
||||
|
||||
namespace Util
|
||||
{
|
||||
|
||||
template<typename T, std::size_t n>
|
||||
class fixed_size_queue
|
||||
{
|
||||
private:
|
||||
T buffer[n+1];
|
||||
std::size_t read_position;
|
||||
std::size_t write_position;
|
||||
public:
|
||||
fixed_size_queue() : read_position(0), write_position(0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
void clear()
|
||||
{
|
||||
read_position = 0;
|
||||
write_position = 0;
|
||||
}
|
||||
std::size_t read_size() const
|
||||
{
|
||||
if ( write_position > read_position )
|
||||
{
|
||||
return write_position - read_position;
|
||||
} else if ( write_position < read_position )
|
||||
{
|
||||
return write_position - read_position + n + 1;
|
||||
} else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
std::size_t write_size() const
|
||||
{
|
||||
if ( write_position > read_position )
|
||||
{
|
||||
return read_position - write_position + n;
|
||||
} else if ( write_position < read_position )
|
||||
{
|
||||
return read_position - write_position - 1;
|
||||
} else
|
||||
{
|
||||
return n;
|
||||
}
|
||||
}
|
||||
bool push( const T & v )
|
||||
{
|
||||
if ( !write_size() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
buffer[write_position] = v;
|
||||
write_position = ( write_position + 1 ) % ( n + 1 );
|
||||
return true;
|
||||
}
|
||||
bool pop() {
|
||||
if ( !read_size() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
read_position = ( read_position + 1 ) % ( n + 1 );
|
||||
return true;
|
||||
}
|
||||
T peek() {
|
||||
if ( !read_size() )
|
||||
{
|
||||
return T();
|
||||
}
|
||||
return buffer[read_position];
|
||||
}
|
||||
const T * peek_p()
|
||||
{
|
||||
if ( !read_size() )
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return &(buffer[read_position]);
|
||||
}
|
||||
const T * peek_next_p()
|
||||
{
|
||||
if ( read_size() < 2 )
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return &(buffer[(read_position+1)%(n+1)]);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Util
|
||||
|
||||
|
||||
namespace Util
|
||||
{
|
||||
|
||||
std::vector<std::byte> HexToBin(const mpt::ustring &src);
|
||||
mpt::ustring BinToHex(mpt::const_byte_span src);
|
||||
|
||||
template <typename T> inline mpt::ustring BinToHex(mpt::span<T> src) { return Util::BinToHex(mpt::byte_cast<mpt::const_byte_span>(src)); }
|
||||
|
||||
} // namespace Util
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER) || (defined(LIBOPENMPT_BUILD) && defined(LIBOPENMPT_BUILD_TEST))
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
// Wrapper around std::getenv.
|
||||
// Instead of returning null pointer if the environment variable is not set,
|
||||
// this wrapper returns the provided default value.
|
||||
std::string getenv(const std::string &env_var, const std::string &def = std::string());
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
#endif // MODPLUG_TRACKER || (LIBOPENMPT_BUILD && LIBOPENMPT_BUILD_TEST)
|
||||
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
template <typename Tstring, typename Tbuf, typename Tsize>
|
||||
Tstring ParseMaybeNullTerminatedStringFromBufferWithSizeInBytes(const Tbuf *buf, Tsize sizeBytes)
|
||||
{
|
||||
// REG_SZ may contain a single NUL terminator, multiple NUL terminators, or no NUL terminator at all
|
||||
return Tstring(reinterpret_cast<const typename Tstring::value_type*>(buf), reinterpret_cast<const typename Tstring::value_type*>(buf) + (sizeBytes / sizeof(typename Tstring::value_type))).c_str();
|
||||
}
|
||||
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* 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"
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
|
||||
#if defined(MPT_ENABLE_ALIGNED_ALLOC)
|
||||
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
#endif // MPT_ENABLE_ALIGNED_ALLOC
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,125 +0,0 @@
|
|||
/*
|
||||
* 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 <array>
|
||||
#include <memory>
|
||||
#include <new>
|
||||
#include <vector>
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
|
||||
namespace mpt {
|
||||
|
||||
|
||||
|
||||
template <typename T> inline mpt::span<T> as_span(std::vector<T> & cont) { return mpt::span<T>(cont); }
|
||||
|
||||
template <typename T> inline mpt::span<const T> as_span(const std::vector<T> & cont) { return mpt::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 std::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<std::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 std::byte *>(v.data()), v.size() * sizeof(T));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
#if defined(MPT_ENABLE_ALIGNED_ALLOC)
|
||||
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
|
||||
|
||||
#if !(MPT_COMPILER_CLANG && defined(__GLIBCXX__)) && !(MPT_COMPILER_CLANG && MPT_OS_MACOSX_OR_IOS)
|
||||
using std::launder;
|
||||
#else
|
||||
template <class T>
|
||||
MPT_NOINLINE T* launder(T* p) noexcept
|
||||
{
|
||||
return p;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
template <typename T, std::size_t count, std::align_val_t alignment>
|
||||
struct alignas(static_cast<std::size_t>(alignment)) aligned_array
|
||||
: std::array<T, count>
|
||||
{
|
||||
static_assert(static_cast<std::size_t>(alignment) >= alignof(T));
|
||||
static_assert(((count * sizeof(T)) % static_cast<std::size_t>(alignment)) == 0);
|
||||
static_assert(sizeof(std::array<T, count>) == (sizeof(T) * count));
|
||||
};
|
||||
|
||||
static_assert(sizeof(mpt::aligned_array<float, 4, std::align_val_t{sizeof(float) * 4}>) == sizeof(std::array<float, 4>));
|
||||
|
||||
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
#endif // MPT_ENABLE_ALIGNED_ALLOC
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,145 +0,0 @@
|
|||
/*
|
||||
* 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(MPT_WITH_MFC) && !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 // !MPT_WITH_MFC
|
||||
|
||||
#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 // MPT_WITH_MFC
|
||||
|
||||
#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 { if constexpr(!(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 static_assert
|
||||
#define MPT_CONSTEXPR14_ASSERT static_assert
|
||||
#define MPT_CONSTEXPR17_ASSERT static_assert
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,272 +0,0 @@
|
|||
/*
|
||||
* 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 <array>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
|
||||
#define MPT_PP_DEFER(m, ...) m(__VA_ARGS__)
|
||||
|
||||
#define MPT_PP_STRINGIFY(x) #x
|
||||
|
||||
#define MPT_PP_JOIN_HELPER(a, b) a ## b
|
||||
#define MPT_PP_JOIN(a, b) MPT_PP_JOIN_HELPER(a, b)
|
||||
|
||||
#define MPT_PP_UNIQUE_IDENTIFIER(prefix) MPT_PP_JOIN(prefix , __LINE__)
|
||||
|
||||
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
|
||||
#define MPT_WARNING(text) __pragma(message(__FILE__ "(" MPT_PP_DEFER(MPT_PP_STRINGIFY, __LINE__) "): Warning: " text))
|
||||
#define MPT_WARNING_STATEMENT(text) __pragma(message(__FILE__ "(" MPT_PP_DEFER(MPT_PP_STRINGIFY, __LINE__) "): Warning: " text))
|
||||
|
||||
#elif MPT_COMPILER_GCC || MPT_COMPILER_CLANG
|
||||
|
||||
#define MPT_WARNING(text) _Pragma(MPT_PP_STRINGIFY(GCC warning text))
|
||||
#define MPT_WARNING_STATEMENT(text) _Pragma(MPT_PP_STRINGIFY(GCC warning text))
|
||||
|
||||
#else
|
||||
|
||||
// portable #pragma message or #warning replacement
|
||||
#define MPT_WARNING(text) \
|
||||
static inline int MPT_PP_UNIQUE_IDENTIFIER(MPT_WARNING_NAME) () noexcept { \
|
||||
int warning [[deprecated("Warning: " text)]] = 0; \
|
||||
return warning; \
|
||||
} \
|
||||
/**/
|
||||
#define MPT_WARNING_STATEMENT(text) \
|
||||
int MPT_PP_UNIQUE_IDENTIFIER(MPT_WARNING_NAME) = [](){ \
|
||||
int warning [[deprecated("Warning: " text)]] = 0; \
|
||||
return warning; \
|
||||
}() \
|
||||
/**/
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// 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_CONSTEXPR14_FUN constexpr MPT_FORCEINLINE
|
||||
#define MPT_CONSTEXPR17_FUN constexpr MPT_FORCEINLINE
|
||||
#if MPT_CXX_AT_LEAST(20)
|
||||
#define MPT_CONSTEXPR20_FUN constexpr MPT_FORCEINLINE
|
||||
#define MPT_CONSTEXPR20_VAR constexpr
|
||||
#else // !C++20
|
||||
#define MPT_CONSTEXPR20_FUN MPT_FORCEINLINE
|
||||
#define MPT_CONSTEXPR20_VAR const
|
||||
#endif // C++20
|
||||
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
template <auto V> struct constant_value { static constexpr decltype(V) value() { return V; } };
|
||||
#define MPT_FORCE_CONSTEXPR(expr) (mpt::constant_value<( expr )>::value())
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
#if MPT_CXX_AT_LEAST(20)
|
||||
#define MPT_IS_CONSTANT_EVALUATED20() std::is_constant_evaluated()
|
||||
#define MPT_IS_CONSTANT_EVALUATED() std::is_constant_evaluated()
|
||||
#else // !C++20
|
||||
#define MPT_IS_CONSTANT_EVALUATED20() false
|
||||
// this pessimizes the case for C++17 by always assuming constexpr context, which implies always running constexpr-friendly code
|
||||
#define MPT_IS_CONSTANT_EVALUATED() true
|
||||
#endif // C++20
|
||||
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
struct stdarray_extent : std::integral_constant<std::size_t, 0> {};
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
struct stdarray_extent<std::array<T, N>> : std::integral_constant<std::size_t, N> {};
|
||||
|
||||
template <typename T>
|
||||
struct is_stdarray : std::false_type {};
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
struct is_stdarray<std::array<T, N>> : std::true_type {};
|
||||
|
||||
// mpt::extent is the same as std::extent,
|
||||
// but also works for std::array,
|
||||
// and asserts that the given type is actually an array type instead of returning 0.
|
||||
// use as:
|
||||
// mpt::extent<decltype(expr)>()
|
||||
// mpt::extent<decltype(variable)>()
|
||||
// mpt::extent<decltype(type)>()
|
||||
// mpt::extent<type>()
|
||||
template <typename T>
|
||||
constexpr std::size_t extent() noexcept
|
||||
{
|
||||
using Tarray = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
|
||||
static_assert(std::is_array<Tarray>::value || mpt::is_stdarray<Tarray>::value);
|
||||
if constexpr(mpt::is_stdarray<Tarray>::value)
|
||||
{
|
||||
return mpt::stdarray_extent<Tarray>();
|
||||
} else
|
||||
{
|
||||
return std::extent<Tarray>();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
// 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
|
||||
|
||||
|
||||
|
||||
#define MPT_ATTR_NODISCARD [[nodiscard]]
|
||||
#define MPT_DISCARD(expr) static_cast<void>(expr)
|
||||
|
||||
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
#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_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)
|
||||
|
||||
|
||||
|
||||
#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
|
|
@ -1,290 +0,0 @@
|
|||
/*
|
||||
* 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>
|
||||
#if MPT_CXX_AT_LEAST(20)
|
||||
#include <source_location>
|
||||
#endif // C++20
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
template <bool cond, typename Ta, typename Tb>
|
||||
struct select_type
|
||||
{
|
||||
};
|
||||
template <typename Ta, typename Tb>
|
||||
struct select_type<true, Ta, Tb>
|
||||
{
|
||||
using type = Ta;
|
||||
};
|
||||
template <typename Ta, typename Tb>
|
||||
struct select_type<false, Ta, Tb>
|
||||
{
|
||||
using type = Tb;
|
||||
};
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
using int8 = std::int8_t;
|
||||
using int16 = std::int16_t;
|
||||
using int32 = std::int32_t;
|
||||
using int64 = std::int64_t;
|
||||
using uint8 = std::uint8_t;
|
||||
using uint16 = std::uint16_t;
|
||||
using uint32 = std::uint32_t;
|
||||
using uint64 = std::uint64_t;
|
||||
|
||||
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();
|
||||
|
||||
|
||||
|
||||
// fp half
|
||||
// n/a
|
||||
|
||||
// fp single
|
||||
using single = float;
|
||||
constexpr single operator"" _fs(long double lit)
|
||||
{
|
||||
return static_cast<single>(lit);
|
||||
}
|
||||
|
||||
// fp double
|
||||
constexpr double operator"" _fd(long double lit)
|
||||
{
|
||||
return static_cast<double>(lit);
|
||||
}
|
||||
|
||||
// fp extended
|
||||
constexpr long double operator"" _fe(long double lit)
|
||||
{
|
||||
return static_cast<long double>(lit);
|
||||
}
|
||||
|
||||
// fp quad
|
||||
// n/a
|
||||
|
||||
using float32 = mpt::select_type<sizeof(float) == 4,
|
||||
float
|
||||
,
|
||||
mpt::select_type<sizeof(double) == 4,
|
||||
double
|
||||
,
|
||||
mpt::select_type<sizeof(long double) == 4,
|
||||
long double
|
||||
,
|
||||
float
|
||||
>::type
|
||||
>::type
|
||||
>::type;
|
||||
constexpr float32 operator"" _f32(long double lit)
|
||||
{
|
||||
return static_cast<float32>(lit);
|
||||
}
|
||||
|
||||
using float64 = mpt::select_type<sizeof(float) == 8,
|
||||
float
|
||||
,
|
||||
mpt::select_type<sizeof(double) == 8,
|
||||
double
|
||||
,
|
||||
mpt::select_type<sizeof(long double) == 8,
|
||||
long double
|
||||
,
|
||||
double
|
||||
>::type
|
||||
>::type
|
||||
>::type;
|
||||
constexpr float64 operator"" _f64(long double lit)
|
||||
{
|
||||
return static_cast<float64>(lit);
|
||||
}
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
template <typename T>
|
||||
struct float_traits
|
||||
{
|
||||
static constexpr bool is_float = !std::numeric_limits<T>::is_integer;
|
||||
static constexpr bool is_hard = is_float && !MPT_COMPILER_QUIRK_FLOAT_EMULATED;
|
||||
static constexpr bool is_soft = is_float && MPT_COMPILER_QUIRK_FLOAT_EMULATED;
|
||||
static constexpr bool is_float32 = is_float && (sizeof(T) == 4);
|
||||
static constexpr bool is_float64 = is_float && (sizeof(T) == 8);
|
||||
static constexpr bool is_native_endian = is_float && !MPT_COMPILER_QUIRK_FLOAT_NOTNATIVEENDIAN;
|
||||
static constexpr bool is_ieee754_binary = is_float && std::numeric_limits<T>::is_iec559 && !MPT_COMPILER_QUIRK_FLOAT_NOTIEEE754;
|
||||
static constexpr bool is_ieee754_binary32 = is_float && is_ieee754_binary && is_float32;
|
||||
static constexpr bool is_ieee754_binary64 = is_float && is_ieee754_binary && is_float64;
|
||||
static constexpr bool is_ieee754_binary32ne = is_float && is_ieee754_binary && is_float32 && is_native_endian;
|
||||
static constexpr bool is_ieee754_binary64ne = is_float && is_ieee754_binary && is_float64 && is_native_endian;
|
||||
};
|
||||
} // namespace mpt
|
||||
|
||||
#if MPT_COMPILER_QUIRK_FLOAT_PREFER32
|
||||
using nativefloat = float32;
|
||||
#elif MPT_COMPILER_QUIRK_FLOAT_PREFER64
|
||||
using nativefloat = float64;
|
||||
#else
|
||||
// prefer smaller floats, but try to use IEEE754 floats
|
||||
using nativefloat = mpt::select_type<std::numeric_limits<float>::is_iec559,
|
||||
float
|
||||
,
|
||||
mpt::select_type<std::numeric_limits<double>::is_iec559,
|
||||
double
|
||||
,
|
||||
mpt::select_type<std::numeric_limits<long double>::is_iec559,
|
||||
long double
|
||||
,
|
||||
float
|
||||
>::type
|
||||
>::type
|
||||
>::type;
|
||||
#endif
|
||||
constexpr nativefloat operator"" _nf(long double lit)
|
||||
{
|
||||
return static_cast<nativefloat>(lit);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static_assert(sizeof(std::uintptr_t) == sizeof(void*));
|
||||
|
||||
|
||||
|
||||
static_assert(std::numeric_limits<unsigned char>::digits == 8);
|
||||
|
||||
static_assert(sizeof(char) == 1);
|
||||
|
||||
static_assert(sizeof(std::byte) == 1);
|
||||
static_assert(alignof(std::byte) == 1);
|
||||
|
||||
|
||||
namespace mpt {
|
||||
inline constexpr int arch_bits = sizeof(void*) * 8;
|
||||
inline constexpr std::size_t pointer_size = sizeof(void*);
|
||||
} // namespace 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
|
||||
{
|
||||
|
||||
#if MPT_CXX_AT_LEAST(20)
|
||||
|
||||
using std::source_location;
|
||||
|
||||
#define MPT_SOURCE_LOCATION_CURRENT() std::source_location::current()
|
||||
|
||||
#else // !C++20
|
||||
|
||||
// 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__ , __func__ , __LINE__ , 0 )
|
||||
|
||||
#endif // C++20
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,704 +0,0 @@
|
|||
/*
|
||||
* 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>
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
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
|
||||
{
|
||||
template <typename T, std::size_t N, typename Tx>
|
||||
MPT_CONSTEXPR14_FUN std::array<T, N> init_array(const Tx & x)
|
||||
{
|
||||
std::array<T, N> result{};
|
||||
for(std::size_t i = 0; i < N; ++i)
|
||||
{
|
||||
result[i] = x;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
// Work-around for the requirement of at least 1 non-throwing function argument combination in C++ (17,2a).
|
||||
|
||||
template <typename Exception>
|
||||
MPT_CONSTEXPR14_FUN bool constexpr_throw_helper(Exception && e, bool really = true)
|
||||
{
|
||||
//return !really ? really : throw std::forward<Exception>(e);
|
||||
if(really)
|
||||
{
|
||||
throw std::forward<Exception>(e);
|
||||
}
|
||||
// cppcheck-suppress identicalConditionAfterEarlyExit
|
||||
return really;
|
||||
}
|
||||
template <typename Exception>
|
||||
MPT_CONSTEXPR14_FUN bool constexpr_throw(Exception && e)
|
||||
{
|
||||
return mpt::constexpr_throw_helper(std::forward<Exception>(e));
|
||||
}
|
||||
|
||||
template <typename T, typename Exception>
|
||||
constexpr T constexpr_throw_helper(Exception && e, bool really = true)
|
||||
{
|
||||
//return !really ? really : throw std::forward<Exception>(e);
|
||||
if(really)
|
||||
{
|
||||
throw std::forward<Exception>(e);
|
||||
}
|
||||
return T{};
|
||||
}
|
||||
template <typename T, typename Exception>
|
||||
constexpr T constexpr_throw(Exception && e)
|
||||
{
|
||||
return mpt::constexpr_throw_helper<T>(std::forward<Exception>(e));
|
||||
}
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
namespace mpt {
|
||||
|
||||
// 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);
|
||||
if constexpr(std::numeric_limits<Tdst>::is_signed && std::numeric_limits<Tsrc>::is_signed)
|
||||
{
|
||||
if constexpr(sizeof(Tdst) >= sizeof(Tsrc))
|
||||
{
|
||||
return static_cast<Tdst>(src);
|
||||
} else
|
||||
{
|
||||
return static_cast<Tdst>(std::max(static_cast<Tsrc>(std::numeric_limits<Tdst>::min()), std::min(src, static_cast<Tsrc>(std::numeric_limits<Tdst>::max()))));
|
||||
}
|
||||
} else if constexpr(!std::numeric_limits<Tdst>::is_signed && !std::numeric_limits<Tsrc>::is_signed)
|
||||
{
|
||||
if constexpr(sizeof(Tdst) >= sizeof(Tsrc))
|
||||
{
|
||||
return static_cast<Tdst>(src);
|
||||
} else
|
||||
{
|
||||
return static_cast<Tdst>(std::min(src, static_cast<Tsrc>(std::numeric_limits<Tdst>::max())));
|
||||
}
|
||||
} else if constexpr(std::numeric_limits<Tdst>::is_signed && !std::numeric_limits<Tsrc>::is_signed)
|
||||
{
|
||||
if constexpr(sizeof(Tdst) > sizeof(Tsrc))
|
||||
{
|
||||
return static_cast<Tdst>(src);
|
||||
} else if constexpr(sizeof(Tdst) == sizeof(Tsrc))
|
||||
{
|
||||
return static_cast<Tdst>(std::min(src, static_cast<Tsrc>(std::numeric_limits<Tdst>::max())));
|
||||
} else
|
||||
{
|
||||
return static_cast<Tdst>(std::min(src, static_cast<Tsrc>(std::numeric_limits<Tdst>::max())));
|
||||
}
|
||||
} else // Tdst unsigned, Tsrc signed
|
||||
{
|
||||
if constexpr(sizeof(Tdst) >= sizeof(Tsrc))
|
||||
{
|
||||
return static_cast<Tdst>(std::max(static_cast<Tsrc>(0), src));
|
||||
} else
|
||||
{
|
||||
return static_cast<Tdst>(std::max(static_cast<Tsrc>(0), std::min(src, static_cast<Tsrc>(std::numeric_limits<Tdst>::max()))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Tdst>
|
||||
inline Tdst saturate_cast(double src)
|
||||
{
|
||||
if(src >= static_cast<double>(std::numeric_limits<Tdst>::max()))
|
||||
{
|
||||
return std::numeric_limits<Tdst>::max();
|
||||
}
|
||||
if(src <= static_cast<double>(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 >= static_cast<float>(std::numeric_limits<Tdst>::max()))
|
||||
{
|
||||
return std::numeric_limits<Tdst>::max();
|
||||
}
|
||||
if(src <= static_cast<float>(std::numeric_limits<Tdst>::min()))
|
||||
{
|
||||
return std::numeric_limits<Tdst>::min();
|
||||
}
|
||||
return static_cast<Tdst>(src);
|
||||
}
|
||||
|
||||
|
||||
#if MPT_CXX_AT_LEAST(20)
|
||||
|
||||
using std::popcount;
|
||||
using std::has_single_bit;
|
||||
using std::bit_ceil;
|
||||
using std::bit_floor;
|
||||
using std::bit_width;
|
||||
using std::rotl;
|
||||
using std::rotr;
|
||||
|
||||
#else
|
||||
|
||||
// C++20 <bit> header.
|
||||
// Note that we do not use SFINAE here but instead rely on static_assert.
|
||||
|
||||
template <typename T>
|
||||
MPT_CONSTEXPR14_FUN int popcount(T val) noexcept
|
||||
{
|
||||
static_assert(std::numeric_limits<T>::is_integer);
|
||||
static_assert(std::is_unsigned<T>::value);
|
||||
int result = 0;
|
||||
while(val > 0)
|
||||
{
|
||||
if(val & 0x1)
|
||||
{
|
||||
result++;
|
||||
}
|
||||
val >>= 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
MPT_CONSTEXPR14_FUN bool has_single_bit(T x) noexcept
|
||||
{
|
||||
static_assert(std::numeric_limits<T>::is_integer);
|
||||
static_assert(std::is_unsigned<T>::value);
|
||||
return mpt::popcount(x) == 1;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
MPT_CONSTEXPR14_FUN T bit_ceil(T x) noexcept
|
||||
{
|
||||
static_assert(std::numeric_limits<T>::is_integer);
|
||||
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 bit_floor(T x) noexcept
|
||||
{
|
||||
static_assert(std::numeric_limits<T>::is_integer);
|
||||
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 bit_width(T x) noexcept
|
||||
{
|
||||
static_assert(std::numeric_limits<T>::is_integer);
|
||||
static_assert(std::is_unsigned<T>::value);
|
||||
T result = 0;
|
||||
while(x > 0)
|
||||
{
|
||||
x >>= 1;
|
||||
result += 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
MPT_CONSTEXPR14_FUN T rotl(T x, int r) noexcept
|
||||
{
|
||||
auto N = std::numeric_limits<T>::digits;
|
||||
return (x >> (N - r)) | (x << r);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
MPT_CONSTEXPR14_FUN T rotr(T x, int r) noexcept
|
||||
{
|
||||
auto N = std::numeric_limits<T>::digits;
|
||||
return (x << (N - r)) | (x >> r);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T>
|
||||
MPT_CONSTEXPR14_FUN T rotl(T x, int s) noexcept
|
||||
{
|
||||
static_assert(std::numeric_limits<T>::is_integer);
|
||||
static_assert(std::is_unsigned<T>::value);
|
||||
auto N = std::numeric_limits<T>::digits;
|
||||
auto r = s % N;
|
||||
return (s < 0) ? detail::rotr(x, -s) : ((x >> (N - r)) | (x << r));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
MPT_CONSTEXPR14_FUN T rotr(T x, int s) noexcept
|
||||
{
|
||||
static_assert(std::numeric_limits<T>::is_integer);
|
||||
static_assert(std::is_unsigned<T>::value);
|
||||
auto N = std::numeric_limits<T>::digits;
|
||||
auto r = s % N;
|
||||
return (s < 0) ? detail::rotl(x, -s) : ((x << (N - r)) | (x >> r));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
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(x >> 1, std::numeric_limits<T>::max() - x);
|
||||
return std::min(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
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
inline T sanitize_nan(T val)
|
||||
{
|
||||
static_assert(std::is_floating_point<T>::value);
|
||||
if(std::isnan(val))
|
||||
{
|
||||
return T(0.0);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T safe_clamp(T v, T lo, T hi)
|
||||
{
|
||||
static_assert(std::is_floating_point<T>::value);
|
||||
return std::clamp(mpt::sanitize_nan(v), lo, hi);
|
||||
}
|
||||
|
||||
} // 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)
|
||||
{
|
||||
static_assert(std::numeric_limits<T>::is_integer);
|
||||
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)
|
||||
{
|
||||
static_assert(std::numeric_limits<T>::is_integer);
|
||||
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)
|
||||
{
|
||||
static_assert(std::numeric_limits<T>::is_integer);
|
||||
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)
|
||||
{
|
||||
static_assert(std::numeric_limits<T>::is_integer);
|
||||
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
|
||||
|
||||
template<typename>
|
||||
struct array_size;
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
struct array_size<std::array<T, N>>
|
||||
{
|
||||
static constexpr std::size_t size = N;
|
||||
};
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
struct array_size<T[N]>
|
||||
{
|
||||
static constexpr std::size_t size = N;
|
||||
};
|
||||
|
||||
} // 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 Util
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,365 +0,0 @@
|
|||
/*
|
||||
* mptCPU.cpp
|
||||
* ----------
|
||||
* Purpose: CPU feature detection.
|
||||
* 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 "mptCPU.h"
|
||||
|
||||
#include "mptStringBuffer.h"
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
#if defined(ENABLE_ASM)
|
||||
|
||||
|
||||
uint32 RealProcSupport = 0;
|
||||
uint32 ProcSupport = 0;
|
||||
char ProcVendorID[16+1] = "";
|
||||
char ProcBrandID[4*4*3+1] = "";
|
||||
uint32 ProcRawCPUID = 0;
|
||||
uint16 ProcFamily = 0;
|
||||
uint8 ProcModel = 0;
|
||||
uint8 ProcStepping = 0;
|
||||
|
||||
|
||||
#if MPT_COMPILER_MSVC && (defined(ENABLE_X86) || defined(ENABLE_X64)) && defined(ENABLE_CPUID)
|
||||
|
||||
|
||||
#include <intrin.h>
|
||||
|
||||
|
||||
typedef char cpuid_result_string[12];
|
||||
|
||||
|
||||
struct cpuid_result {
|
||||
uint32 a;
|
||||
uint32 b;
|
||||
uint32 c;
|
||||
uint32 d;
|
||||
std::string as_string() const
|
||||
{
|
||||
cpuid_result_string result;
|
||||
result[0+0] = (b >> 0) & 0xff;
|
||||
result[0+1] = (b >> 8) & 0xff;
|
||||
result[0+2] = (b >>16) & 0xff;
|
||||
result[0+3] = (b >>24) & 0xff;
|
||||
result[4+0] = (d >> 0) & 0xff;
|
||||
result[4+1] = (d >> 8) & 0xff;
|
||||
result[4+2] = (d >>16) & 0xff;
|
||||
result[4+3] = (d >>24) & 0xff;
|
||||
result[8+0] = (c >> 0) & 0xff;
|
||||
result[8+1] = (c >> 8) & 0xff;
|
||||
result[8+2] = (c >>16) & 0xff;
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static cpuid_result cpuid(uint32 function)
|
||||
{
|
||||
cpuid_result result;
|
||||
int CPUInfo[4];
|
||||
__cpuid(CPUInfo, function);
|
||||
result.a = CPUInfo[0];
|
||||
result.b = CPUInfo[1];
|
||||
result.c = CPUInfo[2];
|
||||
result.d = CPUInfo[3];
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static cpuid_result cpuidex(uint32 function_a, uint32 function_c)
|
||||
{
|
||||
cpuid_result result;
|
||||
int CPUInfo[4];
|
||||
__cpuidex(CPUInfo, function_a, function_c);
|
||||
result.a = CPUInfo[0];
|
||||
result.b = CPUInfo[1];
|
||||
result.c = CPUInfo[2];
|
||||
result.d = CPUInfo[3];
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void InitProcSupport()
|
||||
{
|
||||
|
||||
RealProcSupport = 0;
|
||||
ProcSupport = 0;
|
||||
mpt::String::WriteAutoBuf(ProcVendorID) = "";
|
||||
mpt::String::WriteAutoBuf(ProcBrandID) = "";
|
||||
ProcRawCPUID = 0;
|
||||
ProcFamily = 0;
|
||||
ProcModel = 0;
|
||||
ProcStepping = 0;
|
||||
|
||||
ProcSupport |= PROCSUPPORT_ASM_INTRIN;
|
||||
ProcSupport |= PROCSUPPORT_CPUID;
|
||||
|
||||
{
|
||||
|
||||
cpuid_result VendorString = cpuid(0x00000000u);
|
||||
mpt::String::WriteAutoBuf(ProcVendorID) = VendorString.as_string();
|
||||
if(VendorString.a >= 0x00000001u)
|
||||
{
|
||||
cpuid_result StandardFeatureFlags = cpuid(0x00000001u);
|
||||
ProcRawCPUID = StandardFeatureFlags.a;
|
||||
uint32 Stepping = (StandardFeatureFlags.a >> 0) & 0x0f;
|
||||
uint32 BaseModel = (StandardFeatureFlags.a >> 4) & 0x0f;
|
||||
uint32 BaseFamily = (StandardFeatureFlags.a >> 8) & 0x0f;
|
||||
uint32 ExtModel = (StandardFeatureFlags.a >> 16) & 0x0f;
|
||||
uint32 ExtFamily = (StandardFeatureFlags.a >> 20) & 0xff;
|
||||
if(BaseFamily == 0xf)
|
||||
{
|
||||
ProcFamily = static_cast<uint16>(ExtFamily + BaseFamily);
|
||||
} else
|
||||
{
|
||||
ProcFamily = static_cast<uint16>(BaseFamily);
|
||||
}
|
||||
if((BaseFamily == 0x6) || (BaseFamily == 0xf))
|
||||
{
|
||||
ProcModel = static_cast<uint8>((ExtModel << 4) | (BaseModel << 0));
|
||||
} else
|
||||
{
|
||||
ProcModel = static_cast<uint8>(BaseModel);
|
||||
}
|
||||
ProcStepping = static_cast<uint8>(Stepping);
|
||||
if(StandardFeatureFlags.d & (1<<23)) ProcSupport |= PROCSUPPORT_MMX;
|
||||
if(StandardFeatureFlags.d & (1<<25)) ProcSupport |= PROCSUPPORT_SSE;
|
||||
if(StandardFeatureFlags.d & (1<<26)) ProcSupport |= PROCSUPPORT_SSE2;
|
||||
if(StandardFeatureFlags.c & (1<< 0)) ProcSupport |= PROCSUPPORT_SSE3;
|
||||
if(StandardFeatureFlags.c & (1<< 9)) ProcSupport |= PROCSUPPORT_SSSE3;
|
||||
if(StandardFeatureFlags.c & (1<<19)) ProcSupport |= PROCSUPPORT_SSE4_1;
|
||||
if(StandardFeatureFlags.c & (1<<20)) ProcSupport |= PROCSUPPORT_SSE4_2;
|
||||
if(StandardFeatureFlags.c & (1<<28)) ProcSupport |= PROCSUPPORT_AVX;
|
||||
}
|
||||
if(VendorString.a >= 0x00000007u)
|
||||
{
|
||||
cpuid_result ExtendedFeatures = cpuidex(0x00000007u, 0x00000000u);
|
||||
if(ExtendedFeatures.b & (1<< 5)) ProcSupport |= PROCSUPPORT_AVX2;
|
||||
}
|
||||
|
||||
cpuid_result ExtendedVendorString = cpuid(0x80000000u);
|
||||
if(ExtendedVendorString.a >= 0x80000001u)
|
||||
{
|
||||
cpuid_result ExtendedFeatureFlags = cpuid(0x80000001u);
|
||||
if(ExtendedFeatureFlags.d & (1<<29)) ProcSupport |= PROCSUPPORT_LM;
|
||||
}
|
||||
if(ExtendedVendorString.a >= 0x80000004u)
|
||||
{
|
||||
mpt::String::WriteAutoBuf(ProcBrandID) = cpuid(0x80000002u).as_string4() + cpuid(0x80000003u).as_string4() + cpuid(0x80000004u).as_string4();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
RealProcSupport = ProcSupport;
|
||||
|
||||
}
|
||||
|
||||
|
||||
#elif MPT_COMPILER_MSVC && (defined(ENABLE_X86) || defined(ENABLE_X64))
|
||||
|
||||
|
||||
void InitProcSupport()
|
||||
{
|
||||
|
||||
RealProcSupport = 0;
|
||||
ProcSupport = 0;
|
||||
mpt::String::WriteAutoBuf(ProcVendorID) = "";
|
||||
mpt::String::WriteAutoBuf(ProcBrandID) = "";
|
||||
ProcRawCPUID = 0;
|
||||
ProcFamily = 0;
|
||||
ProcModel = 0;
|
||||
ProcStepping = 0;
|
||||
|
||||
ProcSupport |= PROCSUPPORT_ASM_INTRIN;
|
||||
|
||||
{
|
||||
|
||||
if(IsProcessorFeaturePresent(PF_MMX_INSTRUCTIONS_AVAILABLE) != 0) ProcSupport |= PROCSUPPORT_MMX;
|
||||
if(IsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE) != 0) ProcSupport |= PROCSUPPORT_SSE;
|
||||
if(IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE) != 0) ProcSupport |= PROCSUPPORT_SSE2;
|
||||
if(IsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE) != 0) ProcSupport |= PROCSUPPORT_SSE3;
|
||||
|
||||
}
|
||||
|
||||
RealProcSupport = ProcSupport;
|
||||
|
||||
}
|
||||
|
||||
|
||||
#elif MPT_BUILD_XCODE && defined(__x86_64__)
|
||||
|
||||
|
||||
void InitProcSupport()
|
||||
{
|
||||
|
||||
RealProcSupport = 0;
|
||||
ProcSupport = 0;
|
||||
mpt::String::WriteAutoBuf(ProcVendorID) = "";
|
||||
mpt::String::WriteAutoBuf(ProcBrandID) = "";
|
||||
ProcRawCPUID = 0;
|
||||
ProcFamily = 0;
|
||||
ProcModel = 0;
|
||||
ProcStepping = 0;
|
||||
|
||||
ProcSupport |= PROCSUPPORT_ASM_INTRIN;
|
||||
|
||||
ProcSupport |= PROCSUPPORT_SSE2;
|
||||
|
||||
RealProcSupport = ProcSupport;
|
||||
|
||||
}
|
||||
|
||||
|
||||
#elif MPT_BUILD_XCODE && defined(__arm64__)
|
||||
|
||||
|
||||
void InitProcSupport()
|
||||
{
|
||||
|
||||
RealProcSupport = 0;
|
||||
ProcSupport = 0;
|
||||
mpt::String::WriteAutoBuf(ProcVendorID) = "";
|
||||
mpt::String::WriteAutoBuf(ProcBrandID) = "";
|
||||
ProcRawCPUID = 0;
|
||||
ProcFamily = 0;
|
||||
ProcModel = 0;
|
||||
ProcStepping = 0;
|
||||
|
||||
ProcSupport |= PROCSUPPORT_ASM_INTRIN;
|
||||
|
||||
ProcSupport |= PROCSUPPORT_NEON;
|
||||
|
||||
RealProcSupport = ProcSupport;
|
||||
|
||||
}
|
||||
|
||||
|
||||
#else // !( MPT_COMPILER_MSVC && ENABLE_X86 )
|
||||
|
||||
|
||||
void InitProcSupport()
|
||||
{
|
||||
ProcSupport = 0;
|
||||
}
|
||||
|
||||
|
||||
#endif // MPT_COMPILER_MSVC && ENABLE_X86
|
||||
|
||||
#ifndef MODPLUG_TRACKER
|
||||
static struct initProcSupport
|
||||
{
|
||||
initProcSupport()
|
||||
{
|
||||
InitProcSupport();
|
||||
}
|
||||
} doInitProcSupport;
|
||||
#endif
|
||||
|
||||
#endif // ENABLE_ASM
|
||||
|
||||
|
||||
#ifdef MODPLUG_TRACKER
|
||||
|
||||
|
||||
uint32 GetMinimumProcSupportFlags()
|
||||
{
|
||||
uint32 flags = 0;
|
||||
#ifdef ENABLE_ASM
|
||||
#if MPT_COMPILER_MSVC
|
||||
#if defined(_M_X64)
|
||||
flags |= PROCSUPPORT_AMD64;
|
||||
#elif defined(_M_IX86)
|
||||
#if defined(_M_IX86_FP)
|
||||
#if (_M_IX86_FP >= 2)
|
||||
flags |= PROCSUPPORT_x86_SSE2;
|
||||
#elif (_M_IX86_FP == 1)
|
||||
flags |= PROCSUPPORT_x86_SSE;
|
||||
#endif
|
||||
#else
|
||||
flags |= PROCSUPPORT_i586;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif // ENABLE_ASM
|
||||
return flags;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int GetMinimumSSEVersion()
|
||||
{
|
||||
int minimumSSEVersion = 0;
|
||||
#if MPT_COMPILER_MSVC
|
||||
#if defined(_M_X64)
|
||||
minimumSSEVersion = 2;
|
||||
#elif defined(_M_IX86)
|
||||
#if defined(_M_IX86_FP)
|
||||
#if (_M_IX86_FP >= 2)
|
||||
minimumSSEVersion = 2;
|
||||
#elif (_M_IX86_FP == 1)
|
||||
minimumSSEVersion = 1;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
return minimumSSEVersion;
|
||||
}
|
||||
|
||||
|
||||
int GetMinimumAVXVersion()
|
||||
{
|
||||
int minimumAVXVersion = 0;
|
||||
#if MPT_COMPILER_MSVC
|
||||
#if defined(__AVX2__)
|
||||
minimumAVXVersion = 2;
|
||||
#elif defined(__AVX__)
|
||||
minimumAVXVersion = 1;
|
||||
#endif
|
||||
#endif
|
||||
return minimumAVXVersion;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(MODPLUG_TRACKER) && !defined(ENABLE_ASM)
|
||||
|
||||
MPT_MSVC_WORKAROUND_LNK4221(mptCPU)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,77 +0,0 @@
|
|||
/*
|
||||
* mptCPU.h
|
||||
* --------
|
||||
* Purpose: CPU feature detection.
|
||||
* 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"
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
#ifdef ENABLE_ASM
|
||||
|
||||
#define PROCSUPPORT_ASM_INTRIN 0x00001 // assembly and intrinsics are enabled at runtime
|
||||
#define PROCSUPPORT_CPUID 0x00002 // Processor supports modern cpuid
|
||||
#define PROCSUPPORT_LM 0x00004 // Processor supports long mode (amd64)
|
||||
#define PROCSUPPORT_MMX 0x00010 // Processor supports MMX instructions
|
||||
#define PROCSUPPORT_SSE 0x00100 // Processor supports SSE instructions
|
||||
#define PROCSUPPORT_SSE2 0x00200 // Processor supports SSE2 instructions
|
||||
#define PROCSUPPORT_SSE3 0x00400 // Processor supports SSE3 instructions
|
||||
#define PROCSUPPORT_SSSE3 0x00800 // Processor supports SSSE3 instructions
|
||||
#define PROCSUPPORT_SSE4_1 0x01000 // Processor supports SSE4.1 instructions
|
||||
#define PROCSUPPORT_SSE4_2 0x02000 // Processor supports SSE4.2 instructions
|
||||
#define PROCSUPPORT_AVX 0x10000 // Processor supports AVX instructions
|
||||
#define PROCSUPPORT_AVX2 0x20000 // Processor supports AVX2 instructions
|
||||
|
||||
#define PROCSUPPORT_NEON 0x40000 // Processor supports NEON instructions
|
||||
|
||||
static constexpr uint32 PROCSUPPORT_i586 = 0u ;
|
||||
static constexpr uint32 PROCSUPPORT_x86_SSE = 0u | PROCSUPPORT_SSE ;
|
||||
static constexpr uint32 PROCSUPPORT_x86_SSE2 = 0u | PROCSUPPORT_SSE | PROCSUPPORT_SSE2 ;
|
||||
static constexpr uint32 PROCSUPPORT_AMD64 = 0u | PROCSUPPORT_SSE | PROCSUPPORT_SSE2 | PROCSUPPORT_LM;
|
||||
|
||||
static constexpr uint32 PROCSUPPORT_ARM64 = 0u | PROCSUPPORT_NEON ;
|
||||
|
||||
|
||||
|
||||
extern uint32 RealProcSupport;
|
||||
extern uint32 ProcSupport;
|
||||
extern char ProcVendorID[16+1];
|
||||
extern char ProcBrandID[4*4*3+1];
|
||||
extern uint32 ProcRawCPUID;
|
||||
extern uint16 ProcFamily;
|
||||
extern uint8 ProcModel;
|
||||
extern uint8 ProcStepping;
|
||||
|
||||
void InitProcSupport();
|
||||
|
||||
// enabled processor features for inline asm and intrinsics
|
||||
inline uint32 GetProcSupport()
|
||||
{
|
||||
return ProcSupport;
|
||||
}
|
||||
|
||||
// available processor features
|
||||
inline uint32 GetRealProcSupport()
|
||||
{
|
||||
return RealProcSupport;
|
||||
}
|
||||
|
||||
#endif // ENABLE_ASM
|
||||
|
||||
|
||||
#ifdef MODPLUG_TRACKER
|
||||
uint32 GetMinimumProcSupportFlags();
|
||||
int GetMinimumSSEVersion();
|
||||
int GetMinimumAVXVersion();
|
||||
#endif
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,259 +0,0 @@
|
|||
/*
|
||||
* mptCRC.h
|
||||
* --------
|
||||
* Purpose: generic CRC implementation
|
||||
* Notes : (currently none)
|
||||
* Authors: Joern Heusipp
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
namespace checksum
|
||||
{
|
||||
|
||||
template <typename T, T polynomial, T initial, T resultXOR, bool reverseData>
|
||||
class crc
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
typedef crc self_type;
|
||||
typedef T value_type;
|
||||
typedef uint8 byte_type;
|
||||
|
||||
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:
|
||||
|
||||
template <typename Tint>
|
||||
static inline Tint reverse(Tint value)
|
||||
{
|
||||
const std::size_t bits = sizeof(Tint) * 8;
|
||||
Tint result = 0;
|
||||
for(std::size_t i = 0; i < bits; ++i)
|
||||
{
|
||||
result <<= 1;
|
||||
result |= static_cast<Tint>(value & 0x1);
|
||||
value >>= 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline value_type calculate_table_entry(byte_type pos)
|
||||
{
|
||||
value_type value = 0;
|
||||
value = (static_cast<value_type>(reverseData ? reverse(pos) : pos) << (size_bits - 8));
|
||||
for(std::size_t bit = 0; bit < 8; ++bit)
|
||||
{
|
||||
if(value & top_bit)
|
||||
{
|
||||
value = (value << 1) ^ polynomial;
|
||||
} else
|
||||
{
|
||||
value = (value << 1);
|
||||
}
|
||||
}
|
||||
value = (reverseData ? reverse(value) : value);
|
||||
return value;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static value_type table[256];
|
||||
|
||||
static inline void fill_table()
|
||||
{
|
||||
for(std::size_t i = 0; i < 256; ++i)
|
||||
{
|
||||
table[i] = calculate_table_entry(static_cast<byte_type>(i));
|
||||
}
|
||||
}
|
||||
|
||||
struct table_filler
|
||||
{
|
||||
inline table_filler()
|
||||
{
|
||||
self_type::fill_table();
|
||||
}
|
||||
};
|
||||
|
||||
static inline void init()
|
||||
{
|
||||
static table_filler table_filler;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
inline value_type read_table(byte_type pos) const
|
||||
{
|
||||
return table[pos];
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
value_type value;
|
||||
|
||||
public:
|
||||
|
||||
crc()
|
||||
: value(initial)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
inline void processByte(byte_type byte)
|
||||
{
|
||||
if constexpr(reverseData)
|
||||
{
|
||||
value = (value >> 8) ^ read_table(static_cast<byte_type>((value & 0xff) ^ byte));
|
||||
} else
|
||||
{
|
||||
value = (value << 8) ^ read_table(static_cast<byte_type>(((value >> (size_bits - 8)) & 0xff) ^ byte));
|
||||
}
|
||||
}
|
||||
|
||||
inline value_type result() const
|
||||
{
|
||||
return (value ^ resultXOR);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
inline operator value_type () const
|
||||
{
|
||||
return result();
|
||||
}
|
||||
|
||||
inline crc & process(char c)
|
||||
{
|
||||
processByte(mpt::byte_cast<byte_type>(c));
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline crc & process(signed char c)
|
||||
{
|
||||
processByte(static_cast<byte_type>(c));
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline crc & process(unsigned char c)
|
||||
{
|
||||
processByte(mpt::byte_cast<byte_type>(c));
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline crc & process(std::byte c)
|
||||
{
|
||||
processByte(mpt::byte_cast<byte_type>(c));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename InputIt>
|
||||
crc & process(InputIt beg, InputIt end)
|
||||
{
|
||||
for(InputIt it = beg; it != end; ++it)
|
||||
{
|
||||
static_assert(sizeof(*it) == 1, "1 byte type required");
|
||||
process(*it);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
inline crc & process(const Container &data)
|
||||
{
|
||||
operator () (data.begin(), data.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline crc & operator () (char c)
|
||||
{
|
||||
processByte(mpt::byte_cast<byte_type>(c));
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline crc & operator () (signed char c)
|
||||
{
|
||||
processByte(static_cast<byte_type>(c));
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline crc & operator () (unsigned char c)
|
||||
{
|
||||
processByte(mpt::byte_cast<byte_type>(c));
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline crc & operator () (std::byte c)
|
||||
{
|
||||
processByte(mpt::byte_cast<byte_type>(c));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename InputIt>
|
||||
crc & operator () (InputIt beg, InputIt end)
|
||||
{
|
||||
for(InputIt it = beg; it != end; ++it)
|
||||
{
|
||||
static_assert(sizeof(*it) == 1, "1 byte type required");
|
||||
operator () (*it);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
inline crc & operator () (const Container &data)
|
||||
{
|
||||
operator () (data.begin(), data.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename InputIt>
|
||||
crc(InputIt beg, InputIt end)
|
||||
: value(initial)
|
||||
{
|
||||
init();
|
||||
for(InputIt it = beg; it != end; ++it)
|
||||
{
|
||||
static_assert(sizeof(*it) == 1, "1 byte type required");
|
||||
process(*it);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
inline crc(const Container &data)
|
||||
: value(initial)
|
||||
{
|
||||
init();
|
||||
process(data.begin(), data.end());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <typename T, T polynomial, T initial, T resultXOR, bool reverseData>
|
||||
typename crc<T, polynomial, initial, resultXOR, reverseData>::value_type crc<T, polynomial, initial, resultXOR, reverseData>::table[256];
|
||||
|
||||
typedef crc<uint16, 0x8005, 0, 0, true> crc16;
|
||||
typedef crc<uint32, 0x04C11DB7, 0xFFFFFFFF, 0xFFFFFFFF, true> crc32;
|
||||
typedef crc<uint32, 0x04C11DB7, 0, 0, false> crc32_ogg;
|
||||
typedef crc<uint32, 0x1EDC6F41, 0xFFFFFFFF, 0xFFFFFFFF, true> crc32c;
|
||||
typedef crc<uint64, 0xAD93D23594C935A9ull, 0xFFFFFFFFFFFFFFFFull, 0, true> crc64_jones;
|
||||
|
||||
} // namespace checksum
|
||||
|
||||
using mpt::checksum::crc32;
|
||||
using mpt::checksum::crc32_ogg;
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,56 +0,0 @@
|
|||
/*
|
||||
* 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(MPT_WITH_MFC)
|
||||
#include <new>
|
||||
#endif // !MPT_WITH_MFC
|
||||
|
||||
#if defined(MPT_WITH_MFC)
|
||||
// cppcheck-suppress missingInclude
|
||||
#include <afx.h>
|
||||
#endif // MPT_WITH_MFC
|
||||
|
||||
|
||||
|
||||
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(MPT_WITH_MFC)
|
||||
|
||||
#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 // !MPT_WITH_MFC
|
||||
|
||||
#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 // MPT_WITH_MFC
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,76 +0,0 @@
|
|||
/*
|
||||
* 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return mpt::get_exception_text_impl<T>(e);
|
||||
}
|
||||
template <> inline std::string get_exception_text<std::string>(const std::exception & e)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return mpt::ToLocale(mpt::CharsetException, 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)
|
||||
{
|
||||
return mpt::ToWide(mpt::CharsetException, 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)
|
||||
{
|
||||
return mpt::ToUnicode(mpt::CharsetException, mpt::get_exception_text_impl<std::string>(e));
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,449 +0,0 @@
|
|||
/*
|
||||
* mptFileIO.cpp
|
||||
* -------------
|
||||
* Purpose: File I/O wrappers
|
||||
* 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 "mptFileIO.h"
|
||||
|
||||
#ifdef MODPLUG_TRACKER
|
||||
#if MPT_OS_WINDOWS
|
||||
#include <WinIoCtl.h>
|
||||
#include <io.h>
|
||||
#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
|
||||
|
||||
|
||||
#if defined(MPT_ENABLE_FILEIO)
|
||||
|
||||
|
||||
|
||||
#ifdef MODPLUG_TRACKER
|
||||
#if MPT_OS_WINDOWS
|
||||
bool SetFilesystemCompression(HANDLE hFile)
|
||||
{
|
||||
if(hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
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 != FALSE;
|
||||
}
|
||||
bool SetFilesystemCompression(int fd)
|
||||
{
|
||||
if(fd < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
uintptr_t fhandle = _get_osfhandle(fd);
|
||||
HANDLE hFile = (HANDLE)fhandle;
|
||||
if(hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return SetFilesystemCompression(hFile);
|
||||
}
|
||||
bool SetFilesystemCompression(const mpt::PathString &filename)
|
||||
{
|
||||
DWORD attributes = GetFileAttributes(filename.AsNativePrefixed().c_str());
|
||||
if(attributes == INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(attributes & FILE_ATTRIBUTE_COMPRESSED)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
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);
|
||||
return result;
|
||||
}
|
||||
#endif // MPT_OS_WINDOWS
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
|
||||
#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:
|
||||
[[fallthrough]];
|
||||
case std::ios_base::out | std::ios_base::trunc:
|
||||
fopen_mode = _T("w");
|
||||
break;
|
||||
case std::ios_base::app:
|
||||
[[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:
|
||||
[[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)
|
||||
{
|
||||
const bool mayThrow = (std::uncaught_exceptions() == 0);
|
||||
if(!stream())
|
||||
{
|
||||
#if MPT_COMPILER_MSVC
|
||||
if(m_f)
|
||||
{
|
||||
fclose(m_f);
|
||||
}
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
return;
|
||||
}
|
||||
if(!stream().rdbuf())
|
||||
{
|
||||
#if MPT_COMPILER_MSVC
|
||||
if(m_f)
|
||||
{
|
||||
fclose(m_f);
|
||||
}
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
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
|
||||
if(mayThrow)
|
||||
{
|
||||
// ignore errorOnFlush here, and re-throw the earlier exception
|
||||
// cppcheck-suppress exceptThrowInDestructor
|
||||
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(mayThrow && errorOnFlush && (stream().exceptions() & (std::ios::badbit | std::ios::failbit)))
|
||||
{
|
||||
// cppcheck-suppress exceptThrowInDestructor
|
||||
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<std::byte> &data)
|
||||
{
|
||||
mpt::ofstream file(m_Filename, std::ios::binary);
|
||||
file.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
||||
mpt::IO::WriteRaw(file, mpt::as_span(data));
|
||||
mpt::IO::Flush(file);
|
||||
return *this;
|
||||
}
|
||||
|
||||
LazyFileRef & LazyFileRef::operator = (const std::vector<char> &data)
|
||||
{
|
||||
mpt::ofstream file(m_Filename, std::ios::binary);
|
||||
file.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
||||
mpt::IO::WriteRaw(file, mpt::as_span(data));
|
||||
mpt::IO::Flush(file);
|
||||
return *this;
|
||||
}
|
||||
|
||||
LazyFileRef & LazyFileRef::operator = (const std::string &data)
|
||||
{
|
||||
mpt::ofstream file(m_Filename, std::ios::binary);
|
||||
file.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
||||
mpt::IO::WriteRaw(file, mpt::as_span(data));
|
||||
mpt::IO::Flush(file);
|
||||
return *this;
|
||||
}
|
||||
|
||||
LazyFileRef::operator std::vector<std::byte> () const
|
||||
{
|
||||
mpt::ifstream file(m_Filename, std::ios::binary);
|
||||
if(!mpt::IO::IsValid(file))
|
||||
{
|
||||
return std::vector<std::byte>();
|
||||
}
|
||||
file.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
||||
mpt::IO::SeekEnd(file);
|
||||
std::vector<std::byte> buf(mpt::saturate_cast<std::size_t>(mpt::IO::TellRead(file)));
|
||||
mpt::IO::SeekBegin(file);
|
||||
mpt::IO::ReadRaw(file, mpt::as_span(buf));
|
||||
return buf;
|
||||
}
|
||||
|
||||
LazyFileRef::operator std::vector<char> () const
|
||||
{
|
||||
mpt::ifstream file(m_Filename, std::ios::binary);
|
||||
if(!mpt::IO::IsValid(file))
|
||||
{
|
||||
return std::vector<char>();
|
||||
}
|
||||
file.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
||||
mpt::IO::SeekEnd(file);
|
||||
std::vector<char> buf(mpt::saturate_cast<std::size_t>(mpt::IO::TellRead(file)));
|
||||
mpt::IO::SeekBegin(file);
|
||||
mpt::IO::ReadRaw(file, mpt::as_span(buf));
|
||||
return buf;
|
||||
}
|
||||
|
||||
LazyFileRef::operator std::string () const
|
||||
{
|
||||
mpt::ifstream file(m_Filename, std::ios::binary);
|
||||
if(!mpt::IO::IsValid(file))
|
||||
{
|
||||
return std::string();
|
||||
}
|
||||
file.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
||||
mpt::IO::SeekEnd(file);
|
||||
std::vector<char> buf(mpt::saturate_cast<std::size_t>(mpt::IO::TellRead(file)));
|
||||
mpt::IO::SeekBegin(file);
|
||||
mpt::IO::ReadRaw(file, mpt::as_span(buf));
|
||||
return std::string(buf.begin(), buf.end());
|
||||
}
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
bool InputFile::DefaultToLargeAddressSpaceUsage()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
InputFile::InputFile()
|
||||
: m_IsCached(false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
InputFile::InputFile(const mpt::PathString &filename, bool allowWholeFileCaching)
|
||||
: m_IsCached(false)
|
||||
{
|
||||
Open(filename, allowWholeFileCaching);
|
||||
}
|
||||
|
||||
InputFile::~InputFile()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
bool InputFile::Open(const mpt::PathString &filename, bool allowWholeFileCaching)
|
||||
{
|
||||
m_IsCached = false;
|
||||
m_Cache.resize(0);
|
||||
m_Cache.shrink_to_fit();
|
||||
m_Filename = filename;
|
||||
m_File.open(m_Filename, std::ios::binary | std::ios::in);
|
||||
if(allowWholeFileCaching)
|
||||
{
|
||||
if(mpt::IO::IsReadSeekable(m_File))
|
||||
{
|
||||
if(!mpt::IO::SeekEnd(m_File))
|
||||
{
|
||||
m_File.close();
|
||||
return false;
|
||||
}
|
||||
mpt::IO::Offset filesize = mpt::IO::TellRead(m_File);
|
||||
if(!mpt::IO::SeekBegin(m_File))
|
||||
{
|
||||
m_File.close();
|
||||
return false;
|
||||
}
|
||||
if(Util::TypeCanHoldValue<std::size_t>(filesize))
|
||||
{
|
||||
std::size_t buffersize = mpt::saturate_cast<std::size_t>(filesize);
|
||||
m_Cache.resize(buffersize);
|
||||
if(mpt::IO::ReadRaw(m_File, mpt::as_span(m_Cache)) != filesize)
|
||||
{
|
||||
m_File.close();
|
||||
return false;
|
||||
}
|
||||
if(!mpt::IO::SeekBegin(m_File))
|
||||
{
|
||||
m_File.close();
|
||||
return false;
|
||||
}
|
||||
m_IsCached = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return m_File.good();
|
||||
}
|
||||
|
||||
|
||||
bool InputFile::IsValid() const
|
||||
{
|
||||
return m_File.good();
|
||||
}
|
||||
|
||||
|
||||
bool InputFile::IsCached() const
|
||||
{
|
||||
return m_IsCached;
|
||||
}
|
||||
|
||||
|
||||
const mpt::PathString& InputFile::GetFilenameRef() const
|
||||
{
|
||||
return m_Filename;
|
||||
}
|
||||
|
||||
|
||||
std::istream* InputFile::GetStream()
|
||||
{
|
||||
MPT_ASSERT(!m_IsCached);
|
||||
return &m_File;
|
||||
}
|
||||
|
||||
|
||||
mpt::const_byte_span InputFile::GetCache()
|
||||
{
|
||||
MPT_ASSERT(m_IsCached);
|
||||
return mpt::as_span(m_Cache);
|
||||
}
|
||||
|
||||
|
||||
#else // !MPT_ENABLE_FILEIO
|
||||
|
||||
MPT_MSVC_WORKAROUND_LNK4221(mptFileIO)
|
||||
|
||||
#endif // MPT_ENABLE_FILEIO
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,291 +0,0 @@
|
|||
/*
|
||||
* mptFileIO.h
|
||||
* -----------
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BuildSettings.h"
|
||||
|
||||
#if defined(MPT_ENABLE_FILEIO)
|
||||
|
||||
#include "../common/mptString.h"
|
||||
#include "../common/mptPathString.h"
|
||||
#include "../common/mptIO.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <ios>
|
||||
#include <ostream>
|
||||
#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
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
#if defined(MPT_ENABLE_FILEIO)
|
||||
|
||||
|
||||
// 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.
|
||||
// In almost all cases, the return value should be ignored because most filesystems other than NTFS do not support compression.
|
||||
#ifdef MODPLUG_TRACKER
|
||||
#if MPT_OS_WINDOWS
|
||||
bool SetFilesystemCompression(HANDLE hFile);
|
||||
bool SetFilesystemCompression(int fd);
|
||||
bool SetFilesystemCompression(const mpt::PathString &filename);
|
||||
#endif // MPT_OS_WINDOWS
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
#if MPT_COMPILER_GCC && MPT_OS_WINDOWS
|
||||
// GCC C++ library has no wchar_t overloads
|
||||
#define MPT_FSTREAM_DO_CONVERSIONS_ANSI
|
||||
#endif
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<typename Tbase>
|
||||
inline void fstream_open(Tbase & base, const mpt::PathString & filename, std::ios_base::openmode mode)
|
||||
{
|
||||
#if defined(MPT_FSTREAM_DO_CONVERSIONS_ANSI)
|
||||
base.open(mpt::ToCharset(mpt::Charset::Locale, filename.AsNative()).c_str(), mode);
|
||||
#else
|
||||
base.open(filename.AsNativePrefixed().c_str(), 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)
|
||||
{
|
||||
detail::fstream_open<Tbase>(*this, filename, mode);
|
||||
}
|
||||
void open(const mpt::PathString & filename, std::ios_base::openmode mode = std::ios_base::in | std::ios_base::out)
|
||||
{
|
||||
detail::fstream_open<Tbase>(*this, filename, 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
|
||||
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
|
||||
};
|
||||
|
||||
class ifstream
|
||||
: public std::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)
|
||||
{
|
||||
detail::fstream_open<Tbase>(*this, filename, mode);
|
||||
}
|
||||
void open(const mpt::PathString & filename, std::ios_base::openmode mode = std::ios_base::in)
|
||||
{
|
||||
detail::fstream_open<Tbase>(*this, filename, 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
|
||||
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
|
||||
};
|
||||
|
||||
class ofstream
|
||||
: public std::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);
|
||||
}
|
||||
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
|
||||
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
|
||||
};
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
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 = nullptr;
|
||||
#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
|
||||
{
|
||||
if(!stream().is_open())
|
||||
stream().setstate(mpt::ofstream::failbit);
|
||||
}
|
||||
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.
|
||||
class LazyFileRef {
|
||||
private:
|
||||
const mpt::PathString m_Filename;
|
||||
public:
|
||||
LazyFileRef(const mpt::PathString &filename)
|
||||
: m_Filename(filename)
|
||||
{
|
||||
return;
|
||||
}
|
||||
public:
|
||||
LazyFileRef & operator = (const std::vector<std::byte> &data);
|
||||
LazyFileRef & operator = (const std::vector<char> &data);
|
||||
LazyFileRef & operator = (const std::string &data);
|
||||
operator std::vector<std::byte> () const;
|
||||
operator std::vector<char> () const;
|
||||
operator std::string () const;
|
||||
};
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
class InputFile
|
||||
{
|
||||
private:
|
||||
mpt::PathString m_Filename;
|
||||
mpt::ifstream m_File;
|
||||
bool m_IsCached;
|
||||
std::vector<std::byte> m_Cache;
|
||||
public:
|
||||
static bool DefaultToLargeAddressSpaceUsage();
|
||||
public:
|
||||
InputFile();
|
||||
InputFile(const mpt::PathString &filename, bool allowWholeFileCaching = DefaultToLargeAddressSpaceUsage());
|
||||
~InputFile();
|
||||
bool Open(const mpt::PathString &filename, bool allowWholeFileCaching = DefaultToLargeAddressSpaceUsage());
|
||||
bool IsValid() const;
|
||||
bool IsCached() const;
|
||||
const mpt::PathString& GetFilenameRef() const;
|
||||
std::istream* GetStream();
|
||||
mpt::const_byte_span GetCache();
|
||||
};
|
||||
|
||||
|
||||
#endif // MPT_ENABLE_FILEIO
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
||||
|
|
@ -1,671 +0,0 @@
|
|||
/*
|
||||
* mptIO.cpp
|
||||
* ---------
|
||||
* Purpose: Basic functions for reading/writing binary and endian safe data to/from files/streams.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "mptIO.h"
|
||||
|
||||
#include <ios>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
namespace mpt {
|
||||
|
||||
namespace IO {
|
||||
|
||||
|
||||
//static_assert(sizeof(std::streamoff) == 8); // Assert 64bit file support.
|
||||
bool IsValid(std::ostream & f) { return !f.fail(); }
|
||||
bool IsValid(std::istream & f) { return !f.fail(); }
|
||||
bool IsValid(std::iostream & f) { return !f.fail(); }
|
||||
bool IsReadSeekable(std::istream & f)
|
||||
{
|
||||
f.clear();
|
||||
std::streampos oldpos = f.tellg();
|
||||
if(f.fail() || oldpos == std::streampos(-1))
|
||||
{
|
||||
f.clear();
|
||||
return false;
|
||||
}
|
||||
f.seekg(0, std::ios::beg);
|
||||
if(f.fail())
|
||||
{
|
||||
f.clear();
|
||||
f.seekg(oldpos);
|
||||
f.clear();
|
||||
return false;
|
||||
}
|
||||
f.seekg(0, std::ios::end);
|
||||
if(f.fail())
|
||||
{
|
||||
f.clear();
|
||||
f.seekg(oldpos);
|
||||
f.clear();
|
||||
return false;
|
||||
}
|
||||
std::streampos length = f.tellg();
|
||||
if(f.fail() || length == std::streampos(-1))
|
||||
{
|
||||
f.clear();
|
||||
f.seekg(oldpos);
|
||||
f.clear();
|
||||
return false;
|
||||
}
|
||||
f.seekg(oldpos);
|
||||
f.clear();
|
||||
return true;
|
||||
}
|
||||
bool IsWriteSeekable(std::ostream & f)
|
||||
{
|
||||
f.clear();
|
||||
std::streampos oldpos = f.tellp();
|
||||
if(f.fail() || oldpos == std::streampos(-1))
|
||||
{
|
||||
f.clear();
|
||||
return false;
|
||||
}
|
||||
f.seekp(0, std::ios::beg);
|
||||
if(f.fail())
|
||||
{
|
||||
f.clear();
|
||||
f.seekp(oldpos);
|
||||
f.clear();
|
||||
return false;
|
||||
}
|
||||
f.seekp(0, std::ios::end);
|
||||
if(f.fail())
|
||||
{
|
||||
f.clear();
|
||||
f.seekp(oldpos);
|
||||
f.clear();
|
||||
return false;
|
||||
}
|
||||
std::streampos length = f.tellp();
|
||||
if(f.fail() || length == std::streampos(-1))
|
||||
{
|
||||
f.clear();
|
||||
f.seekp(oldpos);
|
||||
f.clear();
|
||||
return false;
|
||||
}
|
||||
f.seekp(oldpos);
|
||||
f.clear();
|
||||
return true;
|
||||
}
|
||||
IO::Offset TellRead(std::istream & f)
|
||||
{
|
||||
return f.tellg();
|
||||
}
|
||||
IO::Offset TellWrite(std::ostream & f)
|
||||
{
|
||||
return f.tellp();
|
||||
}
|
||||
bool SeekBegin(std::ostream & f)
|
||||
{
|
||||
f.seekp(0); return !f.fail();
|
||||
}
|
||||
bool SeekBegin(std::istream & f)
|
||||
{
|
||||
f.seekg(0); return !f.fail();
|
||||
}
|
||||
bool SeekBegin(std::iostream & f)
|
||||
{
|
||||
f.seekg(0); f.seekp(0); return !f.fail();
|
||||
}
|
||||
bool SeekEnd(std::ostream & f)
|
||||
{
|
||||
f.seekp(0, std::ios::end); return !f.fail();
|
||||
}
|
||||
bool SeekEnd(std::istream & f)
|
||||
{
|
||||
f.seekg(0, std::ios::end); return !f.fail();
|
||||
}
|
||||
bool SeekEnd(std::iostream & f)
|
||||
{
|
||||
f.seekg(0, std::ios::end); f.seekp(0, std::ios::end); return !f.fail();
|
||||
}
|
||||
bool SeekAbsolute(std::ostream & f, IO::Offset pos)
|
||||
{
|
||||
if(!OffsetFits<std::streamoff>(pos)) { return false; }
|
||||
f.seekp(static_cast<std::streamoff>(pos), std::ios::beg); return !f.fail();
|
||||
}
|
||||
bool SeekAbsolute(std::istream & f, IO::Offset pos)
|
||||
{
|
||||
if(!OffsetFits<std::streamoff>(pos)) { return false; }
|
||||
f.seekg(static_cast<std::streamoff>(pos), std::ios::beg); return !f.fail();
|
||||
}
|
||||
bool SeekAbsolute(std::iostream & f, IO::Offset pos)
|
||||
{
|
||||
if(!OffsetFits<std::streamoff>(pos)) { return false; }
|
||||
f.seekg(static_cast<std::streamoff>(pos), std::ios::beg); f.seekp(static_cast<std::streamoff>(pos), std::ios::beg); return !f.fail();
|
||||
}
|
||||
bool SeekRelative(std::ostream & f, IO::Offset off)
|
||||
{
|
||||
if(!OffsetFits<std::streamoff>(off)) { return false; }
|
||||
f.seekp(static_cast<std::streamoff>(off), std::ios::cur); return !f.fail();
|
||||
}
|
||||
bool SeekRelative(std::istream & f, IO::Offset off)
|
||||
{
|
||||
if(!OffsetFits<std::streamoff>(off)) { return false; }
|
||||
f.seekg(static_cast<std::streamoff>(off), std::ios::cur); return !f.fail();
|
||||
}
|
||||
bool SeekRelative(std::iostream & f, IO::Offset off)
|
||||
{
|
||||
if(!OffsetFits<std::streamoff>(off)) { return false; }
|
||||
f.seekg(static_cast<std::streamoff>(off), std::ios::cur); f.seekp(static_cast<std::streamoff>(off), std::ios::cur); return !f.fail();
|
||||
}
|
||||
IO::Offset ReadRawImpl(std::istream & f, mpt::byte_span data) { f.read(mpt::byte_cast<char *>(data.data()), data.size()); return f.gcount(); }
|
||||
bool WriteRawImpl(std::ostream & f, mpt::const_byte_span data) { f.write(mpt::byte_cast<const char *>(data.data()), data.size()); return !f.fail(); }
|
||||
bool IsEof(std::istream & f) { return f.eof(); }
|
||||
bool Flush(std::ostream & f) { f.flush(); return !f.fail(); }
|
||||
|
||||
|
||||
|
||||
} // namespace IO
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
FileDataContainerSeekable::FileDataContainerSeekable(off_t streamLength, bool buffered)
|
||||
: streamLength(streamLength)
|
||||
, cached(false)
|
||||
, m_Buffered(buffered)
|
||||
, m_Buffer(m_Buffered ? static_cast<off_t>(BUFFER_SIZE) : 0)
|
||||
{
|
||||
if(m_Buffered)
|
||||
{
|
||||
for(std::size_t chunkIndex = 0; chunkIndex < NUM_CHUNKS; ++chunkIndex)
|
||||
{
|
||||
m_ChunkIndexLRU[chunkIndex] = chunkIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FileDataContainerSeekable::CacheStream() const
|
||||
{
|
||||
if(cached)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if(m_Buffered)
|
||||
{
|
||||
m_Buffered = false;
|
||||
for (std::size_t chunkIndex = 0; chunkIndex < NUM_CHUNKS; ++chunkIndex)
|
||||
{
|
||||
m_ChunkInfo[chunkIndex].ChunkValid = false;
|
||||
}
|
||||
m_Buffer.resize(0);
|
||||
m_Buffer.shrink_to_fit();
|
||||
}
|
||||
cache.resize(streamLength);
|
||||
InternalRead(cache.data(), 0, streamLength);
|
||||
cached = true;
|
||||
}
|
||||
|
||||
std::size_t FileDataContainerSeekable::InternalFillPageAndReturnIndex(off_t pos) const
|
||||
{
|
||||
pos = Util::AlignDown(pos, static_cast<off_t>(CHUNK_SIZE));
|
||||
for(std::size_t chunkLRUIndex = 0; chunkLRUIndex < NUM_CHUNKS; ++chunkLRUIndex)
|
||||
{
|
||||
std::size_t chunkIndex = m_ChunkIndexLRU[chunkLRUIndex];
|
||||
if(m_ChunkInfo[chunkIndex].ChunkValid && (m_ChunkInfo[chunkIndex].ChunkOffset == pos))
|
||||
{
|
||||
std::size_t chunk = std::move(m_ChunkIndexLRU[chunkLRUIndex]);
|
||||
std::move_backward(m_ChunkIndexLRU.begin(), m_ChunkIndexLRU.begin() + chunkLRUIndex, m_ChunkIndexLRU.begin() + (chunkLRUIndex + 1));
|
||||
m_ChunkIndexLRU[0] = std::move(chunk);
|
||||
return chunkIndex;
|
||||
}
|
||||
}
|
||||
{
|
||||
std::size_t chunk = std::move(m_ChunkIndexLRU[NUM_CHUNKS - 1]);
|
||||
std::move_backward(m_ChunkIndexLRU.begin(), m_ChunkIndexLRU.begin() + (NUM_CHUNKS - 1), m_ChunkIndexLRU.begin() + NUM_CHUNKS);
|
||||
m_ChunkIndexLRU[0] = std::move(chunk);
|
||||
}
|
||||
std::size_t chunkIndex = m_ChunkIndexLRU[0];
|
||||
chunk_info& chunk = m_ChunkInfo[chunkIndex];
|
||||
chunk.ChunkOffset = pos;
|
||||
chunk.ChunkLength = InternalRead(chunk_data(chunkIndex).data(), pos, CHUNK_SIZE);
|
||||
chunk.ChunkValid = true;
|
||||
return chunkIndex;
|
||||
}
|
||||
|
||||
bool FileDataContainerSeekable::IsValid() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FileDataContainerSeekable::HasFastGetLength() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FileDataContainerSeekable::HasPinnedView() const
|
||||
{
|
||||
return cached;
|
||||
}
|
||||
|
||||
const std::byte *FileDataContainerSeekable::GetRawData() const
|
||||
{
|
||||
CacheStream();
|
||||
return cache.data();
|
||||
}
|
||||
|
||||
IFileDataContainer::off_t FileDataContainerSeekable::GetLength() const
|
||||
{
|
||||
return streamLength;
|
||||
}
|
||||
|
||||
IFileDataContainer::off_t FileDataContainerSeekable::Read(std::byte *dst, IFileDataContainer::off_t pos, IFileDataContainer::off_t count) const
|
||||
{
|
||||
if(cached)
|
||||
{
|
||||
IFileDataContainer::off_t cache_avail = std::min(IFileDataContainer::off_t(cache.size()) - pos, count);
|
||||
std::copy(cache.begin() + pos, cache.begin() + pos + cache_avail, dst);
|
||||
return cache_avail;
|
||||
} else
|
||||
{
|
||||
return InternalReadBuffered(dst, pos, count);
|
||||
}
|
||||
}
|
||||
|
||||
IFileDataContainer::off_t FileDataContainerSeekable::InternalReadBuffered(std::byte* dst, off_t pos, off_t count) const
|
||||
{
|
||||
if(!m_Buffered)
|
||||
{
|
||||
return InternalRead(dst, pos, count);
|
||||
}
|
||||
off_t totalRead = 0;
|
||||
while (count > 0)
|
||||
{
|
||||
std::size_t chunkIndex = InternalFillPageAndReturnIndex(pos);
|
||||
off_t pageSkip = pos - m_ChunkInfo[chunkIndex].ChunkOffset;
|
||||
off_t chunkWanted = std::min(static_cast<off_t>(CHUNK_SIZE) - pageSkip, count);
|
||||
off_t chunkGot = (m_ChunkInfo[chunkIndex].ChunkLength > pageSkip) ? (m_ChunkInfo[chunkIndex].ChunkLength - pageSkip) : 0;
|
||||
off_t chunk = std::min(chunkWanted, chunkGot);
|
||||
std::copy(chunk_data(chunkIndex).data() + pageSkip, chunk_data(chunkIndex).data() + pageSkip + chunk, dst);
|
||||
pos += chunk;
|
||||
dst += chunk;
|
||||
totalRead += chunk;
|
||||
count -= chunk;
|
||||
if (chunkWanted > chunk)
|
||||
{
|
||||
return totalRead;
|
||||
}
|
||||
}
|
||||
return totalRead;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool FileDataContainerStdStreamSeekable::IsSeekable(std::istream *stream)
|
||||
{
|
||||
return mpt::IO::IsReadSeekable(*stream);
|
||||
}
|
||||
|
||||
IFileDataContainer::off_t FileDataContainerStdStreamSeekable::GetLength(std::istream *stream)
|
||||
{
|
||||
stream->clear();
|
||||
std::streampos oldpos = stream->tellg();
|
||||
stream->seekg(0, std::ios::end);
|
||||
std::streampos length = stream->tellg();
|
||||
stream->seekg(oldpos);
|
||||
return mpt::saturate_cast<IFileDataContainer::off_t>(static_cast<int64>(length));
|
||||
}
|
||||
|
||||
FileDataContainerStdStreamSeekable::FileDataContainerStdStreamSeekable(std::istream *s)
|
||||
: FileDataContainerSeekable(GetLength(s), true)
|
||||
, stream(s)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IFileDataContainer::off_t FileDataContainerStdStreamSeekable::InternalRead(std::byte *dst, off_t pos, off_t count) const
|
||||
{
|
||||
stream->clear(); // tellg needs eof and fail bits unset
|
||||
std::streampos currentpos = stream->tellg();
|
||||
if(currentpos == std::streampos(-1) || static_cast<int64>(pos) != currentpos)
|
||||
{ // inefficient istream implementations might invalidate their buffer when seeking, even when seeking to the current position
|
||||
stream->seekg(pos);
|
||||
}
|
||||
stream->read(mpt::byte_cast<char*>(dst), count);
|
||||
return static_cast<IFileDataContainer::off_t>(stream->gcount());
|
||||
}
|
||||
|
||||
|
||||
FileDataContainerUnseekable::FileDataContainerUnseekable()
|
||||
: cachesize(0), streamFullyCached(false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void FileDataContainerUnseekable::EnsureCacheBuffer(std::size_t requiredbuffersize) const
|
||||
{
|
||||
if(cache.size() >= cachesize + requiredbuffersize)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if(cache.size() == 0)
|
||||
{
|
||||
cache.resize(Util::AlignUp<std::size_t>(cachesize + requiredbuffersize, BUFFER_SIZE));
|
||||
} else if(Util::ExponentialGrow(cache.size()) < cachesize + requiredbuffersize)
|
||||
{
|
||||
cache.resize(Util::AlignUp<std::size_t>(cachesize + requiredbuffersize, BUFFER_SIZE));
|
||||
} else
|
||||
{
|
||||
cache.resize(Util::ExponentialGrow(cache.size()));
|
||||
}
|
||||
}
|
||||
|
||||
void FileDataContainerUnseekable::CacheStream() const
|
||||
{
|
||||
if(streamFullyCached)
|
||||
{
|
||||
return;
|
||||
}
|
||||
while(!InternalEof())
|
||||
{
|
||||
EnsureCacheBuffer(BUFFER_SIZE);
|
||||
std::size_t readcount = InternalRead(&cache[cachesize], BUFFER_SIZE);
|
||||
cachesize += readcount;
|
||||
}
|
||||
streamFullyCached = true;
|
||||
}
|
||||
|
||||
void FileDataContainerUnseekable::CacheStreamUpTo(off_t pos, off_t length) const
|
||||
{
|
||||
if(streamFullyCached)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if(length > std::numeric_limits<off_t>::max() - pos)
|
||||
{
|
||||
length = std::numeric_limits<off_t>::max() - pos;
|
||||
}
|
||||
std::size_t target = mpt::saturate_cast<std::size_t>(pos + length);
|
||||
if(target <= cachesize)
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::size_t alignedpos = Util::AlignUp<std::size_t>(target, QUANTUM_SIZE);
|
||||
std::size_t needcount = alignedpos - cachesize;
|
||||
EnsureCacheBuffer(needcount);
|
||||
std::size_t readcount = InternalRead(&cache[cachesize], alignedpos - cachesize);
|
||||
cachesize += readcount;
|
||||
if(!InternalEof())
|
||||
{
|
||||
// can read further
|
||||
return;
|
||||
}
|
||||
streamFullyCached = true;
|
||||
}
|
||||
|
||||
void FileDataContainerUnseekable::ReadCached(std::byte *dst, IFileDataContainer::off_t pos, IFileDataContainer::off_t count) const
|
||||
{
|
||||
std::copy(cache.begin() + pos, cache.begin() + pos + count, dst);
|
||||
}
|
||||
|
||||
bool FileDataContainerUnseekable::IsValid() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FileDataContainerUnseekable::HasFastGetLength() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FileDataContainerUnseekable::HasPinnedView() const
|
||||
{
|
||||
return true; // we have the cache which is required for seeking anyway
|
||||
}
|
||||
|
||||
const std::byte *FileDataContainerUnseekable::GetRawData() const
|
||||
{
|
||||
CacheStream();
|
||||
return cache.data();
|
||||
}
|
||||
|
||||
IFileDataContainer::off_t FileDataContainerUnseekable::GetLength() const
|
||||
{
|
||||
CacheStream();
|
||||
return cachesize;
|
||||
}
|
||||
|
||||
IFileDataContainer::off_t FileDataContainerUnseekable::Read(std::byte *dst, IFileDataContainer::off_t pos, IFileDataContainer::off_t count) const
|
||||
{
|
||||
CacheStreamUpTo(pos, count);
|
||||
if(pos >= IFileDataContainer::off_t(cachesize))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
IFileDataContainer::off_t cache_avail = std::min(IFileDataContainer::off_t(cachesize) - pos, count);
|
||||
ReadCached(dst, pos, cache_avail);
|
||||
return cache_avail;
|
||||
}
|
||||
|
||||
bool FileDataContainerUnseekable::CanRead(IFileDataContainer::off_t pos, IFileDataContainer::off_t length) const
|
||||
{
|
||||
CacheStreamUpTo(pos, length);
|
||||
if((pos == IFileDataContainer::off_t(cachesize)) && (length == 0))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if(pos >= IFileDataContainer::off_t(cachesize))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return length <= IFileDataContainer::off_t(cachesize) - pos;
|
||||
}
|
||||
|
||||
IFileDataContainer::off_t FileDataContainerUnseekable::GetReadableLength(IFileDataContainer::off_t pos, IFileDataContainer::off_t length) const
|
||||
{
|
||||
CacheStreamUpTo(pos, length);
|
||||
if(pos >= cachesize)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return std::min(static_cast<IFileDataContainer::off_t>(cachesize) - pos, length);
|
||||
}
|
||||
|
||||
|
||||
|
||||
FileDataContainerStdStream::FileDataContainerStdStream(std::istream *s)
|
||||
: stream(s)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool FileDataContainerStdStream::InternalEof() const
|
||||
{
|
||||
if(*stream)
|
||||
{
|
||||
return false;
|
||||
} else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
IFileDataContainer::off_t FileDataContainerStdStream::InternalRead(std::byte *dst, off_t count) const
|
||||
{
|
||||
stream->read(mpt::byte_cast<char*>(dst), count);
|
||||
return static_cast<std::size_t>(stream->gcount());
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if defined(MPT_FILEREADER_CALLBACK_STREAM)
|
||||
|
||||
|
||||
bool FileDataContainerCallbackStreamSeekable::IsSeekable(CallbackStream stream)
|
||||
{
|
||||
if(!stream.stream)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(!stream.seek)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(!stream.tell)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int64 oldpos = stream.tell(stream.stream);
|
||||
if(oldpos < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(stream.seek(stream.stream, 0, CallbackStream::SeekSet) < 0)
|
||||
{
|
||||
stream.seek(stream.stream, oldpos, CallbackStream::SeekSet);
|
||||
return false;
|
||||
}
|
||||
if(stream.seek(stream.stream, 0, CallbackStream::SeekEnd) < 0)
|
||||
{
|
||||
stream.seek(stream.stream, oldpos, CallbackStream::SeekSet);
|
||||
return false;
|
||||
}
|
||||
int64 length = stream.tell(stream.stream);
|
||||
if(length < 0)
|
||||
{
|
||||
stream.seek(stream.stream, oldpos, CallbackStream::SeekSet);
|
||||
return false;
|
||||
}
|
||||
stream.seek(stream.stream, oldpos, CallbackStream::SeekSet);
|
||||
return true;
|
||||
}
|
||||
|
||||
IFileDataContainer::off_t FileDataContainerCallbackStreamSeekable::GetLength(CallbackStream stream)
|
||||
{
|
||||
if(!stream.stream)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if(!stream.seek)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(!stream.tell)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int64 oldpos = stream.tell(stream.stream);
|
||||
if(oldpos < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if(stream.seek(stream.stream, 0, CallbackStream::SeekSet) < 0)
|
||||
{
|
||||
stream.seek(stream.stream, oldpos, CallbackStream::SeekSet);
|
||||
return 0;
|
||||
}
|
||||
if(stream.seek(stream.stream, 0, CallbackStream::SeekEnd) < 0)
|
||||
{
|
||||
stream.seek(stream.stream, oldpos, CallbackStream::SeekSet);
|
||||
return 0;
|
||||
}
|
||||
int64 length = stream.tell(stream.stream);
|
||||
if(length < 0)
|
||||
{
|
||||
stream.seek(stream.stream, oldpos, CallbackStream::SeekSet);
|
||||
return 0;
|
||||
}
|
||||
stream.seek(stream.stream, oldpos, CallbackStream::SeekSet);
|
||||
return mpt::saturate_cast<IFileDataContainer::off_t>(length);
|
||||
}
|
||||
|
||||
FileDataContainerCallbackStreamSeekable::FileDataContainerCallbackStreamSeekable(CallbackStream s)
|
||||
: FileDataContainerSeekable(GetLength(s), false)
|
||||
, stream(s)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IFileDataContainer::off_t FileDataContainerCallbackStreamSeekable::InternalRead(std::byte *dst, off_t pos, off_t count) const
|
||||
{
|
||||
if(!stream.read)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if(stream.seek(stream.stream, pos, CallbackStream::SeekSet) < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int64 totalread = 0;
|
||||
while(count > 0)
|
||||
{
|
||||
int64 readcount = stream.read(stream.stream, dst, count);
|
||||
if(readcount <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
dst += static_cast<std::size_t>(readcount);
|
||||
count -= static_cast<IFileDataContainer::off_t>(readcount);
|
||||
totalread += readcount;
|
||||
}
|
||||
return static_cast<IFileDataContainer::off_t>(totalread);
|
||||
}
|
||||
|
||||
|
||||
|
||||
FileDataContainerCallbackStream::FileDataContainerCallbackStream(CallbackStream s)
|
||||
: FileDataContainerUnseekable()
|
||||
, stream(s)
|
||||
, eof_reached(false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool FileDataContainerCallbackStream::InternalEof() const
|
||||
{
|
||||
return eof_reached;
|
||||
}
|
||||
|
||||
IFileDataContainer::off_t FileDataContainerCallbackStream::InternalRead(std::byte *dst, off_t count) const
|
||||
{
|
||||
if(eof_reached)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if(!stream.read)
|
||||
{
|
||||
eof_reached = true;
|
||||
return 0;
|
||||
}
|
||||
int64 totalread = 0;
|
||||
while(count > 0)
|
||||
{
|
||||
int64 readcount = stream.read(stream.stream, dst, count);
|
||||
if(readcount <= 0)
|
||||
{
|
||||
eof_reached = true;
|
||||
break;
|
||||
}
|
||||
dst += static_cast<std::size_t>(readcount);
|
||||
count -= static_cast<IFileDataContainer::off_t>(readcount);
|
||||
totalread += readcount;
|
||||
}
|
||||
return static_cast<IFileDataContainer::off_t>(totalread);
|
||||
}
|
||||
|
||||
|
||||
#endif // MPT_FILEREADER_CALLBACK_STREAM
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
File diff suppressed because it is too large
Load diff
|
@ -1,576 +0,0 @@
|
|||
/*
|
||||
* mptLibrary.cpp
|
||||
* --------------
|
||||
* Purpose: Shared library handling.
|
||||
* 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 "mptLibrary.h"
|
||||
|
||||
#if defined(MPT_ENABLE_DYNBIND)
|
||||
#if MPT_OS_WINDOWS
|
||||
#include <windows.h>
|
||||
#elif MPT_OS_ANDROID
|
||||
#include <dlfcn.h>
|
||||
#elif defined(MPT_WITH_LTDL)
|
||||
#include <ltdl.h>
|
||||
#elif defined(MPT_WITH_DL)
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
#if defined(MPT_ENABLE_DYNBIND)
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
|
||||
// KB2533623 / Win8
|
||||
#ifndef LOAD_LIBRARY_SEARCH_DEFAULT_DIRS
|
||||
#define LOAD_LIBRARY_SEARCH_DEFAULT_DIRS 0x00001000
|
||||
#endif
|
||||
#ifndef LOAD_LIBRARY_SEARCH_APPLICATION_DIR
|
||||
#define LOAD_LIBRARY_SEARCH_APPLICATION_DIR 0x00000200
|
||||
#endif
|
||||
#ifndef LOAD_LIBRARY_SEARCH_SYSTEM32
|
||||
#define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800
|
||||
#endif
|
||||
#ifndef LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR
|
||||
#define LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR 0x00000100
|
||||
#endif
|
||||
|
||||
|
||||
class LibraryHandle
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
HMODULE hModule;
|
||||
|
||||
public:
|
||||
|
||||
LibraryHandle(const mpt::LibraryPath &path)
|
||||
: hModule(NULL)
|
||||
{
|
||||
|
||||
#if MPT_OS_WINDOWS_WINRT
|
||||
|
||||
#if (_WIN32_WINNT < 0x0602)
|
||||
(void)path;
|
||||
hModule = NULL; // unsupported
|
||||
#else
|
||||
switch(path.GetSearchPath())
|
||||
{
|
||||
case mpt::LibrarySearchPathDefault:
|
||||
hModule = LoadPackagedLibrary(path.GetFileName().AsNative().c_str(), 0);
|
||||
break;
|
||||
case mpt::LibrarySearchPathApplication:
|
||||
hModule = LoadPackagedLibrary(path.GetFileName().AsNative().c_str(), 0);
|
||||
break;
|
||||
case mpt::LibrarySearchPathSystem:
|
||||
hModule = NULL; // Only application packaged libraries can be loaded dynamically in WinRT
|
||||
break;
|
||||
case mpt::LibrarySearchPathFullPath:
|
||||
hModule = NULL; // Absolute path is not supported in WinRT
|
||||
break;
|
||||
case mpt::LibrarySearchPathInvalid:
|
||||
MPT_ASSERT_NOTREACHED();
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#else // !MPT_OS_WINDOWS_WINRT
|
||||
|
||||
mpt::Windows::Version WindowsVersion = mpt::Windows::Version::Current();
|
||||
|
||||
// Check for KB2533623:
|
||||
bool hasKB2533623 = false;
|
||||
if(WindowsVersion.IsAtLeast(mpt::Windows::Version::Win8))
|
||||
{
|
||||
hasKB2533623 = true;
|
||||
} else
|
||||
{
|
||||
HMODULE hKernel32DLL = LoadLibraryW(L"kernel32.dll");
|
||||
if(hKernel32DLL)
|
||||
{
|
||||
if(::GetProcAddress(hKernel32DLL, "SetDefaultDllDirectories") != nullptr)
|
||||
{
|
||||
hasKB2533623 = true;
|
||||
}
|
||||
FreeLibrary(hKernel32DLL);
|
||||
hKernel32DLL = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if(hasKB2533623)
|
||||
{
|
||||
switch(path.GetSearchPath())
|
||||
{
|
||||
case mpt::LibrarySearchPathDefault:
|
||||
hModule = LoadLibraryEx(path.GetFileName().AsNative().c_str(), NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
|
||||
break;
|
||||
case mpt::LibrarySearchPathSystem:
|
||||
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
|
||||
// recursively.
|
||||
// This fails loading for e.g. Codec or Plugin DLLs in application
|
||||
// directory if they depend on the MSVC C or C++ runtime (which is
|
||||
// located in the system directory).
|
||||
// Just rely on the default search path here.
|
||||
case mpt::LibrarySearchPathApplication:
|
||||
{
|
||||
const mpt::PathString dllPath = mpt::GetExecutablePath();
|
||||
if(!dllPath.empty() && mpt::PathIsAbsolute(dllPath) && dllPath.IsDirectory())
|
||||
{
|
||||
hModule = LoadLibrary((dllPath + path.GetFileName()).AsNative().c_str());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case mpt::LibrarySearchPathFullPath:
|
||||
hModule = LoadLibrary(path.GetFileName().AsNative().c_str());
|
||||
break;
|
||||
#else
|
||||
// For libopenmpt, do the safe thing.
|
||||
case mpt::LibrarySearchPathApplication:
|
||||
hModule = LoadLibraryEx(path.GetFileName().AsNative().c_str(), NULL, LOAD_LIBRARY_SEARCH_APPLICATION_DIR);
|
||||
break;
|
||||
case mpt::LibrarySearchPathFullPath:
|
||||
hModule = LoadLibraryEx(path.GetFileName().AsNative().c_str(), NULL, LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR);
|
||||
break;
|
||||
#endif
|
||||
case mpt::LibrarySearchPathInvalid:
|
||||
MPT_ASSERT_NOTREACHED();
|
||||
break;
|
||||
}
|
||||
} else
|
||||
{
|
||||
switch(path.GetSearchPath())
|
||||
{
|
||||
case mpt::LibrarySearchPathDefault:
|
||||
hModule = LoadLibrary(path.GetFileName().AsNative().c_str());
|
||||
break;
|
||||
case mpt::LibrarySearchPathApplication:
|
||||
{
|
||||
const mpt::PathString dllPath = mpt::GetExecutablePath();
|
||||
if(!dllPath.empty() && mpt::PathIsAbsolute(dllPath) && dllPath.IsDirectory())
|
||||
{
|
||||
hModule = LoadLibrary((dllPath + path.GetFileName()).AsNative().c_str());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case mpt::LibrarySearchPathSystem:
|
||||
{
|
||||
const mpt::PathString dllPath = mpt::GetSystemPath();
|
||||
if(!dllPath.empty() && mpt::PathIsAbsolute(dllPath) && dllPath.IsDirectory())
|
||||
{
|
||||
hModule = LoadLibrary((dllPath + path.GetFileName()).AsNative().c_str());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case mpt::LibrarySearchPathFullPath:
|
||||
hModule = LoadLibrary(path.GetFileName().AsNative().c_str());
|
||||
break;
|
||||
case mpt::LibrarySearchPathInvalid:
|
||||
MPT_ASSERT_NOTREACHED();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MPT_OS_WINDOWS_WINRT
|
||||
|
||||
}
|
||||
|
||||
LibraryHandle(const LibraryHandle &) = delete;
|
||||
|
||||
LibraryHandle & operator=(const LibraryHandle &) = delete;
|
||||
|
||||
~LibraryHandle()
|
||||
{
|
||||
if(IsValid())
|
||||
{
|
||||
FreeLibrary(hModule);
|
||||
}
|
||||
hModule = NULL;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
return (hModule != NULL);
|
||||
}
|
||||
|
||||
FuncPtr GetProcAddress(const std::string &symbol) const
|
||||
{
|
||||
if(!IsValid())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return reinterpret_cast<FuncPtr>(::GetProcAddress(hModule, symbol.c_str()));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
#elif MPT_OS_ANDROID
|
||||
|
||||
|
||||
// Fake implementation.
|
||||
// Load shared objects from the JAVA side of things.
|
||||
class LibraryHandle
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
LibraryHandle(const mpt::LibraryPath &path)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LibraryHandle(const LibraryHandle &) = delete;
|
||||
|
||||
LibraryHandle & operator=(const LibraryHandle &) = delete;
|
||||
|
||||
~LibraryHandle()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
FuncPtr GetProcAddress(const std::string &symbol) const
|
||||
{
|
||||
if(!IsValid())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return reinterpret_cast<FuncPtr>(dlsym(0, symbol.c_str()));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#elif defined(MPT_WITH_LTDL)
|
||||
|
||||
|
||||
class LibraryHandle
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
bool inited;
|
||||
lt_dlhandle handle;
|
||||
|
||||
public:
|
||||
|
||||
LibraryHandle(const mpt::LibraryPath &path)
|
||||
: inited(false)
|
||||
, handle(0)
|
||||
{
|
||||
if(lt_dlinit() != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
inited = true;
|
||||
handle = lt_dlopenext(path.GetFileName().AsNative().c_str());
|
||||
}
|
||||
|
||||
LibraryHandle(const LibraryHandle &) = delete;
|
||||
|
||||
LibraryHandle & operator=(const LibraryHandle &) = delete;
|
||||
|
||||
~LibraryHandle()
|
||||
{
|
||||
if(IsValid())
|
||||
{
|
||||
lt_dlclose(handle);
|
||||
}
|
||||
handle = 0;
|
||||
if(inited)
|
||||
{
|
||||
lt_dlexit();
|
||||
inited = false;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
return handle != 0;
|
||||
}
|
||||
|
||||
FuncPtr GetProcAddress(const std::string &symbol) const
|
||||
{
|
||||
if(!IsValid())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return reinterpret_cast<FuncPtr>(lt_dlsym(handle, symbol.c_str()));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
#elif defined(MPT_WITH_DL)
|
||||
|
||||
|
||||
class LibraryHandle
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
void* handle;
|
||||
|
||||
public:
|
||||
|
||||
LibraryHandle(const mpt::LibraryPath &path)
|
||||
: handle(NULL)
|
||||
{
|
||||
handle = dlopen(path.GetFileName().AsNative().c_str(), RTLD_NOW);
|
||||
}
|
||||
|
||||
LibraryHandle(const LibraryHandle &) = delete;
|
||||
|
||||
LibraryHandle & operator=(const LibraryHandle &) = delete;
|
||||
|
||||
~LibraryHandle()
|
||||
{
|
||||
if(IsValid())
|
||||
{
|
||||
dlclose(handle);
|
||||
}
|
||||
handle = NULL;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
return handle != NULL;
|
||||
}
|
||||
|
||||
FuncPtr GetProcAddress(const std::string &symbol) const
|
||||
{
|
||||
if(!IsValid())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return reinterpret_cast<FuncPtr>(dlsym(handle, symbol.c_str()));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
#else // MPT_OS
|
||||
|
||||
|
||||
// dummy implementation
|
||||
|
||||
class LibraryHandle
|
||||
{
|
||||
public:
|
||||
|
||||
LibraryHandle(const mpt::LibraryPath &path)
|
||||
{
|
||||
MPT_UNREFERENCED_PARAMETER(path);
|
||||
return;
|
||||
}
|
||||
|
||||
LibraryHandle(const LibraryHandle &) = delete;
|
||||
|
||||
LibraryHandle & operator=(const LibraryHandle &) = delete;
|
||||
|
||||
~LibraryHandle()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FuncPtr GetProcAddress(const std::string &symbol) const
|
||||
{
|
||||
MPT_UNREFERENCED_PARAMETER(symbol);
|
||||
if(!IsValid())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // MPT_OS
|
||||
|
||||
|
||||
LibraryPath::LibraryPath(mpt::LibrarySearchPath searchPath, class mpt::PathString const &fileName)
|
||||
: searchPath(searchPath)
|
||||
, fileName(fileName)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
mpt::LibrarySearchPath LibraryPath::GetSearchPath() const
|
||||
{
|
||||
return searchPath;
|
||||
}
|
||||
|
||||
|
||||
mpt::PathString LibraryPath::GetFileName() const
|
||||
{
|
||||
return fileName;
|
||||
}
|
||||
|
||||
|
||||
mpt::PathString LibraryPath::GetDefaultPrefix()
|
||||
{
|
||||
#if MPT_OS_WINDOWS
|
||||
return P_("");
|
||||
#elif MPT_OS_ANDROID
|
||||
return P_("lib");
|
||||
#elif defined(MPT_WITH_LTDL)
|
||||
return P_("lib");
|
||||
#elif defined(MPT_WITH_DL)
|
||||
return P_("lib");
|
||||
#else
|
||||
return P_("lib");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
mpt::PathString LibraryPath::GetDefaultSuffix()
|
||||
{
|
||||
#if MPT_OS_WINDOWS
|
||||
return P_(".dll");
|
||||
#elif MPT_OS_ANDROID
|
||||
return P_(".so");
|
||||
#elif defined(MPT_WITH_LTDL)
|
||||
return P_(""); // handled by libltdl
|
||||
#elif defined(MPT_WITH_DL)
|
||||
return P_(".so");
|
||||
#else
|
||||
return mpt::PathString();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
LibraryPath LibraryPath::App(const mpt::PathString &basename)
|
||||
{
|
||||
return LibraryPath(mpt::LibrarySearchPathApplication, GetDefaultPrefix() + basename + GetDefaultSuffix());
|
||||
}
|
||||
|
||||
|
||||
LibraryPath LibraryPath::AppFullName(const mpt::PathString &fullname)
|
||||
{
|
||||
return LibraryPath(mpt::LibrarySearchPathApplication, fullname + GetDefaultSuffix());
|
||||
}
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER) && !defined(MPT_BUILD_WINESUPPORT)
|
||||
|
||||
LibraryPath LibraryPath::AppDataFullName(const mpt::PathString &fullname, const mpt::PathString &appdata)
|
||||
{
|
||||
if(appdata.empty())
|
||||
{
|
||||
return LibraryPath(mpt::LibrarySearchPathInvalid, P_(""));
|
||||
}
|
||||
return LibraryPath(mpt::LibrarySearchPathFullPath, appdata.WithTrailingSlash() + fullname + GetDefaultSuffix());
|
||||
}
|
||||
|
||||
#endif // MODPLUG_TRACKER && !MPT_BUILD_WINESUPPORT
|
||||
|
||||
|
||||
LibraryPath LibraryPath::System(const mpt::PathString &basename)
|
||||
{
|
||||
return LibraryPath(mpt::LibrarySearchPathSystem, GetDefaultPrefix() + basename + GetDefaultSuffix());
|
||||
}
|
||||
|
||||
|
||||
LibraryPath LibraryPath::FullPath(const mpt::PathString &path)
|
||||
{
|
||||
return LibraryPath(mpt::LibrarySearchPathFullPath, path);
|
||||
}
|
||||
|
||||
|
||||
Library::Library()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Library::Library(const mpt::LibraryPath &path)
|
||||
{
|
||||
if(path.GetSearchPath() == mpt::LibrarySearchPathInvalid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if(path.GetFileName().empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_Handle = std::make_shared<LibraryHandle>(path);
|
||||
}
|
||||
|
||||
|
||||
void Library::Unload()
|
||||
{
|
||||
*this = mpt::Library();
|
||||
}
|
||||
|
||||
|
||||
bool Library::IsValid() const
|
||||
{
|
||||
return m_Handle && m_Handle->IsValid();
|
||||
}
|
||||
|
||||
|
||||
FuncPtr Library::GetProcAddress(const std::string &symbol) const
|
||||
{
|
||||
if(!IsValid())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return m_Handle->GetProcAddress(symbol);
|
||||
}
|
||||
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
#else // !MPT_ENABLE_DYNBIND
|
||||
|
||||
|
||||
MPT_MSVC_WORKAROUND_LNK4221(mptLibrary)
|
||||
|
||||
|
||||
#endif // MPT_ENABLE_DYNBIND
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,120 +0,0 @@
|
|||
/*
|
||||
* mptLibrary.h
|
||||
* ------------
|
||||
* Purpose: Shared library handling.
|
||||
* 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"
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
#if defined(MPT_ENABLE_DYNBIND)
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
|
||||
typedef void* (*FuncPtr)(); // pointer to function returning void*
|
||||
|
||||
class LibraryHandle;
|
||||
|
||||
enum LibrarySearchPath
|
||||
{
|
||||
LibrarySearchPathInvalid,
|
||||
LibrarySearchPathDefault,
|
||||
LibrarySearchPathApplication,
|
||||
LibrarySearchPathSystem,
|
||||
LibrarySearchPathFullPath,
|
||||
};
|
||||
|
||||
class LibraryPath
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
mpt::LibrarySearchPath searchPath;
|
||||
mpt::PathString fileName;
|
||||
|
||||
private:
|
||||
|
||||
LibraryPath(mpt::LibrarySearchPath searchPath, const mpt::PathString &fileName);
|
||||
|
||||
public:
|
||||
|
||||
mpt::LibrarySearchPath GetSearchPath() const;
|
||||
|
||||
mpt::PathString GetFileName() const;
|
||||
|
||||
public:
|
||||
|
||||
// "lib" on Unix-like systems, "" on Windows
|
||||
static mpt::PathString GetDefaultPrefix();
|
||||
|
||||
// ".so" or ".dylib" or ".dll"
|
||||
static mpt::PathString GetDefaultSuffix();
|
||||
|
||||
// Returns the library path in the application directory, with os-specific prefix and suffix added to basename.
|
||||
// e.g.: basename = "unmo3" --> "libunmo3.so" / "apppath/unmo3.dll"
|
||||
static LibraryPath App(const mpt::PathString &basename);
|
||||
|
||||
// Returns the library path in the application directory, with os-specific suffix added to fullname.
|
||||
// e.g.: fullname = "libunmo3" --> "libunmo3.so" / "apppath/libunmo3.dll"
|
||||
static LibraryPath AppFullName(const mpt::PathString &fullname);
|
||||
|
||||
#if defined(MODPLUG_TRACKER) && !defined(MPT_BUILD_WINESUPPORT)
|
||||
|
||||
// Returns the library path in the application data directory, with os-specific suffix added to fullname.
|
||||
// e.g.: fullname = "libunmo3" --> "libunmo3.so" / "appdata/libunmo3.dll" (appdata == C:\Users\SOMEUSER\AppData\OpenMPT\Components\)
|
||||
static LibraryPath AppDataFullName(const mpt::PathString &fullname, const mpt::PathString &appdata);
|
||||
|
||||
#endif // MODPLUG_TRACKER && !MPT_BUILD_WINESUPPORT
|
||||
|
||||
// Returns a system library name with os-specific prefix and suffix added to basename, but without any full path in order to be searched in the default search path.
|
||||
// e.g.: basename = "unmo3" --> "libunmo3.so" / "unmo3.dll"
|
||||
static LibraryPath System(const mpt::PathString &basename);
|
||||
|
||||
// Returns a system library name with os-specific suffix added to path.
|
||||
// e.g.: path = "somepath/foo" --> "somepath/foo.so" / "somepath/foo.dll"
|
||||
static LibraryPath FullPath(const mpt::PathString &path);
|
||||
|
||||
};
|
||||
|
||||
class Library
|
||||
{
|
||||
protected:
|
||||
std::shared_ptr<LibraryHandle> m_Handle;
|
||||
public:
|
||||
Library();
|
||||
Library(const mpt::LibraryPath &path);
|
||||
public:
|
||||
void Unload();
|
||||
bool IsValid() const;
|
||||
FuncPtr GetProcAddress(const std::string &symbol) const;
|
||||
template <typename Tfunc>
|
||||
bool Bind(Tfunc * & f, const std::string &symbol) const
|
||||
{
|
||||
#if !(MPT_OS_WINDOWS && MPT_COMPILER_GCC)
|
||||
// MinGW64 std::is_function is always false for non __cdecl functions.
|
||||
// See https://connect.microsoft.com/VisualStudio/feedback/details/774720/stl-is-function-bug .
|
||||
static_assert(std::is_function<Tfunc>::value);
|
||||
#endif
|
||||
const FuncPtr addr = GetProcAddress(symbol);
|
||||
f = reinterpret_cast<Tfunc*>(addr);
|
||||
return (addr != nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
#endif // MPT_ENABLE_DYNBIND
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,334 +0,0 @@
|
|||
/*
|
||||
* 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 <type_traits>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
|
||||
namespace mpt {
|
||||
|
||||
|
||||
|
||||
typedef mpt::span<std::byte> byte_span;
|
||||
typedef mpt::span<const std::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 { };
|
||||
template <> struct is_byte_castable<std::byte> : 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 { };
|
||||
template <> struct is_byte_castable<const std::byte> : public std::true_type { };
|
||||
|
||||
|
||||
template <typename T> struct is_byte : public std::false_type { };
|
||||
template <> struct is_byte<std::byte> : public std::true_type { };
|
||||
template <> struct is_byte<const std::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 { };
|
||||
template <> struct is_binary_safe<std::byte> : 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, 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) \
|
||||
static_assert(sizeof( type ) == (size) ); \
|
||||
static_assert(alignof( type ) == 1); \
|
||||
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)
|
||||
{
|
||||
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.");
|
||||
static_assert(std::is_standard_layout<T>::value);
|
||||
static_assert((std::is_trivially_default_constructible<T>::value && std::is_trivially_copyable<T>::value) || mpt::is_binary_safe<T>::value);
|
||||
std::memset(&a, 0, sizeof(T));
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace mpt {
|
||||
|
||||
|
||||
|
||||
#if MPT_CXX_AT_LEAST(20)
|
||||
using std::bit_cast;
|
||||
#else
|
||||
// C++2a compatible bit_cast.
|
||||
// Not implementing constexpr because this is not easily possible pre C++20.
|
||||
template <typename Tdst, typename Tsrc>
|
||||
MPT_FORCEINLINE typename std::enable_if<(sizeof(Tdst) == sizeof(Tsrc)) && std::is_trivially_copyable<Tsrc>::value && std::is_trivially_copyable<Tdst>::value, Tdst>::type bit_cast(const Tsrc & src) noexcept
|
||||
{
|
||||
Tdst dst{};
|
||||
std::memcpy(&dst, &src, sizeof(Tdst));
|
||||
return dst;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
template <typename Tdst, typename Tsrc>
|
||||
struct byte_cast_impl
|
||||
{
|
||||
inline Tdst operator () (Tsrc src) const
|
||||
{
|
||||
static_assert(sizeof(Tsrc) == sizeof(std::byte));
|
||||
static_assert(sizeof(Tdst) == sizeof(std::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(std::byte));
|
||||
static_assert(sizeof(Tdst) == sizeof(std::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.data()), mpt::byte_cast_impl<Tdst*, Tsrc*>()(src.data() + src.size()));
|
||||
}
|
||||
};
|
||||
template <typename Tdst, typename Tsrc>
|
||||
struct byte_cast_impl<Tdst*, Tsrc*>
|
||||
{
|
||||
inline Tdst* operator () (Tsrc* src) const
|
||||
{
|
||||
static_assert(sizeof(Tsrc) == sizeof(std::byte));
|
||||
static_assert(sizeof(Tdst) == sizeof(std::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(std::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(std::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(std::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(std::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 std::byte as_byte(T src) noexcept
|
||||
{
|
||||
static_assert(std::is_integral<T>::value);
|
||||
return static_cast<std::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 std::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<std::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 std::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<std::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 std::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 std::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
|
|
@ -1,237 +0,0 @@
|
|||
/*
|
||||
* mptMutex.h
|
||||
* ----------
|
||||
* Purpose: Partially implement c++ mutexes as far as openmpt needs them. Can eventually go away when we only support c++11 compilers some time.
|
||||
* 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 <vector> // some C++ header in order to have the C++ standard library version information available
|
||||
|
||||
#if !MPT_PLATFORM_MULTITHREADED
|
||||
#define MPT_MUTEX_STD 0
|
||||
#define MPT_MUTEX_PTHREAD 0
|
||||
#define MPT_MUTEX_WIN32 0
|
||||
#elif MPT_OS_EMSCRIPTEN
|
||||
#define MPT_MUTEX_STD 0
|
||||
#define MPT_MUTEX_PTHREAD 0
|
||||
#define MPT_MUTEX_WIN32 0
|
||||
#elif MPT_COMPILER_GENERIC
|
||||
#define MPT_MUTEX_STD 1
|
||||
#define MPT_MUTEX_PTHREAD 0
|
||||
#define MPT_MUTEX_WIN32 0
|
||||
#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 (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_GCC
|
||||
#define MPT_MUTEX_STD 1
|
||||
#define MPT_MUTEX_PTHREAD 0
|
||||
#define MPT_MUTEX_WIN32 0
|
||||
#elif MPT_COMPILER_CLANG
|
||||
#define MPT_MUTEX_STD 1
|
||||
#define MPT_MUTEX_PTHREAD 0
|
||||
#define MPT_MUTEX_WIN32 0
|
||||
#elif MPT_OS_WINDOWS
|
||||
#define MPT_MUTEX_STD 0
|
||||
#define MPT_MUTEX_PTHREAD 0
|
||||
#define MPT_MUTEX_WIN32 1
|
||||
#else
|
||||
#define MPT_MUTEX_STD 0
|
||||
#define MPT_MUTEX_PTHREAD 1
|
||||
#define MPT_MUTEX_WIN32 0
|
||||
#endif
|
||||
|
||||
#if !MPT_MUTEX_STD && !MPT_MUTEX_PTHREAD && !MPT_MUTEX_WIN32
|
||||
#define MPT_MUTEX_NONE 1
|
||||
#else
|
||||
#define MPT_MUTEX_NONE 0
|
||||
#endif
|
||||
|
||||
#if defined(MODPLUG_TRACKER) && MPT_MUTEX_NONE
|
||||
#error "OpenMPT requires mutexes."
|
||||
#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
|
||||
#include <pthread.h>
|
||||
#endif // MPT_MUTEX
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
namespace mpt {
|
||||
|
||||
#if MPT_MUTEX_STD
|
||||
|
||||
typedef std::mutex mutex;
|
||||
typedef std::recursive_mutex recursive_mutex;
|
||||
|
||||
#elif MPT_MUTEX_WIN32
|
||||
|
||||
// compatible with c++11 std::mutex, can eventually be replaced without touching any usage site
|
||||
class mutex {
|
||||
private:
|
||||
CRITICAL_SECTION impl;
|
||||
public:
|
||||
mutex() { InitializeCriticalSection(&impl); }
|
||||
~mutex() { DeleteCriticalSection(&impl); }
|
||||
void lock() { EnterCriticalSection(&impl); }
|
||||
bool try_lock() { return TryEnterCriticalSection(&impl) ? true : false; }
|
||||
void unlock() { LeaveCriticalSection(&impl); }
|
||||
};
|
||||
|
||||
// compatible with c++11 std::recursive_mutex, can eventually be replaced without touching any usage site
|
||||
class recursive_mutex {
|
||||
private:
|
||||
CRITICAL_SECTION impl;
|
||||
public:
|
||||
recursive_mutex() { InitializeCriticalSection(&impl); }
|
||||
~recursive_mutex() { DeleteCriticalSection(&impl); }
|
||||
void lock() { EnterCriticalSection(&impl); }
|
||||
bool try_lock() { return TryEnterCriticalSection(&impl) ? true : false; }
|
||||
void unlock() { LeaveCriticalSection(&impl); }
|
||||
};
|
||||
|
||||
#elif MPT_MUTEX_PTHREAD
|
||||
|
||||
class mutex {
|
||||
private:
|
||||
pthread_mutex_t hLock;
|
||||
public:
|
||||
mutex()
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
|
||||
pthread_mutex_init(&hLock, &attr);
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
}
|
||||
~mutex() { pthread_mutex_destroy(&hLock); }
|
||||
void lock() { pthread_mutex_lock(&hLock); }
|
||||
bool try_lock() { return (pthread_mutex_trylock(&hLock) == 0); }
|
||||
void unlock() { pthread_mutex_unlock(&hLock); }
|
||||
};
|
||||
|
||||
class recursive_mutex {
|
||||
private:
|
||||
pthread_mutex_t hLock;
|
||||
public:
|
||||
recursive_mutex()
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||
pthread_mutex_init(&hLock, &attr);
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
}
|
||||
~recursive_mutex() { pthread_mutex_destroy(&hLock); }
|
||||
void lock() { pthread_mutex_lock(&hLock); }
|
||||
bool try_lock() { return (pthread_mutex_trylock(&hLock) == 0); }
|
||||
void unlock() { pthread_mutex_unlock(&hLock); }
|
||||
};
|
||||
|
||||
#else // MPT_MUTEX_NONE
|
||||
|
||||
class mutex {
|
||||
public:
|
||||
mutex() { }
|
||||
~mutex() { }
|
||||
void lock() { }
|
||||
bool try_lock() { return true; }
|
||||
void unlock() { }
|
||||
};
|
||||
|
||||
class recursive_mutex {
|
||||
public:
|
||||
recursive_mutex() { }
|
||||
~recursive_mutex() { }
|
||||
void lock() { }
|
||||
bool try_lock() { return true; }
|
||||
void unlock() { }
|
||||
};
|
||||
|
||||
#endif // MPT_MUTEX
|
||||
|
||||
#if MPT_MUTEX_STD
|
||||
|
||||
template <typename T> using lock_guard = std::lock_guard<T>;
|
||||
|
||||
#else // !MPT_MUTEX_STD
|
||||
|
||||
// compatible with c++11 std::lock_guard, can eventually be replaced without touching any usage site
|
||||
template< typename mutex_type >
|
||||
class lock_guard {
|
||||
private:
|
||||
mutex_type & mutex;
|
||||
public:
|
||||
lock_guard( mutex_type & m ) : mutex(m) { mutex.lock(); }
|
||||
~lock_guard() { mutex.unlock(); }
|
||||
};
|
||||
|
||||
#endif // MPT_MUTEX_STD
|
||||
|
||||
#ifdef MODPLUG_TRACKER
|
||||
|
||||
class recursive_mutex_with_lock_count {
|
||||
private:
|
||||
mpt::recursive_mutex mutex;
|
||||
long lockCount;
|
||||
public:
|
||||
recursive_mutex_with_lock_count()
|
||||
: lockCount(0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
~recursive_mutex_with_lock_count()
|
||||
{
|
||||
return;
|
||||
}
|
||||
void lock()
|
||||
{
|
||||
mutex.lock();
|
||||
lockCount++;
|
||||
}
|
||||
void unlock()
|
||||
{
|
||||
lockCount--;
|
||||
mutex.unlock();
|
||||
}
|
||||
public:
|
||||
bool IsLockedByCurrentThread() // DEBUGGING only
|
||||
{
|
||||
bool islocked = false;
|
||||
if(mutex.try_lock())
|
||||
{
|
||||
islocked = (lockCount > 0);
|
||||
mutex.unlock();
|
||||
}
|
||||
return islocked;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
||||
|
|
@ -1,957 +0,0 @@
|
|||
/*
|
||||
* mptOS.cpp
|
||||
* ---------
|
||||
* Purpose: Operating system version information.
|
||||
* 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 "mptOS.h"
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
#if !MPT_OS_WINDOWS
|
||||
#include <sys/utsname.h>
|
||||
#endif // !MPT_OS_WINDOWS
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
namespace OS
|
||||
{
|
||||
|
||||
mpt::OS::Class GetClassFromSysname(mpt::ustring sysname)
|
||||
{
|
||||
mpt::OS::Class result = mpt::OS::Class::Unknown;
|
||||
if(sysname == U_(""))
|
||||
{
|
||||
result = mpt::OS::Class::Unknown;
|
||||
} else if(sysname == U_("Windows") || sysname == U_("WindowsNT") || sysname == U_("Windows_NT"))
|
||||
{
|
||||
result = mpt::OS::Class::Windows;
|
||||
} else if(sysname == U_("Linux"))
|
||||
{
|
||||
result = mpt::OS::Class::Linux;
|
||||
} else if(sysname == U_("Darwin"))
|
||||
{
|
||||
result = mpt::OS::Class::Darwin;
|
||||
} else if(sysname == U_("FreeBSD") || sysname == U_("DragonFly") || sysname == U_("NetBSD") || sysname == U_("OpenBSD") || sysname == U_("MidnightBSD"))
|
||||
{
|
||||
result = mpt::OS::Class::BSD;
|
||||
} else if(sysname == U_("Haiku"))
|
||||
{
|
||||
result = mpt::OS::Class::Haiku;
|
||||
} else if(sysname == U_("MS-DOS"))
|
||||
{
|
||||
result = mpt::OS::Class::DOS;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
mpt::OS::Class GetClass()
|
||||
{
|
||||
#if MPT_OS_WINDOWS
|
||||
return mpt::OS::Class::Windows;
|
||||
#else // !MPT_OS_WINDOWS
|
||||
utsname uname_result;
|
||||
if(uname(&uname_result) != 0)
|
||||
{
|
||||
return mpt::OS::Class::Unknown;
|
||||
}
|
||||
return mpt::OS::GetClassFromSysname(mpt::ToUnicode(mpt::Charset::ASCII, mpt::String::ReadAutoBuf(uname_result.sysname)));
|
||||
#endif // MPT_OS_WINDOWS
|
||||
}
|
||||
|
||||
} // namespace OS
|
||||
} // namespace mpt
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
namespace Windows
|
||||
{
|
||||
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
|
||||
static mpt::Windows::Version VersionFromNTDDI_VERSION() noexcept
|
||||
{
|
||||
// Initialize to used SDK version
|
||||
mpt::Windows::Version::System System =
|
||||
#if NTDDI_VERSION >= 0x0A000000 // NTDDI_WIN10
|
||||
mpt::Windows::Version::Win10
|
||||
#elif NTDDI_VERSION >= 0x06030000 // NTDDI_WINBLUE
|
||||
mpt::Windows::Version::Win81
|
||||
#elif NTDDI_VERSION >= 0x06020000 // NTDDI_WIN8
|
||||
mpt::Windows::Version::Win8
|
||||
#elif NTDDI_VERSION >= 0x06010000 // NTDDI_WIN7
|
||||
mpt::Windows::Version::Win7
|
||||
#elif NTDDI_VERSION >= 0x06000000 // NTDDI_VISTA
|
||||
mpt::Windows::Version::WinVista
|
||||
#elif NTDDI_VERSION >= 0x05020000 // NTDDI_WS03
|
||||
mpt::Windows::Version::WinXP64
|
||||
#elif NTDDI_VERSION >= NTDDI_WINXP
|
||||
mpt::Windows::Version::WinXP
|
||||
#elif NTDDI_VERSION >= NTDDI_WIN2K
|
||||
mpt::Windows::Version::Win2000
|
||||
#else
|
||||
mpt::Windows::Version::WinNT4
|
||||
#endif
|
||||
;
|
||||
return mpt::Windows::Version(System, mpt::Windows::Version::ServicePack(((NTDDI_VERSION & 0xffffu) >> 8) & 0xffu, ((NTDDI_VERSION & 0xffffu) >> 0) & 0xffu), 0, 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);
|
||||
#if MPT_COMPILER_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4996) // 'GetVersionExW': was declared deprecated
|
||||
#pragma warning(disable:28159) // Consider using 'IsWindows*' instead of 'GetVersionExW'. Reason: Deprecated. Use VerifyVersionInfo* or IsWindows* macros from VersionHelpers.
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
#if MPT_COMPILER_CLANG
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif // MPT_COMPILER_CLANG
|
||||
if(GetVersionExW((LPOSVERSIONINFOW)&versioninfoex) == FALSE)
|
||||
{
|
||||
return VersionFromNTDDI_VERSION();
|
||||
}
|
||||
#if MPT_COMPILER_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
#if MPT_COMPILER_CLANG
|
||||
#pragma clang diagnostic pop
|
||||
#endif // MPT_COMPILER_CLANG
|
||||
if(versioninfoex.dwPlatformId != VER_PLATFORM_WIN32_NT)
|
||||
{
|
||||
return VersionFromNTDDI_VERSION();
|
||||
}
|
||||
DWORD dwProductType = 0;
|
||||
dwProductType = PRODUCT_UNDEFINED;
|
||||
if(GetProductInfo(versioninfoex.dwMajorVersion, versioninfoex.dwMinorVersion, versioninfoex.wServicePackMajor, versioninfoex.wServicePackMinor, &dwProductType) == FALSE)
|
||||
{
|
||||
dwProductType = PRODUCT_UNDEFINED;
|
||||
}
|
||||
return mpt::Windows::Version(
|
||||
mpt::Windows::Version::System(versioninfoex.dwMajorVersion, versioninfoex.dwMinorVersion),
|
||||
mpt::Windows::Version::ServicePack(versioninfoex.wServicePackMajor, versioninfoex.wServicePackMinor),
|
||||
versioninfoex.dwBuildNumber,
|
||||
dwProductType
|
||||
);
|
||||
#endif // MPT_OS_WINDOWS_WINRT
|
||||
}
|
||||
|
||||
|
||||
#ifdef MODPLUG_TRACKER
|
||||
|
||||
namespace {
|
||||
struct WindowsVersionCache
|
||||
{
|
||||
mpt::Windows::Version version;
|
||||
WindowsVersionCache() noexcept
|
||||
: version(GatherWindowsVersion())
|
||||
{
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static mpt::Windows::Version GatherWindowsVersionFromCache() noexcept
|
||||
{
|
||||
static WindowsVersionCache gs_WindowsVersionCache;
|
||||
return gs_WindowsVersionCache.version;
|
||||
}
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
|
||||
Version::Version() noexcept
|
||||
: m_SystemIsWindows(false)
|
||||
, m_System()
|
||||
, m_ServicePack()
|
||||
, m_Build()
|
||||
, m_Type()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Version Version::NoWindows() noexcept
|
||||
{
|
||||
return Version();
|
||||
}
|
||||
|
||||
|
||||
Version::Version(mpt::Windows::Version::System system, mpt::Windows::Version::ServicePack servicePack, mpt::Windows::Version::Build build, mpt::Windows::Version::TypeId type) noexcept
|
||||
: m_SystemIsWindows(true)
|
||||
, m_System(system)
|
||||
, m_ServicePack(servicePack)
|
||||
, m_Build(build)
|
||||
, m_Type(type)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
mpt::Windows::Version Version::Current() noexcept
|
||||
{
|
||||
#if MPT_OS_WINDOWS
|
||||
#ifdef MODPLUG_TRACKER
|
||||
return GatherWindowsVersionFromCache();
|
||||
#else // !MODPLUG_TRACKER
|
||||
return GatherWindowsVersion();
|
||||
#endif // MODPLUG_TRACKER
|
||||
#else // !MPT_OS_WINDOWS
|
||||
return mpt::Windows::Version::NoWindows();
|
||||
#endif // MPT_OS_WINDOWS
|
||||
}
|
||||
|
||||
|
||||
bool Version::IsWindows() const noexcept
|
||||
{
|
||||
return m_SystemIsWindows;
|
||||
}
|
||||
|
||||
|
||||
bool Version::IsBefore(mpt::Windows::Version::System version) const noexcept
|
||||
{
|
||||
if(!m_SystemIsWindows)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return m_System < version;
|
||||
}
|
||||
|
||||
|
||||
bool Version::IsBefore(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::IsBefore(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;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
mpt::Windows::Version::TypeId Version::GetTypeId() const noexcept
|
||||
{
|
||||
return m_Type;
|
||||
}
|
||||
|
||||
|
||||
static constexpr struct { Version::System version; const mpt::uchar * 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(mpt::Windows::Version::System version)
|
||||
{
|
||||
mpt::ustring result;
|
||||
for(const auto &v : versionMap)
|
||||
{
|
||||
if(version > v.version)
|
||||
{
|
||||
result = U_("> ") + v.name;
|
||||
break;
|
||||
} else if(version == v.version)
|
||||
{
|
||||
result = v.name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(result.empty())
|
||||
{
|
||||
result = mpt::format(U_("0x%1"))(mpt::ufmt::hex0<16>(static_cast<uint64>(version)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
mpt::ustring Version::GetName() const
|
||||
{
|
||||
mpt::ustring name = U_("Generic Windows NT");
|
||||
bool showDetails = false;
|
||||
for(const auto &v : versionMap)
|
||||
{
|
||||
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())
|
||||
{
|
||||
mpt::Wine::VersionContext v;
|
||||
if(v.Version().IsValid())
|
||||
{
|
||||
result = mpt::format(U_("Wine %1 (%2)"))(
|
||||
v.Version().AsString()
|
||||
, name
|
||||
);
|
||||
} else
|
||||
{
|
||||
result = mpt::format(U_("Wine (unknown version: '%1') (%2)"))(
|
||||
mpt::ToUnicode(mpt::Charset::UTF8, v.RawVersion())
|
||||
, name
|
||||
);
|
||||
}
|
||||
}
|
||||
#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
#ifdef MODPLUG_TRACKER
|
||||
mpt::ustring Version::GetNameShort() const
|
||||
{
|
||||
mpt::ustring name;
|
||||
if(mpt::Windows::IsWine())
|
||||
{
|
||||
mpt::Wine::VersionContext v;
|
||||
if(v.Version().IsValid())
|
||||
{
|
||||
name = mpt::format(U_("wine-%1"))(v.Version().AsString());
|
||||
} else if(v.RawVersion().length() > 0)
|
||||
{
|
||||
name = U_("wine-") + Util::BinToHex(mpt::as_span(v.RawVersion()));
|
||||
} else
|
||||
{
|
||||
name = U_("wine-");
|
||||
}
|
||||
name += U_("-") + Util::BinToHex(mpt::as_span(v.RawHostSysName()));
|
||||
} else
|
||||
{
|
||||
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::System Version::GetMinimumKernelLevel() noexcept
|
||||
{
|
||||
uint64 minimumKernelVersion = 0;
|
||||
#if MPT_OS_WINDOWS && MPT_COMPILER_MSVC
|
||||
minimumKernelVersion = std::max(minimumKernelVersion, static_cast<uint64>(mpt::Windows::Version::WinVista));
|
||||
#endif
|
||||
return mpt::Windows::Version::System(minimumKernelVersion);
|
||||
}
|
||||
|
||||
|
||||
mpt::Windows::Version::System Version::GetMinimumAPILevel() noexcept
|
||||
{
|
||||
#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 * 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)
|
||||
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
static bool GatherSystemIsWine()
|
||||
{
|
||||
bool SystemIsWine = false;
|
||||
HMODULE hNTDLL = LoadLibrary(TEXT("ntdll.dll"));
|
||||
if(hNTDLL)
|
||||
{
|
||||
SystemIsWine = (GetProcAddress(hNTDLL, "wine_get_version") != NULL);
|
||||
FreeLibrary(hNTDLL);
|
||||
hNTDLL = NULL;
|
||||
}
|
||||
return SystemIsWine;
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct SystemIsWineCache
|
||||
{
|
||||
bool SystemIsWine;
|
||||
SystemIsWineCache()
|
||||
: SystemIsWine(GatherSystemIsWine())
|
||||
{
|
||||
return;
|
||||
}
|
||||
SystemIsWineCache(bool isWine)
|
||||
: SystemIsWine(isWine)
|
||||
{
|
||||
return;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
static bool SystemIsWine(bool allowDetection = true)
|
||||
{
|
||||
#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;
|
||||
#else
|
||||
MPT_UNREFERENCED_PARAMETER(allowDetection);
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void PreventWineDetection()
|
||||
{
|
||||
SystemIsWine(false);
|
||||
}
|
||||
|
||||
bool IsOriginal()
|
||||
{
|
||||
return mpt::Windows::Version::Current().IsWindows() && !SystemIsWine();
|
||||
}
|
||||
|
||||
bool IsWine()
|
||||
{
|
||||
return mpt::Windows::Version::Current().IsWindows() && SystemIsWine();
|
||||
}
|
||||
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
} // namespace Windows
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
namespace Wine
|
||||
{
|
||||
|
||||
|
||||
Version::Version()
|
||||
: valid(false)
|
||||
, vmajor(0)
|
||||
, vminor(0)
|
||||
, vupdate(0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Version::Version(const mpt::ustring &rawVersion)
|
||||
: valid(false)
|
||||
, vmajor(0)
|
||||
, vminor(0)
|
||||
, vupdate(0)
|
||||
{
|
||||
if(rawVersion.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::vector<uint8> version = mpt::String::Split<uint8>(rawVersion, U_("."));
|
||||
if(version.size() < 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
mpt::ustring parsedVersion = mpt::String::Combine(version, U_("."));
|
||||
std::size_t len = std::min(parsedVersion.length(), rawVersion.length());
|
||||
if(len == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if(parsedVersion.substr(0, len) != rawVersion.substr(0, len))
|
||||
{
|
||||
return;
|
||||
}
|
||||
valid = true;
|
||||
vmajor = version[0];
|
||||
vminor = version[1];
|
||||
vupdate = (version.size() >= 3) ? version[2] : 0;
|
||||
}
|
||||
|
||||
|
||||
Version::Version(uint8 vmajor, uint8 vminor, uint8 vupdate)
|
||||
: valid((vmajor > 0) || (vminor > 0) || (vupdate > 0))
|
||||
, vmajor(vmajor)
|
||||
, vminor(vminor)
|
||||
, vupdate(vupdate)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
mpt::Wine::Version Version::FromInteger(uint32 version)
|
||||
{
|
||||
mpt::Wine::Version result;
|
||||
result.valid = (version <= 0xffffff);
|
||||
result.vmajor = static_cast<uint8>(version >> 16);
|
||||
result.vminor = static_cast<uint8>(version >> 8);
|
||||
result.vupdate = static_cast<uint8>(version >> 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool Version::IsValid() const
|
||||
{
|
||||
return valid;
|
||||
}
|
||||
|
||||
|
||||
mpt::ustring Version::AsString() const
|
||||
{
|
||||
return mpt::ufmt::dec(vmajor) + U_(".") + mpt::ufmt::dec(vminor) + U_(".") + mpt::ufmt::dec(vupdate);
|
||||
}
|
||||
|
||||
|
||||
uint32 Version::AsInteger() const
|
||||
{
|
||||
uint32 version = 0;
|
||||
version |= static_cast<uint32>(vmajor) << 16;
|
||||
version |= static_cast<uint32>(vminor) << 8;
|
||||
version |= static_cast<uint32>(vupdate) << 0;
|
||||
return version;
|
||||
}
|
||||
|
||||
|
||||
bool Version::IsBefore(mpt::Wine::Version other) const
|
||||
{
|
||||
if(!IsValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return (AsInteger() < other.AsInteger());
|
||||
}
|
||||
|
||||
|
||||
bool Version::IsAtLeast(mpt::Wine::Version other) const
|
||||
{
|
||||
if(!IsValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return (AsInteger() >= other.AsInteger());
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
minimumWineVersion = mpt::Wine::Version(1,8,0);
|
||||
#endif
|
||||
return minimumWineVersion;
|
||||
}
|
||||
|
||||
|
||||
VersionContext::VersionContext()
|
||||
: m_IsWine(false)
|
||||
, m_HostClass(mpt::OS::Class::Unknown)
|
||||
{
|
||||
#if MPT_OS_WINDOWS
|
||||
m_IsWine = mpt::Windows::IsWine();
|
||||
if(!m_IsWine)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_NTDLL = mpt::Library(mpt::LibraryPath::FullPath(P_("ntdll.dll")));
|
||||
if(m_NTDLL.IsValid())
|
||||
{
|
||||
const char * (__cdecl * wine_get_version)(void) = nullptr;
|
||||
const char * (__cdecl * wine_get_build_id)(void) = nullptr;
|
||||
void (__cdecl * wine_get_host_version)(const char * *, const char * *) = nullptr;
|
||||
m_NTDLL.Bind(wine_get_version, "wine_get_version");
|
||||
m_NTDLL.Bind(wine_get_build_id, "wine_get_build_id");
|
||||
m_NTDLL.Bind(wine_get_host_version, "wine_get_host_version");
|
||||
const char * wine_version = nullptr;
|
||||
const char * wine_build_id = nullptr;
|
||||
const char * wine_host_sysname = nullptr;
|
||||
const char * wine_host_release = nullptr;
|
||||
wine_version = wine_get_version ? wine_get_version() : "";
|
||||
wine_build_id = wine_get_build_id ? wine_get_build_id() : "";
|
||||
if(wine_get_host_version)
|
||||
{
|
||||
wine_get_host_version(&wine_host_sysname, &wine_host_release);
|
||||
}
|
||||
m_RawVersion = wine_version ? wine_version : "";
|
||||
m_RawBuildID = wine_build_id ? wine_build_id : "";
|
||||
m_RawHostSysName = wine_host_sysname ? wine_host_sysname : "";
|
||||
m_RawHostRelease = wine_host_release ? wine_host_release : "";
|
||||
}
|
||||
m_Version = mpt::Wine::Version(mpt::ToUnicode(mpt::Charset::UTF8, m_RawVersion));
|
||||
m_HostClass = mpt::OS::GetClassFromSysname(mpt::ToUnicode(mpt::Charset::UTF8, m_RawHostSysName));
|
||||
#endif // MPT_OS_WINDOWS
|
||||
}
|
||||
|
||||
|
||||
} // namespace Wine
|
||||
} // namespace mpt
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,304 +0,0 @@
|
|||
/*
|
||||
* mptOS.h
|
||||
* -------
|
||||
* Purpose: Operating system version information.
|
||||
* 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 "mptLibrary.h"
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
namespace OS
|
||||
{
|
||||
|
||||
enum class Class
|
||||
{
|
||||
Unknown,
|
||||
Windows,
|
||||
Linux,
|
||||
Darwin,
|
||||
BSD,
|
||||
Haiku,
|
||||
DOS,
|
||||
};
|
||||
|
||||
mpt::OS::Class GetClassFromSysname(mpt::ustring sysname);
|
||||
|
||||
mpt::OS::Class GetClass();
|
||||
|
||||
} // namespace OS
|
||||
} // namespace mpt
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
namespace Windows
|
||||
{
|
||||
|
||||
|
||||
class Version
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
enum Number : uint64
|
||||
{
|
||||
WinNT4 = 0x0000000400000000ull,
|
||||
Win2000 = 0x0000000500000000ull,
|
||||
WinXP = 0x0000000500000001ull,
|
||||
WinXP64 = 0x0000000500000002ull,
|
||||
WinVista = 0x0000000600000000ull,
|
||||
Win7 = 0x0000000600000001ull,
|
||||
Win8 = 0x0000000600000002ull,
|
||||
Win81 = 0x0000000600000003ull,
|
||||
Win10 = 0x0000000a00000000ull,
|
||||
WinNewer = Win10 + 1ull
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
typedef uint32 TypeId;
|
||||
|
||||
static mpt::ustring VersionToString(mpt::Windows::Version::System version);
|
||||
|
||||
private:
|
||||
|
||||
bool m_SystemIsWindows;
|
||||
|
||||
System m_System;
|
||||
ServicePack m_ServicePack;
|
||||
Build m_Build;
|
||||
TypeId m_Type;
|
||||
|
||||
private:
|
||||
|
||||
Version() noexcept;
|
||||
|
||||
public:
|
||||
|
||||
static Version NoWindows() noexcept;
|
||||
|
||||
Version(mpt::Windows::Version::System system, mpt::Windows::Version::ServicePack servicePack, mpt::Windows::Version::Build build, mpt::Windows::Version::TypeId type) noexcept;
|
||||
|
||||
public:
|
||||
|
||||
static mpt::Windows::Version Current() noexcept;
|
||||
|
||||
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::Windows::Version::TypeId GetTypeId() const noexcept;
|
||||
|
||||
mpt::ustring GetName() const;
|
||||
#ifdef MODPLUG_TRACKER
|
||||
mpt::ustring GetNameShort() const;
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
public:
|
||||
|
||||
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();
|
||||
|
||||
bool IsOriginal();
|
||||
bool IsWine();
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
} // namespace Windows
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
namespace Wine
|
||||
{
|
||||
|
||||
class Version
|
||||
{
|
||||
private:
|
||||
bool valid;
|
||||
uint8 vmajor;
|
||||
uint8 vminor;
|
||||
uint8 vupdate;
|
||||
public:
|
||||
Version();
|
||||
Version(uint8 vmajor, uint8 vminor, uint8 vupdate);
|
||||
explicit Version(const mpt::ustring &version);
|
||||
public:
|
||||
bool IsValid() const;
|
||||
mpt::ustring AsString() const;
|
||||
private:
|
||||
static mpt::Wine::Version FromInteger(uint32 version);
|
||||
uint32 AsInteger() const;
|
||||
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();
|
||||
|
||||
class VersionContext
|
||||
{
|
||||
protected:
|
||||
bool m_IsWine;
|
||||
mpt::Library m_NTDLL;
|
||||
std::string m_RawVersion;
|
||||
std::string m_RawBuildID;
|
||||
std::string m_RawHostSysName;
|
||||
std::string m_RawHostRelease;
|
||||
mpt::Wine::Version m_Version;
|
||||
mpt::OS::Class m_HostClass;
|
||||
public:
|
||||
VersionContext();
|
||||
public:
|
||||
bool IsWine() const { return m_IsWine; }
|
||||
mpt::Library NTDLL() const { return m_NTDLL; }
|
||||
std::string RawVersion() const { return m_RawVersion; }
|
||||
std::string RawBuildID() const { return m_RawBuildID; }
|
||||
std::string RawHostSysName() const { return m_RawHostSysName; }
|
||||
std::string RawHostRelease() const { return m_RawHostRelease; }
|
||||
mpt::Wine::Version Version() const { return m_Version; }
|
||||
mpt::OS::Class HostClass() const { return m_HostClass; }
|
||||
};
|
||||
|
||||
} // namespace Wine
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,99 +0,0 @@
|
|||
/*
|
||||
* mptOSError.h
|
||||
* ------------
|
||||
* Purpose: OS-specific error message handling.
|
||||
* 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 "mptException.h"
|
||||
#include "mptString.h"
|
||||
#include "mptStringFormat.h"
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
#if MPT_OS_WINDOWS
|
||||
#include <stdexcept>
|
||||
#endif // MPT_OS_WINDOWS
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
#if MPT_OS_WINDOWS
|
||||
#include <windows.h>
|
||||
#endif // MPT_OS_WINDOWS
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
namespace Windows
|
||||
{
|
||||
|
||||
|
||||
inline mpt::ustring GetErrorMessage(DWORD errorCode, HANDLE hModule = NULL)
|
||||
{
|
||||
mpt::ustring message;
|
||||
void *lpMsgBuf = nullptr;
|
||||
FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | (hModule ? FORMAT_MESSAGE_FROM_HMODULE : 0) | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
hModule,
|
||||
errorCode,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR)&lpMsgBuf,
|
||||
0,
|
||||
NULL);
|
||||
if(!lpMsgBuf)
|
||||
{
|
||||
DWORD e = GetLastError();
|
||||
if((e == ERROR_NOT_ENOUGH_MEMORY) || (e == ERROR_OUTOFMEMORY))
|
||||
{
|
||||
MPT_EXCEPTION_THROW_OUT_OF_MEMORY();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
try
|
||||
{
|
||||
message = mpt::ToUnicode(mpt::winstring((LPTSTR)lpMsgBuf));
|
||||
} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
|
||||
{
|
||||
LocalFree(lpMsgBuf);
|
||||
MPT_EXCEPTION_RETHROW_OUT_OF_MEMORY(e);
|
||||
}
|
||||
LocalFree(lpMsgBuf);
|
||||
return message;
|
||||
}
|
||||
|
||||
|
||||
class Error
|
||||
: public std::runtime_error
|
||||
{
|
||||
public:
|
||||
Error(DWORD errorCode, HANDLE hModule = NULL)
|
||||
: std::runtime_error(mpt::ToCharset(mpt::CharsetException, mpt::format(U_("Windows Error: 0x%1: %2"))(mpt::ufmt::hex0<8>(errorCode), GetErrorMessage(errorCode, hModule))))
|
||||
{
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // namespace Windows
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,188 +0,0 @@
|
|||
/*
|
||||
* mptOSException.h
|
||||
* ----------------
|
||||
* Purpose: platform-specific exception/signal handling
|
||||
* 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"
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
#if MPT_OS_WINDOWS
|
||||
#include <windows.h>
|
||||
#endif // MPT_OS_WINDOWS
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
|
||||
namespace Windows
|
||||
{
|
||||
|
||||
|
||||
namespace SEH
|
||||
{
|
||||
|
||||
|
||||
struct Code
|
||||
{
|
||||
private:
|
||||
DWORD m_Code;
|
||||
public:
|
||||
constexpr Code(DWORD code) noexcept
|
||||
: m_Code(code)
|
||||
{
|
||||
return;
|
||||
}
|
||||
public:
|
||||
constexpr DWORD code() const noexcept
|
||||
{
|
||||
return m_Code;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename Tfn, typename Tfilter, typename Thandler>
|
||||
auto TryFilterHandleThrow(const Tfn &fn, const Tfilter &filter, const Thandler &handler) -> decltype(fn())
|
||||
{
|
||||
static_assert(std::is_trivially_copy_assignable<decltype(fn())>::value);
|
||||
static_assert(std::is_trivially_copy_constructible<decltype(fn())>::value);
|
||||
static_assert(std::is_trivially_move_assignable<decltype(fn())>::value);
|
||||
static_assert(std::is_trivially_move_constructible<decltype(fn())>::value);
|
||||
DWORD code = 0;
|
||||
__try
|
||||
{
|
||||
return fn();
|
||||
} __except(filter(GetExceptionCode(), GetExceptionInformation()))
|
||||
{
|
||||
code = GetExceptionCode();
|
||||
}
|
||||
throw Windows::SEH::Code(code);
|
||||
}
|
||||
|
||||
|
||||
template <typename Tfn, typename Tfilter, typename Thandler>
|
||||
void TryFilterHandleVoid(const Tfn &fn, const Tfilter &filter, const Thandler &handler)
|
||||
{
|
||||
static_assert(std::is_same<decltype(fn()), void>::value || std::is_trivially_copy_assignable<decltype(fn())>::value);
|
||||
static_assert(std::is_same<decltype(fn()), void>::value || std::is_trivially_copy_constructible<decltype(fn())>::value);
|
||||
static_assert(std::is_same<decltype(fn()), void>::value || std::is_trivially_move_assignable<decltype(fn())>::value);
|
||||
static_assert(std::is_same<decltype(fn()), void>::value || std::is_trivially_move_constructible<decltype(fn())>::value);
|
||||
__try
|
||||
{
|
||||
fn();
|
||||
return;
|
||||
} __except(filter(GetExceptionCode(), GetExceptionInformation()))
|
||||
{
|
||||
DWORD code = GetExceptionCode();
|
||||
handler(code);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
template <typename Tfn, typename Tfilter, typename Thandler>
|
||||
auto TryFilterHandleDefault(const Tfn &fn, const Tfilter &filter, const Thandler &handler, decltype(fn()) def = decltype(fn()){}) -> decltype(fn())
|
||||
{
|
||||
static_assert(std::is_trivially_copy_assignable<decltype(fn())>::value);
|
||||
static_assert(std::is_trivially_copy_constructible<decltype(fn())>::value);
|
||||
static_assert(std::is_trivially_move_assignable<decltype(fn())>::value);
|
||||
static_assert(std::is_trivially_move_constructible<decltype(fn())>::value);
|
||||
auto result = def;
|
||||
__try
|
||||
{
|
||||
result = fn();
|
||||
} __except(filter(GetExceptionCode(), GetExceptionInformation()))
|
||||
{
|
||||
DWORD code = GetExceptionCode();
|
||||
result = handler(code);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
template <typename Tfn>
|
||||
auto TryReturnOrThrow(const Tfn &fn) -> decltype(fn())
|
||||
{
|
||||
return TryFilterHandleThrow(
|
||||
fn,
|
||||
[](auto code, auto eptr)
|
||||
{
|
||||
MPT_UNREFERENCED_PARAMETER(code);
|
||||
MPT_UNREFERENCED_PARAMETER(eptr);
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
},
|
||||
[](auto code)
|
||||
{
|
||||
throw Windows::SEH::Code(code);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
template <typename Tfn>
|
||||
DWORD TryOrError(const Tfn &fn)
|
||||
{
|
||||
DWORD result = DWORD{0};
|
||||
TryFilterHandleVoid(
|
||||
fn,
|
||||
[](auto code, auto eptr)
|
||||
{
|
||||
MPT_UNREFERENCED_PARAMETER(code);
|
||||
MPT_UNREFERENCED_PARAMETER(eptr);
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
},
|
||||
[&result](auto code)
|
||||
{
|
||||
result = code;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
template <typename Tfn>
|
||||
auto TryReturnOrDefault(const Tfn &fn, decltype(fn()) def = decltype(fn()){}) -> decltype(fn())
|
||||
{
|
||||
return TryFilterHandleDefault(
|
||||
fn,
|
||||
[](auto code, auto eptr)
|
||||
{
|
||||
MPT_UNREFERENCED_PARAMETER(code);
|
||||
MPT_UNREFERENCED_PARAMETER(eptr);
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
},
|
||||
[def](auto code)
|
||||
{
|
||||
MPT_UNREFERENCED_PARAMETER(code);
|
||||
return def;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
} // namspace SEH
|
||||
|
||||
|
||||
} // namespace Windows
|
||||
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,867 +0,0 @@
|
|||
/*
|
||||
* mptPathString.cpp
|
||||
* -----------------
|
||||
* Purpose: Wrapper class around the platform-native representation of path names. Should be the only type that is used to store path names.
|
||||
* 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 "mptPathString.h"
|
||||
|
||||
#include "misc_util.h"
|
||||
|
||||
#include "mptUUID.h"
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
#include <windows.h>
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
#include <shlwapi.h>
|
||||
#endif
|
||||
#include <tchar.h>
|
||||
#endif
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
|
||||
RawPathString PathString::AsNativePrefixed() const
|
||||
{
|
||||
#if MPT_OS_WINDOWS_WINRT && (_WIN32_WINNT < 0x0a00)
|
||||
// For WinRT on Windows 8, there is no official wy to determine an absolute path.
|
||||
return path;
|
||||
#else
|
||||
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(*this).AsNative();
|
||||
if(absPath.substr(0, 2) == PL_("\\\\"))
|
||||
{
|
||||
// Path is a network share: \\server\foo.bar -> \\?\UNC\server\foo.bar
|
||||
return PL_("\\\\?\\UNC") + absPath.substr(1);
|
||||
} else
|
||||
{
|
||||
// Regular file: C:\foo.bar -> \\?\C:\foo.bar
|
||||
return PL_("\\\\?\\") + absPath;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if !MPT_OS_WINDOWS_WINRT
|
||||
|
||||
int PathString::CompareNoCase(const PathString & a, const PathString & b)
|
||||
{
|
||||
return lstrcmpi(a.path.c_str(), b.path.c_str());
|
||||
}
|
||||
|
||||
#endif // !MPT_OS_WINDOWS_WINRT
|
||||
|
||||
|
||||
// Convert a path to its simplified form, i.e. remove ".\" and "..\" entries
|
||||
// Note: We use our own implementation as PathCanonicalize is limited to MAX_PATH
|
||||
// and unlimited versions are only available on Windows 8 and later.
|
||||
// Furthermore, we also convert forward-slashes to backslashes and always remove trailing slashes.
|
||||
PathString PathString::Simplify() const
|
||||
{
|
||||
if(path.empty())
|
||||
return PathString();
|
||||
|
||||
std::vector<RawPathString> components;
|
||||
RawPathString root;
|
||||
RawPathString::size_type startPos = 0;
|
||||
if(path.size() >= 2 && path[1] == PC_(':'))
|
||||
{
|
||||
// Drive letter
|
||||
root = path.substr(0, 2) + PC_('\\');
|
||||
startPos = 2;
|
||||
} else if(path.substr(0, 2) == PL_("\\\\"))
|
||||
{
|
||||
// Network share
|
||||
root = PL_("\\\\");
|
||||
startPos = 2;
|
||||
} else if(path.substr(0, 2) == PL_(".\\") || path.substr(0, 2) == PL_("./"))
|
||||
{
|
||||
// Special case for relative paths
|
||||
root = PL_(".\\");
|
||||
startPos = 2;
|
||||
} else if(path.size() >= 1 && (path[0] == PC_('\\') || path[0] == PC_('/')))
|
||||
{
|
||||
// Special case for relative paths
|
||||
root = PL_("\\");
|
||||
startPos = 1;
|
||||
}
|
||||
|
||||
while(startPos < path.size())
|
||||
{
|
||||
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 == PL_(".."))
|
||||
{
|
||||
// Go back one directory
|
||||
if(!components.empty())
|
||||
{
|
||||
components.pop_back();
|
||||
}
|
||||
} else if(dir == PL_("."))
|
||||
{
|
||||
// nop
|
||||
} else if(!dir.empty())
|
||||
{
|
||||
components.push_back(std::move(dir));
|
||||
}
|
||||
startPos = pos + 1;
|
||||
}
|
||||
|
||||
RawPathString result = root;
|
||||
result.reserve(path.size());
|
||||
for(const auto &component : components)
|
||||
{
|
||||
result += component + PL_("\\");
|
||||
}
|
||||
if(!components.empty())
|
||||
result.pop_back();
|
||||
return mpt::PathString(result);
|
||||
}
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
|
||||
#if MPT_OS_WINDOWS && (defined(MPT_ENABLE_DYNBIND) || defined(MPT_ENABLE_TEMPFILE))
|
||||
|
||||
void PathString::SplitPath(PathString *drive, PathString *dir, PathString *fname, PathString *ext) const
|
||||
{
|
||||
// We cannot use CRT splitpath here, because:
|
||||
// * limited to _MAX_PATH or similar
|
||||
// * no support for UNC paths
|
||||
// * no support for \\?\ prefixed paths
|
||||
|
||||
if(drive) *drive = mpt::PathString();
|
||||
if(dir) *dir = mpt::PathString();
|
||||
if(fname) *fname = mpt::PathString();
|
||||
if(ext) *ext = mpt::PathString();
|
||||
|
||||
mpt::RawPathString p = path;
|
||||
|
||||
// remove \\?\\ prefix
|
||||
if(p.substr(0, 8) == PL_("\\\\?\\UNC\\"))
|
||||
{
|
||||
p = PL_("\\\\") + p.substr(8);
|
||||
} else if(p.substr(0, 4) == PL_("\\\\?\\"))
|
||||
{
|
||||
p = p.substr(4);
|
||||
}
|
||||
|
||||
if (p.length() >= 2 && (
|
||||
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(PL_("\\/"));
|
||||
if(first_slash != mpt::RawPathString::npos)
|
||||
{
|
||||
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));
|
||||
p = p.substr(2 + first_slash + 1 + second_slash);
|
||||
} else
|
||||
{
|
||||
if(drive) *drive = mpt::PathString::FromNative(p);
|
||||
p = mpt::RawPathString();
|
||||
}
|
||||
} else
|
||||
{
|
||||
if(drive) *drive = mpt::PathString::FromNative(p);
|
||||
p = mpt::RawPathString();
|
||||
}
|
||||
} else
|
||||
{ // local
|
||||
if(p.length() >= 2 && (p[1] == PC_(':')))
|
||||
{
|
||||
if(drive) *drive = mpt::PathString::FromNative(p.substr(0, 2));
|
||||
p = p.substr(2);
|
||||
} else
|
||||
{
|
||||
if(drive) *drive = mpt::PathString();
|
||||
}
|
||||
}
|
||||
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));
|
||||
p = p.substr(last_slash + 1);
|
||||
} else
|
||||
{
|
||||
if(dir) *dir = mpt::PathString();
|
||||
}
|
||||
mpt::RawPathString::size_type last_dot = p.find_last_of(PL_("."));
|
||||
if(last_dot == mpt::RawPathString::npos)
|
||||
{
|
||||
if(fname) *fname = mpt::PathString::FromNative(p);
|
||||
if(ext) *ext = mpt::PathString();
|
||||
} else if(last_dot == 0)
|
||||
{
|
||||
if(fname) *fname = mpt::PathString::FromNative(p);
|
||||
if(ext) *ext = mpt::PathString();
|
||||
} else if(p == PL_(".") || p == PL_(".."))
|
||||
{
|
||||
if(fname) *fname = mpt::PathString::FromNative(p);
|
||||
if(ext) *ext = mpt::PathString();
|
||||
} else
|
||||
{
|
||||
if(fname) *fname = mpt::PathString::FromNative(p.substr(0, last_dot));
|
||||
if(ext) *ext = mpt::PathString::FromNative(p.substr(last_dot));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
PathString PathString::GetDrive() const
|
||||
{
|
||||
PathString drive;
|
||||
SplitPath(&drive, nullptr, nullptr, nullptr);
|
||||
return drive;
|
||||
}
|
||||
PathString PathString::GetDir() const
|
||||
{
|
||||
PathString dir;
|
||||
SplitPath(nullptr, &dir, nullptr, nullptr);
|
||||
return dir;
|
||||
}
|
||||
PathString PathString::GetPath() const
|
||||
{
|
||||
PathString drive, dir;
|
||||
SplitPath(&drive, &dir, nullptr, nullptr);
|
||||
return drive + dir;
|
||||
}
|
||||
PathString PathString::GetFileName() const
|
||||
{
|
||||
PathString fname;
|
||||
SplitPath(nullptr, nullptr, &fname, nullptr);
|
||||
return fname;
|
||||
}
|
||||
PathString PathString::GetFileExt() const
|
||||
{
|
||||
PathString ext;
|
||||
SplitPath(nullptr, nullptr, nullptr, &ext);
|
||||
return ext;
|
||||
}
|
||||
PathString PathString::GetFullFileName() const
|
||||
{
|
||||
PathString name, ext;
|
||||
SplitPath(nullptr, nullptr, &name, &ext);
|
||||
return name + ext;
|
||||
}
|
||||
|
||||
|
||||
bool PathString::IsDirectory() const
|
||||
{
|
||||
// Using PathIsDirectoryW here instead would increase libopenmpt dependencies by shlwapi.dll.
|
||||
// GetFileAttributesW also does the job just fine.
|
||||
#if MPT_OS_WINDOWS_WINRT
|
||||
WIN32_FILE_ATTRIBUTE_DATA data;
|
||||
MemsetZero(data);
|
||||
if(::GetFileAttributesExW(path.c_str(), GetFileExInfoStandard, &data) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
DWORD dwAttrib = data.dwFileAttributes;
|
||||
#else // !MPT_OS_WINDOWS_WINRT
|
||||
DWORD dwAttrib = ::GetFileAttributes(path.c_str());
|
||||
#endif // MPT_OS_WINDOWS_WINRT
|
||||
return ((dwAttrib != INVALID_FILE_ATTRIBUTES) && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
|
||||
}
|
||||
|
||||
bool PathString::IsFile() const
|
||||
{
|
||||
#if MPT_OS_WINDOWS_WINRT
|
||||
WIN32_FILE_ATTRIBUTE_DATA data;
|
||||
MemsetZero(data);
|
||||
if (::GetFileAttributesExW(path.c_str(), GetFileExInfoStandard, &data) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
DWORD dwAttrib = data.dwFileAttributes;
|
||||
#else // !MPT_OS_WINDOWS_WINRT
|
||||
DWORD dwAttrib = ::GetFileAttributes(path.c_str());
|
||||
#endif // MPT_OS_WINDOWS_WINRT
|
||||
return ((dwAttrib != INVALID_FILE_ATTRIBUTES) && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
|
||||
}
|
||||
|
||||
#endif // MPT_OS_WINDOWS && (MPT_ENABLE_DYNBIND || MPT_ENABLE_TEMPFILE)
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
|
||||
|
||||
bool PathString::FileOrDirectoryExists() const
|
||||
{
|
||||
return ::PathFileExists(path.c_str()) != FALSE;
|
||||
}
|
||||
|
||||
#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
|
||||
|
||||
PathString PathString::ReplaceExt(const mpt::PathString &newExt) const
|
||||
{
|
||||
return GetDrive() + GetDir() + GetFileName() + newExt;
|
||||
}
|
||||
|
||||
|
||||
PathString PathString::SanitizeComponent() const
|
||||
{
|
||||
PathString result = *this;
|
||||
SanitizeFilename(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// Convert an absolute path to a path that's relative to "&relativeTo".
|
||||
PathString PathString::AbsolutePathToRelative(const PathString &relativeTo) const
|
||||
{
|
||||
mpt::PathString result = *this;
|
||||
if(path.empty())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
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 = P_(".\\"); // ".\"
|
||||
result += mpt::PathString::FromNative(AsNative().substr(relativeTo.AsNative().length()));
|
||||
} 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));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// Convert a path that is relative to "&relativeTo" to an absolute path.
|
||||
PathString PathString::RelativePathToAbsolute(const PathString &relativeTo) const
|
||||
{
|
||||
mpt::PathString result = *this;
|
||||
if(path.empty())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
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 += 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\"
|
||||
result += mpt::PathString::FromNative(AsNative().substr(2));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS
|
||||
|
||||
|
||||
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 PathIsAbsolute(const mpt::PathString &path) {
|
||||
mpt::RawPathString rawpath = path.AsNative();
|
||||
#if MPT_OS_WINDOWS
|
||||
if(rawpath.substr(0, 8) == PL_("\\\\?\\UNC\\"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if(rawpath.substr(0, 4) == PL_("\\\\?\\"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if(rawpath.substr(0, 2) == PL_("\\\\"))
|
||||
{
|
||||
return true; // UNC
|
||||
}
|
||||
if(rawpath.substr(0, 2) == PL_("//"))
|
||||
{
|
||||
return true; // UNC
|
||||
}
|
||||
return (rawpath.length()) >= 3 && (rawpath[1] == ':') && mpt::PathString::IsPathSeparator(rawpath[2]);
|
||||
#else
|
||||
return (rawpath.length() >= 1) && mpt::PathString::IsPathSeparator(rawpath[0]);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
#if !(MPT_OS_WINDOWS_WINRT && (_WIN32_WINNT < 0x0a00))
|
||||
|
||||
mpt::PathString GetAbsolutePath(const mpt::PathString &path)
|
||||
{
|
||||
DWORD size = GetFullPathName(path.AsNative().c_str(), 0, nullptr, nullptr);
|
||||
if(size == 0)
|
||||
{
|
||||
return path;
|
||||
}
|
||||
std::vector<TCHAR> fullPathName(size, TEXT('\0'));
|
||||
if(GetFullPathName(path.AsNative().c_str(), size, fullPathName.data(), nullptr) == 0)
|
||||
{
|
||||
return path;
|
||||
}
|
||||
return mpt::PathString::FromNative(fullPathName.data());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef MODPLUG_TRACKER
|
||||
|
||||
bool DeleteWholeDirectoryTree(mpt::PathString path)
|
||||
{
|
||||
if(path.AsNative().empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(PathIsRelative(path.AsNative().c_str()) == TRUE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(!path.FileOrDirectoryExists())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if(!path.IsDirectory())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
path.EnsureTrailingSlash();
|
||||
HANDLE hFind = NULL;
|
||||
WIN32_FIND_DATA wfd;
|
||||
MemsetZero(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 != P_(".") && filename != P_(".."))
|
||||
{
|
||||
filename = path + filename;
|
||||
if(filename.IsDirectory())
|
||||
{
|
||||
if(!DeleteWholeDirectoryTree(filename))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} else if(filename.IsFile())
|
||||
{
|
||||
if(DeleteFile(filename.AsNative().c_str()) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while(FindNextFile(hFind, &wfd));
|
||||
FindClose(hFind);
|
||||
}
|
||||
if(RemoveDirectory(path.AsNative().c_str()) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
#if defined(MPT_ENABLE_DYNBIND) || defined(MPT_ENABLE_TEMPFILE)
|
||||
|
||||
mpt::PathString GetExecutablePath()
|
||||
{
|
||||
std::vector<TCHAR> exeFileName(MAX_PATH);
|
||||
while(GetModuleFileName(0, exeFileName.data(), mpt::saturate_cast<DWORD>(exeFileName.size())) >= exeFileName.size())
|
||||
{
|
||||
if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
return mpt::PathString();
|
||||
}
|
||||
exeFileName.resize(exeFileName.size() * 2);
|
||||
}
|
||||
return mpt::GetAbsolutePath(mpt::PathString::FromNative(exeFileName.data()).GetPath());
|
||||
}
|
||||
|
||||
#endif // MPT_ENABLE_DYNBIND || MPT_ENABLE_TEMPFILE
|
||||
|
||||
|
||||
#if defined(MPT_ENABLE_DYNBIND)
|
||||
|
||||
#if !MPT_OS_WINDOWS_WINRT
|
||||
|
||||
mpt::PathString GetSystemPath()
|
||||
{
|
||||
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()) + P_("\\");
|
||||
}
|
||||
|
||||
#endif // !MPT_OS_WINDOWS_WINRT
|
||||
|
||||
#endif // MPT_ENABLE_DYNBIND
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
|
||||
|
||||
#if defined(MPT_ENABLE_TEMPFILE)
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
mpt::PathString GetTempDirectory()
|
||||
{
|
||||
DWORD size = GetTempPath(0, nullptr);
|
||||
if(size)
|
||||
{
|
||||
std::vector<TCHAR> tempPath(size + 1);
|
||||
if(GetTempPath(size + 1, tempPath.data()))
|
||||
{
|
||||
return mpt::PathString::FromNative(tempPath.data());
|
||||
}
|
||||
}
|
||||
// use exe directory as fallback
|
||||
return mpt::GetExecutablePath();
|
||||
}
|
||||
|
||||
mpt::PathString CreateTempFileName(const mpt::PathString &fileNamePrefix, const mpt::PathString &fileNameExtension)
|
||||
{
|
||||
mpt::PathString filename = mpt::GetTempDirectory();
|
||||
filename += (!fileNamePrefix.empty() ? fileNamePrefix + P_("_") : mpt::PathString());
|
||||
filename += mpt::PathString::FromUnicode(mpt::UUID::GenerateLocalUseOnly().ToUString());
|
||||
filename += (!fileNameExtension.empty() ? P_(".") + fileNameExtension : mpt::PathString());
|
||||
return filename;
|
||||
}
|
||||
|
||||
TempFileGuard::TempFileGuard(const mpt::PathString &filename)
|
||||
: filename(filename)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mpt::PathString TempFileGuard::GetFilename() const
|
||||
{
|
||||
return filename;
|
||||
}
|
||||
|
||||
TempFileGuard::~TempFileGuard()
|
||||
{
|
||||
if(!filename.empty())
|
||||
{
|
||||
DeleteFile(filename.AsNative().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MODPLUG_TRACKER
|
||||
|
||||
TempDirGuard::TempDirGuard(const mpt::PathString &dirname_)
|
||||
: dirname(dirname_.WithTrailingSlash())
|
||||
{
|
||||
if(dirname.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
if(::CreateDirectory(dirname.AsNative().c_str(), NULL) == 0)
|
||||
{ // fail
|
||||
dirname = mpt::PathString();
|
||||
}
|
||||
}
|
||||
|
||||
mpt::PathString TempDirGuard::GetDirname() const
|
||||
{
|
||||
return dirname;
|
||||
}
|
||||
|
||||
TempDirGuard::~TempDirGuard()
|
||||
{
|
||||
if(!dirname.empty())
|
||||
{
|
||||
DeleteWholeDirectoryTree(dirname);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
#endif // MPT_ENABLE_TEMPFILE
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
|
||||
static inline char SanitizeFilenameChar(char c)
|
||||
{
|
||||
if( c == '\\' ||
|
||||
c == '\"' ||
|
||||
c == '/' ||
|
||||
c == ':' ||
|
||||
c == '?' ||
|
||||
c == '<' ||
|
||||
c == '>' ||
|
||||
c == '|' ||
|
||||
c == '*')
|
||||
{
|
||||
c = '_';
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
static inline wchar_t SanitizeFilenameChar(wchar_t c)
|
||||
{
|
||||
if( c == L'\\' ||
|
||||
c == L'\"' ||
|
||||
c == L'/' ||
|
||||
c == L':' ||
|
||||
c == L'?' ||
|
||||
c == L'<' ||
|
||||
c == L'>' ||
|
||||
c == L'|' ||
|
||||
c == L'*')
|
||||
{
|
||||
c = L'_';
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
void SanitizeFilename(mpt::PathString &filename)
|
||||
{
|
||||
mpt::RawPathString tmp = filename.AsNative();
|
||||
for(auto &c : tmp)
|
||||
{
|
||||
c = SanitizeFilenameChar(c);
|
||||
}
|
||||
filename = mpt::PathString::FromNative(tmp);
|
||||
}
|
||||
|
||||
void SanitizeFilename(char *beg, char *end)
|
||||
{
|
||||
for(char *it = beg; it != end; ++it)
|
||||
{
|
||||
*it = SanitizeFilenameChar(*it);
|
||||
}
|
||||
}
|
||||
|
||||
void SanitizeFilename(wchar_t *beg, wchar_t *end)
|
||||
{
|
||||
for(wchar_t *it = beg; it != end; ++it)
|
||||
{
|
||||
*it = SanitizeFilenameChar(*it);
|
||||
}
|
||||
}
|
||||
|
||||
void SanitizeFilename(std::string &str)
|
||||
{
|
||||
for(size_t i = 0; i < str.length(); i++)
|
||||
{
|
||||
str[i] = SanitizeFilenameChar(str[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void SanitizeFilename(std::wstring &str)
|
||||
{
|
||||
for(size_t i = 0; i < str.length(); i++)
|
||||
{
|
||||
str[i] = SanitizeFilenameChar(str[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#if MPT_USTRING_MODE_UTF8
|
||||
void SanitizeFilename(mpt::u8string &str)
|
||||
{
|
||||
for(size_t i = 0; i < str.length(); i++)
|
||||
{
|
||||
str[i] = SanitizeFilenameChar(str[i]);
|
||||
}
|
||||
}
|
||||
#endif // MPT_USTRING_MODE_UTF8
|
||||
|
||||
#if defined(MPT_WITH_MFC)
|
||||
void SanitizeFilename(CString &str)
|
||||
{
|
||||
for(int i = 0; i < str.GetLength(); i++)
|
||||
{
|
||||
str.SetAt(i, SanitizeFilenameChar(str.GetAt(i)));
|
||||
}
|
||||
}
|
||||
#endif // MPT_WITH_MFC
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
|
||||
|
||||
mpt::PathString FileType::AsFilterString(FlagSet<FileTypeFormat> format) const
|
||||
{
|
||||
mpt::PathString filter;
|
||||
if(GetShortName().empty() || GetExtensions().empty())
|
||||
{
|
||||
return filter;
|
||||
}
|
||||
if(!GetDescription().empty())
|
||||
{
|
||||
filter += mpt::PathString::FromUnicode(GetDescription());
|
||||
} else
|
||||
{
|
||||
filter += mpt::PathString::FromUnicode(GetShortName());
|
||||
}
|
||||
const auto extensions = GetExtensions();
|
||||
if(format[FileTypeFormatShowExtensions])
|
||||
{
|
||||
filter += P_(" (");
|
||||
bool first = true;
|
||||
for(const auto &ext : extensions)
|
||||
{
|
||||
if(first)
|
||||
{
|
||||
first = false;
|
||||
} else
|
||||
{
|
||||
filter += P_(",");
|
||||
}
|
||||
filter += P_("*.");
|
||||
filter += ext;
|
||||
}
|
||||
filter += P_(")");
|
||||
}
|
||||
filter += P_("|");
|
||||
{
|
||||
bool first = true;
|
||||
for(const auto &ext : extensions)
|
||||
{
|
||||
if(first)
|
||||
{
|
||||
first = false;
|
||||
} else
|
||||
{
|
||||
filter += P_(";");
|
||||
}
|
||||
filter += P_("*.");
|
||||
filter += ext;
|
||||
}
|
||||
}
|
||||
filter += P_("|");
|
||||
return filter;
|
||||
}
|
||||
|
||||
|
||||
mpt::PathString FileType::AsFilterOnlyString() const
|
||||
{
|
||||
mpt::PathString filter;
|
||||
const auto extensions = GetExtensions();
|
||||
{
|
||||
bool first = true;
|
||||
for(const auto &ext : extensions)
|
||||
{
|
||||
if(first)
|
||||
{
|
||||
first = false;
|
||||
} else
|
||||
{
|
||||
filter += P_(";");
|
||||
}
|
||||
filter += P_("*.");
|
||||
filter += ext;
|
||||
}
|
||||
}
|
||||
return filter;
|
||||
}
|
||||
|
||||
|
||||
mpt::PathString ToFilterString(const FileType &fileType, FlagSet<FileTypeFormat> format)
|
||||
{
|
||||
return fileType.AsFilterString(format);
|
||||
}
|
||||
|
||||
|
||||
mpt::PathString ToFilterString(const std::vector<FileType> &fileTypes, FlagSet<FileTypeFormat> format)
|
||||
{
|
||||
mpt::PathString filter;
|
||||
for(const auto &type : fileTypes)
|
||||
{
|
||||
filter += type.AsFilterString(format);
|
||||
}
|
||||
return filter;
|
||||
}
|
||||
|
||||
|
||||
mpt::PathString ToFilterOnlyString(const FileType &fileType, bool prependSemicolonWhenNotEmpty)
|
||||
{
|
||||
mpt::PathString filter = fileType.AsFilterOnlyString();
|
||||
return filter.empty() ? filter : (prependSemicolonWhenNotEmpty ? P_(";") : P_("")) + filter;
|
||||
}
|
||||
|
||||
|
||||
mpt::PathString ToFilterOnlyString(const std::vector<FileType> &fileTypes, bool prependSemicolonWhenNotEmpty)
|
||||
{
|
||||
mpt::PathString filter;
|
||||
for(const auto &type : fileTypes)
|
||||
{
|
||||
filter += type.AsFilterOnlyString();
|
||||
}
|
||||
return filter.empty() ? filter : (prependSemicolonWhenNotEmpty ? P_(";") : P_("")) + filter;
|
||||
}
|
||||
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,508 +0,0 @@
|
|||
/*
|
||||
* mptPathString.h
|
||||
* ---------------
|
||||
* Purpose: Wrapper class around the platform-native representation of path names. Should be the only type that is used to store path names.
|
||||
* 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 <vector>
|
||||
|
||||
#include "FlagSet.h"
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
|
||||
#define MPT_DEPRECATED_PATH
|
||||
//#define MPT_DEPRECATED_PATH [[deprecated]]
|
||||
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
typedef mpt::winstring RawPathString;
|
||||
#else // !MPT_OS_WINDOWS
|
||||
typedef std::string RawPathString;
|
||||
#endif // if MPT_OS_WINDOWS
|
||||
|
||||
|
||||
|
||||
class PathString
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
RawPathString path;
|
||||
|
||||
private:
|
||||
|
||||
explicit PathString(const RawPathString & path)
|
||||
: path(path)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
PathString()
|
||||
{
|
||||
return;
|
||||
}
|
||||
PathString(const PathString & other)
|
||||
: path(other.path)
|
||||
{
|
||||
return;
|
||||
}
|
||||
PathString & assign(const PathString & other)
|
||||
{
|
||||
path = other.path;
|
||||
return *this;
|
||||
}
|
||||
PathString & operator = (const PathString & other)
|
||||
{
|
||||
return assign(other);
|
||||
}
|
||||
PathString & append(const PathString & other)
|
||||
{
|
||||
path.append(other.path);
|
||||
return *this;
|
||||
}
|
||||
PathString & operator += (const PathString & other)
|
||||
{
|
||||
return append(other);
|
||||
}
|
||||
|
||||
friend PathString operator + (const PathString & a, const PathString & b)
|
||||
{
|
||||
return PathString(a).append(b);
|
||||
}
|
||||
|
||||
friend bool operator < (const PathString & a, const PathString & b)
|
||||
{
|
||||
return a.AsNative() < b.AsNative();
|
||||
}
|
||||
friend bool operator == (const PathString & a, const PathString & b)
|
||||
{
|
||||
return a.AsNative() == b.AsNative();
|
||||
}
|
||||
friend bool operator != (const PathString & a, const PathString & b)
|
||||
{
|
||||
return a.AsNative() != b.AsNative();
|
||||
}
|
||||
|
||||
bool empty() const { return path.empty(); }
|
||||
|
||||
std::size_t Length() const { return path.size(); }
|
||||
|
||||
|
||||
|
||||
public:
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
#if !MPT_OS_WINDOWS_WINRT
|
||||
static int CompareNoCase(const PathString & a, const PathString & b);
|
||||
#endif // !MPT_OS_WINDOWS_WINRT
|
||||
#endif
|
||||
|
||||
#if MPT_OS_WINDOWS && (defined(MPT_ENABLE_DYNBIND) || defined(MPT_ENABLE_TEMPFILE))
|
||||
|
||||
void SplitPath(PathString *drive, PathString *dir, PathString *fname, PathString *ext) const;
|
||||
// \\?\ prefixes will be removed and \\?\\UNC prefixes converted to canonical \\ form.
|
||||
PathString GetDrive() const; // Drive letter + colon, e.g. "C:" or \\server\\share
|
||||
PathString GetDir() const; // Directory, e.g. "\OpenMPT\"
|
||||
PathString GetPath() const; // Drive + Dir, e.g. "C:\OpenMPT\"
|
||||
PathString GetFileName() const; // File name without extension, e.g. "OpenMPT"
|
||||
PathString GetFileExt() const; // Extension including dot, e.g. ".exe"
|
||||
PathString GetFullFileName() const; // File name + extension, e.g. "OpenMPT.exe"
|
||||
|
||||
// Verify if this path represents a valid directory on the file system.
|
||||
bool IsDirectory() const;
|
||||
// Verify if this path exists and is a file on the file system.
|
||||
bool IsFile() const;
|
||||
|
||||
#endif // MPT_OS_WINDOWS && (MPT_ENABLE_DYNBIND || MPT_ENABLE_TEMPFILE)
|
||||
|
||||
#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
|
||||
|
||||
bool FileOrDirectoryExists() const;
|
||||
|
||||
#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"
|
||||
PathString ReplaceExt(const mpt::PathString &newExt) const;
|
||||
|
||||
// Removes special characters from a filename component and replaces them with a safe replacement character ("_" on windows).
|
||||
// Returns the result.
|
||||
// Note that this also removes path component separators, so this should only be used on single-component PathString objects.
|
||||
PathString SanitizeComponent() const;
|
||||
|
||||
bool HasTrailingSlash() const
|
||||
{
|
||||
if(path.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
RawPathString::value_type c = path[path.length() - 1];
|
||||
return IsPathSeparator(c);
|
||||
}
|
||||
mpt::PathString &EnsureTrailingSlash()
|
||||
{
|
||||
if(!path.empty() && !HasTrailingSlash())
|
||||
{
|
||||
path += GetDefaultPathSeparator();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
mpt::PathString WithoutTrailingSlash() const
|
||||
{
|
||||
mpt::PathString result = *this;
|
||||
while(result.HasTrailingSlash())
|
||||
{
|
||||
if(result.Length() == 1)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
result = mpt::PathString(result.AsNative().substr(0, result.AsNative().length() - 1));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
mpt::PathString WithTrailingSlash() const
|
||||
{
|
||||
mpt::PathString result = *this;
|
||||
result.EnsureTrailingSlash();
|
||||
return result;
|
||||
}
|
||||
|
||||
// Relative / absolute paths conversion
|
||||
mpt::PathString AbsolutePathToRelative(const mpt::PathString &relativeTo) const;
|
||||
mpt::PathString RelativePathToAbsolute(const mpt::PathString &relativeTo) const;
|
||||
|
||||
#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS
|
||||
|
||||
public:
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
#if !(MPT_WSTRING_CONVERT)
|
||||
#error "mpt::PathString on Windows depends on MPT_WSTRING_CONVERT)"
|
||||
#endif
|
||||
// conversions
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
MPT_DEPRECATED_PATH std::string ToLocale() const { return mpt::ToCharset(mpt::Charset::Locale, path); }
|
||||
#endif
|
||||
std::string ToUTF8() const { return mpt::ToCharset(mpt::Charset::UTF8, 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::ToWin(mpt::Charset::Locale, path)); }
|
||||
static PathString FromLocaleSilent(const std::string &path) { return PathString(mpt::ToWin(mpt::Charset::Locale, path)); }
|
||||
#endif
|
||||
static PathString FromUTF8(const std::string &path) { return PathString(mpt::ToWin(mpt::Charset::UTF8, 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(MPT_WITH_MFC)
|
||||
// CString TCHAR, so this is CHAR or WCHAR, depending on UNICODE
|
||||
CString ToCString() const { return mpt::ToCString(path); }
|
||||
static PathString FromCString(const CString &path) { return PathString(mpt::ToWin(path)); }
|
||||
#endif // MPT_WITH_MFC
|
||||
|
||||
// Convert a path to its simplified form, i.e. remove ".\" and "..\" entries
|
||||
mpt::PathString Simplify() const;
|
||||
|
||||
#else // !MPT_OS_WINDOWS
|
||||
|
||||
// conversions
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
std::string ToLocale() const { return path; }
|
||||
std::string ToUTF8() const { return mpt::ToCharset(mpt::Charset::UTF8, mpt::Charset::Locale, path); }
|
||||
#if MPT_WSTRING_CONVERT
|
||||
std::wstring ToWide() const { return mpt::ToWide(mpt::Charset::Locale, path); }
|
||||
#endif
|
||||
mpt::ustring ToUnicode() const { return mpt::ToUnicode(mpt::Charset::Locale, path); }
|
||||
static PathString FromLocale(const std::string &path) { return PathString(path); }
|
||||
static PathString FromLocaleSilent(const std::string &path) { return PathString(path); }
|
||||
static PathString FromUTF8(const std::string &path) { return PathString(mpt::ToCharset(mpt::Charset::Locale, mpt::Charset::UTF8, path)); }
|
||||
#if MPT_WSTRING_CONVERT
|
||||
static PathString FromWide(const std::wstring &path) { return PathString(mpt::ToCharset(mpt::Charset::Locale, path)); }
|
||||
#endif
|
||||
static PathString FromUnicode(const mpt::ustring &path) { return PathString(mpt::ToCharset(mpt::Charset::Locale, path)); }
|
||||
RawPathString AsNative() const { return path; }
|
||||
RawPathString AsNativePrefixed() const { return path; }
|
||||
static PathString FromNative(const RawPathString &path) { return PathString(path); }
|
||||
#else // !MPT_ENABLE_CHARSET_LOCALE
|
||||
std::string ToUTF8() const { return path; }
|
||||
#if MPT_WSTRING_CONVERT
|
||||
std::wstring ToWide() const { return mpt::ToWide(mpt::Charset::UTF8, path); }
|
||||
#endif
|
||||
mpt::ustring ToUnicode() const { return mpt::ToUnicode(mpt::Charset::UTF8, 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::Charset::UTF8, path)); }
|
||||
#endif
|
||||
static PathString FromUnicode(const mpt::ustring &path) { return PathString(mpt::ToCharset(mpt::Charset::UTF8, path)); }
|
||||
RawPathString AsNative() const { return path; }
|
||||
RawPathString AsNativePrefixed() const { return path; }
|
||||
static PathString FromNative(const RawPathString &path) { return PathString(path); }
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
|
||||
// Convert a path to its simplified form (currently only implemented on Windows)
|
||||
[[deprecated]] mpt::PathString Simplify() const { return PathString(path); }
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
#if MPT_OS_WINDOWS
|
||||
#ifdef UNICODE
|
||||
[[deprecated]] inline std::string ToString(const mpt::PathString & x) { return mpt::ToCharset(mpt::Charset::Locale, x.ToUnicode()); }
|
||||
#else
|
||||
MPT_DEPRECATED_PATH inline std::string ToString(const mpt::PathString & x) { return mpt::ToCharset(mpt::Charset::Locale, x.AsNative()); }
|
||||
#endif
|
||||
#else
|
||||
MPT_DEPRECATED_PATH inline std::string ToString(const mpt::PathString & x) { return mpt::ToCharset(mpt::Charset::Locale, x.ToUnicode()); }
|
||||
#endif
|
||||
#endif
|
||||
inline mpt::ustring ToUString(const mpt::PathString & x) { return x.ToUnicode(); }
|
||||
#if MPT_WSTRING_FORMAT
|
||||
inline std::wstring ToWString(const mpt::PathString & x) { return x.ToWide(); }
|
||||
#endif
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
#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 PathIsAbsolute(const mpt::PathString &path);
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
#if !(MPT_OS_WINDOWS_WINRT && (_WIN32_WINNT < 0x0a00))
|
||||
|
||||
// Returns the absolute path for a potentially relative path and removes ".." or "." components. (same as GetFullPathNameW)
|
||||
mpt::PathString GetAbsolutePath(const mpt::PathString &path);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef MODPLUG_TRACKER
|
||||
|
||||
// Deletes a complete directory tree. Handle with EXTREME care.
|
||||
// Returns false if any file could not be removed and aborts as soon as it
|
||||
// encounters any error. path must be absolute.
|
||||
bool DeleteWholeDirectoryTree(mpt::PathString path);
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
#if defined(MPT_ENABLE_DYNBIND) || defined(MPT_ENABLE_TEMPFILE)
|
||||
|
||||
// Returns the application executable path or an empty string (if unknown), e.g. "C:\mptrack\"
|
||||
mpt::PathString GetExecutablePath();
|
||||
|
||||
#endif // MPT_ENABLE_DYNBIND || MPT_ENABLE_TEMPFILE
|
||||
|
||||
#if defined(MPT_ENABLE_DYNBIND)
|
||||
|
||||
#if !MPT_OS_WINDOWS_WINRT
|
||||
// Returns the system directory path, e.g. "C:\Windows\System32\"
|
||||
mpt::PathString GetSystemPath();
|
||||
#endif // !MPT_OS_WINDOWS_WINRT
|
||||
|
||||
#endif // MPT_ENABLE_DYNBIND
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
#if defined(MPT_ENABLE_TEMPFILE)
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
// Returns temporary directory (with trailing backslash added) (e.g. "C:\TEMP\")
|
||||
mpt::PathString GetTempDirectory();
|
||||
|
||||
// Returns a new unique absolute path.
|
||||
mpt::PathString CreateTempFileName(const mpt::PathString &fileNamePrefix = mpt::PathString(), const mpt::PathString &fileNameExtension = P_("tmp"));
|
||||
|
||||
|
||||
|
||||
// Scoped temporary file guard. Deletes the file when going out of scope.
|
||||
// The file itself is not created automatically.
|
||||
class TempFileGuard
|
||||
{
|
||||
private:
|
||||
const mpt::PathString filename;
|
||||
public:
|
||||
TempFileGuard(const mpt::PathString &filename = CreateTempFileName());
|
||||
mpt::PathString GetFilename() const;
|
||||
~TempFileGuard();
|
||||
};
|
||||
|
||||
#ifdef MODPLUG_TRACKER
|
||||
|
||||
// Scoped temporary directory guard. Deletes the directory when going out of scope.
|
||||
// The directory itself is created automatically.
|
||||
class TempDirGuard
|
||||
{
|
||||
private:
|
||||
mpt::PathString dirname;
|
||||
public:
|
||||
TempDirGuard(const mpt::PathString &dirname_ = CreateTempFileName());
|
||||
mpt::PathString GetDirname() const;
|
||||
~TempDirGuard();
|
||||
};
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
#endif // MPT_ENABLE_TEMPFILE
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
|
||||
// Sanitize a filename (remove special chars)
|
||||
void SanitizeFilename(mpt::PathString &filename);
|
||||
|
||||
void SanitizeFilename(char *beg, char *end);
|
||||
void SanitizeFilename(wchar_t *beg, wchar_t *end);
|
||||
|
||||
void SanitizeFilename(std::string &str);
|
||||
void SanitizeFilename(std::wstring &str);
|
||||
#if MPT_USTRING_MODE_UTF8
|
||||
void SanitizeFilename(mpt::u8string &str);
|
||||
#endif // MPT_USTRING_MODE_UTF8
|
||||
|
||||
template <std::size_t size>
|
||||
void SanitizeFilename(char (&buffer)[size])
|
||||
{
|
||||
static_assert(size > 0);
|
||||
SanitizeFilename(buffer, buffer + size);
|
||||
}
|
||||
|
||||
template <std::size_t size>
|
||||
void SanitizeFilename(wchar_t (&buffer)[size])
|
||||
{
|
||||
static_assert(size > 0);
|
||||
SanitizeFilename(buffer, buffer + size);
|
||||
}
|
||||
|
||||
#if defined(MPT_WITH_MFC)
|
||||
void SanitizeFilename(CString &str);
|
||||
#endif // MPT_WITH_MFC
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
|
||||
enum FileTypeFormat
|
||||
{
|
||||
FileTypeFormatNone = 0 , // do not show extensions after description, i.e. "Foo Files"
|
||||
FileTypeFormatShowExtensions = 1<<0, // show extensions after descripten, i.e. "Foo Files (*.foo,*.bar)"
|
||||
};
|
||||
MPT_DECLARE_ENUM(FileTypeFormat)
|
||||
|
||||
class FileType
|
||||
{
|
||||
private:
|
||||
mpt::ustring m_ShortName; // "flac", "mod" (lowercase)
|
||||
mpt::ustring m_Description; // "FastTracker 2 Module"
|
||||
std::vector<std::string> m_MimeTypes; // "audio/ogg" (in ASCII)
|
||||
std::vector<mpt::PathString> m_Extensions; // "mod", "xm" (lowercase)
|
||||
std::vector<mpt::PathString> m_Prefixes; // "mod" for "mod.*"
|
||||
public:
|
||||
FileType() { }
|
||||
FileType(const std::vector<FileType> &group)
|
||||
{
|
||||
for(const auto &type : group)
|
||||
{
|
||||
m_MimeTypes.insert(m_MimeTypes.end(), type.m_MimeTypes.begin(), type.m_MimeTypes.end());
|
||||
m_Extensions.insert(m_Extensions.end(), type.m_Extensions.begin(), type.m_Extensions.end());
|
||||
m_Prefixes.insert(m_Prefixes.end(), type.m_Prefixes.begin(), type.m_Prefixes.end());
|
||||
}
|
||||
}
|
||||
static FileType Any()
|
||||
{
|
||||
return FileType().ShortName(U_("*")).Description(U_("All Files")).AddExtension(P_("*"));
|
||||
}
|
||||
public:
|
||||
FileType& ShortName(const mpt::ustring &shortName) { m_ShortName = shortName; return *this; }
|
||||
FileType& Description(const mpt::ustring &description) { m_Description = description; return *this; }
|
||||
FileType& MimeTypes(const std::vector<std::string> &mimeTypes) { m_MimeTypes = mimeTypes; return *this; }
|
||||
FileType& Extensions(const std::vector<mpt::PathString> &extensions) { m_Extensions = extensions; return *this; }
|
||||
FileType& Prefixes(const std::vector<mpt::PathString> &prefixes) { m_Prefixes = prefixes; return *this; }
|
||||
FileType& AddMimeType(const std::string &mimeType) { m_MimeTypes.push_back(mimeType); return *this; }
|
||||
FileType& AddExtension(const mpt::PathString &extension) { m_Extensions.push_back(extension); return *this; }
|
||||
FileType& AddPrefix(const mpt::PathString &prefix) { m_Prefixes.push_back(prefix); return *this; }
|
||||
public:
|
||||
mpt::ustring GetShortName() const { return m_ShortName; }
|
||||
mpt::ustring GetDescription() const { return m_Description; }
|
||||
std::vector<std::string> GetMimeTypes() const { return m_MimeTypes; }
|
||||
std::vector<mpt::PathString> GetExtensions() const { return m_Extensions; }
|
||||
std::vector<mpt::PathString> GetPrefixes() const { return m_Prefixes; }
|
||||
public:
|
||||
mpt::PathString AsFilterString(FlagSet<FileTypeFormat> format = FileTypeFormatNone) const;
|
||||
mpt::PathString AsFilterOnlyString() const;
|
||||
}; // class FileType
|
||||
|
||||
|
||||
// "Ogg Vorbis|*.ogg;*.oga|" // FileTypeFormatNone
|
||||
// "Ogg Vorbis (*.ogg,*.oga)|*.ogg;*.oga|" // FileTypeFormatShowExtensions
|
||||
mpt::PathString ToFilterString(const FileType &fileType, FlagSet<FileTypeFormat> format = FileTypeFormatNone);
|
||||
mpt::PathString ToFilterString(const std::vector<FileType> &fileTypes, FlagSet<FileTypeFormat> format = FileTypeFormatNone);
|
||||
|
||||
// "*.ogg;*.oga" / ";*.ogg;*.oga"
|
||||
mpt::PathString ToFilterOnlyString(const FileType &fileType, bool prependSemicolonWhenNotEmpty = false);
|
||||
mpt::PathString ToFilterOnlyString(const std::vector<FileType> &fileTypes, bool prependSemicolonWhenNotEmpty = false);
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,344 +0,0 @@
|
|||
/*
|
||||
* mptRandom.cpp
|
||||
* -------------
|
||||
* Purpose: PRNG
|
||||
* 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 "mptRandom.h"
|
||||
|
||||
#include "Endianness.h"
|
||||
#include "mptCRC.h"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
|
||||
#if !defined(MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE)
|
||||
|
||||
template <typename T>
|
||||
static T log2(T x)
|
||||
{
|
||||
return std::log(x) / std::log(static_cast<T>(2));
|
||||
}
|
||||
|
||||
|
||||
static MPT_CONSTEXPR14_FUN int lower_bound_entropy_bits(unsigned int x)
|
||||
{
|
||||
return detail::lower_bound_entropy_bits(x);
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
static MPT_CONSTEXPR14_FUN bool is_mask(T x)
|
||||
{
|
||||
static_assert(std::numeric_limits<T>::is_integer);
|
||||
typedef typename std::make_unsigned<T>::type unsigned_T;
|
||||
unsigned_T ux = static_cast<unsigned_T>(x);
|
||||
unsigned_T mask = 0;
|
||||
for(std::size_t bits = 0; bits <= (sizeof(unsigned_T) * 8); ++bits)
|
||||
{
|
||||
mask = (mask << 1) | 1u;
|
||||
if(ux == mask)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // !MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE
|
||||
|
||||
|
||||
namespace {
|
||||
template <typename T> struct default_hash { };
|
||||
template <> struct default_hash<uint8> { typedef mpt::checksum::crc16 type; };
|
||||
template <> struct default_hash<uint16> { typedef mpt::checksum::crc16 type; };
|
||||
template <> struct default_hash<uint32> { typedef mpt::checksum::crc32c type; };
|
||||
template <> struct default_hash<uint64> { typedef mpt::checksum::crc64_jones type; };
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static T generate_timeseed()
|
||||
{
|
||||
// Note: CRC is actually not that good a choice here, but it is simple and we
|
||||
// already have an implementaion available. Better choices for mixing entropy
|
||||
// would be a hash function with proper avalanche characteristics or a block
|
||||
// or stream cipher with any pre-choosen random key and IV. The only aspect we
|
||||
// really need here is whitening of the bits.
|
||||
typename mpt::default_hash<T>::type hash;
|
||||
|
||||
#ifdef MPT_BUILD_FUZZER
|
||||
|
||||
return static_cast<T>(mpt::FUZZER_RNG_SEED);
|
||||
|
||||
#else // !MPT_BUILD_FUZZER
|
||||
|
||||
{
|
||||
uint64be time;
|
||||
time = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock().now().time_since_epoch()).count();
|
||||
std::byte bytes[sizeof(time)];
|
||||
std::memcpy(bytes, &time, sizeof(time));
|
||||
hash(std::begin(bytes), std::end(bytes));
|
||||
}
|
||||
|
||||
#if !defined(MPT_COMPILER_QUIRK_CHRONO_NO_HIGH_RESOLUTION_CLOCK)
|
||||
{
|
||||
uint64be time;
|
||||
time = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock().now().time_since_epoch()).count();
|
||||
std::byte bytes[sizeof(time)];
|
||||
std::memcpy(bytes, &time, sizeof(time));
|
||||
hash(std::begin(bytes), std::end(bytes));
|
||||
}
|
||||
#endif // !MPT_COMPILER_QUIRK_CHRONO_NO_HIGH_RESOLUTION_CLOCK
|
||||
|
||||
return static_cast<T>(hash.result());
|
||||
|
||||
#endif // MPT_BUILD_FUZZER
|
||||
|
||||
}
|
||||
|
||||
|
||||
#ifdef MODPLUG_TRACKER
|
||||
|
||||
namespace rng
|
||||
{
|
||||
|
||||
void crand::reseed(uint32 seed)
|
||||
{
|
||||
std::srand(seed);
|
||||
}
|
||||
|
||||
crand::result_type crand::operator()()
|
||||
{
|
||||
return std::rand();
|
||||
}
|
||||
|
||||
} // namespace rng
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
sane_random_device::sane_random_device()
|
||||
#if !defined(MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE)
|
||||
: rd_reliable(false)
|
||||
#endif // MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE
|
||||
{
|
||||
#if !defined(MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE)
|
||||
try
|
||||
{
|
||||
prd = std::make_unique<std::random_device>();
|
||||
rd_reliable = ((*prd).entropy() > 0.0);
|
||||
} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
|
||||
{
|
||||
MPT_EXCEPTION_RETHROW_OUT_OF_MEMORY(e);
|
||||
} catch(const std::exception &)
|
||||
{
|
||||
rd_reliable = false;
|
||||
}
|
||||
if(!rd_reliable)
|
||||
#endif // MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE
|
||||
{
|
||||
init_fallback();
|
||||
}
|
||||
}
|
||||
|
||||
sane_random_device::sane_random_device(const std::string & token_)
|
||||
: token(token_)
|
||||
#if !defined(MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE)
|
||||
, rd_reliable(false)
|
||||
#endif // MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE
|
||||
{
|
||||
#if !defined(MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE)
|
||||
try
|
||||
{
|
||||
prd = std::make_unique<std::random_device>(token);
|
||||
rd_reliable = ((*prd).entropy() > 0.0);
|
||||
} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
|
||||
{
|
||||
MPT_EXCEPTION_RETHROW_OUT_OF_MEMORY(e);
|
||||
} catch(const std::exception &)
|
||||
{
|
||||
rd_reliable = false;
|
||||
}
|
||||
if(!rd_reliable)
|
||||
#endif // MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE
|
||||
{
|
||||
init_fallback();
|
||||
}
|
||||
}
|
||||
|
||||
void sane_random_device::init_fallback()
|
||||
{
|
||||
if(!rd_fallback)
|
||||
{
|
||||
if(token.length() > 0)
|
||||
{
|
||||
uint64 seed_val = mpt::generate_timeseed<uint64>();
|
||||
std::vector<unsigned int> seeds;
|
||||
seeds.push_back(static_cast<uint32>(seed_val >> 32));
|
||||
seeds.push_back(static_cast<uint32>(seed_val >> 0));
|
||||
for(std::size_t i = 0; i < token.length(); ++i)
|
||||
{
|
||||
seeds.push_back(static_cast<unsigned int>(static_cast<unsigned char>(token[i])));
|
||||
}
|
||||
std::seed_seq seed(seeds.begin(), seeds.end());
|
||||
rd_fallback = std::make_unique<std::mt19937>(seed);
|
||||
} else
|
||||
{
|
||||
uint64 seed_val = mpt::generate_timeseed<uint64>();
|
||||
unsigned int seeds[2];
|
||||
seeds[0] = static_cast<uint32>(seed_val >> 32);
|
||||
seeds[1] = static_cast<uint32>(seed_val >> 0);
|
||||
std::seed_seq seed(seeds + 0, seeds + 2);
|
||||
rd_fallback = std::make_unique<std::mt19937>(seed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sane_random_device::result_type sane_random_device::operator()()
|
||||
{
|
||||
mpt::lock_guard<mpt::mutex> l(m);
|
||||
result_type result = 0;
|
||||
#if !defined(MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE)
|
||||
if(prd)
|
||||
{
|
||||
try
|
||||
{
|
||||
if constexpr(std::random_device::min() != 0 || !mpt::is_mask(std::random_device::max()))
|
||||
{ // insane std::random_device
|
||||
// This implementation is not exactly uniformly distributed but good enough
|
||||
// for OpenMPT.
|
||||
double rd_min = static_cast<double>(std::random_device::min());
|
||||
double rd_max = static_cast<double>(std::random_device::max());
|
||||
double rd_range = rd_max - rd_min;
|
||||
double rd_size = rd_range + 1.0;
|
||||
double rd_entropy = mpt::log2(rd_size);
|
||||
int iterations = static_cast<int>(std::ceil(result_bits() / rd_entropy));
|
||||
double tmp = 0.0;
|
||||
for(int i = 0; i < iterations; ++i)
|
||||
{
|
||||
tmp = (tmp * rd_size) + (static_cast<double>((*prd)()) - rd_min);
|
||||
}
|
||||
double result_01 = std::floor(tmp / std::pow(rd_size, iterations));
|
||||
result = static_cast<result_type>(std::floor(result_01 * (static_cast<double>(max() - min()) + 1.0))) + min();
|
||||
} else
|
||||
{ // sane std::random_device
|
||||
result = 0;
|
||||
std::size_t rd_bits = mpt::lower_bound_entropy_bits(std::random_device::max());
|
||||
for(std::size_t entropy = 0; entropy < (sizeof(result_type) * 8); entropy += rd_bits)
|
||||
{
|
||||
if(rd_bits < (sizeof(result_type) * 8))
|
||||
{
|
||||
result = (result << rd_bits) | static_cast<result_type>((*prd)());
|
||||
} else
|
||||
{
|
||||
result = result | static_cast<result_type>((*prd)());
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(const std::exception &)
|
||||
{
|
||||
rd_reliable = false;
|
||||
init_fallback();
|
||||
}
|
||||
} else
|
||||
{
|
||||
rd_reliable = false;
|
||||
}
|
||||
if(!rd_reliable)
|
||||
#endif // MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE
|
||||
{ // std::random_device is unreliable
|
||||
// XOR the generated random number with more entropy from the time-seeded
|
||||
// PRNG.
|
||||
// Note: This is safe even if the std::random_device itself is implemented
|
||||
// as a std::mt19937 PRNG because we are very likely using a different
|
||||
// seed.
|
||||
result ^= mpt::random<result_type>(*rd_fallback);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
prng_random_device_seeder::prng_random_device_seeder()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
uint8 prng_random_device_seeder::generate_seed8()
|
||||
{
|
||||
return mpt::generate_timeseed<uint8>();
|
||||
}
|
||||
|
||||
uint16 prng_random_device_seeder::generate_seed16()
|
||||
{
|
||||
return mpt::generate_timeseed<uint16>();
|
||||
}
|
||||
|
||||
uint32 prng_random_device_seeder::generate_seed32()
|
||||
{
|
||||
return mpt::generate_timeseed<uint32>();
|
||||
}
|
||||
|
||||
uint64 prng_random_device_seeder::generate_seed64()
|
||||
{
|
||||
return mpt::generate_timeseed<uint64>();
|
||||
}
|
||||
|
||||
#if defined(MODPLUG_TRACKER) && !defined(MPT_BUILD_WINESUPPORT)
|
||||
|
||||
static mpt::random_device *g_rd = 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::default_prng> *prng)
|
||||
{
|
||||
g_global_prng = prng;
|
||||
}
|
||||
|
||||
mpt::random_device & global_random_device()
|
||||
{
|
||||
return *g_rd;
|
||||
}
|
||||
|
||||
mpt::thread_safe_prng<mpt::default_prng> & global_prng()
|
||||
{
|
||||
return *g_global_prng;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
mpt::random_device & global_random_device()
|
||||
{
|
||||
static mpt::random_device g_rd;
|
||||
return g_rd;
|
||||
}
|
||||
|
||||
mpt::thread_safe_prng<mpt::default_prng> & global_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
|
||||
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,733 +0,0 @@
|
|||
/*
|
||||
* mptRandom.h
|
||||
* -----------
|
||||
* Purpose: PRNG
|
||||
* 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 "mptMutex.h"
|
||||
|
||||
#include <limits>
|
||||
#include <random>
|
||||
|
||||
#ifdef MODPLUG_TRACKER
|
||||
#include <cstdlib>
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
// NOTE:
|
||||
// We implement our own PRNG and distribution functions as the implementations
|
||||
// of std::uniform_int_distribution is either wrong (not uniform in MSVC2010) or
|
||||
// not guaranteed to be livelock-free for bad PRNGs (in GCC, Clang, boost).
|
||||
// We resort to a simpler implementation with only power-of-2 result ranges for
|
||||
// both the underlying PRNG and our interface function. This saves us from
|
||||
// complicated code having to deal with partial bits of entropy.
|
||||
// Our interface still somewhat follows the mindset of C++11 <random> (with the
|
||||
// addition of a simple wrapper function mpt::random which saves the caller from
|
||||
// instantiating distribution objects for the common uniform distribution case.
|
||||
// We are still using std::random_device for initial seeding when avalable and
|
||||
// after working around its set of problems.
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
|
||||
#ifdef MPT_BUILD_FUZZER
|
||||
static constexpr uint32 FUZZER_RNG_SEED = 3141592653u; // pi
|
||||
#endif // MPT_BUILD_FUZZER
|
||||
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
MPT_CONSTEXPR14_FUN int lower_bound_entropy_bits(unsigned int x)
|
||||
{
|
||||
if(x >= 0xffffffffu)
|
||||
{
|
||||
return 32;
|
||||
} else if(x >= 0x7fffffffu)
|
||||
{
|
||||
return 31;
|
||||
} else if(x >= 0x3fffffffu)
|
||||
{
|
||||
return 30;
|
||||
} else if(x >= 0x1fffffffu)
|
||||
{
|
||||
return 29;
|
||||
} else if(x >= 0x0fffffffu)
|
||||
{
|
||||
return 28;
|
||||
} else if(x >= 0x07ffffffu)
|
||||
{
|
||||
return 27;
|
||||
} else if(x >= 0x03ffffffu)
|
||||
{
|
||||
return 26;
|
||||
} else if(x >= 0x01ffffffu)
|
||||
{
|
||||
return 25;
|
||||
} else if(x >= 0x00ffffffu)
|
||||
{
|
||||
return 24;
|
||||
} else if(x >= 0x007fffffu)
|
||||
{
|
||||
return 23;
|
||||
} else if(x >= 0x003fffffu)
|
||||
{
|
||||
return 22;
|
||||
} else if(x >= 0x001fffffu)
|
||||
{
|
||||
return 21;
|
||||
} else if(x >= 0x000fffffu)
|
||||
{
|
||||
return 20;
|
||||
} else if(x >= 0x0007ffffu)
|
||||
{
|
||||
return 19;
|
||||
} else if(x >= 0x0003ffffu)
|
||||
{
|
||||
return 18;
|
||||
} else if(x >= 0x0001ffffu)
|
||||
{
|
||||
return 17;
|
||||
} else if(x >= 0x0000ffffu)
|
||||
{
|
||||
return 16;
|
||||
} else if(x >= 0x00007fffu)
|
||||
{
|
||||
return 15;
|
||||
} else if(x >= 0x00003fffu)
|
||||
{
|
||||
return 14;
|
||||
} else if(x >= 0x00001fffu)
|
||||
{
|
||||
return 13;
|
||||
} else if(x >= 0x00000fffu)
|
||||
{
|
||||
return 12;
|
||||
} else if(x >= 0x000007ffu)
|
||||
{
|
||||
return 11;
|
||||
} else if(x >= 0x000003ffu)
|
||||
{
|
||||
return 10;
|
||||
} else if(x >= 0x000001ffu)
|
||||
{
|
||||
return 9;
|
||||
} else if(x >= 0x000000ffu)
|
||||
{
|
||||
return 8;
|
||||
} else if(x >= 0x0000007fu)
|
||||
{
|
||||
return 7;
|
||||
} else if(x >= 0x0000003fu)
|
||||
{
|
||||
return 6;
|
||||
} else if(x >= 0x0000001fu)
|
||||
{
|
||||
return 5;
|
||||
} else if(x >= 0x0000000fu)
|
||||
{
|
||||
return 4;
|
||||
} else if(x >= 0x00000007u)
|
||||
{
|
||||
return 3;
|
||||
} else if(x >= 0x00000003u)
|
||||
{
|
||||
return 2;
|
||||
} else if(x >= 0x00000001u)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
template <typename Trng> struct engine_traits
|
||||
{
|
||||
typedef typename Trng::result_type result_type;
|
||||
static MPT_CONSTEXPR11_FUN int result_bits()
|
||||
{
|
||||
return Trng::result_bits();
|
||||
}
|
||||
template<typename Trd>
|
||||
static inline Trng make(Trd & rd)
|
||||
{
|
||||
return Trng(rd);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename T, typename Trng>
|
||||
inline T random(Trng & rng)
|
||||
{
|
||||
static_assert(std::numeric_limits<T>::is_integer);
|
||||
typedef typename std::make_unsigned<T>::type unsigned_T;
|
||||
const unsigned int rng_bits = mpt::engine_traits<Trng>::result_bits();
|
||||
unsigned_T result = 0;
|
||||
for(std::size_t entropy = 0; entropy < (sizeof(T) * 8); entropy += rng_bits)
|
||||
{
|
||||
if constexpr(rng_bits < (sizeof(T) * 8))
|
||||
{
|
||||
constexpr unsigned int shift_bits = rng_bits % (sizeof(T) * 8); // silence utterly stupid MSVC and GCC warnings about shifting by too big amount (in which case this branch is not even taken however)
|
||||
result = (result << shift_bits) ^ static_cast<unsigned_T>(rng());
|
||||
} else
|
||||
{
|
||||
result = static_cast<unsigned_T>(rng());
|
||||
}
|
||||
}
|
||||
return static_cast<T>(result);
|
||||
}
|
||||
|
||||
template <typename T, std::size_t required_entropy_bits, typename Trng>
|
||||
inline T random(Trng & rng)
|
||||
{
|
||||
static_assert(std::numeric_limits<T>::is_integer);
|
||||
typedef typename std::make_unsigned<T>::type unsigned_T;
|
||||
const unsigned int rng_bits = mpt::engine_traits<Trng>::result_bits();
|
||||
unsigned_T result = 0;
|
||||
for(std::size_t entropy = 0; entropy < std::min(required_entropy_bits, sizeof(T) * 8); entropy += rng_bits)
|
||||
{
|
||||
if constexpr(rng_bits < (sizeof(T) * 8))
|
||||
{
|
||||
constexpr unsigned int shift_bits = rng_bits % (sizeof(T) * 8); // silence utterly stupid MSVC and GCC warnings about shifting by too big amount (in which case this branch is not even taken however)
|
||||
result = (result << shift_bits) ^ static_cast<unsigned_T>(rng());
|
||||
} else
|
||||
{
|
||||
result = static_cast<unsigned_T>(rng());
|
||||
}
|
||||
}
|
||||
if constexpr(required_entropy_bits >= (sizeof(T) * 8))
|
||||
{
|
||||
return static_cast<T>(result);
|
||||
} else
|
||||
{
|
||||
return static_cast<T>(result & ((static_cast<unsigned_T>(1) << required_entropy_bits) - static_cast<unsigned_T>(1)));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Trng>
|
||||
inline T random(Trng & rng, std::size_t required_entropy_bits)
|
||||
{
|
||||
static_assert(std::numeric_limits<T>::is_integer);
|
||||
typedef typename std::make_unsigned<T>::type unsigned_T;
|
||||
const unsigned int rng_bits = mpt::engine_traits<Trng>::result_bits();
|
||||
unsigned_T result = 0;
|
||||
for(std::size_t entropy = 0; entropy < std::min(required_entropy_bits, sizeof(T) * 8); entropy += rng_bits)
|
||||
{
|
||||
if constexpr(rng_bits < (sizeof(T) * 8))
|
||||
{
|
||||
constexpr unsigned int shift_bits = rng_bits % (sizeof(T) * 8); // silence utterly stupid MSVC and GCC warnings about shifting by too big amount (in which case this branch is not even taken however)
|
||||
result = (result << shift_bits) ^ static_cast<unsigned_T>(rng());
|
||||
} else
|
||||
{
|
||||
result = static_cast<unsigned_T>(rng());
|
||||
}
|
||||
}
|
||||
if(required_entropy_bits >= (sizeof(T) * 8))
|
||||
{
|
||||
return static_cast<T>(result);
|
||||
} else
|
||||
{
|
||||
return static_cast<T>(result & ((static_cast<unsigned_T>(1) << required_entropy_bits) - static_cast<unsigned_T>(1)));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct uniform_real_distribution
|
||||
{
|
||||
private:
|
||||
T a;
|
||||
T b;
|
||||
public:
|
||||
inline uniform_real_distribution(T a, T b)
|
||||
: a(a)
|
||||
, b(b)
|
||||
{
|
||||
return;
|
||||
}
|
||||
template <typename Trng>
|
||||
inline T operator()(Trng & rng) const
|
||||
{
|
||||
const int mantissa_bits = std::numeric_limits<T>::digits;
|
||||
return ((b - a) * static_cast<T>(mpt::random<uint64, mantissa_bits>(rng)) / static_cast<T>((static_cast<uint64>(1u) << mantissa_bits))) + a;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename T, typename Trng>
|
||||
inline T random(Trng & rng, T min, T max)
|
||||
{
|
||||
static_assert(!std::numeric_limits<T>::is_integer);
|
||||
typedef mpt::uniform_real_distribution<T> dis_type;
|
||||
dis_type dis(min, max);
|
||||
return static_cast<T>(dis(rng));
|
||||
}
|
||||
|
||||
|
||||
namespace rng
|
||||
{
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4724) // potential mod by 0
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
|
||||
template <typename Tstate, typename Tvalue, Tstate m, Tstate a, Tstate c, Tstate result_mask, int result_shift, int result_bits_>
|
||||
class lcg
|
||||
{
|
||||
public:
|
||||
typedef Tstate state_type;
|
||||
typedef Tvalue result_type;
|
||||
private:
|
||||
state_type state;
|
||||
public:
|
||||
template <typename Trng>
|
||||
explicit inline lcg(Trng & rd)
|
||||
: state(mpt::random<state_type>(rd))
|
||||
{
|
||||
operator()(); // we return results from the current state and update state after returning. results in better pipelining.
|
||||
}
|
||||
explicit inline lcg(state_type seed)
|
||||
: state(seed)
|
||||
{
|
||||
operator()(); // we return results from the current state and update state after returning. results in better pipelining.
|
||||
}
|
||||
public:
|
||||
static MPT_CONSTEXPR11_FUN result_type min()
|
||||
{
|
||||
return static_cast<result_type>(0);
|
||||
}
|
||||
static MPT_CONSTEXPR11_FUN result_type max()
|
||||
{
|
||||
static_assert(((result_mask >> result_shift) << result_shift) == result_mask);
|
||||
return static_cast<result_type>(result_mask >> result_shift);
|
||||
}
|
||||
static MPT_CONSTEXPR11_FUN int result_bits()
|
||||
{
|
||||
static_assert(((static_cast<Tstate>(1) << result_bits_) - 1) == (result_mask >> result_shift));
|
||||
return result_bits_;
|
||||
}
|
||||
inline result_type operator()()
|
||||
{
|
||||
// we return results from the current state and update state after returning. results in better pipelining.
|
||||
state_type s = state;
|
||||
result_type result = static_cast<result_type>((s & result_mask) >> result_shift);
|
||||
s = Util::ModIfNotZero<state_type, m>((a * s) + c);
|
||||
state = s;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
|
||||
typedef lcg<uint32, uint16, 0u, 214013u, 2531011u, 0x7fff0000u, 16, 15> lcg_msvc;
|
||||
typedef lcg<uint32, uint16, 0x80000000u, 1103515245u, 12345u, 0x7fff0000u, 16, 15> lcg_c99;
|
||||
typedef lcg<uint64, uint32, 0ull, 6364136223846793005ull, 1ull, 0xffffffff00000000ull, 32, 32> lcg_musl;
|
||||
|
||||
template <typename Tstate, typename Tvalue, Tstate x1, Tstate x2, Tstate x3, Tstate x4, int rol1, int rol2>
|
||||
class modplug
|
||||
{
|
||||
public:
|
||||
typedef Tstate state_type;
|
||||
typedef Tvalue result_type;
|
||||
private:
|
||||
state_type state1;
|
||||
state_type state2;
|
||||
public:
|
||||
template <typename Trng>
|
||||
explicit inline modplug(Trng &rd)
|
||||
: state1(mpt::random<state_type>(rd))
|
||||
, state2(mpt::random<state_type>(rd))
|
||||
{
|
||||
}
|
||||
explicit inline modplug(state_type seed1, state_type seed2)
|
||||
: state1(seed1)
|
||||
, state2(seed2)
|
||||
{
|
||||
}
|
||||
public:
|
||||
static MPT_CONSTEXPR11_FUN result_type min()
|
||||
{
|
||||
return static_cast<result_type>(0);
|
||||
}
|
||||
static MPT_CONSTEXPR11_FUN result_type max()
|
||||
{
|
||||
return std::numeric_limits<result_type>::max();
|
||||
}
|
||||
static MPT_CONSTEXPR11_FUN int result_bits()
|
||||
{
|
||||
static_assert(std::is_integral<result_type>::value);
|
||||
static_assert(std::is_unsigned<result_type>::value);
|
||||
return std::numeric_limits<result_type>::digits;
|
||||
}
|
||||
inline result_type operator()()
|
||||
{
|
||||
state_type a = state1;
|
||||
state_type b = state2;
|
||||
a = mpt::rotl(a, rol1);
|
||||
a ^= x1;
|
||||
a += x2 + (b * x3);
|
||||
b += mpt::rotl(a, rol2) * x4;
|
||||
state1 = a;
|
||||
state2 = b;
|
||||
result_type result = static_cast<result_type>(b);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
typedef modplug<uint32, uint32, 0x10204080u, 0x78649E7Du, 4, 5, 1, 16> modplug_dither;
|
||||
|
||||
} // namespace rng
|
||||
|
||||
|
||||
#ifdef MODPLUG_TRACKER
|
||||
|
||||
namespace rng
|
||||
{
|
||||
|
||||
class crand
|
||||
{
|
||||
public:
|
||||
typedef void state_type;
|
||||
typedef int result_type;
|
||||
private:
|
||||
static void reseed(uint32 seed);
|
||||
public:
|
||||
template <typename Trd>
|
||||
static void reseed(Trd & rd)
|
||||
{
|
||||
reseed(mpt::random<uint32>(rd));
|
||||
}
|
||||
public:
|
||||
crand() { }
|
||||
explicit crand(const std::string &) { }
|
||||
public:
|
||||
static MPT_CONSTEXPR11_FUN result_type min()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static MPT_CONSTEXPR11_FUN result_type max()
|
||||
{
|
||||
return RAND_MAX;
|
||||
}
|
||||
static MPT_CONSTEXPR14_FUN int result_bits()
|
||||
{
|
||||
return detail::lower_bound_entropy_bits(RAND_MAX);
|
||||
}
|
||||
result_type operator()();
|
||||
};
|
||||
|
||||
} // namespace rng
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
// C++11 std::random_device may be implemented as a deterministic PRNG.
|
||||
// There is no way to seed this PRNG and it is allowed to be seeded with the
|
||||
// same value on each program invocation. This makes std::random_device
|
||||
// completely useless even as a non-cryptographic entropy pool.
|
||||
// We fallback to time-seeded std::mt19937 if std::random_device::entropy() is
|
||||
// 0 or less.
|
||||
class sane_random_device
|
||||
{
|
||||
private:
|
||||
mpt::mutex m;
|
||||
std::string token;
|
||||
#if !defined(MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE)
|
||||
std::unique_ptr<std::random_device> prd;
|
||||
bool rd_reliable;
|
||||
#endif // !MPT_COMPILER_QUIRK_RANDOM_NO_RANDOM_DEVICE
|
||||
std::unique_ptr<std::mt19937> rd_fallback;
|
||||
public:
|
||||
typedef unsigned int result_type;
|
||||
private:
|
||||
void init_fallback();
|
||||
public:
|
||||
sane_random_device();
|
||||
sane_random_device(const std::string & token);
|
||||
static MPT_CONSTEXPR11_FUN result_type min()
|
||||
{
|
||||
return std::numeric_limits<result_type>::min();
|
||||
}
|
||||
static MPT_CONSTEXPR11_FUN result_type max()
|
||||
{
|
||||
return std::numeric_limits<result_type>::max();
|
||||
}
|
||||
static MPT_CONSTEXPR11_FUN int result_bits()
|
||||
{
|
||||
return sizeof(result_type) * 8;
|
||||
}
|
||||
result_type operator()();
|
||||
};
|
||||
|
||||
|
||||
template <std::size_t N>
|
||||
class seed_seq_values
|
||||
{
|
||||
private:
|
||||
unsigned int seeds[N];
|
||||
public:
|
||||
template <typename Trd>
|
||||
explicit seed_seq_values(Trd & rd)
|
||||
{
|
||||
for(std::size_t i = 0; i < N; ++i)
|
||||
{
|
||||
seeds[i] = rd();
|
||||
}
|
||||
}
|
||||
const unsigned int * begin() const
|
||||
{
|
||||
return seeds + 0;
|
||||
}
|
||||
const unsigned int * end() const
|
||||
{
|
||||
return seeds + N;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// C++11 random does not provide any sane way to determine the amount of entropy
|
||||
// required to seed a particular engine. VERY STUPID.
|
||||
// List the ones we are likely to use.
|
||||
|
||||
template <> struct engine_traits<std::mt19937> {
|
||||
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)
|
||||
{
|
||||
std::unique_ptr<mpt::seed_seq_values<seed_bits / sizeof(unsigned int)>> values = std::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> {
|
||||
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)
|
||||
{
|
||||
std::unique_ptr<mpt::seed_seq_values<seed_bits / sizeof(unsigned int)>> values = std::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> {
|
||||
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; }
|
||||
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());
|
||||
return rng_type(seed);
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct engine_traits<std::ranlux48_base> {
|
||||
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; }
|
||||
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());
|
||||
return rng_type(seed);
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct engine_traits<std::ranlux24> {
|
||||
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; }
|
||||
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());
|
||||
return rng_type(seed);
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct engine_traits<std::ranlux48> {
|
||||
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; }
|
||||
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());
|
||||
return rng_type(seed);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class prng_random_device_seeder
|
||||
{
|
||||
private:
|
||||
uint8 generate_seed8();
|
||||
uint16 generate_seed16();
|
||||
uint32 generate_seed32();
|
||||
uint64 generate_seed64();
|
||||
protected:
|
||||
template <typename T> inline T generate_seed();
|
||||
protected:
|
||||
prng_random_device_seeder();
|
||||
};
|
||||
|
||||
template <> inline uint8 prng_random_device_seeder::generate_seed() { return generate_seed8(); }
|
||||
template <> inline uint16 prng_random_device_seeder::generate_seed() { return generate_seed16(); }
|
||||
template <> inline uint32 prng_random_device_seeder::generate_seed() { return generate_seed32(); }
|
||||
template <> inline uint64 prng_random_device_seeder::generate_seed() { return generate_seed64(); }
|
||||
|
||||
template <typename Trng = mpt::rng::lcg_musl>
|
||||
class prng_random_device
|
||||
: public prng_random_device_seeder
|
||||
{
|
||||
public:
|
||||
typedef unsigned int result_type;
|
||||
private:
|
||||
mpt::mutex m;
|
||||
Trng rng;
|
||||
public:
|
||||
prng_random_device()
|
||||
: rng(generate_seed<typename Trng::state_type>())
|
||||
{
|
||||
return;
|
||||
}
|
||||
prng_random_device(const std::string &)
|
||||
: rng(generate_seed<typename Trng::state_type>())
|
||||
{
|
||||
return;
|
||||
}
|
||||
static MPT_CONSTEXPR11_FUN result_type min()
|
||||
{
|
||||
return std::numeric_limits<unsigned int>::min();
|
||||
}
|
||||
static MPT_CONSTEXPR11_FUN result_type max()
|
||||
{
|
||||
return std::numeric_limits<unsigned int>::max();
|
||||
}
|
||||
static MPT_CONSTEXPR11_FUN int result_bits()
|
||||
{
|
||||
return sizeof(unsigned int) * 8;
|
||||
}
|
||||
result_type operator()()
|
||||
{
|
||||
mpt::lock_guard<mpt::mutex> l(m);
|
||||
return mpt::random<unsigned int>(rng);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#ifdef MPT_BUILD_FUZZER
|
||||
|
||||
// 1. Use deterministic seeding
|
||||
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_musl good_prng;
|
||||
|
||||
#else // !MPT_BUILD_FUZZER
|
||||
|
||||
// mpt::random_device always generates 32 bits of entropy
|
||||
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::ranlux48 good_prng;
|
||||
|
||||
#endif // MPT_BUILD_FUZZER
|
||||
|
||||
|
||||
typedef mpt::good_prng default_prng;
|
||||
|
||||
|
||||
template <typename Trng, typename Trd>
|
||||
inline Trng make_prng(Trd & rd)
|
||||
{
|
||||
return mpt::engine_traits<Trng>::make(rd);
|
||||
}
|
||||
|
||||
|
||||
template <typename Trng>
|
||||
class thread_safe_prng
|
||||
: private Trng
|
||||
{
|
||||
private:
|
||||
mpt::mutex m;
|
||||
public:
|
||||
typedef typename Trng::result_type result_type;
|
||||
public:
|
||||
template <typename Trd>
|
||||
explicit thread_safe_prng(Trd & rd)
|
||||
: Trng(mpt::make_prng<Trng>(rd))
|
||||
{
|
||||
return;
|
||||
}
|
||||
thread_safe_prng(Trng rng)
|
||||
: Trng(rng)
|
||||
{
|
||||
return;
|
||||
}
|
||||
public:
|
||||
static MPT_CONSTEXPR11_FUN typename engine_traits<Trng>::result_type min()
|
||||
{
|
||||
return Trng::min();
|
||||
}
|
||||
static MPT_CONSTEXPR11_FUN typename engine_traits<Trng>::result_type max()
|
||||
{
|
||||
return Trng::max();
|
||||
}
|
||||
static MPT_CONSTEXPR11_FUN int result_bits()
|
||||
{
|
||||
return engine_traits<Trng>::result_bits();
|
||||
}
|
||||
public:
|
||||
typename engine_traits<Trng>::result_type operator()()
|
||||
{
|
||||
mpt::lock_guard<mpt::mutex> l(m);
|
||||
return Trng::operator()();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
mpt::random_device & global_random_device();
|
||||
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::default_prng> *rng);
|
||||
#endif // MODPLUG_TRACKER && !MPT_BUILD_WINESUPPORT
|
||||
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,139 +0,0 @@
|
|||
/*
|
||||
* mptSpan.h
|
||||
* ---------
|
||||
* Purpose: C++20 span.
|
||||
* 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"
|
||||
|
||||
#if MPT_CXX_AT_LEAST(20)
|
||||
#include <array>
|
||||
#include <span>
|
||||
#else // !C++20
|
||||
#include <array>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
#endif // C++20
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
|
||||
|
||||
namespace mpt {
|
||||
|
||||
|
||||
|
||||
#if MPT_CXX_AT_LEAST(20)
|
||||
|
||||
using std::span;
|
||||
|
||||
#else // !C++20
|
||||
|
||||
// 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:
|
||||
|
||||
using element_type = T;
|
||||
using value_type = typename std::remove_cv<T>::type;
|
||||
using index_type = std::size_t;
|
||||
using pointer = T *;
|
||||
using const_pointer = const T *;
|
||||
using reference = T &;
|
||||
using const_reference = const T &;
|
||||
|
||||
using iterator = pointer;
|
||||
using const_iterator = const_pointer;
|
||||
|
||||
using difference_type = typename std::iterator_traits<iterator>::difference_type;
|
||||
|
||||
private:
|
||||
|
||||
T * m_beg;
|
||||
T * m_end;
|
||||
|
||||
public:
|
||||
|
||||
span() noexcept : m_beg(nullptr), m_end(nullptr) { }
|
||||
|
||||
span(pointer beg, pointer end) : m_beg(beg), m_end(end) { }
|
||||
|
||||
span(pointer data, index_type size) : m_beg(data), m_end(data + size) { }
|
||||
|
||||
template <std::size_t N> span(element_type (&arr)[N]) : m_beg(arr), m_end(arr + N) { }
|
||||
|
||||
template <std::size_t N> span(std::array<value_type, N> &arr) : m_beg(arr.data()), m_end(arr.data() + arr.size()) { }
|
||||
|
||||
template <std::size_t N> span(const std::array<value_type, N> &arr) : m_beg(arr.data()), m_end(arr.data() + arr.size()) { }
|
||||
|
||||
template <typename Cont> span(Cont &cont) : m_beg(std::data(cont)), m_end(std::data(cont) + std::size(cont)) { }
|
||||
|
||||
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 = (const span & other) noexcept = default;
|
||||
|
||||
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[](index_type index) { return at(index); }
|
||||
const_reference operator[](index_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(index_type index) { return m_beg[index]; }
|
||||
const_reference at(index_type index) const { return m_beg[index]; }
|
||||
|
||||
pointer data() const noexcept { return m_beg; }
|
||||
|
||||
bool empty() const noexcept { return size() == 0; }
|
||||
|
||||
index_type size() const noexcept { return static_cast<index_type>(std::distance(m_beg, m_end)); }
|
||||
index_type length() const noexcept { return size(); }
|
||||
|
||||
}; // class span
|
||||
|
||||
#endif // C++20
|
||||
|
||||
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
|
File diff suppressed because it is too large
Load diff
|
@ -1,703 +0,0 @@
|
|||
/*
|
||||
* mptString.h
|
||||
* ----------
|
||||
* Purpose: Small string-related utilities, number and message formatting.
|
||||
* 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 "mptAlloc.h"
|
||||
#include "mptBaseTypes.h"
|
||||
#include "mptSpan.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
using string_type = Tstring;
|
||||
using size_type = typename string_type::size_type;
|
||||
using char_type = typename string_type::value_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(MPT_WITH_MFC)
|
||||
template <>
|
||||
struct string_traits<CString>
|
||||
{
|
||||
|
||||
using string_type = CString;
|
||||
using size_type = int;
|
||||
using char_type = typename CString::XCHAR;
|
||||
|
||||
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 // MPT_WITH_MFC
|
||||
|
||||
|
||||
|
||||
namespace String
|
||||
{
|
||||
|
||||
|
||||
template <typename Tstring> struct Traits {
|
||||
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 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 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
|
||||
template <typename Tstring>
|
||||
inline Tstring LTrim(Tstring str, const Tstring &whitespace = Tstring(mpt::String::Traits<Tstring>::GetDefaultWhitespace()))
|
||||
{
|
||||
typename Tstring::size_type pos = str.find_first_not_of(whitespace);
|
||||
if(pos != Tstring::npos)
|
||||
{
|
||||
str.erase(str.begin(), str.begin() + pos);
|
||||
} else if(pos == Tstring::npos && str.length() > 0 && str.find_last_of(whitespace) == str.length() - 1)
|
||||
{
|
||||
return Tstring();
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
// Remove whitespace at end of string
|
||||
template <typename Tstring>
|
||||
inline Tstring RTrim(Tstring str, const Tstring &whitespace = Tstring(mpt::String::Traits<Tstring>::GetDefaultWhitespace()))
|
||||
{
|
||||
typename Tstring::size_type pos = str.find_last_not_of(whitespace);
|
||||
if(pos != Tstring::npos)
|
||||
{
|
||||
str.erase(str.begin() + pos + 1, str.end());
|
||||
} else if(pos == Tstring::npos && str.length() > 0 && str.find_first_of(whitespace) == 0)
|
||||
{
|
||||
return Tstring();
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
// Remove whitespace at start and end of string
|
||||
template <typename Tstring>
|
||||
inline Tstring Trim(Tstring str, const Tstring &whitespace = Tstring(mpt::String::Traits<Tstring>::GetDefaultWhitespace()))
|
||||
{
|
||||
return RTrim(LTrim(str, whitespace), whitespace);
|
||||
}
|
||||
|
||||
|
||||
template <typename Tstring, typename Tstring2, typename Tstring3>
|
||||
inline Tstring Replace(Tstring str, const Tstring2 &oldStr_, const Tstring3 &newStr_)
|
||||
{
|
||||
std::size_t pos = 0;
|
||||
const Tstring oldStr = oldStr_;
|
||||
const Tstring newStr = newStr_;
|
||||
while((pos = str.find(oldStr, pos)) != Tstring::npos)
|
||||
{
|
||||
str.replace(pos, oldStr.length(), newStr);
|
||||
pos += newStr.length();
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
} // namespace String
|
||||
|
||||
|
||||
inline std::string truncate(std::string str, std::size_t maxLen)
|
||||
{
|
||||
if(str.length() > maxLen)
|
||||
{
|
||||
str.resize(maxLen);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
enum class Charset {
|
||||
|
||||
UTF8,
|
||||
|
||||
ASCII, // strictly 7-bit ASCII
|
||||
|
||||
ISO8859_1,
|
||||
ISO8859_15,
|
||||
|
||||
CP437,
|
||||
CP437AMS,
|
||||
CP437AMS2,
|
||||
|
||||
Windows1252,
|
||||
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
Locale, // CP_ACP on windows, current C locale otherwise
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
// source code / preprocessor (i.e. # token)
|
||||
inline constexpr Charset CharsetSource = Charset::ASCII;
|
||||
|
||||
// debug log files
|
||||
inline constexpr Charset CharsetLogfile = Charset::UTF8;
|
||||
|
||||
// std::clog / std::cout / std::cerr
|
||||
#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS && defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
inline constexpr Charset CharsetStdIO = Charset::Locale;
|
||||
#else
|
||||
inline constexpr Charset CharsetStdIO = Charset::UTF8;
|
||||
#endif
|
||||
|
||||
// std::exception::what()
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
inline constexpr Charset CharsetException = Charset::Locale;
|
||||
#else
|
||||
inline constexpr Charset CharsetException = Charset::UTF8;
|
||||
#endif
|
||||
|
||||
// Locale in tracker builds, UTF8 in non-locale-aware libopenmpt builds.
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
inline constexpr Charset CharsetLocaleOrUTF8 = Charset::Locale;
|
||||
#else
|
||||
inline constexpr Charset CharsetLocaleOrUTF8 = Charset::UTF8;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// Checks if the std::string represents an UTF8 string.
|
||||
// This is currently implemented as converting to std::wstring and back assuming UTF8 both ways,
|
||||
// and comparing the result to the original string.
|
||||
// Caveats:
|
||||
// - can give false negatives because of possible unicode normalization during conversion
|
||||
// - can give false positives if the 8bit encoding contains high-ascii only in valid utf8 groups
|
||||
// - slow because of double conversion
|
||||
bool IsUTF8(const std::string &str);
|
||||
|
||||
|
||||
#define MPT_CHAR_TYPE char
|
||||
#define MPT_CHAR(x) x
|
||||
#define MPT_LITERAL(x) x
|
||||
#define MPT_STRING(x) std::string( x )
|
||||
|
||||
#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR)
|
||||
#define MPT_WCHAR_TYPE wchar_t
|
||||
#define MPT_WCHAR(x) L ## x
|
||||
#define MPT_WLITERAL(x) L ## x
|
||||
#define MPT_WSTRING(x) std::wstring( L ## x )
|
||||
#else // MPT_COMPILER_QUIRK_NO_WCHAR
|
||||
#define MPT_WCHAR_TYPE char32_t
|
||||
#define MPT_WCHAR(x) U ## x
|
||||
#define MPT_WLITERAL(x) U ## x
|
||||
#define MPT_WSTRING(x) std::u32string( U ## x )
|
||||
#endif // !MPT_COMPILER_QUIRK_NO_WCHAR
|
||||
|
||||
|
||||
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)
|
||||
|
||||
using lstring = MPT_ENCODED_STRING_TYPE(mpt::Charset::Locale);
|
||||
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
template <typename Tchar> struct windows_char_traits { };
|
||||
template <> struct windows_char_traits<char> { using string_type = mpt::lstring; };
|
||||
template <> struct windows_char_traits<wchar_t> { using string_type = std::wstring; };
|
||||
|
||||
#ifdef UNICODE
|
||||
using tstring = windows_char_traits<wchar_t>::string_type;
|
||||
#else
|
||||
using tstring = windows_char_traits<char>::string_type;
|
||||
#endif
|
||||
|
||||
using winstring = mpt::tstring;
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
|
||||
#if MPT_ENABLE_U8STRING
|
||||
|
||||
#if MPT_CXX_AT_LEAST(20)
|
||||
|
||||
using u8string = std::u8string;
|
||||
|
||||
#define MPT_U8CHAR_TYPE char8_t
|
||||
#define MPT_U8CHAR(x) u8 ## x
|
||||
#define MPT_U8LITERAL(x) u8 ## x
|
||||
#define MPT_U8STRING(x) std::u8string( u8 ## x )
|
||||
|
||||
#else // !C++20
|
||||
|
||||
using u8string = MPT_ENCODED_STRING_TYPE(mpt::Charset::UTF8);
|
||||
|
||||
#define MPT_U8CHAR_TYPE char
|
||||
#define MPT_U8CHAR(x) x
|
||||
#define MPT_U8LITERAL(x) x
|
||||
#define MPT_U8STRING(x) mpt::u8string( x )
|
||||
|
||||
// mpt::u8string is a moderately type-safe string that is meant to contain
|
||||
// UTF-8 encoded char bytes.
|
||||
//
|
||||
// mpt::u8string is not implicitely convertible to/from std::string, but
|
||||
// it is convertible to/from C strings the same way as std::string is.
|
||||
//
|
||||
// The implementation of mpt::u8string is a compromise of compatibilty
|
||||
// with implementation-defined STL details, efficiency, source code size,
|
||||
// executable bloat, type-safety and simplicity.
|
||||
//
|
||||
// mpt::u8string is not meant to be used directly though.
|
||||
// mpt::u8string is meant as an alternative implementaion to std::wstring
|
||||
// for implementing the unicode string type mpt::ustring.
|
||||
|
||||
#endif // C++20
|
||||
|
||||
#endif // MPT_ENABLE_U8STRING
|
||||
|
||||
|
||||
#if MPT_WSTRING_CONVERT
|
||||
// Convert to a wide character string.
|
||||
// The wide encoding is UTF-16 or UTF-32, based on sizeof(wchar_t).
|
||||
// If str does not contain any invalid characters, this conversion is lossless.
|
||||
// Invalid source bytes will be replaced by some replacement character or string.
|
||||
inline std::wstring ToWide(const std::wstring &str) { return str; }
|
||||
inline std::wstring ToWide(const wchar_t * str) { return (str ? std::wstring(str) : std::wstring()); }
|
||||
std::wstring ToWide(Charset from, const std::string &str);
|
||||
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.
|
||||
// If str does not contain any invalid characters,
|
||||
// this conversion will be lossless iff, and only iff,
|
||||
// 'to' is UTF8.
|
||||
// Invalid source bytes or characters that are not representable in the
|
||||
// destination charset will be replaced by some replacement character or string.
|
||||
#if MPT_WSTRING_CONVERT
|
||||
std::string ToCharset(Charset to, const std::wstring &str);
|
||||
inline std::string ToCharset(Charset to, const wchar_t * str) { return ToCharset(to, str ? std::wstring(str) : std::wstring()); }
|
||||
#endif
|
||||
std::string ToCharset(Charset to, Charset from, const std::string &str);
|
||||
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);
|
||||
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);
|
||||
inline mpt::lstring ToLocale(Charset from, const char * str) { return ToLocale(from, str ? std::string(str): std::string()); }
|
||||
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);
|
||||
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);
|
||||
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(MPT_WITH_MFC)
|
||||
#if !(MPT_WSTRING_CONVERT)
|
||||
#error "MFC depends on MPT_WSTRING_CONVERT)"
|
||||
#endif
|
||||
|
||||
// Convert to a MFC CString. The CString encoding depends on UNICODE.
|
||||
// This should also be used when converting to TCHAR strings.
|
||||
// If UNICODE is defined, this is a completely lossless operation.
|
||||
inline CString ToCString(const CString &str) { return str; }
|
||||
CString ToCString(const std::wstring &str);
|
||||
inline CString ToCString(const wchar_t * str) { return ToCString(str ? std::wstring(str) : std::wstring()); }
|
||||
CString ToCString(Charset from, const std::string &str);
|
||||
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.
|
||||
// If UNICODE is defined, this is a completely lossless operation.
|
||||
std::wstring ToWide(const CString &str);
|
||||
std::string ToCharset(Charset to, const CString &str);
|
||||
|
||||
#endif // MPT_WITH_MFC
|
||||
|
||||
|
||||
// mpt::ustring
|
||||
//
|
||||
// mpt::ustring is a string type that can hold unicode strings.
|
||||
// It is implemented as a std::basic_string either based on wchar_t (i.e. the
|
||||
// same as std::wstring) or a custom-defined char_traits class that is derived
|
||||
// from std::char_traits<char>.
|
||||
// The selection of the underlying implementation is done at compile-time.
|
||||
// MPT_UCHAR, MPT_ULITERAL and MPT_USTRING are macros that ease construction
|
||||
// of ustring char literals, ustring char array literals and ustring objects
|
||||
// from ustring char literals that work consistently in both modes.
|
||||
// Note that these are not supported for non-ASCII characters appearing in
|
||||
// the macro argument.
|
||||
// Also note that, as both UTF8 and UTF16 (it is less of an issue for UTF32)
|
||||
// are variable-length encodings and mpt::ustring is implemented as a
|
||||
// std::basic_string, all member functions that require individual character
|
||||
// access will not work consistently or even at all in a meaningful way.
|
||||
// This in particular affects operator[], at(), find() and substr().
|
||||
// The code makes no effort in preventing these or generating warnings when
|
||||
// these are used on mpt::ustring objects. However, compiling in the
|
||||
// respectively other mpt::ustring mode will catch most of these anyway.
|
||||
|
||||
#if MPT_USTRING_MODE_WIDE
|
||||
#if MPT_USTRING_MODE_UTF8
|
||||
#error "MPT_USTRING_MODE_WIDE and MPT_USTRING_MODE_UTF8 are mutually exclusive."
|
||||
#endif
|
||||
|
||||
using ustring = std::wstring;
|
||||
using uchar = wchar_t;
|
||||
#define MPT_UCHAR(x) L ## x
|
||||
#define MPT_ULITERAL(x) L ## x
|
||||
#define MPT_USTRING(x) std::wstring( L ## x )
|
||||
|
||||
#endif // MPT_USTRING_MODE_WIDE
|
||||
|
||||
#if MPT_USTRING_MODE_UTF8
|
||||
#if MPT_USTRING_MODE_WIDE
|
||||
#error "MPT_USTRING_MODE_WIDE and MPT_USTRING_MODE_UTF8 are mutually exclusive."
|
||||
#endif
|
||||
|
||||
using ustring = mpt::u8string;
|
||||
using uchar = MPT_U8CHAR_TYPE;
|
||||
#define MPT_UCHAR(x) MPT_U8CHAR( x )
|
||||
#define MPT_ULITERAL(x) MPT_U8LITERAL( x )
|
||||
#define MPT_USTRING(x) MPT_U8STRING( x )
|
||||
|
||||
#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)"
|
||||
#endif
|
||||
inline mpt::ustring ToUnicode(const std::wstring &str) { return str; }
|
||||
inline mpt::ustring ToUnicode(const wchar_t * str) { return (str ? std::wstring(str) : std::wstring()); }
|
||||
inline mpt::ustring ToUnicode(Charset from, const std::string &str) { return ToWide(from, str); }
|
||||
inline mpt::ustring ToUnicode(Charset from, const char * str) { return ToUnicode(from, str ? std::string(str) : std::string()); }
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
inline mpt::ustring ToUnicode(const mpt::lstring &str) { return ToWide(str); }
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
#if defined(MPT_WITH_MFC)
|
||||
inline mpt::ustring ToUnicode(const CString &str) { return ToWide(str); }
|
||||
#endif // MFC
|
||||
#else // !MPT_USTRING_MODE_WIDE
|
||||
inline mpt::ustring ToUnicode(const mpt::ustring &str) { return str; }
|
||||
#if MPT_WSTRING_CONVERT
|
||||
mpt::ustring ToUnicode(const std::wstring &str);
|
||||
inline mpt::ustring ToUnicode(const wchar_t * str) { return ToUnicode(str ? std::wstring(str) : std::wstring()); }
|
||||
#endif
|
||||
mpt::ustring ToUnicode(Charset from, const std::string &str);
|
||||
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(MPT_WITH_MFC)
|
||||
mpt::ustring ToUnicode(const CString &str);
|
||||
#endif // MPT_WITH_MFC
|
||||
#endif // MPT_USTRING_MODE_WIDE
|
||||
|
||||
#if MPT_USTRING_MODE_WIDE
|
||||
#if !(MPT_WSTRING_CONVERT)
|
||||
#error "MPT_USTRING_MODE_WIDE depends on MPT_WSTRING_CONVERT)"
|
||||
#endif
|
||||
// nothing, std::wstring overloads will catch all stuff
|
||||
#else // !MPT_USTRING_MODE_WIDE
|
||||
#if MPT_WSTRING_CONVERT
|
||||
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(MPT_WITH_MFC)
|
||||
CString ToCString(const mpt::ustring &str);
|
||||
#endif // MPT_WITH_MFC
|
||||
#endif // MPT_USTRING_MODE_WIDE
|
||||
|
||||
// The MPT_UTF8 allows specifying UTF8 char arrays.
|
||||
// The resulting type is mpt::ustring and the construction might require runtime translation,
|
||||
// i.e. it is NOT generally available at compile time.
|
||||
// Use explicit UTF8 encoding,
|
||||
// i.e. U+00FC (LATIN SMALL LETTER U WITH DIAERESIS) would be written as "\xC3\xBC".
|
||||
#define MPT_UTF8(x) mpt::ToUnicode(mpt::Charset::UTF8, x )
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
mpt::ustring ToUnicode(uint16 codepage, mpt::Charset fallback, const std::string &str);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
char ToLowerCaseAscii(char c);
|
||||
char ToUpperCaseAscii(char c);
|
||||
std::string ToLowerCaseAscii(std::string s);
|
||||
std::string ToUpperCaseAscii(std::string s);
|
||||
|
||||
int CompareNoCaseAscii(const char *a, const char *b, std::size_t n);
|
||||
int CompareNoCaseAscii(std::string_view a, std::string_view b);
|
||||
int CompareNoCaseAscii(const std::string &a, const std::string &b);
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
|
||||
mpt::ustring ToLowerCase(const mpt::ustring &s);
|
||||
mpt::ustring ToUpperCase(const mpt::ustring &s);
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// The AnyString types are meant to be used as function argument types only,
|
||||
// and only during the transition phase to all-unicode strings in the whole codebase.
|
||||
// Using an AnyString type as function argument avoids the need to overload a function for all the
|
||||
// different string types that we currently have.
|
||||
// Warning: These types will silently do charset conversions. Only use them when this can be tolerated.
|
||||
|
||||
// BasicAnyString is convertable to mpt::ustring and constructable from any string at all.
|
||||
template <mpt::Charset charset = mpt::Charset::UTF8, bool tryUTF8 = true>
|
||||
class BasicAnyString : public mpt::ustring
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
static mpt::ustring From8bit(const std::string &str)
|
||||
{
|
||||
if constexpr(charset == mpt::Charset::UTF8)
|
||||
{
|
||||
return mpt::ToUnicode(mpt::Charset::UTF8, str);
|
||||
} else
|
||||
{
|
||||
// auto utf8 detection
|
||||
if constexpr(tryUTF8)
|
||||
{
|
||||
if(mpt::IsUTF8(str))
|
||||
{
|
||||
return mpt::ToUnicode(mpt::Charset::UTF8, str);
|
||||
} else
|
||||
{
|
||||
return mpt::ToUnicode(charset, str);
|
||||
}
|
||||
} else
|
||||
{
|
||||
return mpt::ToUnicode(charset, str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// 8 bit
|
||||
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)) { }
|
||||
#if MPT_USTRING_MODE_UTF8 && MPT_WSTRING_CONVERT
|
||||
BasicAnyString(const std::wstring &str) : mpt::ustring(mpt::ToUnicode(str)) { }
|
||||
#endif
|
||||
#if MPT_WSTRING_CONVERT
|
||||
BasicAnyString(const wchar_t *str) : mpt::ustring(str ? mpt::ToUnicode(str) : mpt::ustring()) { }
|
||||
#endif
|
||||
|
||||
// mfc
|
||||
#if defined(MPT_WITH_MFC)
|
||||
BasicAnyString(const CString &str) : mpt::ustring(mpt::ToUnicode(str)) { }
|
||||
#endif // MPT_WITH_MFC
|
||||
|
||||
// fallback for custom string types
|
||||
template <typename Tstring> BasicAnyString(const Tstring &str) : mpt::ustring(mpt::ToUnicode(str)) { }
|
||||
template <typename Tstring> BasicAnyString(Tstring &&str) : mpt::ustring(mpt::ToUnicode(std::forward<Tstring>(str))) { }
|
||||
|
||||
};
|
||||
|
||||
// AnyUnicodeString is convertable to mpt::ustring and constructable from any unicode string,
|
||||
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)) { }
|
||||
#if MPT_USTRING_MODE_UTF8 && MPT_WSTRING_CONVERT
|
||||
AnyUnicodeString(const std::wstring &str) : mpt::ustring(mpt::ToUnicode(str)) { }
|
||||
#endif
|
||||
#if MPT_WSTRING_CONVERT
|
||||
AnyUnicodeString(const wchar_t *str) : mpt::ustring(str ? mpt::ToUnicode(str) : mpt::ustring()) { }
|
||||
#endif
|
||||
|
||||
// mfc
|
||||
#if defined(MPT_WITH_MFC)
|
||||
AnyUnicodeString(const CString &str) : mpt::ustring(mpt::ToUnicode(str)) { }
|
||||
#endif // MPT_WITH_MFC
|
||||
|
||||
// fallback for custom string types
|
||||
template <typename Tstring> AnyUnicodeString(const Tstring &str) : mpt::ustring(mpt::ToUnicode(str)) { }
|
||||
template <typename Tstring> AnyUnicodeString(Tstring &&str) : mpt::ustring(mpt::ToUnicode(std::forward<Tstring>(str))) { }
|
||||
|
||||
};
|
||||
|
||||
// AnyString
|
||||
// Try to do the smartest auto-magic we can do.
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
using AnyString = BasicAnyString<mpt::Charset::Locale, true>;
|
||||
#elif MPT_OS_WINDOWS
|
||||
using AnyString = BasicAnyString<mpt::Charset::Windows1252, true>;
|
||||
#else
|
||||
using AnyString = BasicAnyString<mpt::Charset::ISO8859_1, true>;
|
||||
#endif
|
||||
|
||||
// AnyStringLocale
|
||||
// char-based strings are assumed to be in locale encoding.
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
using AnyStringLocale = BasicAnyString<mpt::Charset::Locale, false>;
|
||||
#else
|
||||
using AnyStringLocale = BasicAnyString<mpt::Charset::UTF8, false>;
|
||||
#endif
|
||||
|
||||
// AnyStringUTF8orLocale
|
||||
// char-based strings are tried in UTF8 first, if this fails, locale is used.
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
using AnyStringUTF8orLocale = BasicAnyString<mpt::Charset::Locale, true>;
|
||||
#else
|
||||
using AnyStringUTF8orLocale = BasicAnyString<mpt::Charset::UTF8, false>;
|
||||
#endif
|
||||
|
||||
// AnyStringUTF8
|
||||
// char-based strings are assumed to be in UTF8.
|
||||
using AnyStringUTF8 = BasicAnyString<mpt::Charset::UTF8, false>;
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,117 +0,0 @@
|
|||
/*
|
||||
* 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
|
|
@ -1,565 +0,0 @@
|
|||
/*
|
||||
* 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 "mptMemory.h"
|
||||
#include "mptString.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
|
||||
namespace String
|
||||
{
|
||||
|
||||
|
||||
enum ReadWriteMode : uint8
|
||||
{
|
||||
// Reading / Writing: Standard null-terminated string handling.
|
||||
nullTerminated = 1,
|
||||
// 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 = 2,
|
||||
// Reading: String may contain null characters anywhere. They should be treated as spaces.
|
||||
// Writing: A space-padded string is written.
|
||||
spacePadded = 3,
|
||||
// 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 = 4,
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
bool empty() const
|
||||
{
|
||||
return buf[0] == Tchar('\0');
|
||||
}
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
bool empty() const
|
||||
{
|
||||
return buf[0] == Tchar('\0');
|
||||
}
|
||||
};
|
||||
|
||||
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 <std::size_t len, mpt::String::ReadWriteMode mode = static_cast<mpt::String::ReadWriteMode>(0)> struct charbuf;
|
||||
|
||||
template <std::size_t len>
|
||||
struct charbuf<len, static_cast<mpt::String::ReadWriteMode>(0)>
|
||||
{
|
||||
public:
|
||||
typedef char Tchar;
|
||||
using char_type = Tchar;
|
||||
using string_type = std::basic_string<Tchar>;
|
||||
constexpr std::size_t static_length() const { return len; }
|
||||
public:
|
||||
Tchar buf[len];
|
||||
public:
|
||||
charbuf()
|
||||
{
|
||||
Clear(buf);
|
||||
}
|
||||
charbuf(const charbuf &) = default;
|
||||
charbuf(charbuf &&) = default;
|
||||
charbuf & operator = (const charbuf &) = default;
|
||||
charbuf & operator = (charbuf &&) = default;
|
||||
const Tchar & operator[](std::size_t i) const { return buf[i]; }
|
||||
std::string str() const { return static_cast<std::string>(*this); }
|
||||
operator string_type () const
|
||||
{
|
||||
return mpt::String::ReadAutoBuf(buf);
|
||||
}
|
||||
bool empty() const
|
||||
{
|
||||
return mpt::String::ReadAutoBuf(buf).empty();
|
||||
}
|
||||
charbuf & operator = (const string_type & str)
|
||||
{
|
||||
mpt::String::WriteAutoBuf(buf) = str;
|
||||
return *this;
|
||||
}
|
||||
public:
|
||||
friend bool operator!=(const std::string & a, const charbuf & b) { return a != b.str(); }
|
||||
friend bool operator!=(const charbuf & a, const std::string & b) { return a.str() != b; }
|
||||
friend bool operator==(const std::string & a, const charbuf & b) { return a == b.str(); }
|
||||
friend bool operator==(const charbuf & a, const std::string & b) { return a.str() == b; }
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
static_assert(sizeof(Tchar) == 1);
|
||||
}
|
||||
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);
|
||||
}
|
||||
bool empty() const
|
||||
{
|
||||
return String::detail::ReadStringBuffer(mode, buf, size).empty();
|
||||
}
|
||||
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)
|
||||
{
|
||||
static_assert(sizeof(Tchar) == 1);
|
||||
}
|
||||
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);
|
||||
}
|
||||
bool empty() const
|
||||
{
|
||||
return String::detail::ReadStringBuffer(mode, buf, size).empty();
|
||||
}
|
||||
};
|
||||
|
||||
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
|
||||
|
||||
template <std::size_t len, mpt::String::ReadWriteMode mode>
|
||||
struct charbuf
|
||||
{
|
||||
public:
|
||||
typedef char Tchar;
|
||||
using char_type = Tchar;
|
||||
using string_type = std::basic_string<Tchar>;
|
||||
public:
|
||||
Tchar buf[len];
|
||||
public:
|
||||
charbuf() = default;
|
||||
charbuf(const charbuf &) = default;
|
||||
charbuf(charbuf &&) = default;
|
||||
charbuf & operator = (const charbuf &) = default;
|
||||
charbuf & operator = (charbuf &&) = default;
|
||||
operator string_type () const
|
||||
{
|
||||
return mpt::String::ReadBuf(mode, buf);
|
||||
}
|
||||
bool empty() const
|
||||
{
|
||||
return mpt::String::ReadBuf(mode, buf).empty();
|
||||
}
|
||||
charbuf & operator = (const string_type & str)
|
||||
{
|
||||
mpt::String::WriteBuf(mode, buf) = str;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// see MPT_BINARY_STRUCT
|
||||
template <std::size_t len, mpt::String::ReadWriteMode mode>
|
||||
struct is_binary_safe<typename mpt::charbuf<len, mode>> : public std::true_type { };
|
||||
template <std::size_t len>
|
||||
struct is_binary_safe<typename mpt::charbuf<len, static_cast<mpt::String::ReadWriteMode>(0)>> : public std::false_type { };
|
||||
static_assert(sizeof(mpt::charbuf<7>) == 7);
|
||||
static_assert(alignof(mpt::charbuf<7>) == 1);
|
||||
static_assert(std::is_standard_layout<mpt::charbuf<7>>::value);
|
||||
|
||||
|
||||
#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(MPT_WITH_MFC)
|
||||
|
||||
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 // MPT_WITH_MFC
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR)
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#endif // !MPT_COMPILER_QUIRK_NO_WCHAR
|
||||
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
|
||||
|
||||
} // namespace String
|
||||
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,522 +0,0 @@
|
|||
/*
|
||||
* mptStringFormat.cpp
|
||||
* -------------------
|
||||
* Purpose: Convert other types to strings.
|
||||
* 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 "mptStringFormat.h"
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
#define MPT_FORMAT_CXX17_INT 1
|
||||
#else
|
||||
#define MPT_FORMAT_CXX17_INT 0
|
||||
#endif
|
||||
|
||||
#if MPT_FORMAT_CXX17_INT
|
||||
#if MPT_MSVC_AT_LEAST(2019,0) && MPT_MSVC_BEFORE(2019,2)
|
||||
#if !(defined(UNICODE) || defined(_UNICODE))
|
||||
// work-around https://developercommunity.visualstudio.com/content/problem/629849/mfc-headers-conflict-with-c17-charconv-header-in-m.html
|
||||
#pragma push_macro("_M2")
|
||||
#undef _M2
|
||||
#endif
|
||||
#endif
|
||||
#include <charconv>
|
||||
#if MPT_MSVC_AT_LEAST(2019,0) && MPT_MSVC_BEFORE(2019,2)
|
||||
#if !(defined(UNICODE) || defined(_UNICODE))
|
||||
// work-around https://developercommunity.visualstudio.com/content/problem/629849/mfc-headers-conflict-with-c17-charconv-header-in-m.html
|
||||
#pragma pop_macro("_M2")
|
||||
#endif
|
||||
#endif
|
||||
#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
|
||||
|
||||
|
||||
|
||||
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> 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
|
||||
static 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>
|
||||
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());
|
||||
SaneInsert(o, x);
|
||||
return o.str();
|
||||
}
|
||||
|
||||
#if MPT_WSTRING_FORMAT
|
||||
template<typename T>
|
||||
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());
|
||||
SaneInsert(o, x);
|
||||
return o.str();
|
||||
}
|
||||
#endif
|
||||
|
||||
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); }
|
||||
|
||||
#if MPT_WSTRING_FORMAT
|
||||
#if MPT_USTRING_MODE_UTF8
|
||||
mpt::ustring ToUString(const std::wstring & x) { return mpt::ToUnicode(x); }
|
||||
#endif
|
||||
mpt::ustring ToUString(const wchar_t * const & x) { return mpt::ToUnicode(x); }
|
||||
#endif
|
||||
#if defined(MPT_WITH_MFC)
|
||||
mpt::ustring ToUString(const CString & x) { return mpt::ToUnicode(x); }
|
||||
#endif // MPT_WITH_MFC
|
||||
#if MPT_USTRING_MODE_WIDE
|
||||
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::Charset::UTF8, ToStringHelperInt(static_cast<int>(x))); }
|
||||
mpt::ustring ToUString(const signed char & x) { return mpt::ToUnicode(mpt::Charset::UTF8, ToStringHelperInt(x)); }
|
||||
mpt::ustring ToUString(const unsigned char & x) { return mpt::ToUnicode(mpt::Charset::UTF8, ToStringHelperInt(x)); }
|
||||
mpt::ustring ToUString(const signed short & x) { return mpt::ToUnicode(mpt::Charset::UTF8, ToStringHelperInt(x)); }
|
||||
mpt::ustring ToUString(const unsigned short & x) { return mpt::ToUnicode(mpt::Charset::UTF8, ToStringHelperInt(x)); }
|
||||
mpt::ustring ToUString(const signed int & x) { return mpt::ToUnicode(mpt::Charset::UTF8, ToStringHelperInt(x)); }
|
||||
mpt::ustring ToUString(const unsigned int & x) { return mpt::ToUnicode(mpt::Charset::UTF8, ToStringHelperInt(x)); }
|
||||
mpt::ustring ToUString(const signed long & x) { return mpt::ToUnicode(mpt::Charset::UTF8, ToStringHelperInt(x)); }
|
||||
mpt::ustring ToUString(const unsigned long & x) { return mpt::ToUnicode(mpt::Charset::UTF8, ToStringHelperInt(x)); }
|
||||
mpt::ustring ToUString(const signed long long & x) { return mpt::ToUnicode(mpt::Charset::UTF8, ToStringHelperInt(x)); }
|
||||
mpt::ustring ToUString(const unsigned long long & x) { return mpt::ToUnicode(mpt::Charset::UTF8, ToStringHelperInt(x)); }
|
||||
mpt::ustring ToUString(const float & x) { return mpt::ToUnicode(mpt::Charset::UTF8, ToStringHelperFloat(x)); }
|
||||
mpt::ustring ToUString(const double & x) { return mpt::ToUnicode(mpt::Charset::UTF8, ToStringHelperFloat(x)); }
|
||||
mpt::ustring ToUString(const long double & x) { return mpt::ToUnicode(mpt::Charset::UTF8, ToStringHelperFloat(x)); }
|
||||
#endif
|
||||
|
||||
#if MPT_WSTRING_FORMAT
|
||||
#if MPT_USTRING_MODE_UTF8
|
||||
std::wstring ToWString(const mpt::ustring & x) { return mpt::ToWide(x); }
|
||||
#endif
|
||||
#if defined(MPT_WITH_MFC)
|
||||
std::wstring ToWString(const CString & x) { return mpt::ToWide(x); }
|
||||
#endif // MPT_WITH_MFC
|
||||
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 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();
|
||||
if(precision != -1 && width != 0 && !(f & fmt_base::NotaFix) && !(f & fmt_base::NotaSci))
|
||||
{
|
||||
// fixup:
|
||||
// precision behaves differently from .#
|
||||
// avoid default format when precision and width are set
|
||||
f &= ~fmt_base::NotaNrm;
|
||||
f |= fmt_base::NotaFix;
|
||||
}
|
||||
if(f & fmt_base::BaseDec) { o << std::dec; }
|
||||
else if(f & fmt_base::BaseHex) { o << std::hex; }
|
||||
if(f & fmt_base::NotaNrm ) { /*nothing*/ }
|
||||
else if(f & fmt_base::NotaFix ) { o << std::setiosflags(std::ios::fixed); }
|
||||
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')); }
|
||||
}
|
||||
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>
|
||||
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, x);
|
||||
SaneInsert(o, x);
|
||||
return o.str();
|
||||
}
|
||||
|
||||
#if MPT_WSTRING_FORMAT
|
||||
template<typename T>
|
||||
static inline std::wstring FormatValWHelperFloat(const T & x, const FormatSpec & f)
|
||||
{
|
||||
std::wostringstream o;
|
||||
o.imbue(std::locale::classic());
|
||||
ApplyFormat(o, f, x);
|
||||
SaneInsert(o, x);
|
||||
return o.str();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
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); }
|
||||
|
||||
#if MPT_USTRING_MODE_WIDE
|
||||
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 bool & x, const FormatSpec & f) { return mpt::ToUnicode(mpt::Charset::UTF8, FormatValHelperInt(static_cast<int>(x), f)); }
|
||||
mpt::ustring FormatValU(const signed char & x, const FormatSpec & f) { return mpt::ToUnicode(mpt::Charset::UTF8, FormatValHelperInt(x, f)); }
|
||||
mpt::ustring FormatValU(const unsigned char & x, const FormatSpec & f) { return mpt::ToUnicode(mpt::Charset::UTF8, FormatValHelperInt(x, f)); }
|
||||
mpt::ustring FormatValU(const signed short & x, const FormatSpec & f) { return mpt::ToUnicode(mpt::Charset::UTF8, FormatValHelperInt(x, f)); }
|
||||
mpt::ustring FormatValU(const unsigned short & x, const FormatSpec & f) { return mpt::ToUnicode(mpt::Charset::UTF8, FormatValHelperInt(x, f)); }
|
||||
mpt::ustring FormatValU(const signed int & x, const FormatSpec & f) { return mpt::ToUnicode(mpt::Charset::UTF8, FormatValHelperInt(x, f)); }
|
||||
mpt::ustring FormatValU(const unsigned int & x, const FormatSpec & f) { return mpt::ToUnicode(mpt::Charset::UTF8, FormatValHelperInt(x, f)); }
|
||||
mpt::ustring FormatValU(const signed long & x, const FormatSpec & f) { return mpt::ToUnicode(mpt::Charset::UTF8, FormatValHelperInt(x, f)); }
|
||||
mpt::ustring FormatValU(const unsigned long & x, const FormatSpec & f) { return mpt::ToUnicode(mpt::Charset::UTF8, FormatValHelperInt(x, f)); }
|
||||
mpt::ustring FormatValU(const signed long long & x, const FormatSpec & f) { return mpt::ToUnicode(mpt::Charset::UTF8, FormatValHelperInt(x, f)); }
|
||||
mpt::ustring FormatValU(const unsigned long long & x, const FormatSpec & f) { return mpt::ToUnicode(mpt::Charset::UTF8, FormatValHelperInt(x, f)); }
|
||||
mpt::ustring FormatValU(const float & x, const FormatSpec & f) { return mpt::ToUnicode(mpt::Charset::UTF8, FormatValHelperFloat(x, f)); }
|
||||
mpt::ustring FormatValU(const double & x, const FormatSpec & f) { return mpt::ToUnicode(mpt::Charset::UTF8, FormatValHelperFloat(x, f)); }
|
||||
mpt::ustring FormatValU(const long double & x, const FormatSpec & f) { return mpt::ToUnicode(mpt::Charset::UTF8, FormatValHelperFloat(x, f)); }
|
||||
#endif
|
||||
|
||||
#if MPT_WSTRING_FORMAT
|
||||
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
|
||||
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,737 +0,0 @@
|
|||
/*
|
||||
* mptStringFormat.h
|
||||
* -----------------
|
||||
* Purpose: Convert other types to strings.
|
||||
* 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"
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
|
||||
// The following section demands a rationale.
|
||||
// 1. mpt::fmt::val(), mpt::wfmt::val() and mpt::ufmt::val() mimic the semantics of c++11 std::to_string() and std::to_wstring().
|
||||
// There is an important difference though. The c++11 versions are specified in terms of sprintf formatting which in turn
|
||||
// depends on the current C locale. This renders these functions unusable in a library context because the current
|
||||
// C locale is set by the library-using application and could be anything. There is no way a library can get reliable semantics
|
||||
// out of these functions. It is thus better to just avoid them.
|
||||
// ToString() and ToWString() are based on iostream internally, but the the locale of the stream is forced to std::locale::classic(),
|
||||
// which results in "C" ASCII locale behavior.
|
||||
// 2. The full suite of printf-like or iostream like number formatting is generally not required. Instead, a sane subset functionality
|
||||
// is provided here.
|
||||
// For convenience, mpt::fmt::f(const char *, float) allows formatting a single floating point value with a
|
||||
// standard printf-like format string. This itself relies on iostream with classic() locale internally and is thus current locale
|
||||
// agnostic.
|
||||
// When formatting integers, it is recommended to use mpt::fmt::dec or mpt::fmt::hex. Appending a template argument '<n>' sets the width,
|
||||
// the same way as '%nd' would do. Appending a '0' to the function name causes zero-filling as print-like '%0nd' would do. Spelling 'HEX'
|
||||
// in upper-case generates upper-case hex digits. If these are not known at compile-time, a more verbose FormatVal(int, format) can be
|
||||
// used.
|
||||
// 3. mpt::format(format)(...) provides simplified and type-safe message and localization string formatting.
|
||||
// The only specifier allowed is '%' followed by a single digit n. It references to n-th parameter after the format string (1-based).
|
||||
// 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.
|
||||
// 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 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:
|
||||
// - Avoids binary code bloat when too much of iostream operator << gets inlined at every usage site.
|
||||
// - 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::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
|
||||
// move-semantics will kick in if RVO/NRVO fails).
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
// 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 ToUString().
|
||||
|
||||
// fallback to member function ToUString()
|
||||
#if MPT_USTRING_MODE_UTF8
|
||||
template <typename T> auto ToString(const T & x) -> decltype(mpt::ToCharset(mpt::Charset::UTF8, x.ToUString())) { return mpt::ToCharset(mpt::Charset::UTF8, 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
|
||||
|
||||
inline std::string ToString(const std::string & x) { return x; }
|
||||
inline std::string ToString(const char * const & x) { return x; }
|
||||
std::string ToString(const char &x) = delete; // deprecated to catch potential API mis-use, use std::string(1, x) instead
|
||||
#if MPT_WSTRING_FORMAT
|
||||
std::string ToString(const std::wstring & x) = delete; // Unknown encoding.
|
||||
std::string ToString(const wchar_t * const & x) = delete; // Unknown encoding.
|
||||
std::string ToString(const wchar_t &x ) = delete; // deprecated to catch potential API mis-use, use std::wstring(1, x) instead
|
||||
#endif
|
||||
#if MPT_USTRING_MODE_UTF8
|
||||
std::string ToString(const mpt::ustring & x) = delete; // Unknown encoding.
|
||||
#endif
|
||||
#if defined(MPT_WITH_MFC)
|
||||
std::string ToString(const CString & x) = delete; // unknown encoding
|
||||
#endif // MPT_WITH_MFC
|
||||
std::string ToString(const bool & x);
|
||||
std::string ToString(const signed char & x);
|
||||
std::string ToString(const unsigned char & x);
|
||||
std::string ToString(const signed short & x);
|
||||
std::string ToString(const unsigned short & x);
|
||||
std::string ToString(const signed int & x);
|
||||
std::string ToString(const unsigned int & x);
|
||||
std::string ToString(const signed long & x);
|
||||
std::string ToString(const unsigned long & x);
|
||||
std::string ToString(const signed long long & x);
|
||||
std::string ToString(const unsigned long long & x);
|
||||
std::string ToString(const float & x);
|
||||
std::string ToString(const double & x);
|
||||
std::string ToString(const long double & x);
|
||||
|
||||
// fallback to member function ToUString()
|
||||
template <typename T> auto ToUString(const T & x) -> decltype(x.ToUString()) { return x.ToUString(); }
|
||||
|
||||
inline mpt::ustring ToUString(const mpt::ustring & x) { return x; }
|
||||
mpt::ustring ToUString(const std::string & x) = delete; // Unknown encoding.
|
||||
mpt::ustring ToUString(const char * const & x) = delete; // Unknown encoding. Note that this also applies to TCHAR in !UNICODE builds as the type is indistinguishable from char. Wrap with CString or FromTcharStr in this case.
|
||||
mpt::ustring ToUString(const char & x) = delete; // deprecated to catch potential API mis-use, use std::string(1, x) instead
|
||||
#if MPT_WSTRING_FORMAT
|
||||
#if MPT_USTRING_MODE_UTF8
|
||||
mpt::ustring ToUString(const std::wstring & x);
|
||||
#endif
|
||||
mpt::ustring ToUString(const wchar_t * const & x);
|
||||
mpt::ustring ToUString(const wchar_t & x) = delete; // deprecated to catch potential API mis-use, use std::wstring(1, x) instead
|
||||
#endif
|
||||
#if defined(MPT_WITH_MFC)
|
||||
mpt::ustring ToUString(const CString & x);
|
||||
#endif // MPT_WITH_MFC
|
||||
mpt::ustring ToUString(const bool & x);
|
||||
mpt::ustring ToUString(const signed char & x);
|
||||
mpt::ustring ToUString(const unsigned char & x);
|
||||
mpt::ustring ToUString(const signed short & x);
|
||||
mpt::ustring ToUString(const unsigned short & x);
|
||||
mpt::ustring ToUString(const signed int & x);
|
||||
mpt::ustring ToUString(const unsigned int & x);
|
||||
mpt::ustring ToUString(const signed long & x);
|
||||
mpt::ustring ToUString(const unsigned long & x);
|
||||
mpt::ustring ToUString(const signed long long & x);
|
||||
mpt::ustring ToUString(const unsigned long long & x);
|
||||
mpt::ustring ToUString(const float & x);
|
||||
mpt::ustring ToUString(const double & x);
|
||||
mpt::ustring ToUString(const long double & x);
|
||||
|
||||
#if MPT_WSTRING_FORMAT
|
||||
std::wstring ToWString(const std::string & x) = delete; // Unknown encoding.
|
||||
std::wstring ToWString(const char * const & x) = delete; // Unknown encoding. Note that this also applies to TCHAR in !UNICODE builds as the type is indistinguishable from char. Wrap with CString or FromTcharStr in this case.
|
||||
std::wstring ToWString(const char & x) = delete; // deprecated to catch potential API mis-use, use std::string(1, x) instead
|
||||
inline std::wstring ToWString(const std::wstring & x) { return x; }
|
||||
inline std::wstring ToWString(const wchar_t * const & x) { return x; }
|
||||
std::wstring ToWString(const wchar_t & x) = delete; // deprecated to catch potential API mis-use, use std::wstring(1, x) instead
|
||||
#if MPT_USTRING_MODE_UTF8
|
||||
std::wstring ToWString(const mpt::ustring & x);
|
||||
#endif
|
||||
#if defined(MPT_WITH_MFC)
|
||||
std::wstring ToWString(const CString & x);
|
||||
#endif // MPT_WITH_MFC
|
||||
std::wstring ToWString(const bool & x);
|
||||
std::wstring ToWString(const signed char & x);
|
||||
std::wstring ToWString(const unsigned char & x);
|
||||
std::wstring ToWString(const signed short & x);
|
||||
std::wstring ToWString(const unsigned short & x);
|
||||
std::wstring ToWString(const signed int & x);
|
||||
std::wstring ToWString(const unsigned int & x);
|
||||
std::wstring ToWString(const signed long & x);
|
||||
std::wstring ToWString(const unsigned long & x);
|
||||
std::wstring ToWString(const signed long long & x);
|
||||
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(MPT_WITH_MFC)
|
||||
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 // MPT_WITH_MFC
|
||||
|
||||
template <typename Tstring> struct ToStringTFunctor {};
|
||||
template <> struct ToStringTFunctor<std::string> { template <typename T> inline std::string operator() (const T & x) { return ToString(x); } };
|
||||
template <> struct ToStringTFunctor<mpt::ustring> { template <typename T> inline mpt::ustring operator() (const T & x) { return ToUString(x); } };
|
||||
#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(MPT_WITH_MFC)
|
||||
template <> struct ToStringTFunctor<CString> { template <typename T> inline CString operator() (const T & x) { return mpt::ToCStringHelper<T>()(x); } };
|
||||
#endif // MPT_WITH_MFC
|
||||
|
||||
template<typename Tstring, typename T> inline Tstring ToStringT(const T & x) { return ToStringTFunctor<Tstring>()(x); }
|
||||
|
||||
|
||||
|
||||
struct fmt_base
|
||||
{
|
||||
|
||||
enum FormatFlagsEnum
|
||||
{
|
||||
BaseDec = 0x0001, // base 10 (integers only)
|
||||
BaseHex = 0x0002, // base 16 (integers only)
|
||||
CaseLow = 0x0010, // lower case hex digits
|
||||
CaseUpp = 0x0020, // upper case hex digits
|
||||
FillOff = 0x0100, // do not fill up width
|
||||
FillNul = 0x0400, // fill up width with zeros
|
||||
NotaNrm = 0x1000, // float: normal/default notation
|
||||
NotaFix = 0x2000, // float: fixed point notation
|
||||
NotaSci = 0x4000, // float: scientific notation
|
||||
};
|
||||
|
||||
}; // struct fmt_base
|
||||
|
||||
typedef unsigned int FormatFlags;
|
||||
|
||||
static_assert(sizeof(FormatFlags) >= sizeof(fmt_base::FormatFlagsEnum));
|
||||
|
||||
class FormatSpec;
|
||||
|
||||
std::string FormatVal(const char & x, const FormatSpec & f) = delete; // deprecated to catch potential API mis-use, use std::string(1, x) instead
|
||||
#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR)
|
||||
std::string FormatVal(const wchar_t & x, const FormatSpec & f) = delete; // 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);
|
||||
std::string FormatVal(const signed short & x, const FormatSpec & f);
|
||||
std::string FormatVal(const unsigned short & x, const FormatSpec & f);
|
||||
std::string FormatVal(const signed int & x, const FormatSpec & f);
|
||||
std::string FormatVal(const unsigned int & x, const FormatSpec & f);
|
||||
std::string FormatVal(const signed long & x, const FormatSpec & f);
|
||||
std::string FormatVal(const unsigned long & x, const FormatSpec & f);
|
||||
std::string FormatVal(const signed long long & x, const FormatSpec & f);
|
||||
std::string FormatVal(const unsigned long long & x, const FormatSpec & f);
|
||||
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::ustring FormatValU(const char & x, const FormatSpec & f) = delete; // deprecated to catch potential API mis-use, use std::string(1, x) instead
|
||||
#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR)
|
||||
mpt::ustring FormatValU(const wchar_t & x, const FormatSpec & f) = delete; // 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
|
||||
std::wstring FormatValW(const char & x, const FormatSpec & f) = delete; // deprecated to catch potential API mis-use, use std::string(1, x) instead
|
||||
#if !defined(MPT_COMPILER_QUIRK_NO_WCHAR)
|
||||
std::wstring FormatValW(const wchar_t & x, const FormatSpec & f) = delete; // 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);
|
||||
std::wstring FormatValW(const signed short & x, const FormatSpec & f);
|
||||
std::wstring FormatValW(const unsigned short & x, const FormatSpec & f);
|
||||
std::wstring FormatValW(const signed int & x, const FormatSpec & f);
|
||||
std::wstring FormatValW(const unsigned int & x, const FormatSpec & f);
|
||||
std::wstring FormatValW(const signed long & x, const FormatSpec & f);
|
||||
std::wstring FormatValW(const unsigned long & x, const FormatSpec & f);
|
||||
std::wstring FormatValW(const signed long long & x, const FormatSpec & f);
|
||||
std::wstring FormatValW(const unsigned long long & x, const FormatSpec & f);
|
||||
std::wstring FormatValW(const float & x, const FormatSpec & f);
|
||||
std::wstring FormatValW(const double & x, const FormatSpec & f);
|
||||
std::wstring FormatValW(const long double & x, const FormatSpec & f);
|
||||
#endif
|
||||
|
||||
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); } };
|
||||
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 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::Charset::Locale, FormatVal(x, f)); } };
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
#if defined(MPT_WITH_MFC )
|
||||
#ifdef UNICODE
|
||||
template <> struct FormatValTFunctor<CString> { template <typename T> inline CString operator() (const T & x, const FormatSpec & f) { return mpt::ToCString(FormatValW(x, f)); } };
|
||||
#else // !UNICODE
|
||||
template <> struct FormatValTFunctor<CString> { template <typename T> inline CString operator() (const T & x, const FormatSpec & f) { return mpt::ToCString(mpt::Charset::Locale, FormatVal(x, f)); } };
|
||||
#endif // UNICODE
|
||||
#endif // MPT_WITH_MFC
|
||||
|
||||
|
||||
class FormatSpec
|
||||
{
|
||||
private:
|
||||
FormatFlags flags;
|
||||
std::size_t width;
|
||||
int precision;
|
||||
unsigned int group;
|
||||
char group_sep;
|
||||
public:
|
||||
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:
|
||||
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:
|
||||
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:
|
||||
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); }
|
||||
};
|
||||
|
||||
template <typename Tdst, typename Tsrc>
|
||||
struct pointer_cast_helper
|
||||
{
|
||||
Tdst operator()(const Tsrc & src) const { return src; }
|
||||
};
|
||||
template <typename Tdst, typename Tptr>
|
||||
struct pointer_cast_helper<Tdst, const Tptr*>
|
||||
{
|
||||
Tdst operator()(const Tptr * const & src) const { return reinterpret_cast<const Tdst>(src); }
|
||||
};
|
||||
template <typename Tdst, typename Tptr>
|
||||
struct pointer_cast_helper<Tdst, Tptr*>
|
||||
{
|
||||
Tdst operator()(const Tptr * const & src) const { return reinterpret_cast<const Tdst>(src); }
|
||||
};
|
||||
|
||||
|
||||
template <typename Tdst, typename Tsrc>
|
||||
Tdst pointer_cast(const Tsrc & src)
|
||||
{
|
||||
return pointer_cast_helper<Tdst, Tsrc>()(src);
|
||||
}
|
||||
|
||||
template <typename Tstring>
|
||||
struct fmtT : fmt_base
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
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)
|
||||
{
|
||||
static_assert(std::numeric_limits<T>::is_integer);
|
||||
return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseDec().FillOff());
|
||||
}
|
||||
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)
|
||||
{
|
||||
static_assert(std::numeric_limits<T>::is_integer);
|
||||
return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseHex().CaseLow().FillOff());
|
||||
}
|
||||
template<typename T>
|
||||
static inline Tstring HEX(const T& x)
|
||||
{
|
||||
static_assert(std::numeric_limits<T>::is_integer);
|
||||
return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseHex().CaseUpp().FillOff());
|
||||
}
|
||||
template<int width, typename T>
|
||||
static inline Tstring hex0(const T& x)
|
||||
{
|
||||
static_assert(std::numeric_limits<T>::is_integer);
|
||||
return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseHex().CaseLow().FillNul().Width(width));
|
||||
}
|
||||
template<int width, typename T>
|
||||
static inline Tstring HEX0(const T& x)
|
||||
{
|
||||
static_assert(std::numeric_limits<T>::is_integer);
|
||||
return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseHex().CaseUpp().FillNul().Width(width));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline Tstring hex(unsigned int g, char s, const T& x)
|
||||
{
|
||||
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 HEX(unsigned int g, char s, const T& x)
|
||||
{
|
||||
static_assert(std::numeric_limits<T>::is_integer);
|
||||
return FormatValTFunctor<Tstring>()(x, FormatSpec().BaseHex().CaseUpp().FillOff().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().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>
|
||||
static inline Tstring flt(const T& x, int precision = -1)
|
||||
{
|
||||
static_assert(std::is_floating_point<T>::value);
|
||||
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));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline Tstring ptr(const T& x)
|
||||
{
|
||||
static_assert(std::is_pointer<T>::value || std::is_same<T, std::uintptr_t>::value || std::is_same<T, std::intptr_t>::value, "");
|
||||
return hex0<mpt::pointer_size * 2>(pointer_cast<const std::uintptr_t>(x));
|
||||
}
|
||||
template<typename T>
|
||||
static inline Tstring PTR(const T& x)
|
||||
{
|
||||
static_assert(std::is_pointer<T>::value || std::is_same<T, std::uintptr_t>::value || std::is_same<T, std::intptr_t>::value, "");
|
||||
return HEX0<mpt::pointer_size * 2>(pointer_cast<const std::uintptr_t>(x));
|
||||
}
|
||||
|
||||
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;
|
||||
#endif
|
||||
#if MPT_USTRING_MODE_WIDE
|
||||
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(MPT_WITH_MFC)
|
||||
typedef fmtT<CString> cfmt;
|
||||
#endif // MPT_WITH_MFC
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
namespace mpt {
|
||||
|
||||
namespace String {
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <typename T> struct to_string_type { };
|
||||
template <> struct to_string_type<std::string > { typedef std::string type; };
|
||||
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(MPT_WITH_MFC)
|
||||
template <> struct to_string_type<CString > { typedef CString type; };
|
||||
#endif // MPT_WITH_MFC
|
||||
template <typename T, std::size_t N> struct to_string_type<T [N]> { typedef typename to_string_type<T>::type type; };
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace String
|
||||
|
||||
template<typename Tformat>
|
||||
class message_formatter
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
typedef typename mpt::String::detail::to_string_type<Tformat>::type Tstring;
|
||||
|
||||
private:
|
||||
|
||||
Tstring format;
|
||||
|
||||
private:
|
||||
|
||||
MPT_NOINLINE Tstring do_format(mpt::span<const Tstring> vals) const
|
||||
{
|
||||
typedef typename mpt::string_traits<Tstring> traits;
|
||||
Tstring result;
|
||||
const typename traits::size_type len = traits::length(format);
|
||||
traits::reserve(result, len);
|
||||
for(typename traits::size_type pos = 0; pos != len; ++pos)
|
||||
{
|
||||
typename traits::char_type c = format[pos];
|
||||
if(pos + 1 != len && c == typename traits::char_type('%'))
|
||||
{
|
||||
pos++;
|
||||
c = format[pos];
|
||||
if(typename traits::char_type('1') <= c && c <= typename traits::char_type('9'))
|
||||
{
|
||||
const std::size_t n = c - typename traits::char_type('0') - 1;
|
||||
if(n < std::size(vals))
|
||||
{
|
||||
traits::append(result, vals[n]);
|
||||
}
|
||||
continue;
|
||||
} else if(c != typename traits::char_type('%'))
|
||||
{
|
||||
traits::append(result, 1, typename traits::char_type('%'));
|
||||
}
|
||||
}
|
||||
traits::append(result, 1, c);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
message_formatter(Tstring format_)
|
||||
: format(std::move(format_))
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
template<typename ...Ts>
|
||||
Tstring operator() (const Ts&... xs) const
|
||||
{
|
||||
const std::array<Tstring, sizeof...(xs)> vals{{ToStringTFunctor<Tstring>()(xs)...}};
|
||||
return do_format(mpt::as_span(vals));
|
||||
}
|
||||
|
||||
}; // struct message_formatter<Tformat>
|
||||
|
||||
template<typename Tformat>
|
||||
message_formatter<typename mpt::String::detail::to_string_type<Tformat>::type> format(Tformat format)
|
||||
{
|
||||
typedef typename mpt::String::detail::to_string_type<Tformat>::type Tstring;
|
||||
return message_formatter<Tstring>(Tstring(std::move(format)));
|
||||
}
|
||||
|
||||
#if MPT_WSTRING_FORMAT
|
||||
static inline message_formatter<std::wstring> wformat(std::wstring format)
|
||||
{
|
||||
return message_formatter<std::wstring>(std::move(format));
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline message_formatter<mpt::ustring> uformat(mpt::ustring format)
|
||||
{
|
||||
return message_formatter<mpt::ustring>(std::move(format));
|
||||
}
|
||||
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
static inline message_formatter<mpt::lstring> lformat(mpt::lstring format)
|
||||
{
|
||||
return message_formatter<mpt::lstring>(std::move(format));
|
||||
}
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
static inline message_formatter<mpt::tstring> tformat(mpt::tstring format)
|
||||
{
|
||||
return message_formatter<mpt::tstring>(std::move(format));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(MPT_WITH_MFC)
|
||||
static inline message_formatter<CString> cformat(CString format)
|
||||
{
|
||||
return message_formatter<CString>(std::move(format));
|
||||
}
|
||||
#endif // MPT_WITH_MFC
|
||||
|
||||
} // 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
|
|
@ -1,120 +0,0 @@
|
|||
/*
|
||||
* mptStringParse.cpp
|
||||
* ------------------
|
||||
* Purpose: Convert strings to other types.
|
||||
* 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 "mptStringParse.h"
|
||||
|
||||
#include <locale>
|
||||
#include <sstream>
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
template<typename T>
|
||||
inline T ConvertStrToHelper(const std::string &str)
|
||||
{
|
||||
std::istringstream i(str);
|
||||
i.imbue(std::locale::classic());
|
||||
T x;
|
||||
if(!(i >> x))
|
||||
{
|
||||
return T();
|
||||
}
|
||||
return x;
|
||||
}
|
||||
template<> inline bool ConvertStrToHelper(const std::string &str) { return ConvertStrToHelper<int>(str)?true:false; }
|
||||
template<> inline signed char ConvertStrToHelper(const std::string &str) { return static_cast<signed char>(ConvertStrToHelper<signed int>(str)); }
|
||||
template<> inline unsigned char ConvertStrToHelper(const std::string &str) { return static_cast<unsigned char>(ConvertStrToHelper<unsigned int>(str)); }
|
||||
|
||||
#if MPT_WSTRING_FORMAT
|
||||
template<typename T>
|
||||
inline T ConvertStrToHelper(const std::wstring &str)
|
||||
{
|
||||
std::wistringstream i(str);
|
||||
i.imbue(std::locale::classic());
|
||||
T x;
|
||||
if(!(i >> x))
|
||||
{
|
||||
return T();
|
||||
}
|
||||
return x;
|
||||
}
|
||||
template<> inline bool ConvertStrToHelper(const std::wstring &str) { return ConvertStrToHelper<int>(str)?true:false; }
|
||||
template<> inline signed char ConvertStrToHelper(const std::wstring &str) { return static_cast<signed char>(ConvertStrToHelper<signed int>(str)); }
|
||||
template<> inline unsigned char ConvertStrToHelper(const std::wstring &str) { return static_cast<unsigned char>(ConvertStrToHelper<unsigned int>(str)); }
|
||||
#endif
|
||||
|
||||
bool ConvertStrToBool(const std::string &str) { return ConvertStrToHelper<bool>(str); }
|
||||
signed char ConvertStrToSignedChar(const std::string &str) { return ConvertStrToHelper<signed char>(str); }
|
||||
unsigned char ConvertStrToUnsignedChar(const std::string &str) { return ConvertStrToHelper<unsigned char>(str); }
|
||||
signed short ConvertStrToSignedShort(const std::string &str) { return ConvertStrToHelper<signed short>(str); }
|
||||
unsigned short ConvertStrToUnsignedShort(const std::string &str) { return ConvertStrToHelper<unsigned short>(str); }
|
||||
signed int ConvertStrToSignedInt(const std::string &str) { return ConvertStrToHelper<signed int>(str); }
|
||||
unsigned int ConvertStrToUnsignedInt(const std::string &str) { return ConvertStrToHelper<unsigned int>(str); }
|
||||
signed long ConvertStrToSignedLong(const std::string &str) { return ConvertStrToHelper<signed long>(str); }
|
||||
unsigned long ConvertStrToUnsignedLong(const std::string &str) { return ConvertStrToHelper<unsigned long>(str); }
|
||||
signed long long ConvertStrToSignedLongLong(const std::string &str) { return ConvertStrToHelper<signed long long>(str); }
|
||||
unsigned long long ConvertStrToUnsignedLongLong(const std::string &str) { return ConvertStrToHelper<unsigned long long>(str); }
|
||||
float ConvertStrToFloat(const std::string &str) { return ConvertStrToHelper<float>(str); }
|
||||
double ConvertStrToDouble(const std::string &str) { return ConvertStrToHelper<double>(str); }
|
||||
long double ConvertStrToLongDouble(const std::string &str) { return ConvertStrToHelper<long double>(str); }
|
||||
|
||||
#if MPT_WSTRING_FORMAT
|
||||
bool ConvertStrToBool(const std::wstring &str) { return ConvertStrToHelper<bool>(str); }
|
||||
signed char ConvertStrToSignedChar(const std::wstring &str) { return ConvertStrToHelper<signed char>(str); }
|
||||
unsigned char ConvertStrToUnsignedChar(const std::wstring &str) { return ConvertStrToHelper<unsigned char>(str); }
|
||||
signed short ConvertStrToSignedShort(const std::wstring &str) { return ConvertStrToHelper<signed short>(str); }
|
||||
unsigned short ConvertStrToUnsignedShort(const std::wstring &str) { return ConvertStrToHelper<unsigned short>(str); }
|
||||
signed int ConvertStrToSignedInt(const std::wstring &str) { return ConvertStrToHelper<signed int>(str); }
|
||||
unsigned int ConvertStrToUnsignedInt(const std::wstring &str) { return ConvertStrToHelper<unsigned int>(str); }
|
||||
signed long ConvertStrToSignedLong(const std::wstring &str) { return ConvertStrToHelper<signed long>(str); }
|
||||
unsigned long ConvertStrToUnsignedLong(const std::wstring &str) { return ConvertStrToHelper<unsigned long>(str); }
|
||||
signed long long ConvertStrToSignedLongLong(const std::wstring &str) { return ConvertStrToHelper<signed long long>(str); }
|
||||
unsigned long long ConvertStrToUnsignedLongLong(const std::wstring &str) { return ConvertStrToHelper<unsigned long long>(str); }
|
||||
float ConvertStrToFloat(const std::wstring &str) { return ConvertStrToHelper<float>(str); }
|
||||
double ConvertStrToDouble(const std::wstring &str) { return ConvertStrToHelper<double>(str); }
|
||||
long double ConvertStrToLongDouble(const std::wstring &str) { return ConvertStrToHelper<long double>(str); }
|
||||
#endif
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
namespace String
|
||||
{
|
||||
namespace Parse
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
T HexToHelper(const std::string &str)
|
||||
{
|
||||
std::istringstream i(str);
|
||||
i.imbue(std::locale::classic());
|
||||
T x;
|
||||
if(!(i >> std::hex >> x))
|
||||
{
|
||||
return T();
|
||||
}
|
||||
return x;
|
||||
}
|
||||
template<> unsigned char HexToHelper(const std::string &str) { return static_cast<unsigned char>(HexToHelper<unsigned int>(str)); }
|
||||
|
||||
unsigned char HexToUnsignedChar(const std::string &str) { return HexToHelper<unsigned char>(str); }
|
||||
unsigned short HexToUnsignedShort(const std::string &str) { return HexToHelper<unsigned short>(str); }
|
||||
unsigned int HexToUnsignedInt(const std::string &str) { return HexToHelper<unsigned int>(str); }
|
||||
unsigned long HexToUnsignedLong(const std::string &str) { return HexToHelper<unsigned long>(str); }
|
||||
unsigned long long HexToUnsignedLongLong(const std::string &str) { return HexToHelper<unsigned long long>(str); }
|
||||
|
||||
} // namespace Parse
|
||||
} // namespace String
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,250 +0,0 @@
|
|||
/*
|
||||
* mptStringParse.h
|
||||
* ----------------
|
||||
* Purpose: Convert strings to other types.
|
||||
* 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"
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
bool ConvertStrToBool(const std::string &str);
|
||||
signed char ConvertStrToSignedChar(const std::string &str);
|
||||
unsigned char ConvertStrToUnsignedChar(const std::string &str);
|
||||
signed short ConvertStrToSignedShort(const std::string &str);
|
||||
unsigned short ConvertStrToUnsignedShort(const std::string &str);
|
||||
signed int ConvertStrToSignedInt(const std::string &str);
|
||||
unsigned int ConvertStrToUnsignedInt(const std::string &str);
|
||||
signed long ConvertStrToSignedLong(const std::string &str);
|
||||
unsigned long ConvertStrToUnsignedLong(const std::string &str);
|
||||
signed long long ConvertStrToSignedLongLong(const std::string &str);
|
||||
unsigned long long ConvertStrToUnsignedLongLong(const std::string &str);
|
||||
float ConvertStrToFloat(const std::string &str);
|
||||
double ConvertStrToDouble(const std::string &str);
|
||||
long double ConvertStrToLongDouble(const std::string &str);
|
||||
template<typename T> inline T ConvertStrTo(const std::string &str); // not defined, generates compiler error for non-specialized types
|
||||
template<> inline std::string ConvertStrTo(const std::string &str) { return str; }
|
||||
template<> inline bool ConvertStrTo(const std::string &str) { return ConvertStrToBool(str); }
|
||||
template<> inline signed char ConvertStrTo(const std::string &str) { return ConvertStrToSignedChar(str); }
|
||||
template<> inline unsigned char ConvertStrTo(const std::string &str) { return ConvertStrToUnsignedChar(str); }
|
||||
template<> inline signed short ConvertStrTo(const std::string &str) { return ConvertStrToSignedShort(str); }
|
||||
template<> inline unsigned short ConvertStrTo(const std::string &str) { return ConvertStrToUnsignedShort(str); }
|
||||
template<> inline signed int ConvertStrTo(const std::string &str) { return ConvertStrToSignedInt(str); }
|
||||
template<> inline unsigned int ConvertStrTo(const std::string &str) { return ConvertStrToUnsignedInt(str); }
|
||||
template<> inline signed long ConvertStrTo(const std::string &str) { return ConvertStrToSignedLong(str); }
|
||||
template<> inline unsigned long ConvertStrTo(const std::string &str) { return ConvertStrToUnsignedLong(str); }
|
||||
template<> inline signed long long ConvertStrTo(const std::string &str) { return ConvertStrToSignedLongLong(str); }
|
||||
template<> inline unsigned long long ConvertStrTo(const std::string &str) { return ConvertStrToUnsignedLongLong(str); }
|
||||
template<> inline float ConvertStrTo(const std::string &str) { return ConvertStrToFloat(str); }
|
||||
template<> inline double ConvertStrTo(const std::string &str) { return ConvertStrToDouble(str); }
|
||||
template<> inline long double ConvertStrTo(const std::string &str) { return ConvertStrToLongDouble(str); }
|
||||
|
||||
#if MPT_WSTRING_FORMAT
|
||||
bool ConvertStrToBool(const std::wstring &str);
|
||||
signed char ConvertStrToSignedChar(const std::wstring &str);
|
||||
unsigned char ConvertStrToUnsignedChar(const std::wstring &str);
|
||||
signed short ConvertStrToSignedShort(const std::wstring &str);
|
||||
unsigned short ConvertStrToUnsignedShort(const std::wstring &str);
|
||||
signed int ConvertStrToSignedInt(const std::wstring &str);
|
||||
unsigned int ConvertStrToUnsignedInt(const std::wstring &str);
|
||||
signed long ConvertStrToSignedLong(const std::wstring &str);
|
||||
unsigned long ConvertStrToUnsignedLong(const std::wstring &str);
|
||||
signed long long ConvertStrToSignedLongLong(const std::wstring &str);
|
||||
unsigned long long ConvertStrToUnsignedLongLong(const std::wstring &str);
|
||||
float ConvertStrToFloat(const std::wstring &str);
|
||||
double ConvertStrToDouble(const std::wstring &str);
|
||||
long double ConvertStrToLongDouble(const std::wstring &str);
|
||||
template<typename T> inline T ConvertStrTo(const std::wstring &str); // not defined, generates compiler error for non-specialized types
|
||||
template<> inline std::wstring ConvertStrTo(const std::wstring &str) { return str; }
|
||||
template<> inline bool ConvertStrTo(const std::wstring &str) { return ConvertStrToBool(str); }
|
||||
template<> inline signed char ConvertStrTo(const std::wstring &str) { return ConvertStrToSignedChar(str); }
|
||||
template<> inline unsigned char ConvertStrTo(const std::wstring &str) { return ConvertStrToUnsignedChar(str); }
|
||||
template<> inline signed short ConvertStrTo(const std::wstring &str) { return ConvertStrToSignedShort(str); }
|
||||
template<> inline unsigned short ConvertStrTo(const std::wstring &str) { return ConvertStrToUnsignedShort(str); }
|
||||
template<> inline signed int ConvertStrTo(const std::wstring &str) { return ConvertStrToSignedInt(str); }
|
||||
template<> inline unsigned int ConvertStrTo(const std::wstring &str) { return ConvertStrToUnsignedInt(str); }
|
||||
template<> inline signed long ConvertStrTo(const std::wstring &str) { return ConvertStrToSignedLong(str); }
|
||||
template<> inline unsigned long ConvertStrTo(const std::wstring &str) { return ConvertStrToUnsignedLong(str); }
|
||||
template<> inline signed long long ConvertStrTo(const std::wstring &str) { return ConvertStrToSignedLongLong(str); }
|
||||
template<> inline unsigned long long ConvertStrTo(const std::wstring &str) { return ConvertStrToUnsignedLongLong(str); }
|
||||
template<> inline float ConvertStrTo(const std::wstring &str) { return ConvertStrToFloat(str); }
|
||||
template<> inline double ConvertStrTo(const std::wstring &str) { return ConvertStrToDouble(str); }
|
||||
template<> inline long double ConvertStrTo(const std::wstring &str) { return ConvertStrToLongDouble(str); }
|
||||
#endif
|
||||
|
||||
#if defined(MPT_WITH_MFC)
|
||||
template<typename T>
|
||||
inline T ConvertStrTo(const CString &str)
|
||||
{
|
||||
#if defined(UNICODE) && MPT_WSTRING_FORMAT
|
||||
return ConvertStrTo<T>(mpt::ToWide(str));
|
||||
#elif defined(UNICODE)
|
||||
return ConvertStrTo<T>(mpt::ToCharset(mpt::Charset::UTF8, str));
|
||||
#else // !UNICODE
|
||||
return ConvertStrTo<T>(mpt::ToCharset(mpt::Charset::Locale, str));
|
||||
#endif // UNICODE
|
||||
}
|
||||
#endif // MPT_WITH_MFC
|
||||
|
||||
template<typename T>
|
||||
inline T ConvertStrTo(const char *str)
|
||||
{
|
||||
if(!str)
|
||||
{
|
||||
return T();
|
||||
}
|
||||
return ConvertStrTo<T>(std::string(str));
|
||||
}
|
||||
|
||||
#if MPT_WSTRING_FORMAT
|
||||
#if MPT_USTRING_MODE_UTF8
|
||||
template<> inline mpt::ustring ConvertStrTo(const std::wstring &str) { return mpt::ToUnicode(str); }
|
||||
#endif
|
||||
template<typename T>
|
||||
inline T ConvertStrTo(const wchar_t *str)
|
||||
{
|
||||
if(!str)
|
||||
{
|
||||
return T();
|
||||
}
|
||||
return ConvertStrTo<T>(std::wstring(str));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MPT_USTRING_MODE_UTF8
|
||||
template<typename T>
|
||||
inline T ConvertStrTo(const mpt::ustring &str)
|
||||
{
|
||||
return ConvertStrTo<T>(mpt::ToCharset(mpt::Charset::UTF8, str));
|
||||
}
|
||||
template<> inline mpt::ustring ConvertStrTo(const mpt::ustring &str) { return str; }
|
||||
#if MPT_WSTRING_CONVERT
|
||||
template<> inline std::wstring ConvertStrTo(const mpt::ustring &str) { return mpt::ToWide(str); }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
template<typename T>
|
||||
inline T ConvertStrTo(const mpt::lstring &str)
|
||||
{
|
||||
return ConvertStrTo<T>(mpt::ToCharset(mpt::Charset::Locale, str));
|
||||
}
|
||||
template<> inline mpt::lstring ConvertStrTo(const mpt::lstring &str) { return str; }
|
||||
#endif
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
namespace String
|
||||
{
|
||||
namespace Parse
|
||||
{
|
||||
|
||||
unsigned char HexToUnsignedChar(const std::string &str);
|
||||
unsigned short HexToUnsignedShort(const std::string &str);
|
||||
unsigned int HexToUnsignedInt(const std::string &str);
|
||||
unsigned long HexToUnsignedLong(const std::string &str);
|
||||
unsigned long long HexToUnsignedLongLong(const std::string &str);
|
||||
|
||||
template<typename T> inline T Hex(const std::string &str); // not defined, generates compiler error for non-specialized types
|
||||
template<> inline unsigned char Hex(const std::string &str) { return HexToUnsignedChar(str); }
|
||||
template<> inline unsigned short Hex(const std::string &str) { return HexToUnsignedShort(str); }
|
||||
template<> inline unsigned int Hex(const std::string &str) { return HexToUnsignedInt(str); }
|
||||
template<> inline unsigned long Hex(const std::string &str) { return HexToUnsignedLong(str); }
|
||||
template<> inline unsigned long long Hex(const std::string &str) { return HexToUnsignedLongLong(str); }
|
||||
|
||||
template<typename T>
|
||||
inline T Hex(const char *str)
|
||||
{
|
||||
if(!str)
|
||||
{
|
||||
return T();
|
||||
}
|
||||
return Hex<T>(std::string(str));
|
||||
}
|
||||
|
||||
#if MPT_WSTRING_FORMAT
|
||||
|
||||
template<typename T>
|
||||
inline T Hex(const std::wstring &str)
|
||||
{
|
||||
return Hex<T>(mpt::ToCharset(mpt::Charset::UTF8, str));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T Hex(const wchar_t *str)
|
||||
{
|
||||
if(!str)
|
||||
{
|
||||
return T();
|
||||
}
|
||||
return Hex<T>(std::wstring(str));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if MPT_USTRING_MODE_UTF8
|
||||
template<typename T>
|
||||
inline T Hex(const mpt::ustring &str)
|
||||
{
|
||||
return Hex<T>(mpt::ToCharset(mpt::Charset::UTF8, str));
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace Parse
|
||||
} // namespace String
|
||||
} // 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
|
|
@ -1,152 +0,0 @@
|
|||
/*
|
||||
* mptThread.h
|
||||
* -----------
|
||||
* Purpose: Helper class for running threads, with a more or less platform-independent interface.
|
||||
* 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"
|
||||
|
||||
#if defined(MPT_ENABLE_THREAD)
|
||||
|
||||
#include <thread>
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
#if MPT_OS_WINDOWS
|
||||
#include <windows.h>
|
||||
#endif // MPT_OS_WINDOWS
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
#endif // MPT_ENABLE_THREAD
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
#if defined(MPT_ENABLE_THREAD)
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
|
||||
#if MPT_OS_WINDOWS && (MPT_COMPILER_MSVC || MPT_COMPILER_CLANG)
|
||||
|
||||
enum ThreadPriority
|
||||
{
|
||||
ThreadPriorityLowest = THREAD_PRIORITY_LOWEST,
|
||||
ThreadPriorityLower = THREAD_PRIORITY_BELOW_NORMAL,
|
||||
ThreadPriorityNormal = THREAD_PRIORITY_NORMAL,
|
||||
ThreadPriorityHigh = THREAD_PRIORITY_ABOVE_NORMAL,
|
||||
ThreadPriorityHighest = THREAD_PRIORITY_HIGHEST
|
||||
};
|
||||
|
||||
inline void SetThreadPriority(std::thread &t, mpt::ThreadPriority priority)
|
||||
{
|
||||
::SetThreadPriority(t.native_handle(), priority);
|
||||
}
|
||||
|
||||
inline void SetCurrentThreadPriority(mpt::ThreadPriority priority)
|
||||
{
|
||||
::SetThreadPriority(GetCurrentThread(), priority);
|
||||
}
|
||||
|
||||
#else // !MPT_OS_WINDOWS
|
||||
|
||||
enum ThreadPriority
|
||||
{
|
||||
ThreadPriorityLowest = -2,
|
||||
ThreadPriorityLower = -1,
|
||||
ThreadPriorityNormal = 0,
|
||||
ThreadPriorityHigh = 1,
|
||||
ThreadPriorityHighest = 2
|
||||
};
|
||||
|
||||
inline void SetThreadPriority(std::thread & /*t*/ , mpt::ThreadPriority /*priority*/ )
|
||||
{
|
||||
// nothing
|
||||
}
|
||||
|
||||
inline void SetCurrentThreadPriority(mpt::ThreadPriority /*priority*/ )
|
||||
{
|
||||
// nothing
|
||||
}
|
||||
|
||||
#endif // MPT_OS_WINDOWS && (MPT_COMPILER_MSVC || MPT_COMPILER_CLANG)
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
// Default WinAPI thread
|
||||
class UnmanagedThread
|
||||
{
|
||||
protected:
|
||||
HANDLE threadHandle;
|
||||
|
||||
public:
|
||||
|
||||
operator HANDLE& () { return threadHandle; }
|
||||
operator bool () const { return threadHandle != nullptr; }
|
||||
|
||||
UnmanagedThread() : threadHandle(nullptr) { }
|
||||
UnmanagedThread(LPTHREAD_START_ROUTINE function, void *userData = nullptr)
|
||||
{
|
||||
DWORD dummy = 0; // For Win9x
|
||||
threadHandle = CreateThread(NULL, 0, function, userData, 0, &dummy);
|
||||
}
|
||||
|
||||
UnmanagedThread(UnmanagedThread &&) = default;
|
||||
UnmanagedThread & operator=(UnmanagedThread &&) = default;
|
||||
|
||||
UnmanagedThread(const UnmanagedThread &) = delete;
|
||||
UnmanagedThread & operator=(const UnmanagedThread &) = delete;
|
||||
|
||||
// unmanaged, user has to free resources
|
||||
~UnmanagedThread()
|
||||
{
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Thread that operates on a member function
|
||||
template<typename T, void (T::*Fun)()>
|
||||
class UnmanagedThreadMember : public mpt::UnmanagedThread
|
||||
{
|
||||
protected:
|
||||
static DWORD WINAPI wrapperFunc(LPVOID param)
|
||||
{
|
||||
(static_cast<T *>(param)->*Fun)();
|
||||
return 0;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
UnmanagedThreadMember(T *instance) : mpt::UnmanagedThread(wrapperFunc, instance) { }
|
||||
};
|
||||
|
||||
inline void SetThreadPriority(mpt::UnmanagedThread &t, mpt::ThreadPriority priority)
|
||||
{
|
||||
::SetThreadPriority(t, priority);
|
||||
}
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
#endif // MPT_ENABLE_THREAD
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,309 +0,0 @@
|
|||
/*
|
||||
* mptTime.cpp
|
||||
* -----------
|
||||
* Purpose: Various time utility functions.
|
||||
* 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 "mptTime.h"
|
||||
|
||||
#include "mptStringBuffer.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
#include <windows.h>
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
#include <mmsystem.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
namespace Date
|
||||
{
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
namespace ANSI
|
||||
{
|
||||
|
||||
uint64 Now()
|
||||
{
|
||||
FILETIME filetime;
|
||||
GetSystemTimeAsFileTime(&filetime);
|
||||
return ((uint64)filetime.dwHighDateTime << 32 | filetime.dwLowDateTime);
|
||||
}
|
||||
|
||||
mpt::ustring ToUString(uint64 time100ns)
|
||||
{
|
||||
constexpr std::size_t bufsize = 256;
|
||||
|
||||
mpt::ustring result;
|
||||
|
||||
FILETIME filetime;
|
||||
SYSTEMTIME systime;
|
||||
filetime.dwHighDateTime = (DWORD)(((uint64)time100ns) >> 32);
|
||||
filetime.dwLowDateTime = (DWORD)((uint64)time100ns);
|
||||
FileTimeToSystemTime(&filetime, &systime);
|
||||
|
||||
TCHAR buf[bufsize];
|
||||
|
||||
GetDateFormat(LOCALE_SYSTEM_DEFAULT, 0, &systime, TEXT("yyyy-MM-dd"), buf, bufsize);
|
||||
result.append(mpt::ToUnicode(mpt::String::ReadWinBuf(buf)));
|
||||
|
||||
result.append(U_(" "));
|
||||
|
||||
GetTimeFormat(LOCALE_SYSTEM_DEFAULT, TIME_FORCE24HOURFORMAT, &systime, TEXT("HH:mm:ss"), buf, bufsize);
|
||||
result.append(mpt::ToUnicode(mpt::String::ReadWinBuf(buf)));
|
||||
|
||||
result.append(U_("."));
|
||||
|
||||
result.append(mpt::ufmt::dec0<3>((unsigned)systime.wMilliseconds));
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
} // namespace ANSI
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
Unix::Unix()
|
||||
: Value(0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Unix::Unix(int64 unixtime)
|
||||
: Value(unixtime)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Unix::operator int64 () const
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
|
||||
static int32 ToDaynum(int32 year, int32 month, int32 day)
|
||||
{
|
||||
month = (month + 9) % 12;
|
||||
year = year - (month / 10);
|
||||
int32 daynum = year*365 + year/4 - year/100 + year/400 + (month*306 + 5)/10 + (day - 1);
|
||||
return daynum;
|
||||
}
|
||||
|
||||
static void FromDaynum(int32 d, int32 & year, int32 & month, int32 & day)
|
||||
{
|
||||
int64 g = d;
|
||||
int64 y,ddd,mi,mm,dd;
|
||||
|
||||
y = (10000*g + 14780)/3652425;
|
||||
ddd = g - (365*y + y/4 - y/100 + y/400);
|
||||
if(ddd < 0)
|
||||
{
|
||||
y = y - 1;
|
||||
ddd = g - (365*y + y/4 - y/100 + y/400);
|
||||
}
|
||||
mi = (100*ddd + 52)/3060;
|
||||
mm = (mi + 2)%12 + 1;
|
||||
y = y + (mi + 2)/12;
|
||||
dd = ddd - (mi*306 + 5)/10 + 1;
|
||||
|
||||
year = static_cast<int32>(y);
|
||||
month = static_cast<int32>(mm);
|
||||
day = static_cast<int32>(dd);
|
||||
}
|
||||
|
||||
mpt::Date::Unix Unix::FromUTC(tm timeUtc)
|
||||
{
|
||||
int32 daynum = ToDaynum(timeUtc.tm_year+1900, timeUtc.tm_mon+1, timeUtc.tm_mday);
|
||||
int64 seconds = static_cast<int64>(daynum - ToDaynum(1970,1,1))*24*60*60 + timeUtc.tm_hour*60*60 + timeUtc.tm_min*60 + timeUtc.tm_sec;
|
||||
return mpt::Date::Unix(seconds);
|
||||
}
|
||||
|
||||
tm Unix::AsUTC() const
|
||||
{
|
||||
int64 tmp = Value;
|
||||
int64 seconds = tmp % 60; tmp /= 60;
|
||||
int64 minutes = tmp % 60; tmp /= 60;
|
||||
int64 hours = tmp % 24; tmp /= 24;
|
||||
int32 year = 0, month = 0, day = 0;
|
||||
FromDaynum(static_cast<int32>(tmp) + ToDaynum(1970,1,1), year, month, day);
|
||||
tm result;
|
||||
MemsetZero(result);
|
||||
result.tm_year = year - 1900;
|
||||
result.tm_mon = month - 1;
|
||||
result.tm_mday = day;
|
||||
result.tm_hour = static_cast<int32>(hours);
|
||||
result.tm_min = static_cast<int32>(minutes);
|
||||
result.tm_sec = static_cast<int32>(seconds);
|
||||
return result;
|
||||
}
|
||||
|
||||
mpt::ustring ToShortenedISO8601(tm date)
|
||||
{
|
||||
// We assume date in UTC here.
|
||||
// There are too many differences in supported format specifiers in strftime()
|
||||
// and strftime does not support reduced precision ISO8601 at all.
|
||||
// Just do the formatting ourselves.
|
||||
mpt::ustring result;
|
||||
mpt::ustring tz = U_("Z");
|
||||
if(date.tm_year == 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
result += mpt::ufmt::dec0<4>(date.tm_year + 1900);
|
||||
if(date.tm_mon < 0 || date.tm_mon > 11)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
result += U_("-") + mpt::ufmt::dec0<2>(date.tm_mon + 1);
|
||||
if(date.tm_mday < 1 || date.tm_mday > 31)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
result += U_("-") + mpt::ufmt::dec0<2>(date.tm_mday);
|
||||
if(date.tm_hour == 0 && date.tm_min == 0 && date.tm_sec == 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
if(date.tm_hour < 0 || date.tm_hour > 23)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
if(date.tm_min < 0 || date.tm_min > 59)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
result += U_("T");
|
||||
if(date.tm_isdst > 0)
|
||||
{
|
||||
tz = U_("+01:00");
|
||||
}
|
||||
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 += U_(":") + mpt::ufmt::dec0<2>(date.tm_sec);
|
||||
result += tz;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace Date
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
#ifdef MODPLUG_TRACKER
|
||||
|
||||
namespace Util
|
||||
{
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
void MultimediaClock::Init()
|
||||
{
|
||||
m_CurrentPeriod = 0;
|
||||
}
|
||||
|
||||
void MultimediaClock::SetPeriod(uint32 ms)
|
||||
{
|
||||
TIMECAPS caps;
|
||||
MemsetZero(caps);
|
||||
if(timeGetDevCaps(&caps, sizeof(caps)) != MMSYSERR_NOERROR)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if((caps.wPeriodMax == 0) || (caps.wPeriodMin > caps.wPeriodMax))
|
||||
{
|
||||
return;
|
||||
}
|
||||
ms = std::clamp(mpt::saturate_cast<UINT>(ms), caps.wPeriodMin, caps.wPeriodMax);
|
||||
if(timeBeginPeriod(ms) != MMSYSERR_NOERROR)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_CurrentPeriod = ms;
|
||||
}
|
||||
|
||||
void MultimediaClock::Cleanup()
|
||||
{
|
||||
if(m_CurrentPeriod > 0)
|
||||
{
|
||||
if(timeEndPeriod(m_CurrentPeriod) != MMSYSERR_NOERROR)
|
||||
{
|
||||
// should not happen
|
||||
MPT_ASSERT_NOTREACHED();
|
||||
}
|
||||
m_CurrentPeriod = 0;
|
||||
}
|
||||
}
|
||||
|
||||
MultimediaClock::MultimediaClock()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
MultimediaClock::MultimediaClock(uint32 ms)
|
||||
{
|
||||
Init();
|
||||
SetResolution(ms);
|
||||
}
|
||||
|
||||
MultimediaClock::~MultimediaClock()
|
||||
{
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
uint32 MultimediaClock::SetResolution(uint32 ms)
|
||||
{
|
||||
if(m_CurrentPeriod == ms)
|
||||
{
|
||||
return m_CurrentPeriod;
|
||||
}
|
||||
Cleanup();
|
||||
if(ms != 0)
|
||||
{
|
||||
SetPeriod(ms);
|
||||
}
|
||||
return GetResolution();
|
||||
}
|
||||
|
||||
uint32 MultimediaClock::GetResolution() const
|
||||
{
|
||||
return m_CurrentPeriod;
|
||||
}
|
||||
|
||||
uint32 MultimediaClock::Now() const
|
||||
{
|
||||
return timeGetTime();
|
||||
}
|
||||
|
||||
uint64 MultimediaClock::NowNanoseconds() const
|
||||
{
|
||||
return (uint64)timeGetTime() * (uint64)1000000;
|
||||
}
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
} // namespace Util
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,116 +0,0 @@
|
|||
/*
|
||||
* mptTime.h
|
||||
* ---------
|
||||
* Purpose: Various time 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 <string>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
namespace Date
|
||||
{
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
namespace ANSI
|
||||
{
|
||||
// uint64 counts 100ns since 1601-01-01T00:00Z
|
||||
|
||||
uint64 Now();
|
||||
|
||||
mpt::ustring ToUString(uint64 time100ns); // i.e. 2015-01-15 18:32:01.718
|
||||
|
||||
} // namespacee ANSI
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
class Unix
|
||||
{
|
||||
// int64 counts 1s since 1970-01-01T00:00Z
|
||||
private:
|
||||
int64 Value;
|
||||
public:
|
||||
Unix();
|
||||
explicit Unix(int64 unixtime);
|
||||
operator int64 () const;
|
||||
public:
|
||||
static mpt::Date::Unix FromUTC(tm timeUtc);
|
||||
tm AsUTC() const;
|
||||
};
|
||||
|
||||
mpt::ustring ToShortenedISO8601(tm date); // i.e. 2015-01-15T18:32:01Z
|
||||
|
||||
} // namespace Date
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
#ifdef MODPLUG_TRACKER
|
||||
|
||||
namespace Util
|
||||
{
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
// RAII wrapper around timeBeginPeriod/timeEndPeriod/timeGetTime (on Windows).
|
||||
// This clock is monotonic, even across changing its resolution.
|
||||
// This is needed to synchronize time in Steinberg APIs (ASIO and VST).
|
||||
class MultimediaClock
|
||||
{
|
||||
private:
|
||||
uint32 m_CurrentPeriod;
|
||||
private:
|
||||
void Init();
|
||||
void SetPeriod(uint32 ms);
|
||||
void Cleanup();
|
||||
public:
|
||||
MultimediaClock();
|
||||
MultimediaClock(uint32 ms);
|
||||
~MultimediaClock();
|
||||
public:
|
||||
// Sets the desired resolution in milliseconds, returns the obtained resolution in milliseconds.
|
||||
// A parameter of 0 causes the resolution to be reset to system defaults.
|
||||
// A return value of 0 means the resolution is unknown, but timestamps will still be valid.
|
||||
uint32 SetResolution(uint32 ms);
|
||||
// Returns obtained resolution in milliseconds.
|
||||
// A return value of 0 means the resolution is unknown, but timestamps will still be valid.
|
||||
uint32 GetResolution() const;
|
||||
// Returns current instantaneous timestamp in milliseconds.
|
||||
// The epoch (offset) of the timestamps is undefined but constant until the next system reboot.
|
||||
// The resolution is the value returned from GetResolution().
|
||||
uint32 Now() const;
|
||||
// Returns current instantaneous timestamp in nanoseconds.
|
||||
// The epoch (offset) of the timestamps is undefined but constant until the next system reboot.
|
||||
// The resolution is the value returned from GetResolution() in milliseconds.
|
||||
uint64 NowNanoseconds() const;
|
||||
};
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
} // namespace Util
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,561 +0,0 @@
|
|||
/*
|
||||
* mptUUID.cpp
|
||||
* -----------
|
||||
* Purpose: UUID utility functions.
|
||||
* 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 "mptUUID.h"
|
||||
|
||||
#include "mptRandom.h"
|
||||
#include "mptStringFormat.h"
|
||||
#include "Endianness.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
#include <windows.h>
|
||||
#include <rpc.h>
|
||||
#if defined(MODPLUG_TRACKER) || defined(MPT_WITH_DMO) || MPT_OS_WINDOWS_WINRT
|
||||
#include <objbase.h>
|
||||
#endif // MODPLUG_TRACKER || MPT_WITH_DMO || MPT_OS_WINDOWS_WINRT
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
|
||||
namespace Util
|
||||
{
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER) || defined(MPT_WITH_DMO)
|
||||
|
||||
|
||||
mpt::winstring CLSIDToString(CLSID clsid)
|
||||
{
|
||||
std::wstring str;
|
||||
LPOLESTR tmp = nullptr;
|
||||
switch(::StringFromCLSID(clsid, &tmp))
|
||||
{
|
||||
case S_OK:
|
||||
break;
|
||||
case E_OUTOFMEMORY:
|
||||
if(tmp)
|
||||
{
|
||||
::CoTaskMemFree(tmp);
|
||||
tmp = nullptr;
|
||||
}
|
||||
MPT_EXCEPTION_THROW_OUT_OF_MEMORY();
|
||||
break;
|
||||
default:
|
||||
if(tmp)
|
||||
{
|
||||
::CoTaskMemFree(tmp);
|
||||
tmp = nullptr;
|
||||
}
|
||||
throw std::logic_error("StringFromCLSID() failed.");
|
||||
break;
|
||||
}
|
||||
if(!tmp)
|
||||
{
|
||||
throw std::logic_error("StringFromCLSID() failed.");
|
||||
}
|
||||
try
|
||||
{
|
||||
str = tmp;
|
||||
} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
|
||||
{
|
||||
::CoTaskMemFree(tmp);
|
||||
tmp = nullptr;
|
||||
MPT_EXCEPTION_RETHROW_OUT_OF_MEMORY(e);
|
||||
}
|
||||
::CoTaskMemFree(tmp);
|
||||
tmp = nullptr;
|
||||
return mpt::ToWin(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))
|
||||
{
|
||||
case NOERROR:
|
||||
// nothing
|
||||
break;
|
||||
case E_INVALIDARG:
|
||||
clsid = CLSID();
|
||||
break;
|
||||
case CO_E_CLASSSTRING:
|
||||
clsid = CLSID();
|
||||
break;
|
||||
case REGDB_E_CLASSNOTREG:
|
||||
clsid = CLSID();
|
||||
break;
|
||||
case REGDB_E_READREGDB:
|
||||
clsid = CLSID();
|
||||
throw std::runtime_error("CLSIDFromString() failed: REGDB_E_READREGDB.");
|
||||
break;
|
||||
default:
|
||||
clsid = CLSID();
|
||||
throw std::logic_error("CLSIDFromString() failed.");
|
||||
break;
|
||||
}
|
||||
return 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);
|
||||
switch(::CLSIDFromString(tmp.data(), &clsid))
|
||||
{
|
||||
case NOERROR:
|
||||
result = true;
|
||||
break;
|
||||
case E_INVALIDARG:
|
||||
result = false;
|
||||
break;
|
||||
case CO_E_CLASSSTRING:
|
||||
result = false;
|
||||
break;
|
||||
case REGDB_E_CLASSNOTREG:
|
||||
result = false;
|
||||
break;
|
||||
case REGDB_E_READREGDB:
|
||||
throw std::runtime_error("CLSIDFromString() failed: REGDB_E_READREGDB.");
|
||||
break;
|
||||
default:
|
||||
throw std::logic_error("CLSIDFromString() failed.");
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
switch(::CLSIDFromString(tmp.data(), &clsid))
|
||||
{
|
||||
case NOERROR:
|
||||
result = true;
|
||||
break;
|
||||
case E_INVALIDARG:
|
||||
result = false;
|
||||
break;
|
||||
case CO_E_CLASSSTRING:
|
||||
result = false;
|
||||
break;
|
||||
case REGDB_E_CLASSNOTREG:
|
||||
result = false;
|
||||
break;
|
||||
case REGDB_E_READREGDB:
|
||||
result = false;
|
||||
throw std::runtime_error("CLSIDFromString() failed: REGDB_E_READREGDB.");
|
||||
break;
|
||||
default:
|
||||
result = false;
|
||||
throw std::logic_error("CLSIDFromString() failed.");
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
mpt::winstring IIDToString(IID iid)
|
||||
{
|
||||
std::wstring str;
|
||||
LPOLESTR tmp = nullptr;
|
||||
switch(::StringFromIID(iid, &tmp))
|
||||
{
|
||||
case S_OK:
|
||||
break;
|
||||
case E_OUTOFMEMORY:
|
||||
if(tmp)
|
||||
{
|
||||
::CoTaskMemFree(tmp);
|
||||
tmp = nullptr;
|
||||
}
|
||||
MPT_EXCEPTION_THROW_OUT_OF_MEMORY();
|
||||
break;
|
||||
default:
|
||||
if(tmp)
|
||||
{
|
||||
::CoTaskMemFree(tmp);
|
||||
tmp = nullptr;
|
||||
}
|
||||
throw std::logic_error("StringFromIID() failed.");
|
||||
break;
|
||||
}
|
||||
if(!tmp)
|
||||
{
|
||||
throw std::logic_error("StringFromIID() failed.");
|
||||
}
|
||||
try
|
||||
{
|
||||
str = tmp;
|
||||
} MPT_EXCEPTION_CATCH_OUT_OF_MEMORY(e)
|
||||
{
|
||||
::CoTaskMemFree(tmp);
|
||||
tmp = nullptr;
|
||||
MPT_EXCEPTION_RETHROW_OUT_OF_MEMORY(e);
|
||||
}
|
||||
return mpt::ToWin(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))
|
||||
{
|
||||
case S_OK:
|
||||
// nothing
|
||||
break;
|
||||
case E_OUTOFMEMORY:
|
||||
iid = IID();
|
||||
MPT_EXCEPTION_THROW_OUT_OF_MEMORY();
|
||||
break;
|
||||
case E_INVALIDARG:
|
||||
iid = IID();
|
||||
break;
|
||||
default:
|
||||
iid = IID();
|
||||
throw std::logic_error("IIDFromString() failed.");
|
||||
break;
|
||||
}
|
||||
return iid;
|
||||
}
|
||||
|
||||
|
||||
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 mpt::ToWin(tmp.data());
|
||||
}
|
||||
|
||||
|
||||
GUID StringToGUID(const mpt::winstring &str)
|
||||
{
|
||||
return StringToIID(str);
|
||||
}
|
||||
|
||||
|
||||
GUID CreateGUID()
|
||||
{
|
||||
GUID guid = GUID();
|
||||
switch(::CoCreateGuid(&guid))
|
||||
{
|
||||
case S_OK:
|
||||
// nothing
|
||||
break;
|
||||
default:
|
||||
guid = GUID();
|
||||
throw std::runtime_error("CoCreateGuid() failed.");
|
||||
}
|
||||
return guid;
|
||||
}
|
||||
|
||||
|
||||
bool IsValid(UUID uuid)
|
||||
{
|
||||
return false
|
||||
|| uuid.Data1 != 0
|
||||
|| uuid.Data2 != 0
|
||||
|| uuid.Data3 != 0
|
||||
|| uuid.Data4[0] != 0
|
||||
|| uuid.Data4[1] != 0
|
||||
|| uuid.Data4[2] != 0
|
||||
|| uuid.Data4[3] != 0
|
||||
|| uuid.Data4[4] != 0
|
||||
|| uuid.Data4[5] != 0
|
||||
|| uuid.Data4[6] != 0
|
||||
|| uuid.Data4[7] != 0
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
#endif // MODPLUG_TRACKER || MPT_WITH_DMO
|
||||
|
||||
|
||||
} // namespace Util
|
||||
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
mpt::UUID UUIDFromWin32(::UUID uuid)
|
||||
{
|
||||
return mpt::UUID
|
||||
( uuid.Data1
|
||||
, uuid.Data2
|
||||
, uuid.Data3
|
||||
, (static_cast<uint64>(0)
|
||||
| (static_cast<uint64>(uuid.Data4[0]) << 56)
|
||||
| (static_cast<uint64>(uuid.Data4[1]) << 48)
|
||||
| (static_cast<uint64>(uuid.Data4[2]) << 40)
|
||||
| (static_cast<uint64>(uuid.Data4[3]) << 32)
|
||||
| (static_cast<uint64>(uuid.Data4[4]) << 24)
|
||||
| (static_cast<uint64>(uuid.Data4[5]) << 16)
|
||||
| (static_cast<uint64>(uuid.Data4[6]) << 8)
|
||||
| (static_cast<uint64>(uuid.Data4[7]) << 0)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
::UUID UUIDToWin32(mpt::UUID uuid)
|
||||
{
|
||||
::UUID result = ::UUID();
|
||||
result.Data1 = uuid.GetData1();
|
||||
result.Data2 = uuid.GetData2();
|
||||
result.Data3 = uuid.GetData3();
|
||||
result.Data4[0] = static_cast<uint8>(uuid.GetData4() >> 56);
|
||||
result.Data4[1] = static_cast<uint8>(uuid.GetData4() >> 48);
|
||||
result.Data4[2] = static_cast<uint8>(uuid.GetData4() >> 40);
|
||||
result.Data4[3] = static_cast<uint8>(uuid.GetData4() >> 32);
|
||||
result.Data4[4] = static_cast<uint8>(uuid.GetData4() >> 24);
|
||||
result.Data4[5] = static_cast<uint8>(uuid.GetData4() >> 16);
|
||||
result.Data4[6] = static_cast<uint8>(uuid.GetData4() >> 8);
|
||||
result.Data4[7] = static_cast<uint8>(uuid.GetData4() >> 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
#if defined(MODPLUG_TRACKER) || defined(MPT_WITH_DMO)
|
||||
|
||||
UUID::UUID(::UUID uuid)
|
||||
{
|
||||
*this = UUIDFromWin32(uuid);
|
||||
}
|
||||
|
||||
UUID::operator ::UUID () const
|
||||
{
|
||||
return UUIDToWin32(*this);
|
||||
}
|
||||
|
||||
#endif // MODPLUG_TRACKER || MPT_WITH_DMO
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
UUID UUID::Generate()
|
||||
{
|
||||
#if MPT_OS_WINDOWS && MPT_OS_WINDOWS_WINRT
|
||||
#if (_WIN32_WINNT >= 0x0602)
|
||||
::GUID guid = ::GUID();
|
||||
HRESULT result = CoCreateGuid(&guid);
|
||||
if(result != S_OK)
|
||||
{
|
||||
return mpt::UUID::RFC4122Random();
|
||||
}
|
||||
return mpt::UUIDFromWin32(guid);
|
||||
#else
|
||||
return mpt::UUID::RFC4122Random();
|
||||
#endif
|
||||
#elif MPT_OS_WINDOWS && !MPT_OS_WINDOWS_WINRT
|
||||
::UUID uuid = ::UUID();
|
||||
RPC_STATUS status = ::UuidCreate(&uuid);
|
||||
if(status != RPC_S_OK && status != RPC_S_UUID_LOCAL_ONLY)
|
||||
{
|
||||
return mpt::UUID::RFC4122Random();
|
||||
}
|
||||
status = RPC_S_OK;
|
||||
if(UuidIsNil(&uuid, &status) != FALSE)
|
||||
{
|
||||
return mpt::UUID::RFC4122Random();
|
||||
}
|
||||
if(status != RPC_S_OK)
|
||||
{
|
||||
return mpt::UUID::RFC4122Random();
|
||||
}
|
||||
return mpt::UUIDFromWin32(uuid);
|
||||
#else
|
||||
return RFC4122Random();
|
||||
#endif
|
||||
}
|
||||
|
||||
UUID UUID::GenerateLocalUseOnly()
|
||||
{
|
||||
#if MPT_OS_WINDOWS && MPT_OS_WINDOWS_WINRT
|
||||
#if (_WIN32_WINNT >= 0x0602)
|
||||
::GUID guid = ::GUID();
|
||||
HRESULT result = CoCreateGuid(&guid);
|
||||
if(result != S_OK)
|
||||
{
|
||||
return mpt::UUID::RFC4122Random();
|
||||
}
|
||||
return mpt::UUIDFromWin32(guid);
|
||||
#else
|
||||
return mpt::UUID::RFC4122Random();
|
||||
#endif
|
||||
#elif MPT_OS_WINDOWS && !MPT_OS_WINDOWS_WINRT
|
||||
::UUID uuid = ::UUID();
|
||||
RPC_STATUS status = ::UuidCreateSequential(&uuid);
|
||||
if(status != RPC_S_OK && status != RPC_S_UUID_LOCAL_ONLY)
|
||||
{
|
||||
return Generate();
|
||||
}
|
||||
status = RPC_S_OK;
|
||||
if(UuidIsNil(&uuid, &status) != FALSE)
|
||||
{
|
||||
return mpt::UUID::RFC4122Random();
|
||||
}
|
||||
if(status != RPC_S_OK)
|
||||
{
|
||||
return mpt::UUID::RFC4122Random();
|
||||
}
|
||||
return mpt::UUIDFromWin32(uuid);
|
||||
#else
|
||||
return RFC4122Random();
|
||||
#endif
|
||||
}
|
||||
|
||||
UUID UUID::RFC4122Random()
|
||||
{
|
||||
UUID result;
|
||||
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);
|
||||
result.Data4 = mpt::random<uint64>(prng);
|
||||
result.MakeRFC4122(4);
|
||||
return result;
|
||||
}
|
||||
|
||||
void UUID::MakeRFC4122(uint8 version) noexcept
|
||||
{
|
||||
// variant
|
||||
uint8 Nn = static_cast<uint8>((Data4 >> 56) & 0xffu);
|
||||
Data4 &= 0x00ffffffffffffffull;
|
||||
Nn &= ~(0xc0u);
|
||||
Nn |= 0x80u;
|
||||
Data4 |= static_cast<uint64>(Nn) << 56;
|
||||
// version
|
||||
version &= 0x0fu;
|
||||
uint8 Mm = static_cast<uint8>((Data3 >> 8) & 0xffu);
|
||||
Data3 &= 0x00ffu;
|
||||
Mm &= ~(0xf0u);
|
||||
Mm |= (version << 4u);
|
||||
Data3 |= static_cast<uint16>(Mm) << 8;
|
||||
}
|
||||
|
||||
UUID UUID::FromString(const mpt::ustring &str)
|
||||
{
|
||||
std::vector<mpt::ustring> segments = mpt::String::Split<mpt::ustring>(str, U_("-"));
|
||||
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;
|
||||
}
|
||||
|
||||
mpt::ustring UUID::ToUString() const
|
||||
{
|
||||
return mpt::ustring()
|
||||
+ mpt::ufmt::hex0<8>(GetData1())
|
||||
+ U_("-")
|
||||
+ mpt::ufmt::hex0<4>(GetData2())
|
||||
+ U_("-")
|
||||
+ mpt::ufmt::hex0<4>(GetData3())
|
||||
+ U_("-")
|
||||
+ mpt::ufmt::hex0<4>(static_cast<uint16>(GetData4() >> 48))
|
||||
+ 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();
|
||||
Data2 = guid.Data2.get();
|
||||
Data3 = guid.Data3.get();
|
||||
Data4 = guid.Data4.get();
|
||||
}
|
||||
|
||||
UUID::operator UUIDbin() const
|
||||
{
|
||||
UUIDbin result;
|
||||
Clear(result);
|
||||
result.Data1 = GetData1();
|
||||
result.Data2 = GetData2();
|
||||
result.Data3 = GetData3();
|
||||
result.Data4 = GetData4();
|
||||
return result;
|
||||
}
|
||||
|
||||
UUID::operator GUIDms() const
|
||||
{
|
||||
GUIDms result;
|
||||
Clear(result);
|
||||
result.Data1 = GetData1();
|
||||
result.Data2 = GetData2();
|
||||
result.Data3 = GetData3();
|
||||
result.Data4 = GetData4();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,209 +0,0 @@
|
|||
/*
|
||||
* mptUUID.h
|
||||
* ---------
|
||||
* Purpose: UUID 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 "Endianness.h"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
#if defined(MODPLUG_TRACKER) || defined(MPT_WITH_DMO)
|
||||
#include <guiddef.h>
|
||||
#include <rpc.h>
|
||||
#endif // MODPLUG_TRACKER || MPT_WITH_DMO
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
namespace Util
|
||||
{
|
||||
|
||||
#if defined(MODPLUG_TRACKER) || defined(MPT_WITH_DMO)
|
||||
|
||||
// COM CLSID<->string conversion
|
||||
// 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 ))
|
||||
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 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 mpt::winstring &str);
|
||||
mpt::winstring GUIDToString(GUID guid);
|
||||
|
||||
// Create a COM GUID
|
||||
GUID CreateGUID();
|
||||
|
||||
// Checks the UUID against the NULL UUID. Returns false if it is NULL, true otherwise.
|
||||
bool IsValid(UUID uuid);
|
||||
|
||||
#endif // MODPLUG_TRACKER || MPT_WITH_DMO
|
||||
|
||||
} // namespace Util
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
// Microsoft on-disk layout
|
||||
struct GUIDms
|
||||
{
|
||||
uint32le Data1;
|
||||
uint16le Data2;
|
||||
uint16le Data3;
|
||||
uint64be Data4; // yes, big endian here
|
||||
};
|
||||
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:
|
||||
uint32 Data1;
|
||||
uint16 Data2;
|
||||
uint16 Data3;
|
||||
uint64 Data4;
|
||||
public:
|
||||
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:
|
||||
MPT_CONSTEXPR11_FUN uint64 GetData64_1() const noexcept { return (static_cast<uint64>(Data1) << 32) | (static_cast<uint64>(Data2) << 16) | (static_cast<uint64>(Data3) << 0); }
|
||||
MPT_CONSTEXPR11_FUN uint64 GetData64_2() const noexcept { return Data4; }
|
||||
public:
|
||||
// xxxxxxxx-xxxx-Mmxx-Nnxx-xxxxxxxxxxxx
|
||||
// <--32-->-<16>-<16>-<-------64------>
|
||||
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:
|
||||
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(MPT_WITH_DMO))
|
||||
explicit UUID(::UUID uuid);
|
||||
operator ::UUID () const;
|
||||
#endif // MPT_OS_WINDOWS && (MODPLUG_TRACKER || MPT_WITH_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) :
|
||||
mpt::constexpr_throw<uint8>(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:
|
||||
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)
|
||||
)
|
||||
: mpt::constexpr_throw<mpt::UUID>(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;
|
||||
public:
|
||||
// Create a UUID
|
||||
static UUID Generate();
|
||||
// Create a UUID that contains local, traceable information.
|
||||
// Safe for local use. May be faster.
|
||||
static UUID GenerateLocalUseOnly();
|
||||
// Create a RFC4122 Random UUID.
|
||||
static UUID RFC4122Random();
|
||||
public:
|
||||
// General UUID<->string conversion.
|
||||
// The string must/will be in standard UUID format: 4f9a455d-e7ef-4367-b2f0-0c83a38a5c72
|
||||
static UUID FromString(const mpt::ustring &str);
|
||||
mpt::ustring ToUString() const;
|
||||
};
|
||||
|
||||
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
|
|
@ -1,755 +0,0 @@
|
|||
/*
|
||||
* mptWine.cpp
|
||||
* -----------
|
||||
* Purpose: Wine stuff.
|
||||
* 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 "mptWine.h"
|
||||
|
||||
#include "mptOS.h"
|
||||
#include "mptFileIO.h"
|
||||
|
||||
#include <deque>
|
||||
#include <map>
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
namespace Wine
|
||||
{
|
||||
|
||||
|
||||
|
||||
Context::Context(mpt::Wine::VersionContext versionContext)
|
||||
: m_VersionContext(versionContext)
|
||||
, wine_get_dos_file_name(nullptr)
|
||||
, wine_get_unix_file_name(nullptr)
|
||||
{
|
||||
if(!mpt::Windows::IsWine())
|
||||
{
|
||||
throw mpt::Wine::Exception("Wine not detected.");
|
||||
}
|
||||
if(!m_VersionContext.Version().IsValid())
|
||||
{
|
||||
throw mpt::Wine::Exception("Unknown Wine version detected.");
|
||||
}
|
||||
m_Kernel32 = mpt::Library(mpt::LibraryPath::FullPath(P_("kernel32.dll")));
|
||||
if(!m_Kernel32.IsValid())
|
||||
{
|
||||
throw mpt::Wine::Exception("Could not load Wine kernel32.dll.");
|
||||
}
|
||||
if(!m_Kernel32.Bind(wine_get_unix_file_name, "wine_get_unix_file_name"))
|
||||
{
|
||||
throw mpt::Wine::Exception("Could not bind Wine kernel32.dll:wine_get_unix_file_name.");
|
||||
}
|
||||
if(!m_Kernel32.Bind(wine_get_dos_file_name, "wine_get_dos_file_name"))
|
||||
{
|
||||
throw mpt::Wine::Exception("Could not bind Wine kernel32.dll:wine_get_dos_file_name.");
|
||||
}
|
||||
{
|
||||
std::string out;
|
||||
std::string err;
|
||||
try
|
||||
{
|
||||
if(ExecutePosixShellCommand("uname -m", out, err) != 0)
|
||||
{
|
||||
throw mpt::Wine::Exception("Wine 'uname -m' failed.");
|
||||
}
|
||||
if(!err.empty())
|
||||
{
|
||||
throw mpt::Wine::Exception("Wine 'uname -m' failed.");
|
||||
}
|
||||
out = mpt::String::Trim(out, std::string("\r\n"));
|
||||
m_Uname_m = out;
|
||||
} catch(const std::exception &)
|
||||
{
|
||||
m_Uname_m = std::string();
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
m_HOME = GetPosixEnvVar("HOME");
|
||||
} catch(const std::exception &)
|
||||
{
|
||||
m_HOME = std::string();
|
||||
}
|
||||
try
|
||||
{
|
||||
m_XDG_DATA_HOME = GetPosixEnvVar("XDG_DATA_HOME");
|
||||
if(m_XDG_DATA_HOME.empty())
|
||||
{
|
||||
m_XDG_DATA_HOME = m_HOME + "/.local/share";
|
||||
}
|
||||
} catch(const std::exception &)
|
||||
{
|
||||
m_XDG_DATA_HOME = std::string();
|
||||
}
|
||||
try
|
||||
{
|
||||
m_XDG_CACHE_HOME = GetPosixEnvVar("XDG_CACHE_HOME");
|
||||
if(m_XDG_CACHE_HOME.empty())
|
||||
{
|
||||
m_XDG_CACHE_HOME = m_HOME + "/.cache";
|
||||
}
|
||||
} catch(const std::exception &)
|
||||
{
|
||||
m_XDG_CACHE_HOME = std::string();
|
||||
}
|
||||
try
|
||||
{
|
||||
m_XDG_CONFIG_HOME = GetPosixEnvVar("XDG_CONFIG_HOME");
|
||||
if(m_XDG_CONFIG_HOME.empty())
|
||||
{
|
||||
m_XDG_CONFIG_HOME = m_HOME + "/.config";
|
||||
}
|
||||
} catch(const std::exception &)
|
||||
{
|
||||
m_XDG_CONFIG_HOME = std::string();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string Context::PathToPosix(mpt::PathString windowsPath)
|
||||
{
|
||||
std::string result;
|
||||
if(windowsPath.empty())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
if(windowsPath.Length() >= 32000)
|
||||
{
|
||||
throw mpt::Wine::Exception("Path too long.");
|
||||
}
|
||||
LPSTR tmp = nullptr;
|
||||
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.");
|
||||
}
|
||||
result = tmp;
|
||||
HeapFree(GetProcessHeap(), 0, tmp);
|
||||
tmp = nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
mpt::PathString Context::PathToWindows(std::string hostPath)
|
||||
{
|
||||
mpt::PathString result;
|
||||
if(hostPath.empty())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
if(hostPath.length() >= 32000)
|
||||
{
|
||||
throw mpt::Wine::Exception("Path too long.");
|
||||
}
|
||||
LPWSTR tmp = nullptr;
|
||||
tmp = wine_get_dos_file_name(hostPath.c_str());
|
||||
if(!tmp)
|
||||
{
|
||||
throw mpt::Wine::Exception("Wine kernel32.dll:wine_get_dos_file_name failed.");
|
||||
}
|
||||
result = mpt::PathString::FromWide(tmp);
|
||||
HeapFree(GetProcessHeap(), 0, tmp);
|
||||
tmp = nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string Context::PathToPosixCanonical(mpt::PathString windowsPath)
|
||||
{
|
||||
std::string result;
|
||||
std::string hostPath = PathToPosix(windowsPath);
|
||||
if(hostPath.empty())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
std::string output;
|
||||
std::string error;
|
||||
int exitcode = ExecutePosixShellCommand(std::string() + "readlink -f " + EscapePosixShell(hostPath), output, error);
|
||||
if(!error.empty())
|
||||
{
|
||||
throw mpt::Wine::Exception("Wine readlink failed: " + error);
|
||||
}
|
||||
if(exitcode != 0 && exitcode != 1)
|
||||
{
|
||||
throw mpt::Wine::Exception("Wine readlink failed.");
|
||||
}
|
||||
std::string trimmedOutput = mpt::String::Trim(output, std::string("\r\n"));
|
||||
result = trimmedOutput;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static void ExecutePosixCommandProgressDefault(void * /*userdata*/ )
|
||||
{
|
||||
::Sleep(10);
|
||||
return;
|
||||
}
|
||||
|
||||
static ExecuteProgressResult ExecutePosixShellScriptProgressDefault(void * /*userdata*/ )
|
||||
{
|
||||
::Sleep(10);
|
||||
return ExecuteProgressContinueWaiting;
|
||||
}
|
||||
|
||||
|
||||
std::string Context::EscapePosixShell(std::string line)
|
||||
{
|
||||
const char escape_chars [] = { '|', '&', ';', '<', '>', '(', ')', '$', '`', '"', '\'', ' ', '\t' };
|
||||
const char maybe_escape_chars [] = { '*', '?', '[', '#', '~', '=', '%' };
|
||||
line = mpt::String::Replace(line, "\\", "\\\\");
|
||||
for(char c : escape_chars)
|
||||
{
|
||||
line = mpt::String::Replace(line, std::string(1, c), "\\" + std::string(1, c));
|
||||
}
|
||||
for(char c : maybe_escape_chars)
|
||||
{
|
||||
line = mpt::String::Replace(line, std::string(1, c), "\\" + std::string(1, c));
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
|
||||
ExecResult Context::ExecutePosixShellScript(std::string script, FlagSet<ExecFlags> flags, std::map<std::string, std::vector<char> > filetree, std::string title, ExecutePosixCommandProgress progress, ExecutePosixShellScriptProgress progressCancel, void *userdata)
|
||||
{
|
||||
// Relevant documentation:
|
||||
// https://stackoverflow.com/questions/6004070/execute-shell-commands-from-program-running-in-wine
|
||||
// https://www.winehq.org/pipermail/wine-bugs/2014-January/374918.html
|
||||
// https://bugs.winehq.org/show_bug.cgi?id=34730
|
||||
|
||||
if(!progress) progress = &ExecutePosixCommandProgressDefault;
|
||||
if(!progressCancel) progressCancel = &ExecutePosixShellScriptProgressDefault;
|
||||
|
||||
if(flags[ExecFlagInteractive]) flags.reset(ExecFlagSilent);
|
||||
if(flags[ExecFlagSplitOutput]) flags.set(ExecFlagSilent);
|
||||
|
||||
std::vector<mpt::PathString> tempfiles;
|
||||
|
||||
progress(userdata);
|
||||
|
||||
mpt::TempDirGuard dirWindowsTemp(mpt::CreateTempFileName());
|
||||
if(dirWindowsTemp.GetDirname().empty())
|
||||
{
|
||||
throw mpt::Wine::Exception("Creating temporary directoy failed.");
|
||||
}
|
||||
const std::string dirPosix = PathToPosix(dirWindowsTemp.GetDirname());
|
||||
if(dirPosix.empty())
|
||||
{
|
||||
throw mpt::Wine::Exception("mpt::Wine::ConvertWindowsPathToHost returned empty path.");
|
||||
}
|
||||
const std::string dirPosixEscape = EscapePosixShell(dirPosix);
|
||||
const mpt::PathString dirWindows = dirWindowsTemp.GetDirname();
|
||||
|
||||
progress(userdata);
|
||||
|
||||
// write the script to disk
|
||||
mpt::PathString scriptFilenameWindows = dirWindows + P_("script.sh");
|
||||
{
|
||||
mpt::ofstream tempfile(scriptFilenameWindows, std::ios::binary);
|
||||
tempfile << script;
|
||||
tempfile.flush();
|
||||
if(!tempfile)
|
||||
{
|
||||
throw mpt::Wine::Exception("Error writing script.sh.");
|
||||
}
|
||||
}
|
||||
const std::string scriptFilenamePosix = PathToPosix(scriptFilenameWindows);
|
||||
if(scriptFilenamePosix.empty())
|
||||
{
|
||||
throw mpt::Wine::Exception("Error converting script.sh path.");
|
||||
}
|
||||
const std::string scriptFilenamePosixEscape = EscapePosixShell(scriptFilenamePosix);
|
||||
|
||||
progress(userdata);
|
||||
|
||||
// create a wrapper that will call the script and gather result.
|
||||
mpt::PathString wrapperstarterFilenameWindows = dirWindows + P_("wrapperstarter.sh");
|
||||
{
|
||||
mpt::ofstream tempfile(wrapperstarterFilenameWindows, std::ios::binary);
|
||||
std::string wrapperstarterscript;
|
||||
wrapperstarterscript += std::string() + "#!/usr/bin/env sh" "\n";
|
||||
wrapperstarterscript += std::string() + "exec /usr/bin/env sh " + dirPosixEscape + "wrapper.sh" "\n";
|
||||
tempfile << wrapperstarterscript;
|
||||
tempfile.flush();
|
||||
if(!tempfile)
|
||||
{
|
||||
throw mpt::Wine::Exception("Error writing wrapper.sh.");
|
||||
}
|
||||
}
|
||||
mpt::PathString wrapperFilenameWindows = dirWindows + P_("wrapper.sh");
|
||||
std::string cleanupscript;
|
||||
{
|
||||
mpt::ofstream tempfile(wrapperFilenameWindows, std::ios::binary);
|
||||
std::string wrapperscript;
|
||||
if(!flags[ExecFlagSilent])
|
||||
{
|
||||
wrapperscript += "printf \"\\033]0;" + title + "\\a\"" "\n";
|
||||
}
|
||||
wrapperscript += "chmod u+x " + scriptFilenamePosixEscape + "\n";
|
||||
wrapperscript += "cd " + dirPosixEscape + "filetree" "\n";
|
||||
if(flags[ExecFlagInteractive])
|
||||
{ // no stdout/stderr capturing for interactive scripts
|
||||
wrapperscript += scriptFilenamePosixEscape + "\n";
|
||||
wrapperscript += "MPT_RESULT=$?" "\n";
|
||||
wrapperscript += "echo ${MPT_RESULT} > " + dirPosixEscape + "exit" "\n";
|
||||
} else if(flags[ExecFlagSplitOutput])
|
||||
{
|
||||
wrapperscript += "(" + scriptFilenamePosixEscape + "; echo $? >&4) 4>" + dirPosixEscape + "exit 1>" + dirPosixEscape + "out 2>" + dirPosixEscape + "err" "\n";
|
||||
} else
|
||||
{
|
||||
wrapperscript += "(" + scriptFilenamePosixEscape + "; echo $? >&4) 2>&1 4>" + dirPosixEscape + "exit | tee " + dirPosixEscape + "out" "\n";
|
||||
}
|
||||
wrapperscript += "echo done > " + dirPosixEscape + "done" "\n";
|
||||
cleanupscript += "rm " + dirPosixEscape + "done" "\n";
|
||||
cleanupscript += "rm " + dirPosixEscape + "exit" "\n";
|
||||
if(flags[ExecFlagInteractive])
|
||||
{
|
||||
// nothing
|
||||
} else if(flags[ExecFlagSplitOutput])
|
||||
{
|
||||
cleanupscript += "rm " + dirPosixEscape + "out" "\n";
|
||||
cleanupscript += "rm " + dirPosixEscape + "err" "\n";
|
||||
} else
|
||||
{
|
||||
cleanupscript += "rm " + dirPosixEscape + "out" "\n";
|
||||
}
|
||||
cleanupscript += "rm -r " + dirPosixEscape + "filetree" "\n";
|
||||
cleanupscript += "rm " + dirPosixEscape + "script.sh" "\n";
|
||||
cleanupscript += "rm " + dirPosixEscape + "wrapper.sh" "\n";
|
||||
cleanupscript += "rm " + dirPosixEscape + "wrapperstarter.sh" "\n";
|
||||
cleanupscript += "rm " + dirPosixEscape + "terminal.sh" "\n";
|
||||
if(flags[ExecFlagAsync])
|
||||
{
|
||||
wrapperscript += cleanupscript;
|
||||
cleanupscript.clear();
|
||||
}
|
||||
tempfile << wrapperscript;
|
||||
tempfile.flush();
|
||||
if(!tempfile)
|
||||
{
|
||||
throw mpt::Wine::Exception("Error writing wrapper.sh.");
|
||||
}
|
||||
}
|
||||
|
||||
progress(userdata);
|
||||
|
||||
::CreateDirectory((dirWindows + P_("filetree")).AsNative().c_str(), nullptr);
|
||||
for(const auto &file : filetree)
|
||||
{
|
||||
std::vector<mpt::ustring> path = mpt::String::Split<mpt::ustring>(mpt::ToUnicode(mpt::Charset::UTF8, 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)
|
||||
{
|
||||
if(path[singlepath].empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
combinedPath += mpt::PathString::FromUnicode(path[singlepath]);
|
||||
if(!combinedPath.IsDirectory())
|
||||
{
|
||||
if(::CreateDirectory(combinedPath.AsNative().c_str(), nullptr) == 0)
|
||||
{
|
||||
throw mpt::Wine::Exception("Error writing filetree.");
|
||||
}
|
||||
}
|
||||
combinedPath += P_("\\");
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
mpt::LazyFileRef out(dirWindows + P_("filetree") + P_("\\") + mpt::PathString::FromUTF8(mpt::String::Replace(file.first, "/", "\\")));
|
||||
out = file.second;
|
||||
} catch(std::exception &)
|
||||
{
|
||||
throw mpt::Wine::Exception("Error writing filetree.");
|
||||
}
|
||||
}
|
||||
|
||||
progress(userdata);
|
||||
|
||||
// create a wrapper that will find a suitable terminal and run the wrapper script in the terminal window.
|
||||
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.
|
||||
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.
|
||||
terminalscript += "if command -v " + terminal + " 2>/dev/null 1>/dev/null ; then" "\n";
|
||||
terminalscript += " chmod u+x " + dirPosixEscape + "wrapperstarter.sh" "\n";
|
||||
terminalscript += " exec `command -v " + terminal + "` -e \"" + dirPosixEscape + "wrapperstarter.sh\"" "\n";
|
||||
terminalscript += "fi" "\n";
|
||||
}
|
||||
|
||||
tempfile << terminalscript;
|
||||
tempfile.flush();
|
||||
if(!tempfile)
|
||||
{
|
||||
return ExecResult::Error();
|
||||
}
|
||||
}
|
||||
|
||||
progress(userdata);
|
||||
|
||||
// build unix command line
|
||||
std::string unixcommand;
|
||||
bool createProcessSuccess = false;
|
||||
|
||||
if(!createProcessSuccess)
|
||||
{
|
||||
|
||||
if(flags[ExecFlagSilent])
|
||||
{
|
||||
unixcommand = "/usr/bin/env sh \"" + dirPosixEscape + "wrapper.sh\"";
|
||||
} else
|
||||
{
|
||||
unixcommand = "/usr/bin/env sh \"" + dirPosixEscape + "terminal.sh\"";
|
||||
}
|
||||
|
||||
progress(userdata);
|
||||
|
||||
std::wstring unixcommandW = mpt::ToWide(mpt::Charset::UTF8, unixcommand);
|
||||
std::wstring titleW = mpt::ToWide(mpt::Charset::UTF8, title);
|
||||
STARTUPINFOW startupInfo;
|
||||
MemsetZero(startupInfo);
|
||||
startupInfo.lpTitle = titleW.data();
|
||||
startupInfo.cb = sizeof(startupInfo);
|
||||
PROCESS_INFORMATION processInformation;
|
||||
MemsetZero(processInformation);
|
||||
|
||||
progress(userdata);
|
||||
|
||||
BOOL success = FALSE;
|
||||
if(flags[ExecFlagSilent])
|
||||
{
|
||||
success = CreateProcessW(NULL, unixcommandW.data(), NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &startupInfo, &processInformation);
|
||||
} else
|
||||
{
|
||||
success = CreateProcessW(NULL, unixcommandW.data(), NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &startupInfo, &processInformation);
|
||||
}
|
||||
|
||||
progress(userdata);
|
||||
|
||||
createProcessSuccess = (success != FALSE);
|
||||
|
||||
progress(userdata);
|
||||
|
||||
if(success)
|
||||
{
|
||||
|
||||
if(!flags[ExecFlagAsync])
|
||||
{
|
||||
// note: execution is not syncronous with all Wine versions,
|
||||
// we additionally explicitly wait for "done" later
|
||||
while(WaitForSingleObject(processInformation.hProcess, 0) == WAIT_TIMEOUT)
|
||||
{ // wait
|
||||
if(progressCancel(userdata) != ExecuteProgressContinueWaiting)
|
||||
{
|
||||
CloseHandle(processInformation.hThread);
|
||||
CloseHandle(processInformation.hProcess);
|
||||
throw mpt::Wine::Exception("Canceled.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
progress(userdata);
|
||||
|
||||
CloseHandle(processInformation.hThread);
|
||||
CloseHandle(processInformation.hProcess);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
progress(userdata);
|
||||
|
||||
// Work around Wine being unable to execute PIE binaries on Debian 9.
|
||||
// Luckily, /bin/bash is still non-PIE on Debian 9.
|
||||
|
||||
if(!createProcessSuccess)
|
||||
{
|
||||
if(flags[ExecFlagSilent])
|
||||
{
|
||||
unixcommand = "/bin/bash \"" + dirPosixEscape + "wrapper.sh\"";
|
||||
} else
|
||||
{
|
||||
unixcommand = "/bin/bash \"" + dirPosixEscape + "terminal.sh\"";
|
||||
}
|
||||
|
||||
progress(userdata);
|
||||
|
||||
std::wstring unixcommandW = mpt::ToWide(mpt::Charset::UTF8, unixcommand);
|
||||
std::wstring titleW = mpt::ToWide(mpt::Charset::UTF8, title);
|
||||
STARTUPINFOW startupInfo;
|
||||
MemsetZero(startupInfo);
|
||||
startupInfo.lpTitle = titleW.data();
|
||||
startupInfo.cb = sizeof(startupInfo);
|
||||
PROCESS_INFORMATION processInformation;
|
||||
MemsetZero(processInformation);
|
||||
|
||||
progress(userdata);
|
||||
|
||||
BOOL success = FALSE;
|
||||
if(flags[ExecFlagSilent])
|
||||
{
|
||||
success = CreateProcessW(NULL, unixcommandW.data(), NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &startupInfo, &processInformation);
|
||||
} else
|
||||
{
|
||||
success = CreateProcessW(NULL, unixcommandW.data(), NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &startupInfo, &processInformation);
|
||||
}
|
||||
|
||||
progress(userdata);
|
||||
|
||||
createProcessSuccess = (success != FALSE);
|
||||
|
||||
progress(userdata);
|
||||
|
||||
if(success)
|
||||
{
|
||||
if(!flags[ExecFlagAsync])
|
||||
{
|
||||
// note: execution is not syncronous with all Wine versions,
|
||||
// we additionally explicitly wait for "done" later
|
||||
while(WaitForSingleObject(processInformation.hProcess, 0) == WAIT_TIMEOUT)
|
||||
{ // wait
|
||||
if(progressCancel(userdata) != ExecuteProgressContinueWaiting)
|
||||
{
|
||||
CloseHandle(processInformation.hThread);
|
||||
CloseHandle(processInformation.hProcess);
|
||||
throw mpt::Wine::Exception("Canceled.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
progress(userdata);
|
||||
|
||||
CloseHandle(processInformation.hThread);
|
||||
CloseHandle(processInformation.hProcess);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
progress(userdata);
|
||||
|
||||
if(!createProcessSuccess)
|
||||
{
|
||||
throw mpt::Wine::Exception("CreateProcess failed.");
|
||||
}
|
||||
|
||||
progress(userdata);
|
||||
|
||||
if(flags[ExecFlagAsync])
|
||||
{
|
||||
ExecResult result;
|
||||
result.exitcode = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
while(!(dirWindows + P_("done")).IsFile())
|
||||
{ // wait
|
||||
if(progressCancel(userdata) != ExecuteProgressContinueWaiting)
|
||||
{
|
||||
throw mpt::Wine::Exception("Canceled.");
|
||||
}
|
||||
}
|
||||
|
||||
progress(userdata);
|
||||
|
||||
int exitCode = 0;
|
||||
{
|
||||
mpt::ifstream exitFile(dirWindows + P_("exit"), std::ios::binary);
|
||||
if(!exitFile)
|
||||
{
|
||||
throw mpt::Wine::Exception("Script .exit file not found.");
|
||||
}
|
||||
std::string exitString;
|
||||
exitFile >> exitString;
|
||||
if(exitString.empty())
|
||||
{
|
||||
throw mpt::Wine::Exception("Script .exit file empty.");
|
||||
}
|
||||
exitCode = ConvertStrTo<int>(exitString);
|
||||
}
|
||||
|
||||
progress(userdata);
|
||||
|
||||
std::string outputString;
|
||||
if(!flags[ExecFlagInteractive])
|
||||
{
|
||||
mpt::ifstream outputFile(dirWindows + P_("out"), std::ios::binary);
|
||||
if(outputFile)
|
||||
{
|
||||
outputFile.seekg(0, std::ios::end);
|
||||
std::streampos outputFileSize = outputFile.tellg();
|
||||
outputFile.seekg(0, std::ios::beg);
|
||||
std::vector<char> outputFileBuf(mpt::saturate_cast<std::size_t>(static_cast<std::streamoff>(outputFileSize)));
|
||||
outputFile.read(&outputFileBuf[0], outputFileBuf.size());
|
||||
outputString = std::string(outputFileBuf.begin(), outputFileBuf.end());
|
||||
}
|
||||
}
|
||||
|
||||
progress(userdata);
|
||||
|
||||
std::string errorString;
|
||||
if(flags[ExecFlagSplitOutput])
|
||||
{
|
||||
mpt::ifstream errorFile(dirWindows + P_("err"), std::ios::binary);
|
||||
if(errorFile)
|
||||
{
|
||||
errorFile.seekg(0, std::ios::end);
|
||||
std::streampos errorFileSize = errorFile.tellg();
|
||||
errorFile.seekg(0, std::ios::beg);
|
||||
std::vector<char> errorFileBuf(mpt::saturate_cast<std::size_t>(static_cast<std::streamoff>(errorFileSize)));
|
||||
errorFile.read(&errorFileBuf[0], errorFileBuf.size());
|
||||
errorString = std::string(errorFileBuf.begin(), errorFileBuf.end());
|
||||
}
|
||||
}
|
||||
|
||||
progress(userdata);
|
||||
|
||||
ExecResult result;
|
||||
result.exitcode = exitCode;
|
||||
result.output = outputString;
|
||||
result.error = errorString;
|
||||
|
||||
std::deque<mpt::PathString> paths;
|
||||
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_DATA wfd;
|
||||
MemsetZero(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 != P_(".") && filename != P_(".."))
|
||||
{
|
||||
filename = path + filename;
|
||||
filetree[filename.ToUTF8()] = std::vector<char>();
|
||||
if(filename.IsDirectory())
|
||||
{
|
||||
paths.push_back(filename);
|
||||
} else if(filename.IsFile())
|
||||
{
|
||||
try
|
||||
{
|
||||
mpt::LazyFileRef f(filename);
|
||||
std::vector<char> buf = f;
|
||||
mpt::PathString treeFilename = mpt::PathString::FromNative(filename.AsNative().substr(basePath.AsNative().length()));
|
||||
result.filetree[treeFilename.ToUTF8()] = buf;
|
||||
} catch (std::exception &)
|
||||
{
|
||||
// nothing?!
|
||||
}
|
||||
}
|
||||
}
|
||||
} while(FindNextFile(hFind, &wfd));
|
||||
FindClose(hFind);
|
||||
}
|
||||
}
|
||||
|
||||
mpt::DeleteWholeDirectoryTree(dirWindows);
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int Context::ExecutePosixShellCommand(std::string command, std::string & output, std::string & error)
|
||||
{
|
||||
std::string script;
|
||||
script += "#!/usr/bin/env sh" "\n";
|
||||
script += "exec " + command + "\n";
|
||||
mpt::Wine::ExecResult execResult = ExecutePosixShellScript
|
||||
( script
|
||||
, mpt::Wine::ExecFlagSilent | mpt::Wine::ExecFlagSplitOutput, std::map<std::string, std::vector<char> >()
|
||||
, std::string()
|
||||
, nullptr
|
||||
, nullptr
|
||||
, nullptr
|
||||
);
|
||||
output = execResult.output;
|
||||
error = execResult.error;
|
||||
return execResult.exitcode;
|
||||
}
|
||||
|
||||
|
||||
std::string Context::GetPosixEnvVar(std::string var, std::string def)
|
||||
{
|
||||
// We cannot use std::getenv here because Wine overrides SOME env vars,
|
||||
// in particular, HOME is unset in the Wine environment.
|
||||
// Instead, we just spawn a shell that will catch up a sane environment on
|
||||
// its own.
|
||||
std::string output;
|
||||
std::string error;
|
||||
int exitcode = ExecutePosixShellCommand(std::string() + "echo $" + var, output, error);
|
||||
if(!error.empty())
|
||||
{
|
||||
throw mpt::Wine::Exception("Wine echo $var failed: " + error);
|
||||
}
|
||||
if(exitcode != 0)
|
||||
{
|
||||
throw mpt::Wine::Exception("Wine echo $var failed.");
|
||||
}
|
||||
std::string result = mpt::String::RTrim(output, std::string("\r\n"));
|
||||
if(result.empty())
|
||||
{
|
||||
result = def;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
} // namespace Wine
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
#else // !(MODPLUG_TRACKER && MPT_OS_WINDOWS)
|
||||
|
||||
|
||||
MPT_MSVC_WORKAROUND_LNK4221(mptWine)
|
||||
|
||||
|
||||
#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,129 +0,0 @@
|
|||
/*
|
||||
* mptWine.h
|
||||
* ---------
|
||||
* Purpose: Wine stuff.
|
||||
* 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 "mptOS.h"
|
||||
#include "FlagSet.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
namespace Wine
|
||||
{
|
||||
|
||||
|
||||
class Exception
|
||||
: public std::runtime_error
|
||||
{
|
||||
public:
|
||||
Exception(const std::string &text)
|
||||
: std::runtime_error(text)
|
||||
{
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
typedef void (*ExecutePosixCommandProgress)(void *userdata);
|
||||
|
||||
enum ExecuteProgressResult
|
||||
{
|
||||
ExecuteProgressContinueWaiting = 0,
|
||||
ExecuteProgressAsyncCancel = -1,
|
||||
};
|
||||
|
||||
typedef ExecuteProgressResult (*ExecutePosixShellScriptProgress)(void *userdata);
|
||||
|
||||
|
||||
enum ExecFlags
|
||||
{
|
||||
ExecFlagNone = 0,
|
||||
ExecFlagSilent = 1<<0, // do not show a terminal window
|
||||
ExecFlagInteractive = 1<<1, // allow interaction (prevents stdout and stderr capturing and implies !silent)
|
||||
ExecFlagAsync = 1<<2, // do not wait for the script to finish
|
||||
ExecFlagProgressWindow = 1<<3, // not implemented by mptOS
|
||||
ExecFlagSplitOutput = 1<<4, // split stdout and stderr (implies silent)
|
||||
ExecFlagsDefault = ExecFlagNone
|
||||
};
|
||||
MPT_DECLARE_ENUM(ExecFlags)
|
||||
|
||||
struct ExecResult
|
||||
{
|
||||
int exitcode;
|
||||
std::string output;
|
||||
std::string error;
|
||||
std::map<std::string, std::vector<char> > filetree;
|
||||
static ExecResult Error()
|
||||
{
|
||||
ExecResult result;
|
||||
result.exitcode = -1;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Context
|
||||
{
|
||||
protected:
|
||||
mpt::Wine::VersionContext m_VersionContext;
|
||||
mpt::Library m_Kernel32;
|
||||
private:
|
||||
LPWSTR (*CDECL wine_get_dos_file_name)(LPCSTR str);
|
||||
LPSTR (*CDECL wine_get_unix_file_name)(LPCWSTR str);
|
||||
protected:
|
||||
std::string m_Uname_m;
|
||||
std::string m_HOME;
|
||||
std::string m_XDG_DATA_HOME;
|
||||
std::string m_XDG_CACHE_HOME;
|
||||
std::string m_XDG_CONFIG_HOME;
|
||||
public:
|
||||
Context(mpt::Wine::VersionContext versionContext);
|
||||
public:
|
||||
std::string EscapePosixShell(std::string line);
|
||||
std::string PathToPosix(mpt::PathString windowsPath);
|
||||
mpt::PathString PathToWindows(std::string hostPath);
|
||||
ExecResult ExecutePosixShellScript(std::string script, FlagSet<ExecFlags> flags, std::map<std::string, std::vector<char> > filetree, std::string title, ExecutePosixCommandProgress progress, ExecutePosixShellScriptProgress progressCancel, void *userdata);
|
||||
int ExecutePosixShellCommand(std::string command, std::string & output, std::string & error);
|
||||
std::string PathToPosixCanonical(mpt::PathString windowsPath);
|
||||
std::string GetPosixEnvVar(std::string var, std::string def = std::string());
|
||||
public:
|
||||
mpt::Wine::VersionContext VersionContext() const { return m_VersionContext; }
|
||||
mpt::Library Kernel32() const { return m_Kernel32; }
|
||||
std::string Uname_m() const { return m_Uname_m; }
|
||||
std::string HOME() const { return m_HOME; }
|
||||
std::string XDG_DATA_HOME() const { return m_XDG_DATA_HOME; }
|
||||
std::string XDG_CACHE_HOME() const { return m_XDG_CACHE_HOME; }
|
||||
std::string XDG_CONFIG_HOME() const { return m_XDG_CONFIG_HOME; }
|
||||
};
|
||||
|
||||
|
||||
} // namespace Wine
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,737 +0,0 @@
|
|||
/*
|
||||
* serialization_utils.cpp
|
||||
* -----------------------
|
||||
* Purpose: Serializing data to and from MPTM files.
|
||||
* 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 "serialization_utils.h"
|
||||
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "misc_util.h"
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
namespace srlztn
|
||||
{
|
||||
|
||||
|
||||
#ifdef MPT_ALL_LOGGING
|
||||
#define SSB_LOGGING
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef SSB_LOGGING
|
||||
#define SSB_LOG(x) MPT_LOG(LogDebug, "serialization", x)
|
||||
#else
|
||||
#define SSB_LOG(x) MPT_DO { } MPT_WHILE_0
|
||||
#endif
|
||||
|
||||
|
||||
static const uint8 HeaderId_FlagByte = 0;
|
||||
|
||||
// Indexing starts from 0.
|
||||
static inline bool Testbit(uint8 val, uint8 bitindex) {return ((val & (1 << bitindex)) != 0);}
|
||||
|
||||
static inline void Setbit(uint8& val, uint8 bitindex, bool newval)
|
||||
{
|
||||
if(newval) val |= (1 << bitindex);
|
||||
else val &= ~(1 << bitindex);
|
||||
}
|
||||
|
||||
|
||||
bool ID::IsPrintable() const
|
||||
{
|
||||
for(std::size_t i = 0; i < m_ID.length(); ++i)
|
||||
{
|
||||
if(m_ID[i] <= 0 || isprint(static_cast<unsigned char>(m_ID[i])) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//Format: First bit tells whether the size indicator is 1 or 2 bytes.
|
||||
static void WriteAdaptive12String(std::ostream& oStrm, const std::string& str)
|
||||
{
|
||||
uint16 s = static_cast<uint16>(str.size());
|
||||
LimitMax(s, uint16(uint16_max / 2));
|
||||
mpt::IO::WriteAdaptiveInt16LE(oStrm, s);
|
||||
oStrm.write(str.c_str(), s);
|
||||
}
|
||||
|
||||
|
||||
void WriteItemString(std::ostream& oStrm, const std::string &str)
|
||||
{
|
||||
uint32 id = static_cast<uint32>(std::min(str.size(), static_cast<std::size_t>((uint32_max >> 4)))) << 4;
|
||||
id |= 12; // 12 == 1100b
|
||||
Binarywrite<uint32>(oStrm, id);
|
||||
id >>= 4;
|
||||
if(id > 0)
|
||||
oStrm.write(str.data(), id);
|
||||
}
|
||||
|
||||
|
||||
void ReadItemString(std::istream& iStrm, std::string& str, const DataSize)
|
||||
{
|
||||
// bits 0,1: Bytes per char type: 1,2,3,4.
|
||||
// bits 2,3: Bytes in size indicator, 1,2,3,4
|
||||
uint32 id = 0;
|
||||
Binaryread(iStrm, id, 1);
|
||||
const uint8 nSizeBytes = (id & 12) >> 2; // 12 == 1100b
|
||||
if (nSizeBytes > 0)
|
||||
{
|
||||
uint8 bytes = std::min(uint8(3), nSizeBytes);
|
||||
uint8 v2 = 0;
|
||||
uint8 v3 = 0;
|
||||
uint8 v4 = 0;
|
||||
if(bytes >= 1) Binaryread(iStrm, v2);
|
||||
if(bytes >= 2) Binaryread(iStrm, v3);
|
||||
if(bytes >= 3) Binaryread(iStrm, v4);
|
||||
id &= 0xff;
|
||||
id |= (v2 << 8) | (v3 << 16) | (v4 << 24);
|
||||
}
|
||||
// Limit to 1 MB.
|
||||
str.resize(std::min(id >> 4, uint32(1000000)));
|
||||
for(size_t i = 0; i < str.size(); i++)
|
||||
iStrm.read(&str[i], 1);
|
||||
|
||||
id = (id >> 4) - static_cast<uint32>(str.size());
|
||||
if(id > 0)
|
||||
iStrm.ignore(id);
|
||||
}
|
||||
|
||||
|
||||
mpt::ustring ID::AsString() const
|
||||
{
|
||||
if(IsPrintable())
|
||||
{
|
||||
return mpt::ToUnicode(mpt::Charset::ISO8859_1, m_ID);
|
||||
}
|
||||
if(m_ID.length() > 8)
|
||||
{
|
||||
return mpt::ustring();
|
||||
}
|
||||
uint64le val;
|
||||
val.set(0);
|
||||
std::memcpy(&val, m_ID.data(), m_ID.length());
|
||||
return mpt::ufmt::val(val);
|
||||
}
|
||||
|
||||
|
||||
const char Ssb::s_EntryID[3] = {'2','2','8'};
|
||||
|
||||
|
||||
#ifdef SSB_LOGGING
|
||||
static const mpt::uchar tstrWriteHeader[] = UL_("Write header with ID = %1\n");
|
||||
static const mpt::uchar tstrWriteProgress[] = UL_("Wrote entry: {num, id, rpos, size} = {%1, %2, %3, %4}\n");
|
||||
static const mpt::uchar tstrWritingMap[] = UL_("Writing map to rpos: %1\n");
|
||||
static const mpt::uchar tstrMapEntryWrite[] = UL_("Writing map entry: id=%1, rpos=%2, size=%3\n");
|
||||
static const mpt::uchar strWriteNote[] = UL_("Write note: ");
|
||||
static const mpt::uchar tstrEndOfStream[] = UL_("End of stream(rpos): %1\n");
|
||||
|
||||
static const mpt::uchar tstrReadingHeader[] = UL_("Read header with expected ID = %1\n");
|
||||
static const mpt::uchar strNoMapInFile[] = UL_("No map in the file.\n");
|
||||
static const mpt::uchar strIdMismatch[] = UL_("ID mismatch, terminating read.\n");
|
||||
static const mpt::uchar strIdMatch[] = UL_("ID match, continuing reading.\n");
|
||||
static const mpt::uchar tstrReadingMap[] = UL_("Reading map from rpos: %1\n");
|
||||
static const mpt::uchar tstrEndOfMap[] = UL_("End of map(rpos): %1\n");
|
||||
static const mpt::uchar tstrReadProgress[] = UL_("Read entry: {num, id, rpos, size, desc} = {%1, %2, %3, %4, %5}\n");
|
||||
static const mpt::uchar tstrNoEntryFound[] = UL_("No entry with id %1 found.\n");
|
||||
static const mpt::uchar strReadNote[] = UL_("Read note: ");
|
||||
#endif
|
||||
|
||||
|
||||
Ssb::Ssb()
|
||||
: m_Status(SNT_NONE)
|
||||
, m_nFixedEntrySize(0)
|
||||
, m_posStart(0)
|
||||
, m_nIdbytes(IdSizeVariable)
|
||||
, m_nCounter(0)
|
||||
, m_Flags((1 << RwfWMapStartPosEntry) + (1 << RwfWMapSizeEntry) + (1 << RwfWVersionNum))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
SsbWrite::SsbWrite(std::ostream& os)
|
||||
: oStrm(os)
|
||||
, m_posEntrycount(0)
|
||||
, m_posMapPosField(0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
SsbRead::SsbRead(std::istream& is)
|
||||
: iStrm(is)
|
||||
, m_nReadVersion(0)
|
||||
, m_rposMapBegin(0)
|
||||
, m_posMapEnd(0)
|
||||
, m_posDataBegin(0)
|
||||
, m_rposEndofHdrData(0)
|
||||
, m_nReadEntrycount(0)
|
||||
, m_nNextReadHint(0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void SsbWrite::AddWriteNote(const SsbStatus s)
|
||||
{
|
||||
m_Status |= 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(U_("%1: 0x%2\n"))(strReadNote, mpt::ufmt::hex(s)));
|
||||
}
|
||||
|
||||
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() : U_(""),
|
||||
(pRe) ? pRe->rposStart : 0,
|
||||
(pRe && pRe->nSize != invalidDatasize) ? mpt::ufmt::val(pRe->nSize) : U_(""),
|
||||
U_("")));
|
||||
#ifndef SSB_LOGGING
|
||||
MPT_UNREFERENCED_PARAMETER(pRe);
|
||||
MPT_UNREFERENCED_PARAMETER(nNum);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Called after writing an entry.
|
||||
void SsbWrite::AddWriteNote(const ID &id, const NumType nEntryNum, const DataSize nBytecount, const RposType rposStart)
|
||||
{
|
||||
m_Status |= SNT_PROGRESS;
|
||||
SSB_LOG(mpt::format(mpt::ustring(tstrWriteProgress))(nEntryNum, id.AsString(), rposStart, nBytecount));
|
||||
#ifndef SSB_LOGGING
|
||||
MPT_UNREFERENCED_PARAMETER(id);
|
||||
MPT_UNREFERENCED_PARAMETER(nEntryNum);
|
||||
MPT_UNREFERENCED_PARAMETER(nBytecount);
|
||||
MPT_UNREFERENCED_PARAMETER(rposStart);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void SsbRead::ResetReadstatus()
|
||||
{
|
||||
m_Status = SNT_NONE;
|
||||
m_Idarray.reserve(32);
|
||||
m_Idarray.push_back(0);
|
||||
}
|
||||
|
||||
|
||||
void SsbWrite::WriteMapItem(const ID &id,
|
||||
const RposType& rposDataStart,
|
||||
const DataSize& nDatasize,
|
||||
const char* pszDesc)
|
||||
{
|
||||
SSB_LOG(mpt::format(mpt::ustring(tstrMapEntryWrite))(
|
||||
(id.GetSize() > 0) ? id.AsString() : U_(""),
|
||||
rposDataStart,
|
||||
nDatasize));
|
||||
|
||||
std::ostringstream mapStream;
|
||||
|
||||
if(m_nIdbytes > 0)
|
||||
{
|
||||
if (m_nIdbytes != IdSizeVariable && id.GetSize() != m_nIdbytes)
|
||||
{ AddWriteNote(SNW_CHANGING_IDSIZE_WITH_FIXED_IDSIZESETTING); return; }
|
||||
|
||||
if (m_nIdbytes == IdSizeVariable) //Variablesize ID?
|
||||
mpt::IO::WriteAdaptiveInt16LE(mapStream, static_cast<uint16>(id.GetSize()));
|
||||
|
||||
if(id.GetSize() > 0)
|
||||
mapStream.write(id.GetBytes(), id.GetSize());
|
||||
}
|
||||
|
||||
if (GetFlag(RwfWMapStartPosEntry)) //Startpos
|
||||
mpt::IO::WriteAdaptiveInt64LE(mapStream, rposDataStart);
|
||||
if (GetFlag(RwfWMapSizeEntry)) //Entrysize
|
||||
mpt::IO::WriteAdaptiveInt64LE(mapStream, nDatasize);
|
||||
if (GetFlag(RwfWMapDescEntry)) //Entry descriptions
|
||||
WriteAdaptive12String(mapStream, std::string(pszDesc));
|
||||
|
||||
m_MapStreamString.append(mapStream.str());
|
||||
|
||||
}
|
||||
|
||||
|
||||
void SsbWrite::IncrementWriteCounter()
|
||||
{
|
||||
m_nCounter++;
|
||||
if (m_nCounter >= (uint16_max >> 2))
|
||||
{
|
||||
FinishWrite();
|
||||
AddWriteNote(SNW_MAX_WRITE_COUNT_REACHED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SsbWrite::BeginWrite(const ID &id, const uint64& nVersion)
|
||||
{
|
||||
SSB_LOG(mpt::format(mpt::ustring(tstrWriteHeader))(id.AsString()));
|
||||
|
||||
ResetWritestatus();
|
||||
|
||||
if(!oStrm.good())
|
||||
{ AddWriteNote(SNRW_BADGIVEN_STREAM); return; }
|
||||
|
||||
// Start bytes.
|
||||
oStrm.write(s_EntryID, sizeof(s_EntryID));
|
||||
|
||||
m_posStart = oStrm.tellp() - Offtype(sizeof(s_EntryID));
|
||||
|
||||
// Object ID.
|
||||
{
|
||||
uint8 idsize = static_cast<uint8>(id.GetSize());
|
||||
Binarywrite<uint8>(oStrm, idsize);
|
||||
if(idsize > 0) oStrm.write(id.GetBytes(), id.GetSize());
|
||||
}
|
||||
|
||||
// Form header.
|
||||
uint8 header = 0;
|
||||
|
||||
SetFlag(RwfWMapStartPosEntry, GetFlag(RwfWMapStartPosEntry) && m_nFixedEntrySize == 0);
|
||||
SetFlag(RwfWMapSizeEntry, GetFlag(RwfWMapSizeEntry) && m_nFixedEntrySize == 0);
|
||||
|
||||
header = (m_nIdbytes != 4) ? (m_nIdbytes & 3) : 3; //0,1 : Bytes per IDtype, 0,1,2,4
|
||||
Setbit(header, 2, GetFlag(RwfWMapStartPosEntry)); //2 : Startpos in map?
|
||||
Setbit(header, 3, GetFlag(RwfWMapSizeEntry)); //3 : Datasize in map?
|
||||
Setbit(header, 4, GetFlag(RwfWVersionNum)); //4 : Version numeric field?
|
||||
Setbit(header, 7, GetFlag(RwfWMapDescEntry)); //7 : Entrydescriptions in map?
|
||||
|
||||
// Write header
|
||||
Binarywrite<uint8>(oStrm, header);
|
||||
|
||||
// Additional options.
|
||||
uint8 tempU8 = 0;
|
||||
Setbit(tempU8, 0, (m_nIdbytes == IdSizeVariable) || (m_nIdbytes == 3) || (m_nIdbytes > 4));
|
||||
Setbit(tempU8, 1, m_nFixedEntrySize != 0);
|
||||
|
||||
const uint8 flags = tempU8;
|
||||
if(flags != s_DefaultFlagbyte)
|
||||
{
|
||||
mpt::IO::WriteAdaptiveInt32LE(oStrm, 2); //Headersize - now it is 2.
|
||||
Binarywrite<uint8>(oStrm, HeaderId_FlagByte);
|
||||
Binarywrite<uint8>(oStrm, flags);
|
||||
}
|
||||
else
|
||||
mpt::IO::WriteAdaptiveInt32LE(oStrm, 0);
|
||||
|
||||
if(Testbit(header, 4)) // Version(numeric)?
|
||||
mpt::IO::WriteAdaptiveInt64LE(oStrm, nVersion);
|
||||
|
||||
if(Testbit(flags, 0)) // Custom IDbytecount?
|
||||
{
|
||||
uint8 n = (m_nIdbytes == IdSizeVariable) ? 1 : static_cast<uint8>((m_nIdbytes << 1));
|
||||
Binarywrite<uint8>(oStrm, n);
|
||||
}
|
||||
|
||||
if(Testbit(flags, 1)) // Fixedsize entries?
|
||||
mpt::IO::WriteAdaptiveInt32LE(oStrm, m_nFixedEntrySize);
|
||||
|
||||
//Entrycount. Reserve two bytes(max uint16_max / 4 entries), actual value is written after writing data.
|
||||
m_posEntrycount = oStrm.tellp();
|
||||
Binarywrite<uint16>(oStrm, 0);
|
||||
|
||||
SetFlag(RwfRwHasMap, (m_nIdbytes != 0 || GetFlag(RwfWMapStartPosEntry) || GetFlag(RwfWMapSizeEntry) || GetFlag(RwfWMapDescEntry)));
|
||||
|
||||
m_posMapPosField = oStrm.tellp();
|
||||
if (GetFlag(RwfRwHasMap)) //Mapping begin pos(reserve space - actual value is written after writing data)
|
||||
Binarywrite<uint64>(oStrm, 0);
|
||||
}
|
||||
|
||||
|
||||
SsbRead::ReadRv SsbRead::OnReadEntry(const ReadEntry* pE, const ID &id, const Postype& posReadBegin)
|
||||
{
|
||||
if (pE != nullptr)
|
||||
AddReadNote(pE, m_nCounter);
|
||||
else if (GetFlag(RwfRMapHasId) == false) // Not ID's in map.
|
||||
{
|
||||
ReadEntry e;
|
||||
e.rposStart = static_cast<RposType>(posReadBegin - m_posStart);
|
||||
e.nSize = static_cast<DataSize>(iStrm.tellg() - posReadBegin);
|
||||
AddReadNote(&e, m_nCounter);
|
||||
}
|
||||
else // Entry not found.
|
||||
{
|
||||
SSB_LOG(mpt::format(mpt::ustring(tstrNoEntryFound))(id.AsString()));
|
||||
#ifndef SSB_LOGGING
|
||||
MPT_UNREFERENCED_PARAMETER(id);
|
||||
#endif
|
||||
return EntryNotFound;
|
||||
}
|
||||
m_nCounter++;
|
||||
return EntryRead;
|
||||
}
|
||||
|
||||
|
||||
void SsbWrite::OnWroteItem(const ID &id, const Postype& posBeforeWrite)
|
||||
{
|
||||
const Offtype nRawEntrySize = oStrm.tellp() - posBeforeWrite;
|
||||
|
||||
MPT_MAYBE_CONSTANT_IF(nRawEntrySize < 0 || static_cast<uint64>(nRawEntrySize) > std::numeric_limits<DataSize>::max())
|
||||
{
|
||||
AddWriteNote(SNW_INSUFFICIENT_DATASIZETYPE);
|
||||
return;
|
||||
}
|
||||
|
||||
if(GetFlag(RwfRMapHasSize) && (nRawEntrySize < 0 || static_cast<uint64>(nRawEntrySize) > (std::numeric_limits<DataSize>::max() >> 2)))
|
||||
{ AddWriteNote(SNW_DATASIZETYPE_OVERFLOW); return; }
|
||||
|
||||
DataSize nEntrySize = static_cast<DataSize>(nRawEntrySize);
|
||||
|
||||
// Handle fixed size entries:
|
||||
if (m_nFixedEntrySize > 0)
|
||||
{
|
||||
if(nEntrySize <= m_nFixedEntrySize)
|
||||
{
|
||||
for(uint32 i = 0; i<m_nFixedEntrySize-nEntrySize; i++)
|
||||
oStrm.put(0);
|
||||
nEntrySize = m_nFixedEntrySize;
|
||||
}
|
||||
else
|
||||
{ AddWriteNote(SNW_INSUFFICIENT_FIXEDSIZE); return; }
|
||||
}
|
||||
if (GetFlag(RwfRwHasMap))
|
||||
WriteMapItem(id, static_cast<RposType>(posBeforeWrite - m_posStart), nEntrySize, "");
|
||||
|
||||
AddWriteNote(id, m_nCounter, nEntrySize, static_cast<RposType>(posBeforeWrite - m_posStart));
|
||||
IncrementWriteCounter();
|
||||
}
|
||||
|
||||
|
||||
void SsbRead::BeginRead(const ID &id, const uint64& nVersion)
|
||||
{
|
||||
SSB_LOG(mpt::format(mpt::ustring(tstrReadingHeader))(id.AsString()));
|
||||
|
||||
ResetReadstatus();
|
||||
|
||||
if (!iStrm.good())
|
||||
{ AddReadNote(SNRW_BADGIVEN_STREAM); return; }
|
||||
|
||||
m_posStart = iStrm.tellg();
|
||||
|
||||
// Start bytes.
|
||||
{
|
||||
char temp[sizeof(s_EntryID)];
|
||||
ArrayReader<char>(sizeof(s_EntryID))(iStrm, temp, sizeof(s_EntryID));
|
||||
if(std::memcmp(temp, s_EntryID, sizeof(s_EntryID)))
|
||||
{
|
||||
AddReadNote(SNR_STARTBYTE_MISMATCH);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Compare IDs.
|
||||
uint8 storedIdLen = 0;
|
||||
Binaryread<uint8>(iStrm, storedIdLen);
|
||||
char storedIdBuf[256];
|
||||
Clear(storedIdBuf);
|
||||
if(storedIdLen > 0)
|
||||
{
|
||||
iStrm.read(storedIdBuf, storedIdLen);
|
||||
}
|
||||
if(!(id == ID(storedIdBuf, storedIdLen)))
|
||||
{
|
||||
AddReadNote(SNR_OBJECTCLASS_IDMISMATCH);
|
||||
}
|
||||
if ((m_Status & SNT_FAILURE) != 0)
|
||||
{
|
||||
SSB_LOG(mpt::ustring(strIdMismatch));
|
||||
return;
|
||||
}
|
||||
|
||||
SSB_LOG(mpt::ustring(strIdMatch));
|
||||
|
||||
// Header
|
||||
uint8 tempU8;
|
||||
Binaryread<uint8>(iStrm, tempU8);
|
||||
const uint8 header = tempU8;
|
||||
m_nIdbytes = ((header & 3) == 3) ? 4 : (header & 3);
|
||||
if (Testbit(header, 6))
|
||||
SetFlag(RwfRTwoBytesDescChar, true);
|
||||
|
||||
// Read headerdata size
|
||||
uint32 tempU32 = 0;
|
||||
mpt::IO::ReadAdaptiveInt32LE(iStrm, tempU32);
|
||||
const uint32 headerdatasize = tempU32;
|
||||
|
||||
// If headerdatasize != 0, read known headerdata and ignore rest.
|
||||
uint8 flagbyte = s_DefaultFlagbyte;
|
||||
if(headerdatasize >= 2)
|
||||
{
|
||||
Binaryread<uint8>(iStrm, tempU8);
|
||||
if(tempU8 == HeaderId_FlagByte)
|
||||
Binaryread<uint8>(iStrm, flagbyte);
|
||||
|
||||
iStrm.ignore( (tempU8 == HeaderId_FlagByte) ? headerdatasize - 2 : headerdatasize - 1);
|
||||
}
|
||||
|
||||
uint64 tempU64 = 0;
|
||||
|
||||
// Read version numeric if available.
|
||||
if (Testbit(header, 4))
|
||||
{
|
||||
mpt::IO::ReadAdaptiveInt64LE(iStrm, tempU64);
|
||||
m_nReadVersion = tempU64;
|
||||
if(tempU64 > nVersion)
|
||||
AddReadNote(SNR_LOADING_OBJECT_WITH_LARGER_VERSION);
|
||||
}
|
||||
|
||||
if (Testbit(header, 5))
|
||||
{
|
||||
Binaryread<uint8>(iStrm, tempU8);
|
||||
iStrm.ignore(tempU8);
|
||||
}
|
||||
|
||||
if(Testbit(flagbyte, 0)) // Custom ID?
|
||||
{
|
||||
Binaryread<uint8>(iStrm, tempU8);
|
||||
if ((tempU8 & 1) != 0)
|
||||
m_nIdbytes = IdSizeVariable;
|
||||
else
|
||||
m_nIdbytes = (tempU8 >> 1);
|
||||
if(m_nIdbytes == 0)
|
||||
AddReadNote(SNR_NO_ENTRYIDS_WITH_CUSTOMID_DEFINED);
|
||||
}
|
||||
|
||||
m_nFixedEntrySize = 0;
|
||||
if(Testbit(flagbyte, 1)) // Fixedsize entries?
|
||||
mpt::IO::ReadAdaptiveInt32LE(iStrm, m_nFixedEntrySize);
|
||||
|
||||
SetFlag(RwfRMapHasStartpos, Testbit(header, 2));
|
||||
SetFlag(RwfRMapHasSize, Testbit(header, 3));
|
||||
SetFlag(RwfRMapHasId, (m_nIdbytes > 0));
|
||||
SetFlag(RwfRMapHasDesc, Testbit(header, 7));
|
||||
SetFlag(RwfRwHasMap, GetFlag(RwfRMapHasId) || GetFlag(RwfRMapHasStartpos) || GetFlag(RwfRMapHasSize) || GetFlag(RwfRMapHasDesc));
|
||||
|
||||
if (GetFlag(RwfRwHasMap) == false)
|
||||
{
|
||||
SSB_LOG(mpt::ustring(strNoMapInFile));
|
||||
}
|
||||
|
||||
if (Testbit(flagbyte, 2)) // Object description?
|
||||
{
|
||||
uint16 size = 0;
|
||||
mpt::IO::ReadAdaptiveInt16LE(iStrm, size);
|
||||
iStrm.ignore(size * (GetFlag(RwfRTwoBytesDescChar) ? 2 : 1));
|
||||
}
|
||||
|
||||
if(Testbit(flagbyte, 3))
|
||||
iStrm.ignore(5);
|
||||
|
||||
// Read entrycount
|
||||
mpt::IO::ReadAdaptiveInt64LE(iStrm, tempU64);
|
||||
if(tempU64 > 16000)
|
||||
// The current code can only write 16383 entries because it uses a Adaptive64LE with a fixed size=2
|
||||
// Additionally, 16000 is an arbitrary limit to avoid an out-of-memory DoS when caching the map.
|
||||
{ AddReadNote(SNR_TOO_MANY_ENTRIES_TO_READ); return; }
|
||||
|
||||
m_nReadEntrycount = static_cast<NumType>(tempU64);
|
||||
if(m_nReadEntrycount == 0)
|
||||
AddReadNote(SNR_ZEROENTRYCOUNT);
|
||||
|
||||
// Read map rpos if map exists.
|
||||
if (GetFlag(RwfRwHasMap))
|
||||
{
|
||||
mpt::IO::ReadAdaptiveInt64LE(iStrm, tempU64);
|
||||
if(tempU64 > static_cast<uint64>(std::numeric_limits<Offtype>::max()))
|
||||
{ AddReadNote(SNR_INSUFFICIENT_STREAM_OFFTYPE); return; }
|
||||
}
|
||||
|
||||
const Offtype rawEndOfHdrData = iStrm.tellg() - m_posStart;
|
||||
|
||||
MPT_MAYBE_CONSTANT_IF(rawEndOfHdrData < 0 || static_cast<uint64>(rawEndOfHdrData) > std::numeric_limits<RposType>::max())
|
||||
{
|
||||
AddReadNote(SNR_INSUFFICIENT_RPOSTYPE);
|
||||
return;
|
||||
}
|
||||
|
||||
m_rposEndofHdrData = static_cast<RposType>(rawEndOfHdrData);
|
||||
m_rposMapBegin = (GetFlag(RwfRwHasMap)) ? static_cast<RposType>(tempU64) : m_rposEndofHdrData;
|
||||
|
||||
if (GetFlag(RwfRwHasMap) == false)
|
||||
m_posMapEnd = m_posStart + m_rposEndofHdrData;
|
||||
|
||||
SetFlag(RwfRHeaderIsRead, true);
|
||||
}
|
||||
|
||||
|
||||
void SsbRead::CacheMap()
|
||||
{
|
||||
if(GetFlag(RwfRwHasMap) || m_nFixedEntrySize > 0)
|
||||
{
|
||||
iStrm.seekg(m_posStart + m_rposMapBegin);
|
||||
|
||||
if(iStrm.fail())
|
||||
{ AddReadNote(SNR_BADSTREAM_AFTER_MAPHEADERSEEK); return; }
|
||||
|
||||
SSB_LOG(mpt::format(mpt::ustring(tstrReadingMap))(m_rposMapBegin));
|
||||
|
||||
mapData.resize(m_nReadEntrycount);
|
||||
m_Idarray.reserve(m_nReadEntrycount * 4);
|
||||
|
||||
//Read map
|
||||
for(NumType i = 0; i<m_nReadEntrycount; i++)
|
||||
{
|
||||
if(iStrm.fail())
|
||||
{ AddReadNote(SNR_BADSTREAM_AT_MAP_READ); return; }
|
||||
|
||||
// Read ID.
|
||||
uint16 nIdsize = m_nIdbytes;
|
||||
if(nIdsize == IdSizeVariable) //Variablesize ID
|
||||
mpt::IO::ReadAdaptiveInt16LE(iStrm, nIdsize);
|
||||
const size_t nOldEnd = m_Idarray.size();
|
||||
if (nIdsize > 0 && (Util::MaxValueOfType(nOldEnd) - nOldEnd >= nIdsize))
|
||||
{
|
||||
m_Idarray.resize(nOldEnd + nIdsize);
|
||||
iStrm.read(&m_Idarray[nOldEnd], nIdsize);
|
||||
}
|
||||
mapData[i].nIdLength = nIdsize;
|
||||
mapData[i].nIdpos = nOldEnd;
|
||||
|
||||
// Read position.
|
||||
if(GetFlag(RwfRMapHasStartpos))
|
||||
{
|
||||
uint64 tempU64;
|
||||
mpt::IO::ReadAdaptiveInt64LE(iStrm, tempU64);
|
||||
if(tempU64 > static_cast<uint64>(std::numeric_limits<Offtype>::max()))
|
||||
{ AddReadNote(SNR_INSUFFICIENT_STREAM_OFFTYPE); return; }
|
||||
mapData[i].rposStart = static_cast<RposType>(tempU64);
|
||||
}
|
||||
|
||||
// Read entry size.
|
||||
if (m_nFixedEntrySize > 0)
|
||||
mapData[i].nSize = m_nFixedEntrySize;
|
||||
else if(GetFlag(RwfRMapHasSize)) // Map has datasize field.
|
||||
{
|
||||
uint64 tempU64;
|
||||
mpt::IO::ReadAdaptiveInt64LE(iStrm, tempU64);
|
||||
if(tempU64 > static_cast<uint64>(std::numeric_limits<Offtype>::max()))
|
||||
{ AddReadNote(SNR_INSUFFICIENT_STREAM_OFFTYPE); return; }
|
||||
mapData[i].nSize = static_cast<DataSize>(tempU64);
|
||||
}
|
||||
|
||||
// If there's no entry startpos in map, count start pos from datasizes.
|
||||
// Here readentry.rposStart is set to relative position from databegin.
|
||||
if (mapData[i].nSize != invalidDatasize && GetFlag(RwfRMapHasStartpos) == false)
|
||||
mapData[i].rposStart = (i > 0) ? mapData[i-1].rposStart + mapData[i-1].nSize : 0;
|
||||
|
||||
if(GetFlag(RwfRMapHasDesc)) //Map has entrydescriptions?
|
||||
{
|
||||
uint16 size = 0;
|
||||
mpt::IO::ReadAdaptiveInt16LE(iStrm, size);
|
||||
if(GetFlag(RwfRTwoBytesDescChar))
|
||||
iStrm.ignore(size * 2);
|
||||
else
|
||||
iStrm.ignore(size);
|
||||
}
|
||||
}
|
||||
m_posMapEnd = iStrm.tellg();
|
||||
SSB_LOG(mpt::format(mpt::ustring(tstrEndOfMap))(m_posMapEnd - m_posStart));
|
||||
}
|
||||
|
||||
SetFlag(RwfRMapCached, true);
|
||||
m_posDataBegin = (m_rposMapBegin == m_rposEndofHdrData) ? m_posMapEnd : m_posStart + Postype(m_rposEndofHdrData);
|
||||
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
|
||||
// startpos.
|
||||
if (GetFlag(RwfRMapHasStartpos) == false && (GetFlag(RwfRMapHasSize) || m_nFixedEntrySize > 0))
|
||||
{
|
||||
const RposType offset = static_cast<RposType>(m_posDataBegin - m_posStart);
|
||||
for(size_t i = 0; i < m_nReadEntrycount; i++)
|
||||
mapData[i].rposStart += offset;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const ReadEntry* SsbRead::Find(const ID &id)
|
||||
{
|
||||
iStrm.clear();
|
||||
if (GetFlag(RwfRMapCached) == false)
|
||||
CacheMap();
|
||||
|
||||
if (m_nFixedEntrySize > 0 && GetFlag(RwfRMapHasStartpos) == false && GetFlag(RwfRMapHasSize) == false)
|
||||
iStrm.seekg(m_posDataBegin + Postype(m_nFixedEntrySize * m_nCounter));
|
||||
|
||||
if (GetFlag(RwfRMapHasId) == true)
|
||||
{
|
||||
const size_t nEntries = mapData.size();
|
||||
for(size_t i0 = 0; i0 < nEntries; i0++)
|
||||
{
|
||||
const size_t i = (i0 + m_nNextReadHint) % nEntries;
|
||||
if(mapData[i].nIdpos < m_Idarray.size() && id == ID(&m_Idarray[mapData[i].nIdpos], mapData[i].nIdLength))
|
||||
{
|
||||
m_nNextReadHint = (i + 1) % nEntries;
|
||||
if (mapData[i].rposStart != 0)
|
||||
iStrm.seekg(m_posStart + Postype(mapData[i].rposStart));
|
||||
return &mapData[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void SsbWrite::FinishWrite()
|
||||
{
|
||||
const Postype posDataEnd = oStrm.tellp();
|
||||
|
||||
Postype posMapStart = oStrm.tellp();
|
||||
|
||||
SSB_LOG(mpt::format(mpt::ustring(tstrWritingMap))(posMapStart - m_posStart));
|
||||
|
||||
if (GetFlag(RwfRwHasMap)) //Write map
|
||||
{
|
||||
oStrm.write(m_MapStreamString.c_str(), m_MapStreamString.length());
|
||||
}
|
||||
|
||||
const Postype posMapEnd = oStrm.tellp();
|
||||
|
||||
// Write entry count.
|
||||
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);
|
||||
|
||||
if (GetFlag(RwfRwHasMap))
|
||||
{ // Write map start position.
|
||||
oStrm.seekp(m_posMapPosField);
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
// Seek to end.
|
||||
oStrm.seekp(std::max(posMapEnd, posDataEnd));
|
||||
|
||||
SSB_LOG(mpt::format(mpt::ustring(tstrEndOfStream))(oStrm.tellp() - m_posStart));
|
||||
}
|
||||
|
||||
} // namespace srlztn
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,553 +0,0 @@
|
|||
/*
|
||||
* serialization_utils.h
|
||||
* ---------------------
|
||||
* Purpose: Serializing data to and from MPTM files.
|
||||
* 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 "../common/mptBaseTypes.h"
|
||||
#include "../common/mptIO.h"
|
||||
#include "../common/Endianness.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <bitset>
|
||||
#include <ios>
|
||||
#include <iosfwd>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
namespace srlztn //SeRiaLiZaTioN
|
||||
{
|
||||
|
||||
typedef std::ios::off_type Offtype;
|
||||
typedef Offtype Postype;
|
||||
|
||||
typedef uintptr_t DataSize; // Data size type.
|
||||
typedef uintptr_t RposType; // Relative position type.
|
||||
typedef uintptr_t NumType; // Entry count type.
|
||||
|
||||
const DataSize invalidDatasize = DataSize(-1);
|
||||
|
||||
enum
|
||||
{
|
||||
SNT_PROGRESS = 0x08000000, // = 1 << 27
|
||||
SNT_FAILURE = 0x40000000, // = 1 << 30
|
||||
SNT_NOTE = 0x20000000, // = 1 << 29
|
||||
SNT_WARNING = 0x10000000, // = 1 << 28
|
||||
SNT_NONE = 0,
|
||||
|
||||
SNRW_BADGIVEN_STREAM = 1 | SNT_FAILURE,
|
||||
|
||||
// Read failures.
|
||||
SNR_BADSTREAM_AFTER_MAPHEADERSEEK = 2 | SNT_FAILURE,
|
||||
SNR_STARTBYTE_MISMATCH = 3 | SNT_FAILURE,
|
||||
SNR_BADSTREAM_AT_MAP_READ = 4 | SNT_FAILURE,
|
||||
SNR_INSUFFICIENT_STREAM_OFFTYPE = 5 | SNT_FAILURE,
|
||||
SNR_OBJECTCLASS_IDMISMATCH = 6 | SNT_FAILURE,
|
||||
SNR_TOO_MANY_ENTRIES_TO_READ = 7 | SNT_FAILURE,
|
||||
SNR_INSUFFICIENT_RPOSTYPE = 8 | SNT_FAILURE,
|
||||
|
||||
// Read notes and warnings.
|
||||
SNR_ZEROENTRYCOUNT = 0x80 | SNT_NOTE, // 0x80 == 1 << 7
|
||||
SNR_NO_ENTRYIDS_WITH_CUSTOMID_DEFINED = 0x100 | SNT_NOTE,
|
||||
SNR_LOADING_OBJECT_WITH_LARGER_VERSION = 0x200 | SNT_NOTE,
|
||||
|
||||
// Write failures.
|
||||
SNW_INSUFFICIENT_FIXEDSIZE = (0x10) | SNT_FAILURE,
|
||||
SNW_CHANGING_IDSIZE_WITH_FIXED_IDSIZESETTING = (0x11) | SNT_FAILURE,
|
||||
SNW_DATASIZETYPE_OVERFLOW = (0x13) | SNT_FAILURE,
|
||||
SNW_MAX_WRITE_COUNT_REACHED = (0x14) | SNT_FAILURE,
|
||||
SNW_INSUFFICIENT_DATASIZETYPE = (0x16) | SNT_FAILURE
|
||||
};
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
IdSizeVariable = uint16_max,
|
||||
IdSizeMaxFixedSize = (uint8_max >> 1)
|
||||
};
|
||||
|
||||
typedef int32 SsbStatus;
|
||||
|
||||
|
||||
struct ReadEntry
|
||||
{
|
||||
ReadEntry() : nIdpos(0), rposStart(0), nSize(invalidDatasize), nIdLength(0) {}
|
||||
|
||||
uintptr_t nIdpos; // Index of id start in ID array.
|
||||
RposType rposStart; // Entry start position.
|
||||
DataSize nSize; // Entry size.
|
||||
uint16 nIdLength; // Length of id.
|
||||
};
|
||||
|
||||
|
||||
enum Rwf
|
||||
{
|
||||
RwfWMapStartPosEntry, // Write. True to include data start pos entry to map.
|
||||
RwfWMapSizeEntry, // Write. True to include data size entry to map.
|
||||
RwfWMapDescEntry, // Write. True to include description entry to map.
|
||||
RwfWVersionNum, // Write. True to include version numeric.
|
||||
RwfRMapCached, // Read. True if map has been cached.
|
||||
RwfRMapHasId, // Read. True if map has IDs
|
||||
RwfRMapHasStartpos, // Read. True if map data start pos.
|
||||
RwfRMapHasSize, // Read. True if map has entry size.
|
||||
RwfRMapHasDesc, // Read. True if map has entry description.
|
||||
RwfRTwoBytesDescChar, // Read. True if map description characters are two bytes.
|
||||
RwfRHeaderIsRead, // Read. True when header is read.
|
||||
RwfRwHasMap, // Read/write. True if map exists.
|
||||
RwfNumFlags
|
||||
};
|
||||
|
||||
|
||||
template<class T>
|
||||
inline void Binarywrite(std::ostream& oStrm, const T& data)
|
||||
{
|
||||
mpt::IO::WriteIntLE(oStrm, data);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void Binarywrite(std::ostream& oStrm, const float& data)
|
||||
{
|
||||
IEEE754binary32LE tmp = IEEE754binary32LE(data);
|
||||
mpt::IO::Write(oStrm, tmp);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void Binarywrite(std::ostream& oStrm, const double& data)
|
||||
{
|
||||
IEEE754binary64LE tmp = IEEE754binary64LE(data);
|
||||
mpt::IO::Write(oStrm, tmp);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void WriteItem(std::ostream& oStrm, const T& data)
|
||||
{
|
||||
static_assert(std::is_trivial<T>::value == true, "");
|
||||
Binarywrite(oStrm, data);
|
||||
}
|
||||
|
||||
void WriteItemString(std::ostream& oStrm, const std::string &str);
|
||||
|
||||
template <>
|
||||
inline void WriteItem<std::string>(std::ostream& oStrm, const std::string& str) {WriteItemString(oStrm, str);}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline void Binaryread(std::istream& iStrm, T& data)
|
||||
{
|
||||
mpt::IO::ReadIntLE(iStrm, data);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void Binaryread(std::istream& iStrm, float& data)
|
||||
{
|
||||
IEEE754binary32LE tmp = IEEE754binary32LE(0.0f);
|
||||
mpt::IO::Read(iStrm, tmp);
|
||||
data = tmp;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline void Binaryread(std::istream& iStrm, double& data)
|
||||
{
|
||||
IEEE754binary64LE tmp = IEEE754binary64LE(0.0);
|
||||
mpt::IO::Read(iStrm, tmp);
|
||||
data = tmp;
|
||||
}
|
||||
|
||||
//Read only given number of bytes to the beginning of data; data bytes are memset to 0 before reading.
|
||||
template <class T>
|
||||
inline void Binaryread(std::istream& iStrm, T& data, const Offtype bytecount)
|
||||
{
|
||||
mpt::IO::ReadBinaryTruncatedLE(iStrm, data, static_cast<std::size_t>(bytecount));
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void Binaryread<float>(std::istream& iStrm, float& data, const Offtype bytecount)
|
||||
{
|
||||
typedef IEEE754binary32LE T;
|
||||
std::byte bytes[sizeof(T)];
|
||||
std::memset(bytes, 0, sizeof(T));
|
||||
mpt::IO::ReadRaw(iStrm, bytes, std::min(static_cast<std::size_t>(bytecount), sizeof(T)));
|
||||
// There is not much we can sanely do for truncated floats,
|
||||
// thus we ignore what we just read and return 0.
|
||||
data = 0.0f;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void Binaryread<double>(std::istream& iStrm, double& data, const Offtype bytecount)
|
||||
{
|
||||
typedef IEEE754binary64LE T;
|
||||
std::byte bytes[sizeof(T)];
|
||||
std::memset(bytes, 0, sizeof(T));
|
||||
mpt::IO::ReadRaw(iStrm, bytes, std::min(static_cast<std::size_t>(bytecount), sizeof(T)));
|
||||
// There is not much we can sanely do for truncated floats,
|
||||
// thus we ignore what we just read and return 0.
|
||||
data = 0.0;
|
||||
}
|
||||
|
||||
|
||||
template <class T>
|
||||
inline void ReadItem(std::istream& iStrm, T& data, const DataSize nSize)
|
||||
{
|
||||
static_assert(std::is_trivial<T>::value == true, "");
|
||||
if (nSize == sizeof(T) || nSize == invalidDatasize)
|
||||
Binaryread(iStrm, data);
|
||||
else
|
||||
Binaryread(iStrm, data, nSize);
|
||||
}
|
||||
|
||||
void ReadItemString(std::istream& iStrm, std::string& str, const DataSize);
|
||||
|
||||
template <>
|
||||
inline void ReadItem<std::string>(std::istream& iStrm, std::string& str, const DataSize nSize)
|
||||
{
|
||||
ReadItemString(iStrm, str, nSize);
|
||||
}
|
||||
|
||||
|
||||
|
||||
class ID
|
||||
{
|
||||
private:
|
||||
std::string m_ID; // NOTE: can contain null characters ('\0')
|
||||
public:
|
||||
ID() { }
|
||||
ID(const std::string &id) : m_ID(id) { }
|
||||
ID(const char *beg, const char *end) : m_ID(beg, end) { }
|
||||
ID(const char *id) : m_ID(id?id:"") { }
|
||||
ID(const char * str, std::size_t len) : m_ID(str, str + len) { }
|
||||
template <typename T>
|
||||
static ID FromInt(const T &val)
|
||||
{
|
||||
static_assert(std::numeric_limits<T>::is_integer);
|
||||
typename mpt::make_le<T>::type valle;
|
||||
valle = val;
|
||||
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;
|
||||
const char *GetBytes() const { return m_ID.c_str(); }
|
||||
std::size_t GetSize() const { return m_ID.length(); }
|
||||
bool operator == (const ID &other) const { return m_ID == other.m_ID; }
|
||||
bool operator != (const ID &other) const { return m_ID != other.m_ID; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
class Ssb
|
||||
{
|
||||
|
||||
protected:
|
||||
|
||||
Ssb();
|
||||
|
||||
public:
|
||||
|
||||
SsbStatus GetStatus() const
|
||||
{
|
||||
return m_Status;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
// When writing, returns the number of entries written.
|
||||
// When reading, returns the number of entries read not including unrecognized entries.
|
||||
NumType GetCounter() const {return m_nCounter;}
|
||||
|
||||
void SetFlag(Rwf flag, bool val) {m_Flags.set(flag, val);}
|
||||
bool GetFlag(Rwf flag) const {return m_Flags[flag];}
|
||||
|
||||
protected:
|
||||
|
||||
SsbStatus m_Status;
|
||||
|
||||
uint32 m_nFixedEntrySize; // Read/write: If > 0, data entries have given fixed size.
|
||||
|
||||
Postype m_posStart; // Read/write: Stream position at the beginning of object.
|
||||
|
||||
uint16 m_nIdbytes; // Read/Write: Tells map ID entry size in bytes. If size is variable, value is IdSizeVariable.
|
||||
NumType m_nCounter; // Read/write: Keeps count of entries written/read.
|
||||
|
||||
std::bitset<RwfNumFlags> m_Flags; // Read/write: Various flags.
|
||||
|
||||
protected:
|
||||
|
||||
enum : uint8 { s_DefaultFlagbyte = 0 };
|
||||
static const char s_EntryID[3];
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
class SsbRead
|
||||
: public Ssb
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
enum ReadRv // Read return value.
|
||||
{
|
||||
EntryRead,
|
||||
EntryNotFound
|
||||
};
|
||||
enum IdMatchStatus
|
||||
{
|
||||
IdMatch, IdMismatch
|
||||
};
|
||||
typedef std::vector<ReadEntry>::const_iterator ReadIterator;
|
||||
|
||||
SsbRead(std::istream& iStrm);
|
||||
|
||||
// Call this to begin reading: must be called before other read functions.
|
||||
void BeginRead(const ID &id, const uint64& nVersion);
|
||||
|
||||
// After calling BeginRead(), this returns number of entries in the file.
|
||||
NumType GetNumEntries() const {return m_nReadEntrycount;}
|
||||
|
||||
// Returns read iterator to the beginning of entries.
|
||||
// The behaviour of read iterators is undefined if map doesn't
|
||||
// contain entry ids or data begin positions.
|
||||
ReadIterator GetReadBegin();
|
||||
|
||||
// Returns read iterator to the end(one past last) of entries.
|
||||
ReadIterator GetReadEnd();
|
||||
|
||||
// Compares given id with read entry id
|
||||
IdMatchStatus CompareId(const ReadIterator& iter, const ID &id);
|
||||
|
||||
uint64 GetReadVersion() {return m_nReadVersion;}
|
||||
|
||||
// Read item using default read implementation.
|
||||
template <class T>
|
||||
ReadRv ReadItem(T& obj, const ID &id) {return ReadItem(obj, id, srlztn::ReadItem<T>);}
|
||||
|
||||
// Read item using given function.
|
||||
template <class T, class FuncObj>
|
||||
ReadRv ReadItem(T& obj, const ID &id, FuncObj);
|
||||
|
||||
// Read item using read iterator.
|
||||
template <class T>
|
||||
ReadRv ReadIterItem(const ReadIterator& iter, T& obj) {return ReadIterItem(iter, obj, srlztn::ReadItem<T>);}
|
||||
template <class T, class FuncObj>
|
||||
ReadRv ReadIterItem(const ReadIterator& iter, T& obj, FuncObj func);
|
||||
|
||||
private:
|
||||
|
||||
// Reads map to cache.
|
||||
void CacheMap();
|
||||
|
||||
// Searches for entry with given ID. If found, returns pointer to corresponding entry, else
|
||||
// returns nullptr.
|
||||
const ReadEntry* Find(const ID &id);
|
||||
|
||||
// Called after reading an object.
|
||||
ReadRv OnReadEntry(const ReadEntry* pE, const ID &id, const Postype& posReadBegin);
|
||||
|
||||
void AddReadNote(const SsbStatus s);
|
||||
|
||||
// Called after reading entry. pRe is a pointer to associated map entry if exists.
|
||||
void AddReadNote(const ReadEntry* const pRe, const NumType nNum);
|
||||
|
||||
void ResetReadstatus();
|
||||
|
||||
private:
|
||||
|
||||
// mapData is a cache that facilitates faster access to the stored data
|
||||
// without having to reparse on every access.
|
||||
// Iterator invalidation in CacheMap() is not a problem because every code
|
||||
// path that ever returns an iterator into mapData does CacheMap exactly once
|
||||
// beforehand. Following calls use this already cached map. As the data is
|
||||
// immutable when reading, there is no need to ever invalidate the cache and
|
||||
// redo CacheMap().
|
||||
|
||||
std::istream& iStrm;
|
||||
|
||||
std::vector<char> m_Idarray; // Read: Holds entry ids.
|
||||
|
||||
std::vector<ReadEntry> mapData; // Read: Contains map information.
|
||||
uint64 m_nReadVersion; // Read: Version is placed here when reading.
|
||||
RposType m_rposMapBegin; // Read: If map exists, rpos of map begin, else m_rposEndofHdrData.
|
||||
Postype m_posMapEnd; // Read: If map exists, map end position, else pos of end of hdrData.
|
||||
Postype m_posDataBegin; // Read: Data begin position.
|
||||
RposType m_rposEndofHdrData; // Read: rpos of end of header data.
|
||||
NumType m_nReadEntrycount; // Read: Number of entries.
|
||||
|
||||
NumType m_nNextReadHint; // Read: Hint where to start looking for the next read entry.
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
class SsbWrite
|
||||
: public Ssb
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
SsbWrite(std::ostream& oStrm);
|
||||
|
||||
// Write header
|
||||
void BeginWrite(const ID &id, const uint64& nVersion);
|
||||
|
||||
// Write item using default write implementation.
|
||||
template <class T>
|
||||
void WriteItem(const T& obj, const ID &id) {WriteItem(obj, id, &srlztn::WriteItem<T>);}
|
||||
|
||||
// Write item using given function.
|
||||
template <class T, class FuncObj>
|
||||
void WriteItem(const T& obj, const ID &id, FuncObj);
|
||||
|
||||
// Writes mapping.
|
||||
void FinishWrite();
|
||||
|
||||
private:
|
||||
|
||||
// Called after writing an item.
|
||||
void OnWroteItem(const ID &id, const Postype& posBeforeWrite);
|
||||
|
||||
void AddWriteNote(const SsbStatus s);
|
||||
void AddWriteNote(const ID &id,
|
||||
const NumType nEntryNum,
|
||||
const DataSize nBytecount,
|
||||
const RposType rposStart);
|
||||
|
||||
// Writes mapping item to mapstream.
|
||||
void WriteMapItem(const ID &id,
|
||||
const RposType& rposDataStart,
|
||||
const DataSize& nDatasize,
|
||||
const char* pszDesc);
|
||||
|
||||
void ResetWritestatus() {m_Status = SNT_NONE;}
|
||||
|
||||
void IncrementWriteCounter();
|
||||
|
||||
private:
|
||||
|
||||
std::ostream& oStrm;
|
||||
|
||||
Postype m_posEntrycount; // Write: Pos of entrycount field.
|
||||
Postype m_posMapPosField; // Write: Pos of map position field.
|
||||
std::string m_MapStreamString; // Write: Map stream string.
|
||||
|
||||
};
|
||||
|
||||
|
||||
template <class T, class FuncObj>
|
||||
void SsbWrite::WriteItem(const T& obj, const ID &id, FuncObj Func)
|
||||
{
|
||||
const Postype pos = oStrm.tellp();
|
||||
Func(oStrm, obj);
|
||||
OnWroteItem(id, pos);
|
||||
}
|
||||
|
||||
template <class T, class FuncObj>
|
||||
SsbRead::ReadRv SsbRead::ReadItem(T& obj, const ID &id, FuncObj Func)
|
||||
{
|
||||
const ReadEntry* pE = Find(id);
|
||||
const Postype pos = iStrm.tellg();
|
||||
if (pE != nullptr || GetFlag(RwfRMapHasId) == false)
|
||||
Func(iStrm, obj, (pE) ? (pE->nSize) : invalidDatasize);
|
||||
return OnReadEntry(pE, id, pos);
|
||||
}
|
||||
|
||||
|
||||
template <class T, class FuncObj>
|
||||
SsbRead::ReadRv SsbRead::ReadIterItem(const ReadIterator& iter, T& obj, FuncObj func)
|
||||
{
|
||||
iStrm.clear();
|
||||
if (iter->rposStart != 0)
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
inline SsbRead::IdMatchStatus SsbRead::CompareId(const ReadIterator& iter, const ID &id)
|
||||
{
|
||||
if(iter->nIdpos >= m_Idarray.size()) return IdMismatch;
|
||||
return (id == ID(&m_Idarray[iter->nIdpos], iter->nIdLength)) ? IdMatch : IdMismatch;
|
||||
}
|
||||
|
||||
|
||||
inline SsbRead::ReadIterator SsbRead::GetReadBegin()
|
||||
{
|
||||
MPT_ASSERT(GetFlag(RwfRMapHasId) && (GetFlag(RwfRMapHasStartpos) || GetFlag(RwfRMapHasSize) || m_nFixedEntrySize > 0));
|
||||
if (GetFlag(RwfRMapCached) == false)
|
||||
CacheMap();
|
||||
return mapData.begin();
|
||||
}
|
||||
|
||||
|
||||
inline SsbRead::ReadIterator SsbRead::GetReadEnd()
|
||||
{
|
||||
if (GetFlag(RwfRMapCached) == false)
|
||||
CacheMap();
|
||||
return mapData.end();
|
||||
}
|
||||
|
||||
|
||||
template <class T>
|
||||
struct VectorWriter
|
||||
{
|
||||
VectorWriter(size_t nCount) : m_nCount(nCount) {}
|
||||
void operator()(std::ostream &oStrm, const std::vector<T> &vec)
|
||||
{
|
||||
for(size_t i = 0; i < m_nCount; i++)
|
||||
{
|
||||
Binarywrite(oStrm, vec[i]);
|
||||
}
|
||||
}
|
||||
size_t m_nCount;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct VectorReader
|
||||
{
|
||||
VectorReader(size_t nCount) : m_nCount(nCount) {}
|
||||
void operator()(std::istream& iStrm, std::vector<T> &vec, const size_t)
|
||||
{
|
||||
vec.resize(m_nCount);
|
||||
for(std::size_t i = 0; i < m_nCount; ++i)
|
||||
{
|
||||
Binaryread(iStrm, vec[i]);
|
||||
}
|
||||
}
|
||||
size_t m_nCount;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct ArrayReader
|
||||
{
|
||||
ArrayReader(size_t nCount) : m_nCount(nCount) {}
|
||||
void operator()(std::istream& iStrm, T* pData, const size_t)
|
||||
{
|
||||
for(std::size_t i=0; i<m_nCount; ++i)
|
||||
{
|
||||
Binaryread(iStrm, pData[i]);
|
||||
}
|
||||
}
|
||||
size_t m_nCount;
|
||||
};
|
||||
|
||||
|
||||
|
||||
} //namespace srlztn.
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,157 +0,0 @@
|
|||
/*
|
||||
* StdAfx.h
|
||||
* --------
|
||||
* Purpose: Include file for standard system include files, or project specific include files that are used frequently, but are changed infrequently. Also includes the global build settings from BuildSettings.h.
|
||||
* Notes : (currently none)
|
||||
* Authors: Olivier Lapicque
|
||||
* OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
// has to be first
|
||||
#include "BuildSettings.h"
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
|
||||
#if defined(MPT_WITH_MFC)
|
||||
|
||||
// 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_WITH_MFC
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
#include <shlwapi.h>
|
||||
#include <mmsystem.h>
|
||||
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
|
||||
// this will be available everywhere
|
||||
|
||||
#include "../common/mptBaseMacros.h"
|
||||
// <array>
|
||||
// <iterator>
|
||||
// <type_traits>
|
||||
// <cstddef>
|
||||
// <cstdint>
|
||||
|
||||
#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>
|
||||
// <type_traits>
|
||||
// <cstring>
|
||||
|
||||
#include "../common/mptAlloc.h"
|
||||
// "mptBaseMacros.h"
|
||||
// "mptMemory.h"
|
||||
// "mptSpan.h"
|
||||
// <array>
|
||||
// <memory>
|
||||
// <new>
|
||||
// <vector>
|
||||
|
||||
#include "../common/mptString.h"
|
||||
// <algorithm>
|
||||
// <limits>
|
||||
// <string>
|
||||
// <string_view>
|
||||
// <type_traits>
|
||||
// <cstring>
|
||||
|
||||
#include "../common/mptStringBuffer.h"
|
||||
|
||||
#include "../common/mptOSError.h"
|
||||
// "mptException.h"
|
||||
// "mptString.h"
|
||||
// <exception>
|
||||
// <stdexcept>
|
||||
|
||||
#include "../common/mptExceptionText.h"
|
||||
// "mptException.h"
|
||||
// "mptString.h"
|
||||
// <exception>
|
||||
|
||||
#include "../common/mptStringFormat.h"
|
||||
|
||||
#include "../common/mptPathString.h"
|
||||
|
||||
#include "../common/Logging.h"
|
||||
// <atomic>
|
||||
|
||||
#include "../common/misc_util.h"
|
||||
// <stdexcept>
|
||||
// <vector>
|
||||
|
||||
// for std::abs
|
||||
#include <cstdlib>
|
||||
#include <stdlib.h>
|
||||
#include <cmath>
|
||||
#include <math.h>
|
||||
|
||||
|
||||
//{{AFX_INSERT_LOCATION}}
|
||||
// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
|
||||
|
||||
#endif
|
|
@ -1,795 +0,0 @@
|
|||
/*
|
||||
* version.cpp
|
||||
* -----------
|
||||
* Purpose: OpenMPT version handling.
|
||||
* 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 "version.h"
|
||||
|
||||
#include "mptString.h"
|
||||
#include "mptStringFormat.h"
|
||||
#include "mptStringParse.h"
|
||||
|
||||
#include "versionNumber.h"
|
||||
#include "svn_version.h"
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
|
||||
#define MPT_MAKE_VERSION_NUMERIC_HELPER(prefix,v0,v1,v2,v3) Version( prefix ## v0 , prefix ## v1 , prefix ## v2 , prefix ## v3 )
|
||||
#define MPT_MAKE_VERSION_NUMERIC(v0,v1,v2,v3) MPT_MAKE_VERSION_NUMERIC_HELPER(0x, v0, v1, v2, v3)
|
||||
|
||||
#define MPT_VERSION_CURRENT MPT_MAKE_VERSION_NUMERIC(VER_MAJORMAJOR,VER_MAJOR,VER_MINOR,VER_MINORMINOR)
|
||||
|
||||
|
||||
|
||||
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).");
|
||||
|
||||
|
||||
|
||||
Version Version::Current() noexcept
|
||||
{
|
||||
return MPT_VERSION_CURRENT;
|
||||
}
|
||||
|
||||
mpt::ustring Version::GetOpenMPTVersionString() const
|
||||
{
|
||||
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);
|
||||
}
|
||||
return Version(result);
|
||||
}
|
||||
|
||||
mpt::ustring Version::ToUString() const
|
||||
{
|
||||
uint32 v = m_Version;
|
||||
if(v == 0)
|
||||
{
|
||||
// Unknown version
|
||||
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(U_("%1.%2"))(mpt::ufmt::HEX((v >> 24) & 0xFF), mpt::ufmt::HEX0<2>((v >> 16) & 0xFF));
|
||||
} else
|
||||
{
|
||||
// Full version info available
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
Version Version::WithoutTestNumber() const noexcept
|
||||
{
|
||||
return Version(m_Version & 0xFFFFFF00u);
|
||||
}
|
||||
|
||||
Version Version::WithoutPatchOrTestNumbers() const noexcept
|
||||
{
|
||||
return Version(m_Version & 0xFFFF0000u);
|
||||
}
|
||||
|
||||
bool Version::IsTestVersion() const noexcept
|
||||
{
|
||||
return (
|
||||
// Legacy
|
||||
(*this > MPT_V("1.17.02.54") && *this < MPT_V("1.18.02.00") && *this != MPT_V("1.18.00.00"))
|
||||
||
|
||||
// Test builds have non-zero VER_MINORMINOR
|
||||
(*this > MPT_V("1.18.02.00") && ((m_Version & 0xFFFFFF00u) != m_Version))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace Source {
|
||||
|
||||
static mpt::ustring GetUrl()
|
||||
{
|
||||
#ifdef OPENMPT_VERSION_URL
|
||||
return mpt::ToUnicode(mpt::Charset::ASCII, OPENMPT_VERSION_URL);
|
||||
#else
|
||||
return mpt::ustring();
|
||||
#endif
|
||||
}
|
||||
|
||||
static int GetRevision()
|
||||
{
|
||||
#if defined(OPENMPT_VERSION_REVISION)
|
||||
return OPENMPT_VERSION_REVISION;
|
||||
#elif defined(OPENMPT_VERSION_SVNVERSION)
|
||||
std::string svnversion = OPENMPT_VERSION_SVNVERSION;
|
||||
if(svnversion.length() == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if(svnversion.find(":") != std::string::npos)
|
||||
{
|
||||
svnversion = svnversion.substr(svnversion.find(":") + 1);
|
||||
}
|
||||
if(svnversion.find("-") != std::string::npos)
|
||||
{
|
||||
svnversion = svnversion.substr(svnversion.find("-") + 1);
|
||||
}
|
||||
if(svnversion.find("M") != std::string::npos)
|
||||
{
|
||||
svnversion = svnversion.substr(0, svnversion.find("M"));
|
||||
}
|
||||
if(svnversion.find("S") != std::string::npos)
|
||||
{
|
||||
svnversion = svnversion.substr(0, svnversion.find("S"));
|
||||
}
|
||||
if(svnversion.find("P") != std::string::npos)
|
||||
{
|
||||
svnversion = svnversion.substr(0, svnversion.find("P"));
|
||||
}
|
||||
return ConvertStrTo<int>(svnversion);
|
||||
#else
|
||||
MPT_WARNING_STATEMENT("SVN revision unknown. Please check your build system.");
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool IsDirty()
|
||||
{
|
||||
#if defined(OPENMPT_VERSION_DIRTY)
|
||||
return OPENMPT_VERSION_DIRTY != 0;
|
||||
#elif defined(OPENMPT_VERSION_SVNVERSION)
|
||||
std::string svnversion = OPENMPT_VERSION_SVNVERSION;
|
||||
if(svnversion.length() == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(svnversion.find("M") != std::string::npos)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool HasMixedRevisions()
|
||||
{
|
||||
#if defined(OPENMPT_VERSION_MIXEDREVISIONS)
|
||||
return OPENMPT_VERSION_MIXEDREVISIONS != 0;
|
||||
#elif defined(OPENMPT_VERSION_SVNVERSION)
|
||||
std::string svnversion = OPENMPT_VERSION_SVNVERSION;
|
||||
if(svnversion.length() == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(svnversion.find(":") != std::string::npos)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if(svnversion.find("-") != std::string::npos)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if(svnversion.find("S") != std::string::npos)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if(svnversion.find("P") != std::string::npos)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool IsPackage()
|
||||
{
|
||||
#if defined(OPENMPT_VERSION_IS_PACKAGE)
|
||||
return OPENMPT_VERSION_IS_PACKAGE != 0;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static mpt::ustring GetSourceDate()
|
||||
{
|
||||
#if defined(OPENMPT_VERSION_DATE)
|
||||
return mpt::ToUnicode(mpt::Charset::ASCII, OPENMPT_VERSION_DATE);
|
||||
#else
|
||||
return mpt::ustring();
|
||||
#endif
|
||||
}
|
||||
|
||||
} // 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())
|
||||
{
|
||||
}
|
||||
|
||||
mpt::ustring SourceInfo::GetUrlWithRevision() const
|
||||
{
|
||||
if(m_Url.empty() || (m_Revision == 0))
|
||||
{
|
||||
return mpt::ustring();
|
||||
}
|
||||
return m_Url + UL_("@") + mpt::ufmt::val(m_Revision);
|
||||
}
|
||||
|
||||
mpt::ustring SourceInfo::GetStateString() const
|
||||
{
|
||||
mpt::ustring retval;
|
||||
if(m_IsDirty)
|
||||
{
|
||||
retval += UL_("+dirty");
|
||||
}
|
||||
if(m_HasMixedRevisions)
|
||||
{
|
||||
retval += UL_("+mixed");
|
||||
}
|
||||
if(retval.empty())
|
||||
{
|
||||
retval += UL_("clean");
|
||||
}
|
||||
if(m_IsPackage)
|
||||
{
|
||||
retval += UL_("-pkg");
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
SourceInfo SourceInfo::Current()
|
||||
{
|
||||
return SourceInfo();
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace Build {
|
||||
|
||||
bool IsReleasedBuild()
|
||||
{
|
||||
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 defined(OPENMPT_BUILD_DATE)
|
||||
result = mpt::ToUnicode(mpt::Charset::ASCII, OPENMPT_BUILD_DATE );
|
||||
#else
|
||||
result = mpt::ToUnicode(mpt::Charset::ASCII, __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 += UL_(" TEST");
|
||||
}
|
||||
#endif // MODPLUG_TRACKER
|
||||
if(IsDebugBuild())
|
||||
{
|
||||
retval += UL_(" DEBUG");
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
mpt::ustring GetBuildFeaturesString()
|
||||
{
|
||||
mpt::ustring retval;
|
||||
#ifdef LIBOPENMPT_BUILD
|
||||
retval = UL_("")
|
||||
#if defined(MPT_WITH_ZLIB)
|
||||
UL_(" +ZLIB")
|
||||
#endif
|
||||
#if defined(MPT_WITH_MINIZ)
|
||||
UL_(" +MINIZ")
|
||||
#endif
|
||||
#if !defined(MPT_WITH_ZLIB) && !defined(MPT_WITH_MINIZ)
|
||||
UL_(" -INFLATE")
|
||||
#endif
|
||||
#if defined(MPT_WITH_MPG123)
|
||||
UL_(" +MPG123")
|
||||
#endif
|
||||
#if defined(MPT_WITH_MINIMP3)
|
||||
UL_(" +MINIMP3")
|
||||
#endif
|
||||
#if defined(MPT_WITH_MEDIAFOUNDATION)
|
||||
UL_(" +MF")
|
||||
#endif
|
||||
#if !defined(MPT_WITH_MPG123) && !defined(MPT_WITH_MINIMP3) && !defined(MPT_WITH_MEDIAFOUNDATION)
|
||||
UL_(" -MP3")
|
||||
#endif
|
||||
#if defined(MPT_WITH_OGG) && defined(MPT_WITH_VORBIS) && defined(MPT_WITH_VORBISFILE)
|
||||
UL_(" +VORBIS")
|
||||
#endif
|
||||
#if defined(MPT_WITH_STBVORBIS)
|
||||
UL_(" +STBVORBIS")
|
||||
#endif
|
||||
#if !(defined(MPT_WITH_OGG) && defined(MPT_WITH_VORBIS) && defined(MPT_WITH_VORBISFILE)) && !defined(MPT_WITH_STBVORBIS)
|
||||
UL_(" -VORBIS")
|
||||
#endif
|
||||
#if !defined(NO_PLUGINS)
|
||||
UL_(" +PLUGINS")
|
||||
#else
|
||||
UL_(" -PLUGINS")
|
||||
#endif
|
||||
#if defined(MPT_WITH_DMO)
|
||||
UL_(" +DMO")
|
||||
#endif
|
||||
;
|
||||
#endif
|
||||
#ifdef MODPLUG_TRACKER
|
||||
retval += UL_("")
|
||||
#if defined(UNICODE)
|
||||
UL_(" UNICODE")
|
||||
#else
|
||||
UL_(" ANSI")
|
||||
#endif
|
||||
#ifdef NO_VST
|
||||
UL_(" NO_VST")
|
||||
#endif
|
||||
#ifndef MPT_WITH_DMO
|
||||
UL_(" NO_DMO")
|
||||
#endif
|
||||
#ifdef NO_PLUGINS
|
||||
UL_(" NO_PLUGINS")
|
||||
#endif
|
||||
#ifndef MPT_WITH_ASIO
|
||||
UL_(" NO_ASIO")
|
||||
#endif
|
||||
;
|
||||
#endif
|
||||
return retval;
|
||||
}
|
||||
|
||||
mpt::ustring GetBuildCompilerString()
|
||||
{
|
||||
mpt::ustring retval;
|
||||
#if MPT_COMPILER_GENERIC
|
||||
retval += U_("Generic C++11 Compiler");
|
||||
#elif MPT_COMPILER_MSVC
|
||||
#if defined(_MSC_FULL_VER) && defined(_MSC_BUILD) && (_MSC_BUILD > 0)
|
||||
retval += mpt::format(U_("Microsoft Compiler %1.%2.%3.%4"))
|
||||
( _MSC_FULL_VER / 10000000
|
||||
, 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(U_("Microsoft Compiler %1.%2.%3"))
|
||||
( _MSC_FULL_VER / 10000000
|
||||
, mpt::ufmt::dec0<2>((_MSC_FULL_VER / 100000) % 100)
|
||||
, mpt::ufmt::dec0<5>(_MSC_FULL_VER % 100000)
|
||||
);
|
||||
#else
|
||||
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(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(U_("Clang %1.%2.%3"))(MPT_COMPILER_CLANG_VERSION / 10000, (MPT_COMPILER_CLANG_VERSION / 100) % 100, MPT_COMPILER_CLANG_VERSION % 100);
|
||||
#else
|
||||
retval += U_("unknown");
|
||||
#endif
|
||||
return retval;
|
||||
}
|
||||
|
||||
static mpt::ustring GetRevisionString()
|
||||
{
|
||||
mpt::ustring result;
|
||||
if(Source::GetRevision() == 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
result = U_("-r") + mpt::ufmt::val(Source::GetRevision());
|
||||
if(Source::HasMixedRevisions())
|
||||
{
|
||||
result += UL_("!");
|
||||
}
|
||||
if(Source::IsDirty())
|
||||
{
|
||||
result += UL_("+");
|
||||
}
|
||||
if(Source::IsPackage())
|
||||
{
|
||||
result += UL_("p");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
mpt::ustring GetVersionString(FlagSet<Build::Strings> strings)
|
||||
{
|
||||
std::vector<mpt::ustring> result;
|
||||
if(strings[StringVersion])
|
||||
{
|
||||
result.push_back(mpt::ufmt::val(Version::Current()));
|
||||
}
|
||||
if(strings[StringRevision])
|
||||
{
|
||||
if(!IsReleasedBuild())
|
||||
{
|
||||
result.push_back(GetRevisionString());
|
||||
}
|
||||
}
|
||||
if(strings[StringBitness])
|
||||
{
|
||||
result.push_back(mpt::format(U_(" %1 bit"))(mpt::arch_bits));
|
||||
}
|
||||
if(strings[StringSourceInfo])
|
||||
{
|
||||
const SourceInfo sourceInfo = SourceInfo::Current();
|
||||
if(!sourceInfo.GetUrlWithRevision().empty())
|
||||
{
|
||||
result.push_back(mpt::format(U_(" %1"))(sourceInfo.GetUrlWithRevision()));
|
||||
}
|
||||
if(!sourceInfo.Date().empty())
|
||||
{
|
||||
result.push_back(mpt::format(U_(" (%1)"))(sourceInfo.Date()));
|
||||
}
|
||||
if(!sourceInfo.GetStateString().empty())
|
||||
{
|
||||
result.push_back(mpt::format(U_(" %1"))(sourceInfo.GetStateString()));
|
||||
}
|
||||
}
|
||||
if(strings[StringBuildFlags])
|
||||
{
|
||||
if(!IsReleasedBuild())
|
||||
{
|
||||
result.push_back(GetBuildFlagsString());
|
||||
}
|
||||
}
|
||||
if(strings[StringBuildFeatures])
|
||||
{
|
||||
result.push_back(GetBuildFeaturesString());
|
||||
}
|
||||
return mpt::String::Trim(mpt::String::Combine<mpt::ustring>(result, U_("")));
|
||||
}
|
||||
|
||||
mpt::ustring GetVersionStringPure()
|
||||
{
|
||||
FlagSet<Build::Strings> strings;
|
||||
strings |= Build::StringVersion;
|
||||
strings |= Build::StringRevision;
|
||||
#ifdef MODPLUG_TRACKER
|
||||
strings |= Build::StringBitness;
|
||||
#endif
|
||||
return GetVersionString(strings);
|
||||
}
|
||||
|
||||
mpt::ustring GetVersionStringSimple()
|
||||
{
|
||||
FlagSet<Build::Strings> strings;
|
||||
strings |= Build::StringVersion;
|
||||
strings |= Build::StringRevision;
|
||||
strings |= Build::StringBuildFlags;
|
||||
return GetVersionString(strings);
|
||||
}
|
||||
|
||||
mpt::ustring GetVersionStringExtended()
|
||||
{
|
||||
FlagSet<Build::Strings> strings;
|
||||
strings |= Build::StringVersion;
|
||||
strings |= Build::StringRevision;
|
||||
#ifdef MODPLUG_TRACKER
|
||||
strings |= Build::StringBitness;
|
||||
#endif
|
||||
#ifndef MODPLUG_TRACKER
|
||||
strings |= Build::StringSourceInfo;
|
||||
#endif
|
||||
strings |= Build::StringBuildFlags;
|
||||
#ifdef MODPLUG_TRACKER
|
||||
strings |= Build::StringBuildFeatures;
|
||||
#endif
|
||||
return GetVersionString(strings);
|
||||
}
|
||||
|
||||
mpt::ustring GetURL(Build::Url key)
|
||||
{
|
||||
mpt::ustring result;
|
||||
switch(key)
|
||||
{
|
||||
case Url::Website:
|
||||
#ifdef LIBOPENMPT_BUILD
|
||||
result = U_("https://lib.openmpt.org/");
|
||||
#else
|
||||
result = U_("https://openmpt.org/");
|
||||
#endif
|
||||
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;
|
||||
}
|
||||
|
||||
mpt::ustring GetFullCreditsString()
|
||||
{
|
||||
return mpt::ToUnicode(mpt::Charset::UTF8,
|
||||
#ifdef MODPLUG_TRACKER
|
||||
"OpenMPT / ModPlug Tracker\n"
|
||||
#else
|
||||
"libopenmpt (based on OpenMPT / ModPlug Tracker)\n"
|
||||
#endif
|
||||
"\n"
|
||||
"Copyright \xC2\xA9 2004-2022 Contributors\n"
|
||||
"Copyright \xC2\xA9 1997-2003 Olivier Lapicque\n"
|
||||
"\n"
|
||||
"Contributors:\n"
|
||||
"Johannes Schultz (2008-2022)\n"
|
||||
"J\xC3\xB6rn Heusipp (2012-2022)\n"
|
||||
"Ahti Lepp\xC3\xA4nen (2005-2011)\n"
|
||||
"Robin Fernandes (2004-2007)\n"
|
||||
"Sergiy Pylypenko (2007)\n"
|
||||
"Eric Chavanon (2004-2005)\n"
|
||||
"Trevor Nunes (2004)\n"
|
||||
"Olivier Lapicque (1997-2003)\n"
|
||||
"\n"
|
||||
"Additional patch submitters:\n"
|
||||
"coda (https://coda.s3m.us/)\n"
|
||||
"Jo\xC3\xA3o Baptista de Paula e Silva (https://joaobapt.com/)\n"
|
||||
"kode54 (https://kode54.net/)\n"
|
||||
"Revenant (https://revenant1.net/)\n"
|
||||
"xaimus (http://xaimus.com/)\n"
|
||||
"\n"
|
||||
"Thanks to:\n"
|
||||
"\n"
|
||||
"Konstanty for the XMMS-ModPlug resampling implementation\n"
|
||||
"http://modplug-xmms.sourceforge.net/\n"
|
||||
"\n"
|
||||
#ifdef MODPLUG_TRACKER
|
||||
"Stephan M. Bernsee for pitch shifting source code\n"
|
||||
"http://www.dspdimension.com/\n"
|
||||
"\n"
|
||||
"Aleksey Vaneev of Voxengo for r8brain sample rate converter\n"
|
||||
"https://github.com/avaneev/r8brain-free-src\n"
|
||||
"\n"
|
||||
"Olli Parviainen for SoundTouch Library (time stretching)\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"
|
||||
"http://schismtracker.org/\n"
|
||||
"\n"
|
||||
"Sergei \"x0r\" Kolzun for various hints on Scream Tracker 2 compatibility\n"
|
||||
"https://github.com/viiri/st2play\n"
|
||||
"\n"
|
||||
"Laurent Cl\xc3\xA9vy for unofficial MO3 documentation and decompression code\n"
|
||||
"https://github.com/lclevy/unmo3\n"
|
||||
"\n"
|
||||
"Ben \"GreaseMonkey\" Russell for IT sample compression code\n"
|
||||
"https://github.com/iamgreaser/it2everything/\n"
|
||||
"\n"
|
||||
"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"
|
||||
"Ryuhei Mori for TinyFFT\n"
|
||||
"https://github.com/ryuhei-mori/tinyfft\n"
|
||||
"\n"
|
||||
#ifdef MPT_WITH_ZLIB
|
||||
"Jean-loup Gailly and Mark Adler for zlib\n"
|
||||
"https://zlib.net/\n"
|
||||
"\n"
|
||||
#endif
|
||||
#ifdef MPT_WITH_MINIZ
|
||||
"Rich Geldreich et al. for miniz\n"
|
||||
"https://github.com/richgel999/miniz\n"
|
||||
"\n"
|
||||
#endif
|
||||
#ifdef MPT_WITH_LHASA
|
||||
"Simon Howard for lhasa\n"
|
||||
"https://fragglet.github.io/lhasa/\n"
|
||||
"\n"
|
||||
#endif
|
||||
#ifdef MPT_WITH_UNRAR
|
||||
"Alexander L. Roshal for UnRAR\n"
|
||||
"https://rarlab.com/\n"
|
||||
"\n"
|
||||
#endif
|
||||
#ifdef MPT_WITH_PORTAUDIO
|
||||
"PortAudio contributors\n"
|
||||
"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"
|
||||
"\n"
|
||||
#endif
|
||||
#if defined(MPT_WITH_MPG123)
|
||||
"The mpg123 project for libmpg123\n"
|
||||
"https://mpg123.de/\n"
|
||||
"\n"
|
||||
#endif
|
||||
#ifdef MPT_WITH_MINIMP3
|
||||
"Lion (github.com/lieff) for minimp3\n"
|
||||
"https://github.com/lieff/minimp3/\n"
|
||||
"\n"
|
||||
#endif
|
||||
#ifdef MPT_WITH_STBVORBIS
|
||||
"Sean Barrett for stb_vorbis\n"
|
||||
"https://github.com/nothings/stb/\n"
|
||||
"\n"
|
||||
#endif
|
||||
#ifdef MPT_WITH_OGG
|
||||
"Xiph.Org Foundation for libogg\n"
|
||||
"https://xiph.org/ogg/\n"
|
||||
"\n"
|
||||
#endif
|
||||
#if defined(MPT_WITH_VORBIS) || defined(MPT_WITH_LIBVORBISFILE)
|
||||
"Xiph.Org Foundation for libvorbis\n"
|
||||
"https://xiph.org/vorbis/\n"
|
||||
"\n"
|
||||
#endif
|
||||
#if defined(MPT_WITH_OPUS)
|
||||
"Xiph.Org, Skype Limited, Octasic, Jean-Marc Valin, Timothy B. Terriberry,\n"
|
||||
"CSIRO, Gregory Maxwell, Mark Borgerding, Erik de Castro Lopo,\n"
|
||||
"Xiph.Org Foundation, Microsoft Corporation, Broadcom Corporation for libopus\n"
|
||||
"https://opus-codec.org/\n"
|
||||
"\n"
|
||||
#endif
|
||||
#if defined(MPT_WITH_OPUSFILE)
|
||||
"Xiph.Org Foundation and contributors for libopusfile\n"
|
||||
"https://opus-codec.org/\n"
|
||||
"\n"
|
||||
#endif
|
||||
#if defined(MPT_WITH_OPUSENC)
|
||||
"Xiph.Org Foundation, Jean-Marc Valin and contributors for libopusenc\n"
|
||||
"https://git.xiph.org/?p=libopusenc.git;a=summary\n"
|
||||
"\n"
|
||||
#endif
|
||||
#if defined(MPT_WITH_LAME)
|
||||
"The LAME project for LAME\n"
|
||||
"https://lame.sourceforge.io/\n"
|
||||
"\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
|
||||
"Lennart Poettering and David Henningsson for RealtimeKit\n"
|
||||
"http://git.0pointer.net/rtkit.git/\n"
|
||||
"\n"
|
||||
"Gary P. Scavone for RtMidi\n"
|
||||
"https://www.music.mcgill.ca/~gary/rtmidi/\n"
|
||||
"\n"
|
||||
"Alexander Uckun for decimal input field\n"
|
||||
"https://www.codeproject.com/Articles/21257/_\n"
|
||||
"\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
|
||||
"Daniel Collin (emoon/TBL) for providing test infrastructure\n"
|
||||
"https://twitter.com/daniel_collin\n"
|
||||
"\n"
|
||||
"The people at ModPlug forums for crucial contribution\n"
|
||||
"in the form of ideas, testing and support;\n"
|
||||
"thanks particularly to:\n"
|
||||
"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, Teimoso, Waxhead\n"
|
||||
"\n"
|
||||
#ifndef NO_VST
|
||||
"VST PlugIn Technology by Steinberg Media Technologies GmbH\n"
|
||||
"\n"
|
||||
#endif
|
||||
#ifdef MPT_WITH_ASIO
|
||||
"ASIO Technology by Steinberg Media Technologies GmbH\n"
|
||||
"\n"
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
mpt::ustring GetLicenseString()
|
||||
{
|
||||
return MPT_UTF8(
|
||||
"Copyright (c) 2004-2022, OpenMPT contributors" "\n"
|
||||
"Copyright (c) 1997-2003, Olivier Lapicque" "\n"
|
||||
"All rights reserved." "\n"
|
||||
"" "\n"
|
||||
"Redistribution and use in source and binary forms, with or without" "\n"
|
||||
"modification, are permitted provided that the following conditions are met:" "\n"
|
||||
" * Redistributions of source code must retain the above copyright" "\n"
|
||||
" notice, this list of conditions and the following disclaimer." "\n"
|
||||
" * Redistributions in binary form must reproduce the above copyright" "\n"
|
||||
" notice, this list of conditions and the following disclaimer in the" "\n"
|
||||
" documentation and/or other materials provided with the distribution." "\n"
|
||||
" * Neither the name of the OpenMPT project nor the" "\n"
|
||||
" names of its contributors may be used to endorse or promote products" "\n"
|
||||
" derived from this software without specific prior written permission." "\n"
|
||||
"" "\n"
|
||||
"THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY" "\n"
|
||||
"EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED" "\n"
|
||||
"WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE" "\n"
|
||||
"DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY" "\n"
|
||||
"DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES" "\n"
|
||||
"(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;" "\n"
|
||||
"LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND" "\n"
|
||||
"ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT" "\n"
|
||||
"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS" "\n"
|
||||
"SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." "\n"
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace Build
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,311 +0,0 @@
|
|||
/*
|
||||
* version.h
|
||||
* ---------
|
||||
* Purpose: OpenMPT version handling.
|
||||
* 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 "FlagSet.h"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
class Version
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
uint32 m_Version; // e.g. 0x01170208
|
||||
|
||||
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.
|
||||
static Version Parse(const mpt::ustring &s);
|
||||
|
||||
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.
|
||||
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 IsTestVersion() const noexcept;
|
||||
|
||||
public:
|
||||
|
||||
struct LiteralParser
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
// Work-around for GCC 5 which complains about instanciating non-literal type inside a constexpr function when using mpt::constexpr_throw(std::runtime_error("")).
|
||||
struct ParseException {};
|
||||
|
||||
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) :
|
||||
mpt::constexpr_throw<uint8>(std::domain_error(""));
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
static MPT_CONSTEXPR14_FUN Version Parse(const char * str, std::size_t len)
|
||||
{
|
||||
// 0123456789
|
||||
// 1.23.45.67
|
||||
uint8 v[4] = {0, 0, 0, 0};
|
||||
std::size_t field = 0;
|
||||
std::size_t fieldlen = 0;
|
||||
for(std::size_t i = 0; i < len; ++i)
|
||||
{
|
||||
char c = str[i];
|
||||
if(c == '.')
|
||||
{
|
||||
if(field >= 3)
|
||||
{
|
||||
mpt::constexpr_throw(ParseException());
|
||||
}
|
||||
if(fieldlen == 0)
|
||||
{
|
||||
mpt::constexpr_throw(ParseException());
|
||||
}
|
||||
field++;
|
||||
fieldlen = 0;
|
||||
} else if(('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'))
|
||||
{
|
||||
fieldlen++;
|
||||
if(fieldlen > 2)
|
||||
{
|
||||
mpt::constexpr_throw(ParseException());
|
||||
}
|
||||
v[field] <<= 4;
|
||||
v[field] |= NibbleFromChar(c);
|
||||
} else
|
||||
{
|
||||
mpt::constexpr_throw(ParseException());
|
||||
}
|
||||
}
|
||||
if(fieldlen == 0)
|
||||
{
|
||||
mpt::constexpr_throw(ParseException());
|
||||
}
|
||||
return Version(v[0], v[1], v[2], v[3]);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
MPT_CONSTEXPR14_FUN Version operator "" _LiteralVersionImpl (const char * str, std::size_t len)
|
||||
{
|
||||
return Version::LiteralParser::Parse(str, len);
|
||||
}
|
||||
|
||||
// Create Version object from version string and check syntax, all at compile time.
|
||||
// cppcheck false-positive
|
||||
// cppcheck-suppress preprocessorErrorDirective
|
||||
#define MPT_V(strver) Version{MPT_FORCE_CONSTEXPR(( strver ## _LiteralVersionImpl ).GetRawVersion())}
|
||||
|
||||
|
||||
|
||||
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();
|
||||
|
||||
// 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)
|
||||
mpt::ustring GetBuildDateString();
|
||||
|
||||
// Return a string decribing some of the build features
|
||||
mpt::ustring GetBuildFeaturesString(); // e.g. " NO_VST NO_DSOUND"
|
||||
|
||||
// Return a string describing the compiler version used for building.
|
||||
mpt::ustring GetBuildCompilerString(); // e.g. "Microsoft Compiler 15.00.20706.01"
|
||||
|
||||
enum Strings
|
||||
{
|
||||
StringsNone = 0,
|
||||
StringVersion = 1<<0, // "1.23.35.45"
|
||||
StringRevision = 1<<2, // "-r1234+"
|
||||
StringBitness = 1<<3, // "32 bit"
|
||||
StringSourceInfo = 1<<4, // "https://source.openmpt.org/svn/openmpt/trunk/OpenMPT@1234 (2016-01-02) +dirty"
|
||||
StringBuildFlags = 1<<5, // "TEST DEBUG"
|
||||
StringBuildFeatures = 1<<6, // "NO_VST NO_DSOUND"
|
||||
};
|
||||
MPT_DECLARE_ENUM(Strings)
|
||||
|
||||
// Returns a versions string with the fields selected via @strings.
|
||||
mpt::ustring GetVersionString(FlagSet<Build::Strings> strings);
|
||||
|
||||
// Returns a pure version string
|
||||
mpt::ustring GetVersionStringPure(); // e.g. "1.17.02.08-r1234+ 32 bit"
|
||||
|
||||
// Returns a simple version string
|
||||
mpt::ustring GetVersionStringSimple(); // e.g. "1.17.02.08-r1234+ TEST"
|
||||
|
||||
// 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"
|
||||
|
||||
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();
|
||||
|
||||
// Returns the OpenMPT license text
|
||||
mpt::ustring GetLicenseString();
|
||||
|
||||
} //namespace Build
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,23 +0,0 @@
|
|||
/*
|
||||
* versionNumber.h
|
||||
* ---------------
|
||||
* Purpose: OpenMPT version number.
|
||||
* 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"
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
// Version definitions. The only thing that needs to be changed when changing version number.
|
||||
#define VER_MAJORMAJOR 1
|
||||
#define VER_MAJOR 29
|
||||
#define VER_MINOR 15
|
||||
#define VER_MINORMINOR 08
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
|
@ -1,304 +0,0 @@
|
|||
669="if"
|
||||
669="JN"
|
||||
|
||||
amf="ASYLUM Music Format V1.0\x00"
|
||||
amf="AMF\x0A"
|
||||
|
||||
ams="Extreme"
|
||||
ams="AMShdr\x1A\x02\x02"
|
||||
|
||||
#dbm="DBM0"
|
||||
dbm="NAME"
|
||||
dbm="INFO"
|
||||
dbm="SONG"
|
||||
dbm="INST"
|
||||
dbm="VENV"
|
||||
dbm="PENV"
|
||||
dbm="PNAM"
|
||||
dbm="SMPL"
|
||||
dbm="DSPE"
|
||||
#dbm="MPEG"
|
||||
|
||||
digi="DIGI Booster module\x00"
|
||||
|
||||
dmf="DDMF"
|
||||
#dmf="XTRACKER"
|
||||
dmf="CMSG"
|
||||
dmf="SEQU"
|
||||
dmf="SMPI"
|
||||
dmf="SMPD"
|
||||
#dmf="SMPJ"
|
||||
#dmf="ENDE"
|
||||
#dmf="SETT"
|
||||
|
||||
dsm="RIFF"
|
||||
dsm="DSMF"
|
||||
|
||||
dtm="D.T."
|
||||
dtm="S.Q."
|
||||
#dtm="PATT"
|
||||
#dtm="INST"
|
||||
dtm="DAPT"
|
||||
dtm="DAIT"
|
||||
|
||||
far="FAR\xFE"
|
||||
far="\x0D\x0A\x1A"
|
||||
|
||||
gdm="GDM\xFE"
|
||||
gdm="GMFS"
|
||||
|
||||
imf="IM10"
|
||||
imf="IS10"
|
||||
|
||||
it="IMPM"
|
||||
it="IMPI"
|
||||
it="IMPS"
|
||||
#it="OMPT"
|
||||
it="PNAM"
|
||||
it="CNAM"
|
||||
it="STPM"
|
||||
it="XTPM"
|
||||
it="CHBI"
|
||||
it="FX00"
|
||||
it="F255"
|
||||
it="DWRT"
|
||||
it="PROG"
|
||||
it="CHFX"
|
||||
|
||||
it="..TD"
|
||||
it="DTFR"
|
||||
it=".BPR"
|
||||
it=".MPR"
|
||||
it="...C"
|
||||
it="SnhC"
|
||||
it="..MT"
|
||||
it=".MMP"
|
||||
it=".VWC"
|
||||
it="VWSL"
|
||||
it=".APS"
|
||||
it="VTSV"
|
||||
it=".VGD"
|
||||
it="..PR"
|
||||
it="RSMP"
|
||||
it="CUES"
|
||||
it="SWNG"
|
||||
it=".FSM"
|
||||
it="AUTH"
|
||||
|
||||
itp=".pti\x03\x01\x00\x00"
|
||||
|
||||
j2b="MUSE\xDE\xAD\xBE\xAF"
|
||||
j2b="MUSE\xDE\xAD\xBA\xBE"
|
||||
j2b="AMFF"
|
||||
j2b="AM "
|
||||
j2b="MAIN"
|
||||
j2b="INIT"
|
||||
j2b="ORDR"
|
||||
j2b="AI "
|
||||
j2b="AS "
|
||||
|
||||
MDL="DMDL"
|
||||
# Most chunk IDs are commented out as they are substrings of other dictionary entries
|
||||
#mdl="IN"
|
||||
mdl="ME"
|
||||
#mdl="PA"
|
||||
#mdl="TR"
|
||||
mdl="II"
|
||||
#mdl="VE"
|
||||
#mdl="PE"
|
||||
#mdl="FE"
|
||||
#mdl="IS"
|
||||
#mdl="SA"
|
||||
|
||||
med="MMD1"
|
||||
|
||||
mo3="MO3\x05"
|
||||
|
||||
# A couple of magic bytes are commented out because they do not modify the loader's behaviour, apart from setting a "made with" string.
|
||||
mod="M.K."
|
||||
#mod="M!K!"
|
||||
mod="M&K!"
|
||||
mod="N.T."
|
||||
#mod="FEST"
|
||||
#mod="NSMS"
|
||||
#mod="LARD"
|
||||
mod="OKTA"
|
||||
#mod="OCTA"
|
||||
#mod="CD61"
|
||||
mod="CD81"
|
||||
#mod="FA08"
|
||||
mod="FLT8"
|
||||
#mod="EXO8"
|
||||
# Depending on the byte offset in the file, we generate either a "xCHN" or "xxCH" magic
|
||||
mod="99CHN"
|
||||
mod="TDZ8"
|
||||
ice="MTN\x00"
|
||||
ice="IT10"
|
||||
pt36="CMNT"
|
||||
pt36="PTDT"
|
||||
sfx="SO31"
|
||||
# External Startrekker instrument files.
|
||||
stam="ST1.3 ModuleINFO"
|
||||
stam="AudioSculpture10"
|
||||
|
||||
mptm="->MPT_ORIGINAL_IT<-"
|
||||
mptm=".tpm"
|
||||
mptm="mptm"
|
||||
mptm="\x89\x08"
|
||||
mptm="\x8D\x08"
|
||||
# No structural changes in these format versions
|
||||
#mptm="\x8E\x08"
|
||||
#mptm="\x8F\x08"
|
||||
#mptm="\x90\x08"
|
||||
mptm="\x91\x08"
|
||||
mptm="228\x04"
|
||||
|
||||
mt2="MT20"
|
||||
#mt2="MadTracker 2.0"
|
||||
mt2="BPM+"
|
||||
mt2="TFXM"
|
||||
mt2="TRKS"
|
||||
mt2="TRKL"
|
||||
mt2="PATN"
|
||||
mt2="MSG\x00"
|
||||
#mt2="PICT"
|
||||
mt2="SUM\x00"
|
||||
mt2="VST2"
|
||||
|
||||
mtm="MTM\x10"
|
||||
|
||||
okt="OKTASONG"
|
||||
okt="CMOD"
|
||||
okt="SAMP"
|
||||
okt="SPEE"
|
||||
okt="SLEN"
|
||||
okt="PLEN"
|
||||
okt="PATT"
|
||||
okt="PBOD"
|
||||
okt="SBOD"
|
||||
|
||||
plm="PLM\x1A"
|
||||
plm="PLS\x1A"
|
||||
|
||||
psm="PSM "
|
||||
psm="FILE"
|
||||
psm="TITL"
|
||||
psm="SDFT"
|
||||
psm="DATE"
|
||||
psm="OPLH"
|
||||
psm="PPAN"
|
||||
psm="DSAM"
|
||||
psm="DSMP"
|
||||
psm="MAINSONG"
|
||||
psm="\x00\xFF\x00\x00\x01\x00"
|
||||
psm16="PSM\xFE"
|
||||
psm16="PORD"
|
||||
#psm16="PPAN"
|
||||
psm16="PSAH"
|
||||
psm16="PPAT"
|
||||
|
||||
ptm="PTMF"
|
||||
ptm="\x1A\x03\x02"
|
||||
|
||||
s3m="SCRM"
|
||||
#s3m="SCRS"
|
||||
#s3m="SCRI"
|
||||
|
||||
stm="\x1A\x02\x15"
|
||||
|
||||
stp="STP3\x02"
|
||||
|
||||
ult="MAS_UTrack_V004"
|
||||
|
||||
umx="\xC1\x83\x2A\x9E"
|
||||
umx="music"
|
||||
umx="sound"
|
||||
|
||||
xm="Extended Module: "
|
||||
xm="OpenMPT "
|
||||
#xm="FastTracker v 2.00 "
|
||||
xm="MilkyTracker "
|
||||
xm="text"
|
||||
xm="MIDI"
|
||||
|
||||
it="..OF"
|
||||
it="LTTP"
|
||||
it="PTTF"
|
||||
it="..Fd"
|
||||
it="..VG"
|
||||
it="...P"
|
||||
it="..EV"
|
||||
it="..EP"
|
||||
it=".EiP"
|
||||
it=".SLV"
|
||||
it=".ELV"
|
||||
it=".BSV"
|
||||
it=".ESV"
|
||||
it=".SLP"
|
||||
it=".ELP"
|
||||
it=".BSP"
|
||||
it=".ESP"
|
||||
it="SLiP"
|
||||
it="ELiP"
|
||||
it="BSiP"
|
||||
it="ESiP"
|
||||
it=".ANN"
|
||||
it=".TCD"
|
||||
it=".AND"
|
||||
it="..SP"
|
||||
it="..SV"
|
||||
it=".CFI"
|
||||
it=".RFI"
|
||||
it="..BM"
|
||||
it="..PM"
|
||||
it="..CM"
|
||||
it=".SPP"
|
||||
it=".CPP"
|
||||
it=".[PV"
|
||||
it=".[PP"
|
||||
it="[PiP"
|
||||
it=".[EV"
|
||||
it=".[EP"
|
||||
it="[EiP"
|
||||
it="..[K"
|
||||
it="..[n"
|
||||
it=".[MN"
|
||||
it=".[nf"
|
||||
it=".PiM"
|
||||
it="..RV"
|
||||
it="...R"
|
||||
it="..SC"
|
||||
it="..SR"
|
||||
it="..MF"
|
||||
it="HEVP"
|
||||
it="HOVP"
|
||||
it="NREP"
|
||||
it="NREA"
|
||||
it="NREV"
|
||||
it="GLFP"
|
||||
it="GLFA"
|
||||
it="GLFV"
|
||||
it="DWPM"
|
||||
|
||||
mmcmp="ziRCONia\x0e\x00"
|
||||
|
||||
xpk="XPKF\x00\x10\x00\x00SQSH"
|
||||
|
||||
pp20="PP20"
|
||||
|
||||
plugin_chorus="OMXD\x9C\x62\xE6\xEF"
|
||||
plugin_compressor="OMXD\x79\x1F\x01\xEF"
|
||||
plugin_distortion="OMXD\x90\x4C\x11\xEF"
|
||||
plugin_echo="OMXD\x2C\x93\x3E\xEF"
|
||||
plugin_flanger="OMXD\x92\x3D\xCA\xEF"
|
||||
plugin_gargle="OMXD\x10\x82\xFD\xDA"
|
||||
plugin_i3dl2reverb="OMXD\x71\x5E\x98\xEF"
|
||||
plugin_parameq="OMXD\x89\xED\x0C\x12"
|
||||
plugin_wavesreverb="OMDX\x68\x02\xFC\x87"
|
||||
plugin_lfo="OMPTLFO "
|
||||
plugin_dbproecho="DBM0Echo"
|
||||
|
||||
midi="MThd\x00\x00\x00\x06\x00\x01\x00\x01\x01\xE0MTrk"
|
||||
|
||||
wave="WAVEfmt "
|
||||
wave="data"
|
|
@ -1,4 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
cd "${0%/*}"
|
||||
cd ../..
|
||||
AFL_HARDEN=1 CONFIG=afl make clean all EXAMPLES=0 TEST=0 OPENMPT123=0 NO_VORBIS=1 NO_VORBISFILE=1 NO_MPG123=1 CHECKED_ADDRESS=1
|
|
@ -1,13 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
cd "${0%/*}"
|
||||
. ./fuzz-settings.sh
|
||||
|
||||
# Create tmpfs for storing temporary fuzzing data
|
||||
mkdir $FUZZING_TEMPDIR
|
||||
sudo mount -t tmpfs -o size=300M none $FUZZING_TEMPDIR
|
||||
rm -rf $FUZZING_TEMPDIR/bin
|
||||
mkdir $FUZZING_TEMPDIR/bin
|
||||
cp -d ../../bin/* $FUZZING_TEMPDIR/bin/
|
||||
|
||||
#export AFL_PRELOAD=$AFL_DIR/libdislocator.so
|
||||
LD_LIBRARY_PATH=$FUZZING_TEMPDIR/bin $AFL_DIR/afl-fuzz -p exploit -f $FUZZING_TEMPDIR/infile01 -x all_formats.dict -t $FUZZING_TIMEOUT $FUZZING_INPUT -o $FUZZING_FINDINGS_DIR -D -M fuzzer01 $FUZZING_TEMPDIR/bin/fuzz $FUZZING_TEMPDIR/infile01
|
|
@ -1,6 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
cd "${0%/*}"
|
||||
. ./fuzz-settings.sh
|
||||
|
||||
#export AFL_PRELOAD=$AFL_DIR/libdislocator.so
|
||||
LD_LIBRARY_PATH=$FUZZING_TEMPDIR/bin $AFL_DIR/afl-fuzz -p coe -f $FUZZING_TEMPDIR/infile02 -x all_formats.dict -t $FUZZING_TIMEOUT $FUZZING_INPUT -o $FUZZING_FINDINGS_DIR -S fuzzer02 $FUZZING_TEMPDIR/bin/fuzz $FUZZING_TEMPDIR/infile02
|
|
@ -1,6 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
cd "${0%/*}"
|
||||
. ./fuzz-settings.sh
|
||||
|
||||
#export AFL_PRELOAD=$AFL_DIR/libdislocator.so
|
||||
LD_LIBRARY_PATH=$FUZZING_TEMPDIR/bin $AFL_DIR/afl-fuzz -p explore -f $FUZZING_TEMPDIR/infile03 -x all_formats.dict -t $FUZZING_TIMEOUT $FUZZING_INPUT -o $FUZZING_FINDINGS_DIR -S fuzzer03 $FUZZING_TEMPDIR/bin/fuzz $FUZZING_TEMPDIR/infile03
|
|
@ -1,18 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Input data for fuzzer
|
||||
# If you run the fuzzer for the first time, specify a directory with some input
|
||||
# files for the fuzzer, e.g.
|
||||
# FUZZING_INPUT="-i /home/foo/testcases/"
|
||||
# If you want to continue fuzzing using the previous findings, use:
|
||||
# FUZZING_INPUT=-i-
|
||||
FUZZING_INPUT=-i-
|
||||
|
||||
# Directory to place temporary fuzzing data into
|
||||
FUZZING_TEMPDIR=~/libopenmpt-fuzzing-temp
|
||||
# Directory to store permanent fuzzing data (e.g. found crashes) into
|
||||
FUZZING_FINDINGS_DIR=~/libopenmpt-fuzzing
|
||||
# Fuzzer timeout in ms, + = don't abort on timeout
|
||||
FUZZING_TIMEOUT=5000+
|
||||
# Path to afl-fuzz binary
|
||||
AFL_DIR=afl
|
|
@ -1,59 +0,0 @@
|
|||
/*
|
||||
* fuzz.c
|
||||
* ------
|
||||
* Purpose: Tiny libopenmpt user to be used by fuzzing tools
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
#include <memory.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libopenmpt/libopenmpt.h>
|
||||
#include <libopenmpt/libopenmpt_stream_callbacks_file.h>
|
||||
|
||||
#define BUFFERSIZE 450 // shouldn't match OpenMPT's internal mix buffer size (512)
|
||||
#define SAMPLERATE 22050
|
||||
|
||||
static int16_t buffer[BUFFERSIZE];
|
||||
|
||||
int main( int argc, char * argv[] ) {
|
||||
static FILE * file = NULL;
|
||||
static openmpt_module * mod = NULL;
|
||||
static size_t count = 0;
|
||||
static int i = 0;
|
||||
(void)argc;
|
||||
#ifdef __AFL_HAVE_MANUAL_CONTROL
|
||||
__AFL_INIT();
|
||||
#endif
|
||||
file = fopen( argv[1], "rb" );
|
||||
mod = openmpt_module_create( openmpt_stream_get_file_callbacks(), file, NULL, NULL, NULL );
|
||||
fclose( file );
|
||||
if ( mod == NULL ) return 1;
|
||||
openmpt_module_ctl_set( mod, "render.resampler.emulate_amiga", (openmpt_module_get_num_orders( mod ) & 1) ? "0" : "1" );
|
||||
/* render about a second of the module for fuzzing the actual mix routines */
|
||||
for(; i < 50; i++) {
|
||||
count = openmpt_module_read_mono( mod, SAMPLERATE, BUFFERSIZE, buffer );
|
||||
if ( count == 0 ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
openmpt_module_set_position_seconds( mod, 1.0 );
|
||||
openmpt_module_read_mono( mod, SAMPLERATE, BUFFERSIZE, buffer );
|
||||
openmpt_module_set_position_order_row( mod, 3, 16 );
|
||||
openmpt_module_read_mono( mod, SAMPLERATE, BUFFERSIZE, buffer );
|
||||
|
||||
/* fuzz string-related stuff */
|
||||
openmpt_free_string ( openmpt_module_get_metadata( mod, "date" ) );
|
||||
openmpt_free_string ( openmpt_module_get_metadata( mod, "message" ) );
|
||||
openmpt_module_destroy( mod );
|
||||
return 0;
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
cd "${0%/*}"
|
||||
|
||||
GET_AFL_VERSION?="$(wget --quiet -O - "https://api.github.com/repos/AFLplusplus/AFLplusplus/releases/latest" | grep -Po '"tag_name": "\K.*?(?=")')"
|
||||
AFL_FILENAME="$GET_AFL_VERSION.tar.gz"
|
||||
AFL_URL="https://github.com/AFLplusplus/AFLplusplus/archive/$AFL_FILENAME"
|
||||
|
||||
rm $AFL_FILENAME
|
||||
wget $AFL_URL || exit
|
||||
tar -xzvf $AFL_FILENAME
|
||||
rm $AFL_FILENAME
|
||||
cd AFLplusplus-*
|
||||
make source-only || exit
|
||||
cd ..
|
||||
rm -rf afl
|
||||
mv AFLplusplus-* afl
|
|
@ -1,51 +0,0 @@
|
|||
libopenmpt fuzz suite
|
||||
=====================
|
||||
|
||||
In this directory, you can find the necessary tools for fuzzing libopenmpt with
|
||||
the American Fuzzy Lop fuzzer (afl++).
|
||||
|
||||
Contents:
|
||||
|
||||
* `all_formats.dict`: A dictionary containing magic bytes from all supported
|
||||
module formats to make the life of the fuzzer a bit easier.
|
||||
* `fuzz-main.sh`: Script to launch the main fuzzing process. If you want to
|
||||
use just one fuzzer instance, run this one.
|
||||
* `fuzz-secondary[1|2].sh`: Scripts to launch the secondary fuzzing process. It
|
||||
is recommended to run at least two fuzzer instances, as the deterministic and
|
||||
random fuzz mode have been found to complement each other really well. The two
|
||||
scripts are set up to use different exploration strategies
|
||||
* `fuzz-settings.sh`: Set up your preferences and afl settings here before the
|
||||
first run.
|
||||
* `fuzz.c`: A tiny C program that is used by the fuzzer to test libopenmpt.
|
||||
* `get-afl.sh`: A simple script to obtain the latest version of afl++.
|
||||
You can also make it download from a specific branch or tag, e.g.
|
||||
`GET_AFL_VERSION=stable ./get-afl.sh` to download the latest stable but
|
||||
unreleased code.
|
||||
|
||||
Prerequisites
|
||||
=============
|
||||
* [afl++](https://github.com/AFLplusplus/AFLplusplus) - the makefile expects
|
||||
this to be installed in `contrib/fuzzing/afl`, as it is automatically done by
|
||||
the `get-afl.sh` install script.
|
||||
* Clang with LLVM dev headers (llvm-config needs to be installed).
|
||||
afl also works with gcc, but our makefile has been set up to make use of afl's
|
||||
faster LLVM-LTO mode.
|
||||
|
||||
How to use
|
||||
==========
|
||||
* Run `get-afl.sh`, or manually extract afl to `contrib/fuzzing/afl`, use
|
||||
`make source-only` to build. If building fails because `llvm-config` cannot be
|
||||
found, try prepending `LLVM_CONFIG=/usr/bin/llvm-config-12` or similar, and
|
||||
read the afl manual.
|
||||
* Build libopenmpt with the `build.sh` script in this directory.
|
||||
* Set up `fuzz-settings.sh` to your taste. Most importantly, you will have to
|
||||
specify the input directory for first use.
|
||||
The default setup mounts a tmpfs folder for all temporary files. You may
|
||||
change this behaviour if you do not have root privileges.
|
||||
* Run `fuzz-main.sh` for the first (deterministic) instance of afl-fuzz.
|
||||
* For a "secondary" instance to run on another core, run `fuzz-secondary1.sh`
|
||||
and/or `fuzz-secondary2.sh`.
|
||||
* If you want to make use of even more cores, create more copies
|
||||
`fuzz-secondary2.sh` and adjust "infile03" / "fuzzer03" to
|
||||
"infile04" / "fuzzer04" and so o (they need to be unique). Try variying the
|
||||
fuzzing strategey (the -p parameter) to get results more quickly.
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue