Build libOpenMPT from source once again
Bundle libOpenMPT as a dynamic framework, which should be safe once again, now that there is only one version to bundle. Also, now it is using the versions of libvorbisfile and libmpg123 that are bundled with the player, instead of compiling minimp3 and stbvorbis. Signed-off-by: Christopher Snowhill <kode54@gmail.com>
This commit is contained in:
parent
919497148a
commit
731e52c440
556 changed files with 183978 additions and 223 deletions
26
Frameworks/OpenMPT/Info.plist
Normal file
26
Frameworks/OpenMPT/Info.plist
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?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>
|
152
Frameworks/OpenMPT/OpenMPT/.clang-format
Normal file
152
Frameworks/OpenMPT/OpenMPT/.clang-format
Normal file
|
@ -0,0 +1,152 @@
|
|||
# clang-format 13
|
||||
|
||||
Language: Cpp
|
||||
Standard: c++20
|
||||
|
||||
AccessModifierOffset: -4 #?
|
||||
AlignAfterOpenBracket: AlwaysBreak
|
||||
AlignArrayOfStructures: Left
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveBitFields: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignConsecutiveMacros: true
|
||||
AlignEscapedNewlines: DontAlign
|
||||
AlignOperands: AlignAfterOperator
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllConstructorInitializersOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: Always
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
AllowShortEnumsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||
AllowShortLambdasOnASingleLine: Inline
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: true
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BinPackArguments: true
|
||||
BinPackParameters: false
|
||||
BitFieldColonSpacing: Both
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: true
|
||||
AfterClass: true
|
||||
AfterControlStatement: Always
|
||||
AfterEnum: true
|
||||
AfterFunction: true
|
||||
AfterNamespace: true
|
||||
#AfterObjCDeclaration
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
AfterExternBlock: true
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
BeforeLambdaBody: true
|
||||
BeforeWhile: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
#BreakAfterJavaFieldAnnotations
|
||||
BreakBeforeBinaryOperators: NonAssignment
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeConceptDeclarations: true
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
BreakInheritanceList: BeforeComma
|
||||
BreakStringLiterals: false
|
||||
ColumnLimit: 0
|
||||
CommentPragmas: '' #?
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 4 #?
|
||||
ContinuationIndentWidth: 4 #?
|
||||
Cpp11BracedListStyle: true
|
||||
DeriveLineEnding: true
|
||||
DerivePointerAlignment: false
|
||||
EmptyLineAfterAccessModifier: Leave
|
||||
EmptyLineBeforeAccessModifier: Leave
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros: []
|
||||
IfMacros: ['MPT_MAYBE_CONSTANT_IF']
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories: [] #?
|
||||
IncludeIsMainRegex: '' #?
|
||||
IncludeIsMainSourceRegex: '' #?
|
||||
IndentAccessModifiers: false
|
||||
IndentCaseBlocks: true
|
||||
IndentCaseLabels: true
|
||||
IndentExternBlock: NoIndent
|
||||
IndentGotoLabels: false
|
||||
IndentPPDirectives: None
|
||||
#IndentRequiresClause: true
|
||||
#BeforeHash
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: true
|
||||
InsertTrailingCommas: None
|
||||
#JavaImportGroups
|
||||
#JavaScriptQuotes
|
||||
#JavaScriptWrapImports
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
LambdaBodyIndentation: OuterScope
|
||||
MacroBlockBegin: '^MPT_TEST_GROUP_BEGIN|BEGIN_MESSAGE_MAP$' #?
|
||||
MacroBlockEnd: '^MPT_TEST_GROUP_END|END_MESSAGE_MAP$' #?
|
||||
MaxEmptyLinesToKeep: 5
|
||||
NamespaceIndentation: None
|
||||
NamespaceMacros: [] #?
|
||||
#ObjCBinPackProtocolList
|
||||
#ObjCBlockIndentWidth
|
||||
#ObjCBreakBeforeNestedBlockParam
|
||||
#ObjCSpaceAfterProperty
|
||||
#ObjCSpaceBeforeProtocolList
|
||||
#PenaltyBreakAssignment
|
||||
#PenaltyBreakBeforeFirstCallParameter
|
||||
#PenaltyBreakComment
|
||||
#PenaltyBreakFirstLessLess
|
||||
#PenaltyBreakString
|
||||
#PenaltyBreakTemplateDeclaration
|
||||
#PenaltyExcessCharacter
|
||||
#PenaltyIndentedWhitespace
|
||||
#PenaltyReturnTypeOnItsOwnLine
|
||||
PointerAlignment: Right
|
||||
PPIndentWidth: -1
|
||||
#RawStringFormats
|
||||
ReferenceAlignment: Pointer
|
||||
ReflowComments: false
|
||||
ShortNamespaceLines: 1
|
||||
SortIncludes: false
|
||||
#SortJavaStaticImport
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceAroundPointerQualifiers: Default
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCaseColon: false
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: Never
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceBeforeSquareBrackets: false
|
||||
SpaceInEmptyBlock: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 2
|
||||
SpacesInAngles: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInConditionalStatement: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInLineCommentPrefix:
|
||||
Minimum: 1
|
||||
Maximum: -1
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
StatementAttributeLikeMacros: []
|
||||
StatementMacros: [ 'OPENMPT_NAMESPACE_BEGIN', 'OPENMPT_NAMESPACE_END', 'MPT_MSVC_WORKAROUND_LNK4221', 'MPT_WARNING', 'MPT_TEST_GROUP_INLINE_IDENTIFIER', 'MPT_TEST_GROUP_INLINE', 'MPT_TEST_GROUP_STATIC' ] #?
|
||||
TabWidth: 4
|
||||
TypenameMacros: [] #?
|
||||
UseCRLF: false
|
||||
UseTab: ForContinuationAndIndentation
|
||||
WhitespaceSensitiveMacros:
|
||||
- MPT_PP_STRINGIFY
|
25
Frameworks/OpenMPT/OpenMPT/LICENSE
Normal file
25
Frameworks/OpenMPT/OpenMPT/LICENSE
Normal file
|
@ -0,0 +1,25 @@
|
|||
Copyright (c) 2004-2022, OpenMPT Project Developers and 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 COPYRIGHT HOLDERS AND 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 COPYRIGHT HOLDER OR 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.
|
1901
Frameworks/OpenMPT/OpenMPT/Makefile
Normal file
1901
Frameworks/OpenMPT/OpenMPT/Makefile
Normal file
File diff suppressed because it is too large
Load diff
86
Frameworks/OpenMPT/OpenMPT/README.md
Normal file
86
Frameworks/OpenMPT/OpenMPT/README.md
Normal file
|
@ -0,0 +1,86 @@
|
|||
|
||||
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, 2019, and 2022 Community/Professional/Enterprise
|
||||
|
||||
To compile the project, open `build/vsVERSIONwin7/OpenMPT.sln` (VERSION
|
||||
being 2017, 2019, or 2022) and hit the compile button. Other target
|
||||
systems can be found in the `vs2017*`, `vs2019*`, and `vs2022*` sibling
|
||||
folders.
|
||||
|
||||
Note that you have to build the `PluginBridge` and `PluginBridgeLegacy`
|
||||
projects manually for architectures other than the one you are building
|
||||
OpenMPT for, as Visual Studio only builds one architecture configuration
|
||||
at a time.
|
||||
|
||||
Please note that we do not support building with a later Visual Studio
|
||||
installation with an earlier compiler version. This is because, while
|
||||
later Visual Studio versions allow installing earlier compilers to be
|
||||
available via the later version's environment, in this configuration,
|
||||
the earlier compiler will still use the later C and C++ runtime's
|
||||
headers and implementation, which significantly increases the matrix of
|
||||
possible configurations to test.
|
||||
|
||||
- OpenMPT requires the compile host system to be Windows 8.1 (or later) amd64,
|
||||
or Windows 11 (or later) ARM64.
|
||||
|
||||
- In order to build OpenMPT for Windows XP, the Visual Studio 2017 XP
|
||||
targetting toolset as well as the Windows 8.1 SDK need to be installed. The
|
||||
SDK is optionally included with Visual Studio 2017, but must be separately
|
||||
installed with later Visual Studio versions.
|
||||
|
||||
The Windows 8.1 SDK is available from
|
||||
<https://developer.microsoft.com/en-us/windows/downloads/sdk-archive/> or
|
||||
directly from
|
||||
<https://download.microsoft.com/download/B/0/C/B0C80BA3-8AD6-4958-810B-6882485230B5/standalonesdk/sdksetup.exe>
|
||||
.
|
||||
|
||||
- Microsoft Foundation Classes (MFC) are required to build OpenMPT.
|
||||
|
||||
|
||||
### libopenmpt and openmpt123
|
||||
|
||||
See [Dependencies](libopenmpt/dox/dependencies.md) and
|
||||
[Getting Started](libopenmpt/dox/gettingstarted.md).
|
||||
|
||||
|
||||
Contributing to OpenMPT/libopenmpt
|
||||
----------------------------------
|
||||
|
||||
|
||||
See [contributing](doc/contributing.md).
|
||||
|
222
Frameworks/OpenMPT/OpenMPT/build/android_ndk/Android.mk
Normal file
222
Frameworks/OpenMPT/OpenMPT/build/android_ndk/Android.mk
Normal file
|
@ -0,0 +1,222 @@
|
|||
|
||||
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)/src $(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/Logging.cpp \
|
||||
common/mptFileIO.cpp \
|
||||
common/mptPathString.cpp \
|
||||
common/mptRandom.cpp \
|
||||
common/mptString.cpp \
|
||||
common/mptStringBuffer.cpp \
|
||||
common/mptStringFormat.cpp \
|
||||
common/mptStringParse.cpp \
|
||||
common/mptTime.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 \
|
||||
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_dsym.cpp \
|
||||
soundlib/Load_dtm.cpp \
|
||||
soundlib/Load_far.cpp \
|
||||
soundlib/Load_fmt.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_mus_km.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_symmod.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/DMOUtils.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 \
|
||||
soundlib/plugins/SymMODEcho.cpp \
|
||||
sounddsp/AGC.cpp \
|
||||
sounddsp/DSP.cpp \
|
||||
sounddsp/EQ.cpp \
|
||||
sounddsp/Reverb.cpp \
|
||||
test/TestToolsLib.cpp \
|
||||
test/test.cpp
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
|
||||
APP_CFLAGS :=#-std=c99
|
||||
APP_CPPFLAGS := -std=c++17 -fexceptions -frtti
|
||||
APP_LDFLAGS :=
|
||||
APP_STL := c++_shared
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
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.
|
||||
|
4
Frameworks/OpenMPT/OpenMPT/build/dist.mk
Normal file
4
Frameworks/OpenMPT/OpenMPT/build/dist.mk
Normal file
|
@ -0,0 +1,4 @@
|
|||
|
||||
MPT_SVNVERSION=17609
|
||||
MPT_SVNURL=https://source.openmpt.org/svn/openmpt/branches/OpenMPT-1.30
|
||||
MPT_SVNDATE=2022-06-30T15:43:27.573631Z
|
56
Frameworks/OpenMPT/OpenMPT/build/make/config-afl.mk
Normal file
56
Frameworks/OpenMPT/OpenMPT/build/make/config-afl.mk
Normal file
|
@ -0,0 +1,56 @@
|
|||
|
||||
ifeq ($(origin CC),default)
|
||||
CC = contrib/fuzzing/afl/afl-clang-lto
|
||||
endif
|
||||
ifeq ($(origin CXX),default)
|
||||
CXX = contrib/fuzzing/afl/afl-clang-lto++
|
||||
endif
|
||||
ifeq ($(origin LD),default)
|
||||
LD = $(CXX)
|
||||
endif
|
||||
ifeq ($(origin AR),default)
|
||||
AR = ar
|
||||
endif
|
||||
|
||||
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
|
||||
|
||||
include build/make/warnings-clang.mk
|
||||
|
||||
EXESUFFIX=
|
||||
|
||||
FUZZ=1
|
||||
CPPFLAGS += -DMPT_BUILD_FUZZER -DMPT_BUILD_FATAL_ASSERTS
|
||||
|
50
Frameworks/OpenMPT/OpenMPT/build/make/config-clang.mk
Normal file
50
Frameworks/OpenMPT/OpenMPT/build/make/config-clang.mk
Normal file
|
@ -0,0 +1,50 @@
|
|||
|
||||
ifeq ($(origin CC),default)
|
||||
CC = $(TOOLCHAIN_PREFIX)clang$(TOOLCHAIN_SUFFIX)
|
||||
endif
|
||||
ifeq ($(origin CXX),default)
|
||||
CXX = $(TOOLCHAIN_PREFIX)clang++$(TOOLCHAIN_SUFFIX)
|
||||
endif
|
||||
ifeq ($(origin LD),default)
|
||||
LD = $(CXX)
|
||||
endif
|
||||
ifeq ($(origin AR),default)
|
||||
AR = $(TOOLCHAIN_PREFIX)ar$(TOOLCHAIN_SUFFIX)
|
||||
endif
|
||||
|
||||
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 ($(OPTIMIZE_LTO),1)
|
||||
CXXFLAGS += -flto=thin
|
||||
CFLAGS += -flto=thin
|
||||
endif
|
||||
|
||||
ifeq ($(CHECKED_ADDRESS),1)
|
||||
CXXFLAGS += -fsanitize=address
|
||||
CFLAGS += -fsanitize=address
|
||||
endif
|
||||
|
||||
ifeq ($(CHECKED_UNDEFINED),1)
|
||||
CXXFLAGS += -fsanitize=undefined
|
||||
CFLAGS += -fsanitize=undefined
|
||||
endif
|
||||
|
||||
include build/make/warnings-clang.mk
|
||||
|
||||
EXESUFFIX=
|
69
Frameworks/OpenMPT/OpenMPT/build/make/config-defaults.mk
Normal file
69
Frameworks/OpenMPT/OpenMPT/build/make/config-defaults.mk
Normal file
|
@ -0,0 +1,69 @@
|
|||
|
||||
ifeq ($(HOST),unix)
|
||||
|
||||
ifeq ($(HOST_FLAVOUR),MACOSX)
|
||||
|
||||
NO_PULSEAUDIO?=1
|
||||
include build/make/config-clang.mk
|
||||
# Mac OS X overrides
|
||||
DYNLINK=0
|
||||
SHARED_SONAME=0
|
||||
|
||||
else ifeq ($(HOST_FLAVOUR),MSYS2)
|
||||
|
||||
ifeq ($(MSYSTEM),MINGW64)
|
||||
WINDOWS_ARCH=amd64
|
||||
include build/make/config-mingw-w64.mk
|
||||
else ifeq ($(MSYSTEM),MINGW32)
|
||||
WINDOWS_ARCH=x86
|
||||
include build/make/config-mingw-w64.mk
|
||||
else ifeq ($(MSYSTEM),UCRT64)
|
||||
WINDOWS_ARCH=amd64
|
||||
include build/make/config-mingw-w64.mk
|
||||
else ifeq ($(MSYSTEM),CLANG64)
|
||||
WINDOWS_ARCH=amd64
|
||||
MINGW_COMPILER=clang
|
||||
include build/make/config-mingw-w64.mk
|
||||
else
|
||||
WINDOWS_ARCH=x86
|
||||
include build/make/config-mingw-w64.mk
|
||||
endif
|
||||
|
||||
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),OPENBSD)
|
||||
|
||||
NO_PORTAUDIOCPP?=1
|
||||
NO_PULSEAUDIO?=1
|
||||
include build/make/config-clang.mk
|
||||
|
||||
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
|
||||
|
88
Frameworks/OpenMPT/OpenMPT/build/make/config-djgpp.mk
Normal file
88
Frameworks/OpenMPT/OpenMPT/build/make/config-djgpp.mk
Normal file
|
@ -0,0 +1,88 @@
|
|||
|
||||
ifeq ($(origin CC),default)
|
||||
CC = i386-pc-msdosdjgpp-gcc
|
||||
endif
|
||||
ifeq ($(origin CXX),default)
|
||||
CXX = i386-pc-msdosdjgpp-g++
|
||||
endif
|
||||
ifeq ($(origin LD),default)
|
||||
LD = $(CXX)
|
||||
endif
|
||||
ifeq ($(origin AR),default)
|
||||
AR = i386-pc-msdosdjgpp-ar
|
||||
endif
|
||||
|
||||
# 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 -ffast-math
|
||||
CFLAGS += -march=i386 -m80387 -mtune=pentium -ffast-math
|
||||
LDFLAGS +=
|
||||
LDLIBS += -lm
|
||||
ARFLAGS := rcs
|
||||
|
||||
include build/make/warnings-gcc.mk
|
||||
|
||||
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,
|
||||
# makes memory locking difficult
|
||||
MPT_COMPILER_NOGCSECTIONS=1
|
||||
|
||||
ifeq ($(ALLOW_LGPL),1)
|
||||
LOCAL_ZLIB=1
|
||||
LOCAL_MPG123=1
|
||||
LOCAL_OGG=1
|
||||
LOCAL_VORBIS=1
|
||||
else
|
||||
NO_ZLIB=1
|
||||
NO_MPG123=1
|
||||
NO_OGG=1
|
||||
NO_VORBIS=1
|
||||
NO_VORBISFILE=1
|
||||
endif
|
||||
|
||||
NO_LTDL=1
|
||||
NO_DL=1
|
||||
NO_PORTAUDIO=1
|
||||
NO_PORTAUDIOCPP=1
|
||||
NO_PULSEAUDIO=1
|
||||
NO_SDL=1
|
||||
NO_SDL2=1
|
||||
NO_SNDFILE=1
|
||||
NO_FLAC=1
|
||||
|
||||
ifeq ($(BUNDLED_ALLEGRO42),1)
|
||||
|
||||
CPPFLAGS_ALLEGRO42 := -Iinclude/allegro42/include -DALLEGRO_HAVE_STDINT_H -DLONG_LONG="long long"
|
||||
LDFLAGS_ALLEGRO42 :=
|
||||
LDLIBS_ALLEGRO42 := include/allegro42/lib/djgpp/liballeg.a
|
||||
|
||||
include/allegro42/lib/djgpp/liballeg.a:
|
||||
+cd include/allegro42 && ./xmake.sh clean
|
||||
+cd include/allegro42 && ./xmake.sh lib
|
||||
|
||||
bin/openmpt123$(EXESUFFIX): include/allegro42/lib/djgpp/liballeg.a
|
||||
|
||||
MISC_OUTPUTS += include/allegro42/lib/djgpp/liballeg.a
|
||||
|
||||
endif
|
168
Frameworks/OpenMPT/OpenMPT/build/make/config-emscripten.mk
Normal file
168
Frameworks/OpenMPT/OpenMPT/build/make/config-emscripten.mk
Normal file
|
@ -0,0 +1,168 @@
|
|||
|
||||
ifeq ($(origin CC),default)
|
||||
CC = emcc -c
|
||||
endif
|
||||
ifeq ($(origin CXX),default)
|
||||
CXX = em++ -c
|
||||
endif
|
||||
ifeq ($(origin LD),default)
|
||||
LD = em++
|
||||
endif
|
||||
ifeq ($(origin AR),default)
|
||||
AR = emar
|
||||
endif
|
||||
LINK.cc = em++ $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
|
||||
|
||||
EMSCRIPTEN_TARGET?=default
|
||||
EMSCRIPTEN_THREADS?=0
|
||||
EMSCRIPTEN_PORTS?=0
|
||||
|
||||
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
|
||||
|
||||
ifeq ($(EMSCRIPTEN_THREADS),1)
|
||||
CXXFLAGS += -pthread
|
||||
CFLAGS += -pthread
|
||||
LDFLAGS += -pthread
|
||||
endif
|
||||
|
||||
ifeq ($(EMSCRIPTEN_PORTS),1)
|
||||
CXXFLAGS += -s USE_ZLIB=1 -sUSE_MPG123=1 -sUSE_OGG=1 -sUSE_VORBIS=1 -DMPT_WITH_ZLIB -DMPT_WITH_MPG123 -DMPT_WITH_VORBIS -DMPT_WITH_VORBISFI
|
||||
CFLAGS += -s USE_ZLIB=1 -sUSE_MPG123=1 -sUSE_OGG=1 -sUSE_VORBIS=1 -DMPT_WITH_ZLIB -DMPT_WITH_MPG123 -DMPT_WITH_VORBIS -DMPT_WITH_VORBISFI
|
||||
LDFLAGS += -s USE_ZLIB=1 -sUSE_MPG123=1 -sUSE_OGG=1 -sUSE_VORBIS=1
|
||||
NO_MINIZ=1
|
||||
NO_MINIMP3=1
|
||||
NO_STBVORBIS=1
|
||||
endif
|
||||
|
||||
CXXFLAGS += -Oz
|
||||
CFLAGS += -Oz
|
||||
LDFLAGS += -Oz
|
||||
|
||||
# Enable LTO as recommended by Emscripten
|
||||
#CXXFLAGS += -flto=thin
|
||||
#CFLAGS += -flto=thin
|
||||
#LDFLAGS += -flto=thin -Wl,--thinlto-jobs=all
|
||||
# As per recommendation in <https://github.com/emscripten-core/emscripten/issues/15638#issuecomment-982772770>,
|
||||
# thinLTO is not as well tested as full LTO. Stick to full LTO for now.
|
||||
CXXFLAGS += -flto
|
||||
CFLAGS += -flto
|
||||
LDFLAGS += -flto
|
||||
|
||||
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
|
||||
CFLAGS += -s DISABLE_EXCEPTION_CATCHING=0 -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'"
|
||||
|
||||
include build/make/warnings-clang.mk
|
||||
|
||||
REQUIRES_RUNPREFIX=1
|
||||
|
||||
EXESUFFIX=.js
|
||||
SOSUFFIX=.js
|
||||
RUNPREFIX=node
|
||||
TEST_LDFLAGS= --pre-js build/make/test-pre.js -lnodefs.js
|
||||
|
||||
ifeq ($(EMSCRIPTEN_THREADS),1)
|
||||
RUNPREFIX+=--experimental-wasm-threads --experimental-wasm-bulk-memory
|
||||
endif
|
||||
|
||||
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
|
||||
|
||||
ifeq ($(ALLOW_LGPL),1)
|
||||
LOCAL_ZLIB=1
|
||||
LOCAL_MPG123=1
|
||||
LOCAL_OGG=1
|
||||
LOCAL_VORBIS=1
|
||||
else
|
||||
NO_ZLIB=1
|
||||
NO_MPG123=1
|
||||
NO_OGG=1
|
||||
NO_VORBIS=1
|
||||
NO_VORBISFILE=1
|
||||
endif
|
||||
NO_LTDL=1
|
||||
NO_DL=1
|
||||
NO_PORTAUDIO=1
|
||||
NO_PORTAUDIOCPP=1
|
||||
NO_PULSEAUDIO=1
|
||||
NO_SDL=1
|
||||
NO_SDL2=1
|
||||
NO_FLAC=1
|
||||
NO_SNDFILE=1
|
||||
|
51
Frameworks/OpenMPT/OpenMPT/build/make/config-gcc.mk
Normal file
51
Frameworks/OpenMPT/OpenMPT/build/make/config-gcc.mk
Normal file
|
@ -0,0 +1,51 @@
|
|||
|
||||
ifeq ($(origin CC),default)
|
||||
CC = $(TOOLCHAIN_PREFIX)gcc$(TOOLCHAIN_SUFFIX)
|
||||
endif
|
||||
ifeq ($(origin CXX),default)
|
||||
CXX = $(TOOLCHAIN_PREFIX)g++$(TOOLCHAIN_SUFFIX)
|
||||
endif
|
||||
ifeq ($(origin LD),default)
|
||||
LD = $(CXX)
|
||||
endif
|
||||
ifeq ($(origin AR),default)
|
||||
AR = $(TOOLCHAIN_PREFIX)ar$(TOOLCHAIN_SUFFIX)
|
||||
endif
|
||||
|
||||
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 ($(OPTIMIZE_LTO),1)
|
||||
CXXFLAGS += -flto
|
||||
CFLAGS += -flto
|
||||
endif
|
||||
|
||||
ifeq ($(CHECKED_ADDRESS),1)
|
||||
CXXFLAGS += -fsanitize=address
|
||||
CFLAGS += -fsanitize=address
|
||||
endif
|
||||
|
||||
ifeq ($(CHECKED_UNDEFINED),1)
|
||||
CXXFLAGS += -fsanitize=undefined
|
||||
CFLAGS += -fsanitize=undefined
|
||||
endif
|
||||
|
||||
include build/make/warnings-gcc.mk
|
||||
|
||||
EXESUFFIX=
|
||||
|
34
Frameworks/OpenMPT/OpenMPT/build/make/config-generic.mk
Normal file
34
Frameworks/OpenMPT/OpenMPT/build/make/config-generic.mk
Normal file
|
@ -0,0 +1,34 @@
|
|||
|
||||
$(warning warning: CONFIG=generic is deprecated. Use CONFIG=standard instead.)
|
||||
|
||||
ifeq ($(origin CC),default)
|
||||
CC = cc
|
||||
endif
|
||||
ifeq ($(origin CXX),default)
|
||||
CXX = c++
|
||||
endif
|
||||
ifeq ($(origin LD),default)
|
||||
LD = $(CXX)
|
||||
endif
|
||||
ifeq ($(origin AR),default)
|
||||
AR = ar
|
||||
endif
|
||||
|
||||
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=
|
||||
|
4
Frameworks/OpenMPT/OpenMPT/build/make/config-haiku.mk
Normal file
4
Frameworks/OpenMPT/OpenMPT/build/make/config-haiku.mk
Normal file
|
@ -0,0 +1,4 @@
|
|||
|
||||
$(warning warning: CONFIG=haiku is deprecated. The OS is auto-detected.)
|
||||
|
||||
include config-defaults.mk
|
4
Frameworks/OpenMPT/OpenMPT/build/make/config-macosx.mk
Normal file
4
Frameworks/OpenMPT/OpenMPT/build/make/config-macosx.mk
Normal file
|
@ -0,0 +1,4 @@
|
|||
|
||||
$(warning warning: CONFIG=macosx is deprecated. The OS is auto-detected.)
|
||||
|
||||
include config-defaults.mk
|
132
Frameworks/OpenMPT/OpenMPT/build/make/config-mingw-w64.mk
Normal file
132
Frameworks/OpenMPT/OpenMPT/build/make/config-mingw-w64.mk
Normal file
|
@ -0,0 +1,132 @@
|
|||
|
||||
ifeq ($(WINDOWS_ARCH),)
|
||||
MINGW_ARCH = i686
|
||||
else ifeq ($(WINDOWS_ARCH),x86)
|
||||
MINGW_ARCH = i686
|
||||
else ifeq ($(WINDOWS_ARCH),amd64)
|
||||
MINGW_ARCH = x86_64
|
||||
#else ifeq ($(WINDOWS_ARCH),arm)
|
||||
#MINGW_ARCH =
|
||||
#else ifeq ($(WINDOWS_ARCH),arm64)
|
||||
#MINGW_ARCH =
|
||||
else
|
||||
$(error unknown WINDOWS_ARCH)
|
||||
endif
|
||||
|
||||
ifeq ($(origin CC),default)
|
||||
CC = $(MINGW_ARCH)-w64-mingw32-gcc$(MINGW_FLAVOUR)
|
||||
endif
|
||||
ifeq ($(origin CXX),default)
|
||||
CXX = $(MINGW_ARCH)-w64-mingw32-g++$(MINGW_FLAVOUR)
|
||||
endif
|
||||
ifeq ($(origin LD),default)
|
||||
LD = $(CXX)
|
||||
endif
|
||||
ifeq ($(origin AR),default)
|
||||
AR = $(MINGW_ARCH)-w64-mingw32-ar$(MINGW_FLAVOUR)
|
||||
endif
|
||||
|
||||
CXXFLAGS_STDCXX = -std=c++17 -fexceptions -frtti
|
||||
CFLAGS_STDC = -std=c99
|
||||
CXXFLAGS += $(CXXFLAGS_STDCXX)
|
||||
CFLAGS += $(CFLAGS_STDC)
|
||||
|
||||
CPPFLAGS +=
|
||||
ifeq ($(MINGW_COMPILER),clang)
|
||||
CXXFLAGS += -municode
|
||||
CFLAGS += -municode
|
||||
LDFLAGS += -mconsole -mthreads
|
||||
else
|
||||
CXXFLAGS += -municode -mthreads
|
||||
CFLAGS += -municode -mthreads
|
||||
LDFLAGS += -mconsole
|
||||
endif
|
||||
LDLIBS += -lm -lole32 -lrpcrt4 -lwinmm
|
||||
ARFLAGS := rcs
|
||||
|
||||
PC_LIBS_PRIVATE += -lole32 -lrpcrt4
|
||||
|
||||
ifeq ($(WINDOWS_FAMILY),)
|
||||
# nothing
|
||||
else ifeq ($(WINDOWS_FAMILY),desktop-app)
|
||||
# nothing
|
||||
else ifeq ($(WINDOWS_FAMILY),app)
|
||||
CPPFLAGS += -DWINAPI_FAMILY=2
|
||||
OPENMPT123=0
|
||||
else ifeq ($(WINDOWS_FAMILY),phone-app)
|
||||
CPPFLAGS += -DWINAPI_FAMILY=3
|
||||
OPENMPT123=0
|
||||
else ifeq ($(WINDOWS_FAMILY),pc-app)
|
||||
CPPFLAGS += -DWINAPI_FAMILY=2
|
||||
OPENMPT123=0
|
||||
else
|
||||
$(error unknown WINDOWS_FAMILY)
|
||||
endif
|
||||
|
||||
ifeq ($(WINDOWS_VERSION),)
|
||||
# nothing
|
||||
else ifeq ($(WINDOWS_VERSION),win95)
|
||||
CPPFLAGS += -D_WIN32_WINDOWS=0x0400
|
||||
else ifeq ($(WINDOWS_VERSION),win98)
|
||||
CPPFLAGS += -D_WIN32_WINDOWS=0x0410
|
||||
else ifeq ($(WINDOWS_VERSION),winme)
|
||||
CPPFLAGS += -D_WIN32_WINDOWS=0x0490
|
||||
else ifeq ($(WINDOWS_VERSION),winnt4)
|
||||
CPPFLAGS += -D_WIN32_WINNT=0x0400
|
||||
else ifeq ($(WINDOWS_VERSION),win2000)
|
||||
CPPFLAGS += -D_WIN32_WINNT=0x0500
|
||||
else ifeq ($(WINDOWS_VERSION),winxp)
|
||||
CPPFLAGS += -D_WIN32_WINNT=0x0501
|
||||
else ifeq ($(WINDOWS_VERSION),winxp64)
|
||||
CPPFLAGS += -D_WIN32_WINNT=0x0502
|
||||
else ifeq ($(WINDOWS_VERSION),winvista)
|
||||
CPPFLAGS += -DNTDDI_VERSION=0x06000000
|
||||
else ifeq ($(WINDOWS_VERSION),win7)
|
||||
CPPFLAGS += -DNTDDI_VERSION=0x06010000
|
||||
else ifeq ($(WINDOWS_VERSION),win8)
|
||||
CPPFLAGS += -DNTDDI_VERSION=0x06020000
|
||||
else ifeq ($(WINDOWS_VERSION),win8.1)
|
||||
CPPFLAGS += -DNTDDI_VERSION=0x06030000
|
||||
else ifeq ($(WINDOWS_VERSION),win10)
|
||||
CPPFLAGS += -DNTDDI_VERSION=0x0A000000
|
||||
else
|
||||
$(error unknown WINDOWS_VERSION)
|
||||
endif
|
||||
|
||||
ifeq ($(MINGW_COMPILER),clang)
|
||||
include build/make/warnings-clang.mk
|
||||
else
|
||||
include build/make/warnings-gcc.mk
|
||||
endif
|
||||
|
||||
EXESUFFIX=.exe
|
||||
SOSUFFIX=.dll
|
||||
SOSUFFIXWINDOWS=1
|
||||
|
||||
DYNLINK=0
|
||||
SHARED_LIB=1
|
||||
STATIC_LIB=0
|
||||
SHARED_SONAME=0
|
||||
|
||||
ifeq ($(HOST_FLAVOUR),MSYS2)
|
||||
|
||||
else
|
||||
|
||||
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
|
||||
|
||||
endif
|
69
Frameworks/OpenMPT/OpenMPT/build/make/config-mingw-win9x.mk
Normal file
69
Frameworks/OpenMPT/OpenMPT/build/make/config-mingw-win9x.mk
Normal file
|
@ -0,0 +1,69 @@
|
|||
|
||||
ifeq ($(origin CC),default)
|
||||
CC = mingw32-gcc$(MINGW_FLAVOUR)
|
||||
endif
|
||||
ifeq ($(origin CXX),default)
|
||||
CXX = mingw32-g++$(MINGW_FLAVOUR)
|
||||
endif
|
||||
ifeq ($(origin LD),default)
|
||||
LD = $(CXX)
|
||||
endif
|
||||
ifeq ($(origin AR),default)
|
||||
AR = mingw32-gcc-ar$(MINGW_FLAVOUR)
|
||||
endif
|
||||
|
||||
CXXFLAGS_STDCXX = -std=gnu++17
|
||||
CFLAGS_STDC = -std=gnu99
|
||||
CXXFLAGS += $(CXXFLAGS_STDCXX)
|
||||
CFLAGS += $(CFLAGS_STDC)
|
||||
|
||||
CPPFLAGS += -DWIN32 -D_WIN32 -DWINVER=0x0410 -D_WIN32_WINDOWS=0x0410 -DMPT_BUILD_RETRO
|
||||
CXXFLAGS += -mconsole -mthreads
|
||||
CFLAGS += -mconsole -mthreads
|
||||
LDFLAGS +=
|
||||
LDLIBS += -lm -lole32 -lrpcrt4 -lwinmm
|
||||
ARFLAGS := rcs
|
||||
|
||||
LDFLAGS += -static -static-libgcc -static-libstdc++
|
||||
|
||||
#CXXFLAGS += -ffunction-sections -fdata-sections
|
||||
#CFLAGS += -ffunction-sections -fdata-sections
|
||||
#LDFLAGS += -Wl,--gc-sections
|
||||
|
||||
CXXFLAGS += -march=i486 -m80387 -mtune=pentium
|
||||
CFLAGS += -march=i486 -m80387 -mtune=pentium
|
||||
|
||||
PC_LIBS_PRIVATE += -lole32 -lrpcrt4
|
||||
|
||||
include build/make/warnings-gcc.mk
|
||||
|
||||
EXESUFFIX=.exe
|
||||
SOSUFFIX=.dll
|
||||
SOSUFFIXWINDOWS=1
|
||||
|
||||
DYNLINK=0
|
||||
SHARED_LIB=1
|
||||
STATIC_LIB=0
|
||||
SHARED_SONAME=0
|
||||
|
||||
FORCE_UNIX_STYLE_COMMANDS=1
|
||||
|
||||
IN_OPENMPT=1
|
||||
XMP_OPENMPT=1
|
||||
|
||||
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
|
|
@ -0,0 +1,65 @@
|
|||
|
||||
ifeq ($(origin CC),default)
|
||||
CC = i686-w64-mingw32-gcc$(MINGW_FLAVOUR)
|
||||
endif
|
||||
ifeq ($(origin CXX),default)
|
||||
CXX = i686-w64-mingw32-g++$(MINGW_FLAVOUR)
|
||||
endif
|
||||
ifeq ($(origin LD),default)
|
||||
LD = $(CXX)
|
||||
endif
|
||||
ifeq ($(origin AR),default)
|
||||
AR = i686-w64-mingw32-ar$(MINGW_FLAVOUR)
|
||||
endif
|
||||
|
||||
CXXFLAGS_STDCXX = -std=c++17
|
||||
CFLAGS_STDC = -std=c99
|
||||
CXXFLAGS += $(CXXFLAGS_STDCXX)
|
||||
CFLAGS += $(CFLAGS_STDC)
|
||||
|
||||
CPPFLAGS += -DWIN32 -D_WIN32
|
||||
ifeq ($(MINGW_COMPILER),clang)
|
||||
CXXFLAGS += -municode
|
||||
CFLAGS += -municode
|
||||
LDFLAGS += -mconsole -mthreads
|
||||
else
|
||||
CXXFLAGS += -municode -mthreads
|
||||
CFLAGS += -municode -mthreads
|
||||
LDFLAGS += -mconsole
|
||||
endif
|
||||
LDLIBS += -lm -lole32 -lrpcrt4 -lwinmm
|
||||
ARFLAGS := rcs
|
||||
|
||||
PC_LIBS_PRIVATE += -lole32 -lrpcrt4
|
||||
|
||||
ifeq ($(MINGW_COMPILER),clang)
|
||||
include build/make/warnings-clang.mk
|
||||
else
|
||||
include build/make/warnings-gcc.mk
|
||||
endif
|
||||
|
||||
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
|
|
@ -0,0 +1,65 @@
|
|||
|
||||
ifeq ($(origin CC),default)
|
||||
CC = x86_64-w64-mingw32-gcc$(MINGW_FLAVOUR)
|
||||
endif
|
||||
ifeq ($(origin CXX),default)
|
||||
CXX = x86_64-w64-mingw32-g++$(MINGW_FLAVOUR)
|
||||
endif
|
||||
ifeq ($(origin LD),default)
|
||||
LD = $(CXX)
|
||||
endif
|
||||
ifeq ($(origin AR),default)
|
||||
AR = x86_64-w64-mingw32-ar$(MINGW_FLAVOUR)
|
||||
endif
|
||||
|
||||
CXXFLAGS_STDCXX = -std=c++17
|
||||
CFLAGS_STDC = -std=c99
|
||||
CXXFLAGS += $(CXXFLAGS_STDCXX)
|
||||
CFLAGS += $(CFLAGS_STDC)
|
||||
|
||||
CPPFLAGS += -DWIN32 -D_WIN32 -DWIN64 -D_WIN64
|
||||
ifeq ($(MINGW_COMPILER),clang)
|
||||
CXXFLAGS += -municode
|
||||
CFLAGS += -municode
|
||||
LDFLAGS += -mconsole -mthreads
|
||||
else
|
||||
CXXFLAGS += -municode -mthreads
|
||||
CFLAGS += -municode -mthreads
|
||||
LDFLAGS += -mconsole
|
||||
endif
|
||||
LDLIBS += -lm -lole32 -lrpcrt4 -lwinmm
|
||||
ARFLAGS := rcs
|
||||
|
||||
PC_LIBS_PRIVATE += -lole32 -lrpcrt4
|
||||
|
||||
ifeq ($(MINGW_COMPILER),clang)
|
||||
include build/make/warnings-clang.mk
|
||||
else
|
||||
include build/make/warnings-gcc.mk
|
||||
endif
|
||||
|
||||
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
|
|
@ -0,0 +1,67 @@
|
|||
|
||||
ifeq ($(origin CC),default)
|
||||
CC = x86_64-w64-mingw32-gcc$(MINGW_FLAVOUR)
|
||||
endif
|
||||
ifeq ($(origin CXX),default)
|
||||
CXX = x86_64-w64-mingw32-g++$(MINGW_FLAVOUR)
|
||||
endif
|
||||
ifeq ($(origin LD),default)
|
||||
LD = $(CXX)
|
||||
endif
|
||||
ifeq ($(origin AR),default)
|
||||
AR = x86_64-w64-mingw32-ar$(MINGW_FLAVOUR)
|
||||
endif
|
||||
|
||||
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
|
||||
ifeq ($(MINGW_COMPILER),clang)
|
||||
CXXFLAGS += -municode
|
||||
CFLAGS += -municode
|
||||
LDFLAGS += -mconsole -mthreads
|
||||
else
|
||||
CXXFLAGS += -municode -mthreads
|
||||
CFLAGS += -municode -mthreads
|
||||
LDFLAGS += -mconsole
|
||||
endif
|
||||
LDLIBS += -lm -lole32 -lwinmm
|
||||
ARFLAGS := rcs
|
||||
|
||||
PC_LIBS_PRIVATE += -lole32 -lrpcrt4
|
||||
|
||||
ifeq ($(MINGW_COMPILER),clang)
|
||||
include build/make/warnings-clang.mk
|
||||
else
|
||||
include build/make/warnings-gcc.mk
|
||||
endif
|
||||
|
||||
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
|
|
@ -0,0 +1,67 @@
|
|||
|
||||
ifeq ($(origin CC),default)
|
||||
CC = i686-w64-mingw32-gcc$(MINGW_FLAVOUR)
|
||||
endif
|
||||
ifeq ($(origin CXX),default)
|
||||
CXX = i686-w64-mingw32-g++$(MINGW_FLAVOUR)
|
||||
endif
|
||||
ifeq ($(origin LD),default)
|
||||
LD = $(CXX)
|
||||
endif
|
||||
ifeq ($(origin AR),default)
|
||||
AR = i686-w64-mingw32-ar$(MINGW_FLAVOUR)
|
||||
endif
|
||||
|
||||
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
|
||||
ifeq ($(MINGW_COMPILER),clang)
|
||||
CXXFLAGS += -municode
|
||||
CFLAGS += -municode
|
||||
LDFLAGS += -mconsole -mthreads
|
||||
else
|
||||
CXXFLAGS += -municode -mthreads
|
||||
CFLAGS += -municode -mthreads
|
||||
LDFLAGS += -mconsole
|
||||
endif
|
||||
LDLIBS += -lm -lole32 -lrpcrt4 -lwinmm
|
||||
ARFLAGS := rcs
|
||||
|
||||
PC_LIBS_PRIVATE += -lole32 -lrpcrt4
|
||||
|
||||
ifeq ($(MINGW_COMPILER),clang)
|
||||
include build/make/warnings-clang.mk
|
||||
else
|
||||
include build/make/warnings-gcc.mk
|
||||
endif
|
||||
|
||||
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
|
32
Frameworks/OpenMPT/OpenMPT/build/make/config-standard.mk
Normal file
32
Frameworks/OpenMPT/OpenMPT/build/make/config-standard.mk
Normal file
|
@ -0,0 +1,32 @@
|
|||
|
||||
ifeq ($(origin CC),default)
|
||||
CC = cc
|
||||
endif
|
||||
ifeq ($(origin CXX),default)
|
||||
CXX = c++
|
||||
endif
|
||||
ifeq ($(origin LD),default)
|
||||
LD = $(CXX)
|
||||
endif
|
||||
ifeq ($(origin AR),default)
|
||||
AR = ar
|
||||
endif
|
||||
|
||||
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=
|
||||
|
9
Frameworks/OpenMPT/OpenMPT/build/make/test-pre.js
Normal file
9
Frameworks/OpenMPT/OpenMPT/build/make/test-pre.js
Normal file
|
@ -0,0 +1,9 @@
|
|||
|
||||
var Module = {
|
||||
'preInit': function(text) {
|
||||
FS.mkdir('/test');
|
||||
FS.mount(NODEFS, {'root': '../test/'}, '/test');
|
||||
FS.mkdir('/libopenmpt');
|
||||
FS.mount(NODEFS, {'root': '../libopenmpt/'}, '/libopenmpt');
|
||||
}
|
||||
};
|
32
Frameworks/OpenMPT/OpenMPT/build/make/warnings-clang.mk
Normal file
32
Frameworks/OpenMPT/OpenMPT/build/make/warnings-clang.mk
Normal file
|
@ -0,0 +1,32 @@
|
|||
|
||||
CXXFLAGS_WARNINGS += -Wcast-align -Wcast-qual -Wmissing-prototypes -Wshift-count-negative -Wshift-count-overflow -Wshift-op-parentheses -Wshift-overflow -Wshift-sign-overflow -Wundef
|
||||
CFLAGS_WARNINGS += -Wcast-align -Wcast-qual -Wmissing-prototypes -Wshift-count-negative -Wshift-count-overflow -Wshift-op-parentheses -Wshift-overflow -Wshift-sign-overflow -Wundef
|
||||
|
||||
CXXFLAGS_WARNINGS += -Wdeprecated -Wextra-semi -Wframe-larger-than=16000 -Wglobal-constructors -Wimplicit-fallthrough -Wmissing-declarations -Wnon-virtual-dtor -Wreserved-id-macro
|
||||
|
||||
#CXXFLAGS_WARNINGS += -Wfloat-equal
|
||||
#CXXFLAGS_WARNINGS += -Wdocumentation
|
||||
#CXXFLAGS_WARNINGS += -Wconversion
|
||||
#CXXFLAGS_WARNINGS += -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-c++98-c++11-c++14-compat -Wno-padded -Wno-weak-vtables -Wno-sign-conversion -Wno-shadow-field-in-constructor -Wno-conversion -Wno-switch-enum -Wno-old-style-cast
|
||||
|
||||
ifeq ($(MODERN),1)
|
||||
LDFLAGS += -fuse-ld=lld
|
||||
ifeq ($(OPTIMIZE_LTO),1)
|
||||
LDFLAGS += -Wl,--thinlto-jobs=all
|
||||
endif
|
||||
CXXFLAGS_WARNINGS +=
|
||||
CFLAGS_WARNINGS += -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-\#warnings
|
||||
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
|
||||
CFLAGS_SILENT += -Wno-unused-variable
|
27
Frameworks/OpenMPT/OpenMPT/build/make/warnings-gcc.mk
Normal file
27
Frameworks/OpenMPT/OpenMPT/build/make/warnings-gcc.mk
Normal file
|
@ -0,0 +1,27 @@
|
|||
|
||||
CXXFLAGS_WARNINGS += -Wcast-align -Wcast-qual -Wfloat-conversion -Wframe-larger-than=16000 -Winit-self -Wlogical-op -Wmissing-declarations -Wpointer-arith -Wstrict-aliasing -Wsuggest-override -Wundef
|
||||
CFLAGS_WARNINGS += -Wcast-align -Wcast-qual -Wfloat-conversion -Wlogical-op -Wundef
|
||||
|
||||
CXXFLAGS_WARNINGS += -Wno-psabi
|
||||
|
||||
ifeq ($(MODERN),1)
|
||||
LDFLAGS += -fuse-ld=gold
|
||||
CXXFLAGS_WARNINGS +=
|
||||
CFLAGS_WARNINGS += -Wframe-larger-than=4000
|
||||
#CXXFLAGS_WARNINGS += -Wstrict-aliasing -Wpointer-arith -Winit-self -Wshadow -Wswitch-enum -Wstrict-prototypes
|
||||
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-float-conversion
|
||||
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
|
10
Frameworks/OpenMPT/OpenMPT/build/svn_version/svn_version.h
Normal file
10
Frameworks/OpenMPT/OpenMPT/build/svn_version/svn_version.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
|
||||
#pragma once
|
||||
#define OPENMPT_VERSION_SVNVERSION "17609"
|
||||
#define OPENMPT_VERSION_REVISION 17609
|
||||
#define OPENMPT_VERSION_DIRTY 0
|
||||
#define OPENMPT_VERSION_MIXEDREVISIONS 0
|
||||
#define OPENMPT_VERSION_URL "https://source.openmpt.org/svn/openmpt/branches/OpenMPT-1.30"
|
||||
#define OPENMPT_VERSION_DATE "2022-06-30T15:43:27.573631Z"
|
||||
#define OPENMPT_VERSION_IS_PACKAGE 1
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
#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$"
|
|
@ -0,0 +1,6 @@
|
|||
@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
|
687
Frameworks/OpenMPT/OpenMPT/common/BuildSettings.h
Normal file
687
Frameworks/OpenMPT/OpenMPT/common/BuildSettings.h
Normal file
|
@ -0,0 +1,687 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
|
||||
#include "mpt/base/detect_compiler.hpp"
|
||||
#include "mpt/base/detect_os.hpp"
|
||||
#include "mpt/base/detect_quirks.hpp"
|
||||
|
||||
|
||||
|
||||
// set windows version early so that we can deduce dependencies from SDK version
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
#if !defined(WINVER) && !defined(_WIN32_WINDOWS) && !defined(_WIN32_WINNT)
|
||||
#if MPT_COMPILER_CLANG
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wreserved-id-macro"
|
||||
#endif // MPT_COMPILER_CLANG
|
||||
#define _WIN32_WINNT 0x0601 // _WIN32_WINNT_WIN7
|
||||
#if MPT_COMPILER_CLANG
|
||||
#pragma clang diagnostic pop
|
||||
#endif // MPT_COMPILER_CLANG
|
||||
#endif
|
||||
|
||||
#ifndef WINVER
|
||||
#if defined(_WIN32_WINNT)
|
||||
#define WINVER _WIN32_WINNT
|
||||
#elif defined(_WIN32_WINDOWS)
|
||||
#define WINVER _WIN32_WINDOWS
|
||||
#endif
|
||||
#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
|
||||
#define MPT_INLINE_NS mptx
|
||||
#elif defined(LIBOPENMPT_BUILD)
|
||||
// nothing
|
||||
#define MPT_INLINE_NS mpt_libopenmpt
|
||||
#else
|
||||
#error "either MODPLUG_TRACKER or LIBOPENMPT_BUILD has to be defined"
|
||||
#endif // MODPLUG_TRACKER || LIBOPENMPT_BUILD
|
||||
|
||||
|
||||
|
||||
#if defined(LIBOPENMPT_BUILD)
|
||||
|
||||
// Fixup dependencies which are currently not used in libopenmpt itself,
|
||||
// however might be set by some build systems like autotools anyway for simplicity.
|
||||
#ifdef MPT_WITH_FLAC
|
||||
#undef MPT_WITH_FLAC
|
||||
#endif
|
||||
|
||||
#endif // LIBOPENMPT_BUILD
|
||||
|
||||
|
||||
|
||||
// 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) && !defined(MPT_BUILD_UPDATESIGNTOOL)
|
||||
#define MPT_WITH_MFC
|
||||
#endif // !MPT_BUILD_WINESUPPORT && !MPT_BUILD_UPDATESIGNTOOL
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
// OpenMPT-only dependencies
|
||||
#define MPT_WITH_ANCIENT
|
||||
#if !defined(MPT_BUILD_RETRO) && !MPT_COMPILER_CLANG && !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
|
||||
#if defined(MPT_BUILD_RETRO)
|
||||
#define MPT_WITH_DIRECTSOUND
|
||||
#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
|
||||
#define MPT_WITH_VST
|
||||
|
||||
// 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
|
||||
#if (_WIN32_WINNT >= 0x0601)
|
||||
#define MPT_WITH_MEDIAFOUNDATION
|
||||
#endif
|
||||
#endif
|
||||
//#define MPT_WITH_MINIMP3
|
||||
//#define MPT_WITH_MINIZ
|
||||
#define MPT_WITH_MPG123
|
||||
#define MPT_WITH_OGG
|
||||
//#define MPT_WITH_STBVORBIS
|
||||
#define MPT_WITH_VORBIS
|
||||
#define MPT_WITH_VORBISFILE
|
||||
#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
|
||||
#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 global ComponentManager
|
||||
#define MPT_COMPONENT_MANAGER 1
|
||||
|
||||
// Support for externally linked samples e.g. in MPTM files
|
||||
#define MPT_EXTERNAL_SAMPLES
|
||||
|
||||
// Support mpt::ChartsetLocale
|
||||
#define MPT_ENABLE_CHARSET_LOCALE
|
||||
|
||||
// Use architecture-specific intrinsics
|
||||
#define MPT_ENABLE_ARCH_INTRINSICS
|
||||
|
||||
#if !defined(MPT_BUILD_RETRO)
|
||||
#define MPT_ENABLE_UPDATE
|
||||
#endif // !MPT_BUILD_RETRO
|
||||
|
||||
// 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
|
||||
|
||||
// (HACK) Define to build without any plugin support
|
||||
//#define NO_PLUGINS
|
||||
|
||||
#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 MPT_ALL_LOGGING
|
||||
#define MPT_COMPONENT_MANAGER 0
|
||||
//#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 architecture-specifid intrinsics in library builds. There is just about no codepath which would use it anyway.
|
||||
//#define MPT_ENABLE_ARCH_INTRINSICS
|
||||
#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_PLUGINS
|
||||
|
||||
#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
|
||||
|
||||
#elif MPT_OS_MACOSX_OR_IOS
|
||||
|
||||
#elif MPT_OS_DJGPP
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if (MPT_COMPILER_MSVC && !defined(MPT_USTRING_MODE_UTF8_FORCE)) || defined(MODPLUG_TRACKER)
|
||||
|
||||
// Use wide strings for MSVC because this is the native encoding on
|
||||
// microsoft platforms.
|
||||
|
||||
// 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_COMPILER_MSVC && !defined(MPT_USTRING_MODE_UTF8_FORCE)) || MPT_OS_WINDOWS || 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::ToAString 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 defined(MPT_ENABLE_ARCH_INTRINSICS)
|
||||
#if MPT_COMPILER_MSVC && defined(_M_IX86)
|
||||
|
||||
#define MPT_ENABLE_ARCH_X86
|
||||
|
||||
#define MPT_ENABLE_ARCH_INTRINSICS_SSE
|
||||
#define MPT_ENABLE_ARCH_INTRINSICS_SSE2
|
||||
|
||||
#elif MPT_COMPILER_MSVC && defined(_M_X64)
|
||||
|
||||
#define MPT_ENABLE_ARCH_AMD64
|
||||
|
||||
#define MPT_ENABLE_ARCH_INTRINSICS_SSE
|
||||
#define MPT_ENABLE_ARCH_INTRINSICS_SSE2
|
||||
|
||||
#endif // arch
|
||||
#endif // MPT_ENABLE_ARCH_INTRINSICS
|
||||
|
||||
#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_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(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.
|
||||
#if defined(MPT_WITH_VST)
|
||||
#undef MPT_WITH_VST
|
||||
#endif
|
||||
#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
|
||||
#define _CSTRING_DISABLE_NARROW_WIDE_CONVERSION
|
||||
#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
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX // Macros min(a,b) and max(a,b)
|
||||
#endif
|
||||
#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_FORMAT_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
|
||||
|
||||
#pragma warning(default:4800) // Implicit conversion from 'int' to bool. Possible information loss
|
||||
|
||||
#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
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
#ifndef UNICODE
|
||||
#define MPT_CHECK_WINDOWS_IGNORE_WARNING_NO_UNICODE
|
||||
#endif // !UNICODE
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
#ifdef MPT_WITH_ANCIENT
|
||||
#ifdef MPT_BUILD_MSVC_SHARED
|
||||
#define ANCIENT_API_DECLSPEC_DLLIMPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "mpt/base/namespace.hpp"
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
namespace mpt {
|
||||
|
||||
#ifndef MPT_NO_NAMESPACE
|
||||
using namespace ::mpt;
|
||||
#endif
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
||||
|
||||
#endif
|
475
Frameworks/OpenMPT/OpenMPT/common/ComponentManager.cpp
Normal file
475
Frameworks/OpenMPT/OpenMPT/common/ComponentManager.cpp
Normal file
|
@ -0,0 +1,475 @@
|
|||
/*
|
||||
* 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 "mpt/mutex/mutex.hpp"
|
||||
|
||||
#include "Logging.h"
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
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(MODPLUG_TRACKER)
|
||||
|
||||
|
||||
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 // MODPLUG_TRACKER
|
||||
|
||||
|
||||
#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_GLOBAL(LogInformation, "Components",
|
||||
MPT_UFORMAT("Constructing Component {}")
|
||||
( 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_ComponentListHeadEmpty = {nullptr, nullptr};
|
||||
static ComponentListEntry *g_ComponentListHead = &g_ComponentListHeadEmpty;
|
||||
return g_ComponentListHead;
|
||||
}
|
||||
|
||||
bool ComponentListPush(ComponentListEntry *entry)
|
||||
{
|
||||
mpt::lock_guard<mpt::mutex> guard(ComponentListMutex());
|
||||
#if MPT_MSVC_BEFORE(2019,0)
|
||||
// Guard against VS2017 compiler bug causing repeated initialization of inline variables.
|
||||
// See <https://developercommunity.visualstudio.com/t/static-inline-variable-gets-destroyed-multiple-tim/297876>.
|
||||
if(entry->next)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
entry->next = ComponentListHead();
|
||||
ComponentListHead() = entry;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static std::shared_ptr<ComponentManager> g_ComponentManager;
|
||||
|
||||
|
||||
void ComponentManager::Init(const IComponentManagerSettings &settings)
|
||||
{
|
||||
MPT_LOG_GLOBAL(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_GLOBAL(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)
|
||||
{
|
||||
if(entry->reg)
|
||||
{
|
||||
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_GLOBAL(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
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
508
Frameworks/OpenMPT/OpenMPT/common/ComponentManager.h
Normal file
508
Frameworks/OpenMPT/OpenMPT/common/ComponentManager.h
Normal file
|
@ -0,0 +1,508 @@
|
|||
/*
|
||||
* 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 "openmpt/all/BuildSettings.hpp"
|
||||
|
||||
#include "mpt/mutex/mutex.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "../common/misc_util.h"
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
#include "../misc/mptLibrary.h"
|
||||
#endif
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
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:
|
||||
|
||||
~ComponentBase() override;
|
||||
|
||||
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(MODPLUG_TRACKER)
|
||||
|
||||
|
||||
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) do { if(!Bind( func , libName , #func )) { SetBindFailed(); } } while(0)
|
||||
#define MPT_COMPONENT_BIND_OPTIONAL(libName, func) Bind( func , libName , #func )
|
||||
#define MPT_COMPONENT_BIND_SYMBOL(libName, symbol, func) do { if(!Bind( func , libName , symbol )) { SetBindFailed(); } } 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) do { if(!Bind( func , libName , #func MPT_COMPONENT_BINDWIN_SUFFIX )) { SetBindFailed(); } } 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) do { if(!Bind( func , libName , symbol MPT_COMPONENT_BINDWIN_SUFFIX )) { SetBindFailed(); } } 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 // MODPLUG_TRACKER
|
||||
|
||||
|
||||
#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);
|
||||
|
||||
template <typename TComponent>
|
||||
struct ComponentRegisterer
|
||||
{
|
||||
static inline void RegisterComponent(ComponentManager &componentManager)
|
||||
{
|
||||
componentManager.Register(ComponentFactory<TComponent>());
|
||||
}
|
||||
static inline ComponentListEntry &GetComponentListEntry()
|
||||
{
|
||||
static ComponentListEntry s_ComponentListEntry = {nullptr, &RegisterComponent};
|
||||
return s_ComponentListEntry;
|
||||
}
|
||||
static inline bool g_ComponentRegistered = ComponentListPush(&GetComponentListEntry());
|
||||
};
|
||||
|
||||
#define MPT_DECLARE_COMPONENT_MEMBERS(name, settingsKey) \
|
||||
public: \
|
||||
static constexpr const char *g_ID = #name ; \
|
||||
static constexpr const char *g_SettingsKey = settingsKey ; \
|
||||
static inline ComponentRegisterer< name > s_ComponentRegisterer; \
|
||||
/**/
|
||||
|
||||
|
||||
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(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;
|
||||
}
|
||||
|
||||
|
||||
#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();
|
||||
}
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
86
Frameworks/OpenMPT/OpenMPT/common/Dither.h
Normal file
86
Frameworks/OpenMPT/OpenMPT/common/Dither.h
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Dither.h
|
||||
* --------
|
||||
* Purpose: Dithering when converting to lower resolution sample formats.
|
||||
* 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
|
||||
|
||||
#include "openmpt/all/BuildSettings.hpp"
|
||||
|
||||
#include "mpt/base/macros.hpp"
|
||||
#include "mpt/string/types.hpp"
|
||||
#include "openmpt/soundbase/Dither.hpp"
|
||||
#include "openmpt/soundbase/DitherModPlug.hpp"
|
||||
#include "openmpt/soundbase/DitherNone.hpp"
|
||||
#include "openmpt/soundbase/DitherSimple.hpp"
|
||||
|
||||
#include "mptRandom.h"
|
||||
|
||||
#include <vector>
|
||||
#include <variant>
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
using Dither_Default = Dither_Simple;
|
||||
|
||||
|
||||
class DitherNamesOpenMPT
|
||||
{
|
||||
public:
|
||||
static mpt::ustring GetModeName(std::size_t mode)
|
||||
{
|
||||
mpt::ustring result;
|
||||
switch(mode)
|
||||
{
|
||||
case 0:
|
||||
// no dither
|
||||
result = MPT_USTRING("no");
|
||||
break;
|
||||
case 1:
|
||||
// chosen by OpenMPT code, might change
|
||||
result = MPT_USTRING("default");
|
||||
break;
|
||||
case 2:
|
||||
// rectangular, 0.5 bit depth, no noise shaping (original ModPlug Tracker)
|
||||
result = MPT_USTRING("0.5 bit");
|
||||
break;
|
||||
case 3:
|
||||
// rectangular, 1 bit depth, simple 1st order noise shaping
|
||||
result = MPT_USTRING("1 bit");
|
||||
break;
|
||||
default:
|
||||
result = MPT_USTRING("");
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
using DithersOpenMPT =
|
||||
Dithers<std::variant<MultiChannelDither<Dither_None>, MultiChannelDither<Dither_Default>, MultiChannelDither<Dither_ModPlug>, MultiChannelDither<Dither_Simple>>, DitherNamesOpenMPT, 4, 1, 0, mpt::good_prng>;
|
||||
|
||||
|
||||
struct DithersWrapperOpenMPT
|
||||
: DithersOpenMPT
|
||||
{
|
||||
template <typename Trd>
|
||||
DithersWrapperOpenMPT(Trd &rd, std::size_t mode = DithersOpenMPT::DefaultDither, std::size_t channels = DithersOpenMPT::DefaultChannels)
|
||||
: DithersOpenMPT(rd, mode, channels)
|
||||
{
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
453
Frameworks/OpenMPT/OpenMPT/common/FileReader.h
Normal file
453
Frameworks/OpenMPT/OpenMPT/common/FileReader.h
Normal file
|
@ -0,0 +1,453 @@
|
|||
/*
|
||||
* FileReader.h
|
||||
* ------------
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "openmpt/all/BuildSettings.hpp"
|
||||
|
||||
#include "mpt/io_read/filecursor.hpp"
|
||||
#include "mpt/io_read/filecursor_filename_traits.hpp"
|
||||
#include "mpt/io_read/filecursor_traits_filedata.hpp"
|
||||
#include "mpt/io_read/filecursor_traits_memory.hpp"
|
||||
#include "mpt/io_read/filereader.hpp"
|
||||
|
||||
#include "openmpt/base/Types.hpp"
|
||||
|
||||
#include "mptPathString.h"
|
||||
#include "mptStringBuffer.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "FileReaderFwd.h"
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
namespace FileReaderExt
|
||||
{
|
||||
|
||||
// Read a string of length srcSize into fixed-length char array destBuffer using a given read mode.
|
||||
// The file cursor is advanced by "srcSize" bytes.
|
||||
// Returns true if at least one byte could be read or 0 bytes were requested.
|
||||
template<mpt::String::ReadWriteMode mode, size_t destSize, typename TFileCursor>
|
||||
bool ReadString(TFileCursor &f, char (&destBuffer)[destSize], const typename TFileCursor::pos_type srcSize)
|
||||
{
|
||||
typename TFileCursor::PinnedView source = f.ReadPinnedView(srcSize); // Make sure the string is cached properly.
|
||||
typename TFileCursor::pos_type realSrcSize = source.size(); // In case fewer bytes are available
|
||||
mpt::String::WriteAutoBuf(destBuffer) = mpt::String::ReadBuf(mode, mpt::byte_cast<const char*>(source.data()), realSrcSize);
|
||||
return (realSrcSize > 0 || srcSize == 0);
|
||||
}
|
||||
|
||||
// Read a string of length srcSize into a std::string dest using a given read mode.
|
||||
// The file cursor is advanced by "srcSize" bytes.
|
||||
// Returns true if at least one character could be read or 0 characters were requested.
|
||||
template<mpt::String::ReadWriteMode mode, typename TFileCursor>
|
||||
bool ReadString(TFileCursor &f, std::string &dest, const typename TFileCursor::pos_type srcSize)
|
||||
{
|
||||
dest.clear();
|
||||
typename TFileCursor::PinnedView source = f.ReadPinnedView(srcSize); // Make sure the string is cached properly.
|
||||
typename TFileCursor::pos_type realSrcSize = source.size(); // In case fewer bytes are available
|
||||
dest = mpt::String::ReadBuf(mode, mpt::byte_cast<const char*>(source.data()), realSrcSize);
|
||||
return (realSrcSize > 0 || srcSize == 0);
|
||||
}
|
||||
|
||||
// Read a string of length srcSize into a mpt::charbuf dest using a given read mode.
|
||||
// The file cursor is advanced by "srcSize" bytes.
|
||||
// Returns true if at least one character could be read or 0 characters were requested.
|
||||
template<mpt::String::ReadWriteMode mode, std::size_t len, typename TFileCursor>
|
||||
bool ReadString(TFileCursor &f, mpt::charbuf<len> &dest, const typename TFileCursor::pos_type srcSize)
|
||||
{
|
||||
typename TFileCursor::PinnedView source = f.ReadPinnedView(srcSize); // Make sure the string is cached properly.
|
||||
typename TFileCursor::pos_type realSrcSize = source.size(); // In case fewer bytes are available
|
||||
dest = mpt::String::ReadBuf(mode, mpt::byte_cast<const char*>(source.data()), realSrcSize);
|
||||
return (realSrcSize > 0 || srcSize == 0);
|
||||
}
|
||||
|
||||
// Read a charset encoded string of length srcSize into a mpt::ustring dest using a given read mode.
|
||||
// The file cursor is advanced by "srcSize" bytes.
|
||||
// Returns true if at least one character could be read or 0 characters were requested.
|
||||
template<mpt::String::ReadWriteMode mode, typename TFileCursor>
|
||||
bool ReadString(TFileCursor &f, mpt::ustring &dest, mpt::Charset charset, const typename TFileCursor::pos_type srcSize)
|
||||
{
|
||||
dest.clear();
|
||||
typename TFileCursor::PinnedView source = f.ReadPinnedView(srcSize); // Make sure the string is cached properly.
|
||||
typename TFileCursor::pos_type realSrcSize = source.size(); // In case fewer bytes are available
|
||||
dest = mpt::ToUnicode(charset, mpt::String::ReadBuf(mode, mpt::byte_cast<const char*>(source.data()), realSrcSize));
|
||||
return (realSrcSize > 0 || srcSize == 0);
|
||||
}
|
||||
|
||||
// Read a string with a preprended length field of type Tsize (must be a packed<*,*> type) into a std::string dest using a given read mode.
|
||||
// The file cursor is advanced by the string length.
|
||||
// Returns true if the size field could be read and at least one character could be read or 0 characters were requested.
|
||||
template<typename Tsize, mpt::String::ReadWriteMode mode, size_t destSize, typename TFileCursor>
|
||||
bool ReadSizedString(TFileCursor &f, char (&destBuffer)[destSize], const typename TFileCursor::pos_type maxLength = std::numeric_limits<typename TFileCursor::pos_type>::max())
|
||||
{
|
||||
mpt::packed<typename Tsize::base_type, typename Tsize::endian_type> srcSize; // Enforce usage of a packed type by ensuring that the passed type has the required typedefs
|
||||
if(!mpt::IO::FileReader::Read(f, srcSize))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return FileReaderExt::ReadString<mode>(f, destBuffer, std::min(static_cast<typename TFileCursor::pos_type>(srcSize), maxLength));
|
||||
}
|
||||
|
||||
// Read a string with a preprended length field of type Tsize (must be a packed<*,*> type) into a std::string dest using a given read mode.
|
||||
// The file cursor is advanced by the string length.
|
||||
// Returns true if the size field could be read and at least one character could be read or 0 characters were requested.
|
||||
template<typename Tsize, mpt::String::ReadWriteMode mode, typename TFileCursor>
|
||||
bool ReadSizedString(TFileCursor &f, std::string &dest, const typename TFileCursor::pos_type maxLength = std::numeric_limits<typename TFileCursor::pos_type>::max())
|
||||
{
|
||||
mpt::packed<typename Tsize::base_type, typename Tsize::endian_type> srcSize; // Enforce usage of a packed type by ensuring that the passed type has the required typedefs
|
||||
if(!mpt::IO::FileReader::Read(f, srcSize))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return FileReaderExt::ReadString<mode>(f, dest, std::min(static_cast<typename TFileCursor::pos_type>(srcSize), maxLength));
|
||||
}
|
||||
|
||||
// Read a string with a preprended length field of type Tsize (must be a packed<*,*> type) into a mpt::charbuf dest using a given read mode.
|
||||
// The file cursor is advanced by the string length.
|
||||
// Returns true if the size field could be read and at least one character could be read or 0 characters were requested.
|
||||
template<typename Tsize, mpt::String::ReadWriteMode mode, std::size_t len, typename TFileCursor>
|
||||
bool ReadSizedString(TFileCursor &f, mpt::charbuf<len> &dest, const typename TFileCursor::pos_type maxLength = std::numeric_limits<typename TFileCursor::pos_type>::max())
|
||||
{
|
||||
mpt::packed<typename Tsize::base_type, typename Tsize::endian_type> srcSize; // Enforce usage of a packed type by ensuring that the passed type has the required typedefs
|
||||
if(!mpt::IO::FileReader::Read(f, srcSize))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return FileReaderExt::ReadString<mode>(f, dest, std::min(static_cast<typename TFileCursor::pos_type>(srcSize), maxLength));
|
||||
}
|
||||
|
||||
} // namespace FileReaderExt
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename Ttraits, typename Tfilenametraits>
|
||||
using FileCursor = mpt::IO::FileCursor<Ttraits, Tfilenametraits>;
|
||||
|
||||
template <typename Ttraits, typename Tfilenametraits>
|
||||
class FileReader
|
||||
: public FileCursor<Ttraits, Tfilenametraits>
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
using traits_type = Ttraits;
|
||||
using filename_traits_type = Tfilenametraits;
|
||||
|
||||
public:
|
||||
|
||||
using pos_type = typename traits_type::pos_type;
|
||||
using off_t = pos_type;
|
||||
|
||||
using data_type = typename traits_type::data_type;
|
||||
using ref_data_type = typename traits_type::ref_data_type;
|
||||
using shared_data_type = typename traits_type::shared_data_type;
|
||||
using value_data_type = typename traits_type::value_data_type;
|
||||
|
||||
using shared_filename_type = typename filename_traits_type::shared_filename_type;
|
||||
|
||||
public:
|
||||
|
||||
// Initialize invalid file reader object.
|
||||
FileReader()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FileReader(const FileCursor<Ttraits, Tfilenametraits> &other)
|
||||
: FileCursor<Ttraits, Tfilenametraits>(other)
|
||||
{
|
||||
return;
|
||||
}
|
||||
FileReader(FileCursor<Ttraits, Tfilenametraits> &&other)
|
||||
: FileCursor<Ttraits, Tfilenametraits>(std::move(other))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize file reader object with pointer to data and data length.
|
||||
template <typename Tbyte>
|
||||
explicit FileReader(mpt::span<Tbyte> bytedata, shared_filename_type filename = shared_filename_type{})
|
||||
: FileCursor<Ttraits, Tfilenametraits>(bytedata, std::move(filename))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize file reader object based on an existing file reader object window.
|
||||
explicit FileReader(value_data_type other, shared_filename_type filename = shared_filename_type{})
|
||||
: FileCursor<Ttraits, Tfilenametraits>(std::move(other), std::move(filename))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
template <typename T>
|
||||
bool Read(T &target)
|
||||
{
|
||||
return mpt::IO::FileReader::Read(*this, target);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T ReadIntLE()
|
||||
{
|
||||
return mpt::IO::FileReader::ReadIntLE<T>(*this);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T ReadIntBE()
|
||||
{
|
||||
return mpt::IO::FileReader::ReadIntLE<T>(*this);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T ReadTruncatedIntLE(pos_type size)
|
||||
{
|
||||
return mpt::IO::FileReader::ReadTruncatedIntLE<T>(*this, size);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T ReadSizedIntLE(pos_type size)
|
||||
{
|
||||
return mpt::IO::FileReader::ReadSizedIntLE<T>(*this, size);
|
||||
}
|
||||
|
||||
uint32 ReadUint32LE()
|
||||
{
|
||||
return mpt::IO::FileReader::ReadUint32LE(*this);
|
||||
}
|
||||
|
||||
uint32 ReadUint32BE()
|
||||
{
|
||||
return mpt::IO::FileReader::ReadUint32BE(*this);
|
||||
}
|
||||
|
||||
int32 ReadInt32LE()
|
||||
{
|
||||
return mpt::IO::FileReader::ReadInt32LE(*this);
|
||||
}
|
||||
|
||||
int32 ReadInt32BE()
|
||||
{
|
||||
return mpt::IO::FileReader::ReadInt32BE(*this);
|
||||
}
|
||||
|
||||
uint32 ReadUint24LE()
|
||||
{
|
||||
return mpt::IO::FileReader::ReadUint24LE(*this);
|
||||
}
|
||||
|
||||
uint32 ReadUint24BE()
|
||||
{
|
||||
return mpt::IO::FileReader::ReadUint24BE(*this);
|
||||
}
|
||||
|
||||
uint16 ReadUint16LE()
|
||||
{
|
||||
return mpt::IO::FileReader::ReadUint16LE(*this);
|
||||
}
|
||||
|
||||
uint16 ReadUint16BE()
|
||||
{
|
||||
return mpt::IO::FileReader::ReadUint16BE(*this);
|
||||
}
|
||||
|
||||
int16 ReadInt16LE()
|
||||
{
|
||||
return mpt::IO::FileReader::ReadInt16LE(*this);
|
||||
}
|
||||
|
||||
int16 ReadInt16BE()
|
||||
{
|
||||
return mpt::IO::FileReader::ReadInt16BE(*this);
|
||||
}
|
||||
|
||||
char ReadChar()
|
||||
{
|
||||
return mpt::IO::FileReader::ReadChar(*this);
|
||||
}
|
||||
|
||||
uint8 ReadUint8()
|
||||
{
|
||||
return mpt::IO::FileReader::ReadUint8(*this);
|
||||
}
|
||||
|
||||
int8 ReadInt8()
|
||||
{
|
||||
return mpt::IO::FileReader::ReadInt8(*this);
|
||||
}
|
||||
|
||||
float ReadFloatLE()
|
||||
{
|
||||
return mpt::IO::FileReader::ReadFloatLE(*this);
|
||||
}
|
||||
|
||||
float ReadFloatBE()
|
||||
{
|
||||
return mpt::IO::FileReader::ReadFloatBE(*this);
|
||||
}
|
||||
|
||||
double ReadDoubleLE()
|
||||
{
|
||||
return mpt::IO::FileReader::ReadDoubleLE(*this);
|
||||
}
|
||||
|
||||
double ReadDoubleBE()
|
||||
{
|
||||
return mpt::IO::FileReader::ReadDoubleBE(*this);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool ReadStruct(T &target)
|
||||
{
|
||||
return mpt::IO::FileReader::ReadStruct(*this, target);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
size_t ReadStructPartial(T &target, size_t partialSize = sizeof(T))
|
||||
{
|
||||
return mpt::IO::FileReader::ReadStructPartial(*this, target, partialSize);
|
||||
}
|
||||
|
||||
bool ReadNullString(std::string &dest, const pos_type maxLength = std::numeric_limits<pos_type>::max())
|
||||
{
|
||||
return mpt::IO::FileReader::ReadNullString(*this, dest, maxLength);
|
||||
}
|
||||
|
||||
bool ReadLine(std::string &dest, const pos_type maxLength = std::numeric_limits<pos_type>::max())
|
||||
{
|
||||
return mpt::IO::FileReader::ReadLine(*this, dest, maxLength);
|
||||
}
|
||||
|
||||
template<typename T, std::size_t destSize>
|
||||
bool ReadArray(T (&destArray)[destSize])
|
||||
{
|
||||
return mpt::IO::FileReader::ReadArray(*this, destArray);
|
||||
}
|
||||
|
||||
template<typename T, std::size_t destSize>
|
||||
bool ReadArray(std::array<T, destSize> &destArray)
|
||||
{
|
||||
return mpt::IO::FileReader::ReadArray(*this, destArray);
|
||||
}
|
||||
|
||||
template <typename T, std::size_t destSize>
|
||||
std::array<T, destSize> ReadArray()
|
||||
{
|
||||
return mpt::IO::FileReader::ReadArray<T, destSize>(*this);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool ReadVector(std::vector<T> &destVector, size_t destSize)
|
||||
{
|
||||
return mpt::IO::FileReader::ReadVector(*this, destVector, destSize);
|
||||
}
|
||||
|
||||
template<size_t N>
|
||||
bool ReadMagic(const char (&magic)[N])
|
||||
{
|
||||
return mpt::IO::FileReader::ReadMagic(*this, magic);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool ReadVarInt(T &target)
|
||||
{
|
||||
return mpt::IO::FileReader::ReadVarInt(*this, target);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
using Item = mpt::IO::FileReader::Chunk<T, FileReader>;
|
||||
|
||||
template <typename T>
|
||||
using ChunkList = mpt::IO::FileReader::ChunkList<T, FileReader>;
|
||||
|
||||
template<typename T>
|
||||
Item<T> ReadNextChunk(off_t alignment)
|
||||
{
|
||||
return mpt::IO::FileReader::ReadNextChunk<T, FileReader>(*this, alignment);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ChunkList<T> ReadChunks(off_t alignment)
|
||||
{
|
||||
return mpt::IO::FileReader::ReadChunks<T, FileReader>(*this, alignment);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ChunkList<T> ReadChunksUntil(off_t alignment, decltype(T().GetID()) stopAtID)
|
||||
{
|
||||
return mpt::IO::FileReader::ReadChunksUntil<T, FileReader>(*this, alignment, stopAtID);
|
||||
}
|
||||
|
||||
template<mpt::String::ReadWriteMode mode, size_t destSize>
|
||||
bool ReadString(char (&destBuffer)[destSize], const pos_type srcSize)
|
||||
{
|
||||
return FileReaderExt::ReadString<mode>(*this, destBuffer, srcSize);
|
||||
}
|
||||
|
||||
template<mpt::String::ReadWriteMode mode>
|
||||
bool ReadString(std::string &dest, const pos_type srcSize)
|
||||
{
|
||||
return FileReaderExt::ReadString<mode>(*this, dest, srcSize);
|
||||
}
|
||||
|
||||
template<mpt::String::ReadWriteMode mode, std::size_t len>
|
||||
bool ReadString(mpt::charbuf<len> &dest, const pos_type srcSize)
|
||||
{
|
||||
return FileReaderExt::ReadString<mode>(*this, dest, srcSize);
|
||||
}
|
||||
|
||||
template<mpt::String::ReadWriteMode mode>
|
||||
bool ReadString(mpt::ustring &dest, mpt::Charset charset, const pos_type srcSize)
|
||||
{
|
||||
return FileReaderExt::ReadString<mode>(*this, dest, charset, srcSize);
|
||||
}
|
||||
|
||||
template<typename Tsize, mpt::String::ReadWriteMode mode, size_t destSize>
|
||||
bool ReadSizedString(char (&destBuffer)[destSize], const pos_type maxLength = std::numeric_limits<pos_type>::max())
|
||||
{
|
||||
return FileReaderExt::ReadSizedString<Tsize, mode>(*this, destBuffer, maxLength);
|
||||
}
|
||||
|
||||
template<typename Tsize, mpt::String::ReadWriteMode mode>
|
||||
bool ReadSizedString(std::string &dest, const pos_type maxLength = std::numeric_limits<pos_type>::max())
|
||||
{
|
||||
return FileReaderExt::ReadSizedString<Tsize, mode>(*this, dest, maxLength);
|
||||
}
|
||||
|
||||
template<typename Tsize, mpt::String::ReadWriteMode mode, std::size_t len>
|
||||
bool ReadSizedString(mpt::charbuf<len> &dest, const pos_type maxLength = std::numeric_limits<pos_type>::max())
|
||||
{
|
||||
return FileReaderExt::ReadSizedString<Tsize, mode, len>(*this, dest, maxLength);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
using FileCursor = detail::FileCursor<mpt::IO::FileCursorTraitsFileData, mpt::IO::FileCursorFilenameTraits<mpt::PathString>>;
|
||||
using FileReader = detail::FileReader<mpt::IO::FileCursorTraitsFileData, mpt::IO::FileCursorFilenameTraits<mpt::PathString>>;
|
||||
|
||||
using ChunkReader = FileReader;
|
||||
|
||||
using MemoryFileCursor = detail::FileCursor<mpt::IO::FileCursorTraitsMemory, mpt::IO::FileCursorFilenameTraitsNone>;
|
||||
using MemoryFileReader = detail::FileReader<mpt::IO::FileCursorTraitsMemory, mpt::IO::FileCursorFilenameTraitsNone>;
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
65
Frameworks/OpenMPT/OpenMPT/common/FileReaderFwd.h
Normal file
65
Frameworks/OpenMPT/OpenMPT/common/FileReaderFwd.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* 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 "openmpt/all/BuildSettings.hpp"
|
||||
|
||||
#include "mpt/base/namespace.hpp"
|
||||
|
||||
namespace mpt {
|
||||
inline namespace MPT_INLINE_NS {
|
||||
namespace IO {
|
||||
|
||||
class FileCursorTraitsMemory;
|
||||
|
||||
class FileCursorTraitsFileData;
|
||||
|
||||
class FileCursorFilenameTraitsNone;
|
||||
|
||||
template <typename Tpath>
|
||||
class FileCursorFilenameTraits;
|
||||
|
||||
template <typename Ttraits, typename Tfilenametraits>
|
||||
class FileCursor;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
namespace mpt {
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename Ttraits, typename Tfilenametraits>
|
||||
using FileCursor = mpt::IO::FileCursor<Ttraits, Tfilenametraits>;
|
||||
|
||||
template <typename Ttraits, typename Tfilenametraits>
|
||||
class FileReader;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
namespace mpt {
|
||||
|
||||
class PathString;
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
using FileCursor = detail::FileCursor<mpt::IO::FileCursorTraitsFileData, mpt::IO::FileCursorFilenameTraits<mpt::PathString>>;
|
||||
using FileReader = detail::FileReader<mpt::IO::FileCursorTraitsFileData, mpt::IO::FileCursorFilenameTraits<mpt::PathString>>;
|
||||
|
||||
using MemoryFileCursor = detail::FileCursor<mpt::IO::FileCursorTraitsMemory, mpt::IO::FileCursorFilenameTraitsNone>;
|
||||
using MemoryFileReader = detail::FileReader<mpt::IO::FileCursorTraitsMemory, mpt::IO::FileCursorFilenameTraitsNone>;
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
||||
|
430
Frameworks/OpenMPT/OpenMPT/common/Logging.cpp
Normal file
430
Frameworks/OpenMPT/OpenMPT/common/Logging.cpp
Normal file
|
@ -0,0 +1,430 @@
|
|||
/*
|
||||
* 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 "mpt/io/base.hpp"
|
||||
#include "mpt/io/io.hpp"
|
||||
#include "mpt/io/io_stdstream.hpp"
|
||||
|
||||
#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
|
||||
{
|
||||
|
||||
|
||||
|
||||
#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) noexcept
|
||||
{
|
||||
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 GlobalLogger::SendLogMessage(const mpt::source_location &loc, LogLevel level, const char *facility, const mpt::ustring &text) const
|
||||
{
|
||||
#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::trim_right(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 std::optional<mpt::ofstream> s_logfile;
|
||||
if(!s_logfile)
|
||||
{
|
||||
s_logfile.emplace(P_("mptrack.log"), std::ios::app);
|
||||
}
|
||||
if(s_logfile)
|
||||
{
|
||||
mpt::IO::WriteText(*s_logfile, mpt::ToCharset(mpt::CharsetLogfile, MPT_UFORMAT("{}+{} {}({}): {} [{}]\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_UFORMAT("{}({}): +{} {} [{}]\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
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
|
||||
namespace Trace {
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
// Debugging functionality will use simple globals.
|
||||
|
||||
std::atomic<bool> g_Enabled{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::afmt::fix(period) << std::endl;
|
||||
f << "Events/second: " << mpt::afmt::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_AFORMAT("0x{}")(mpt::afmt::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::afmt::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
|
228
Frameworks/OpenMPT/OpenMPT/common/Logging.h
Normal file
228
Frameworks/OpenMPT/OpenMPT/common/Logging.h
Normal file
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
* 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 "openmpt/all/BuildSettings.hpp"
|
||||
|
||||
#include "openmpt/logging/Logger.hpp"
|
||||
|
||||
#include "mptPathString.h"
|
||||
#include "mptString.h"
|
||||
|
||||
#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
|
||||
#include <atomic>
|
||||
#endif
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
/*
|
||||
|
||||
|
||||
Build time logging configuration:
|
||||
|
||||
* #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_GLOBAL(LogWarning, "sounddev", "some message");
|
||||
MPT_LOG_GLOBAL(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_GLOBAL(LogWarning, "sounddev", MPT_UFORMAT("Some message: foo={}, bar=0x{}")(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_GLOBAL(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.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
|
||||
|
||||
#if defined(MPT_LOG_GLOBAL_LEVEL_STATIC)
|
||||
#if (MPT_LOG_GLOBAL_LEVEL <= 0)
|
||||
// All logging has beeen statically disabled.
|
||||
// All logging code gets compiled and immediately dead-code eliminated.
|
||||
#define MPT_LOG_IS_DISABLED
|
||||
#endif
|
||||
inline 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) noexcept;
|
||||
#else
|
||||
MPT_FORCEINLINE bool IsFacilityActive(const char * /*facility*/ ) noexcept { return true; }
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
class GlobalLogger final
|
||||
: public ILogger
|
||||
{
|
||||
public:
|
||||
GlobalLogger() = default;
|
||||
~GlobalLogger() final = default;
|
||||
public:
|
||||
bool IsLevelActive(LogLevel level) const noexcept override
|
||||
{
|
||||
return (mpt::log::GlobalLogLevel >= level);
|
||||
}
|
||||
bool IsFacilityActive(const char *facility) const noexcept override
|
||||
{
|
||||
return mpt::log::IsFacilityActive(facility);
|
||||
}
|
||||
void SendLogMessage(const mpt::source_location &loc, LogLevel level, const char *facility, const mpt::ustring &message) const override;
|
||||
};
|
||||
|
||||
|
||||
#define MPT_LOG_GLOBAL(level, facility, text) MPT_LOG(mpt::log::GlobalLogger{}, (level), (facility), (text))
|
||||
|
||||
|
||||
|
||||
#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() do { if(mpt::log::Trace::g_Enabled) { mpt::log::Trace::Trace(MPT_SOURCE_LOCATION_CURRENT()); } } while(0)
|
||||
|
||||
} // namespace Trace
|
||||
|
||||
#else // !MODPLUG_TRACKER
|
||||
|
||||
#define MPT_TRACE_SCOPE() do { } while(0)
|
||||
|
||||
#define MPT_TRACE() do { } while(0)
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
|
||||
} // namespace log
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
221
Frameworks/OpenMPT/OpenMPT/common/Profiler.cpp
Normal file
221
Frameworks/OpenMPT/OpenMPT/common/Profiler.cpp
Normal file
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
* 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::afmt::right(6, mpt::afmt::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
|
128
Frameworks/OpenMPT/OpenMPT/common/Profiler.h
Normal file
128
Frameworks/OpenMPT/OpenMPT/common/Profiler.h
Normal file
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* 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 "openmpt/all/BuildSettings.hpp"
|
||||
|
||||
|
||||
#include "mpt/mutex/mutex.hpp"
|
||||
|
||||
#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) do { } while(0)
|
||||
#define OPENMPT_PROFILE_FUNCTION(cat) do { } while(0)
|
||||
|
||||
|
||||
#endif // USE_PROFILER
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
221
Frameworks/OpenMPT/OpenMPT/common/misc_util.h
Normal file
221
Frameworks/OpenMPT/OpenMPT/common/misc_util.h
Normal file
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
* 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 "openmpt/all/BuildSettings.hpp"
|
||||
|
||||
#include "mpt/base/span.hpp"
|
||||
#include "mpt/exception_text/exception_text.hpp"
|
||||
|
||||
#include "mptAssert.h"
|
||||
#include "mptBaseMacros.h"
|
||||
#include "mptBaseTypes.h"
|
||||
#include "mptBaseUtils.h"
|
||||
#include "mptString.h"
|
||||
|
||||
// old
|
||||
#include "mptBaseUtils.h"
|
||||
#include "mptStringFormat.h"
|
||||
#include "mptStringParse.h"
|
||||
#include "mptTime.h"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <optional>
|
||||
#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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
||||
#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
|
139
Frameworks/OpenMPT/OpenMPT/common/mptAssert.h
Normal file
139
Frameworks/OpenMPT/OpenMPT/common/mptAssert.h
Normal file
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* 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 "openmpt/all/BuildSettings.hpp"
|
||||
|
||||
|
||||
#include "mpt/base/source_location.hpp"
|
||||
#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) do { } 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) do { if(!(expr)) { OPENMPT_NAMESPACE::AssertHandler(MPT_SOURCE_LOCATION_CURRENT(), #expr); } MPT_CHECKER_ASSUME(expr); } while(0)
|
||||
#define MPT_ASSERT_ALWAYS_MSG(expr, msg) do { if(!(expr)) { OPENMPT_NAMESPACE::AssertHandler(MPT_SOURCE_LOCATION_CURRENT(), #expr, msg); } MPT_CHECKER_ASSUME(expr); } 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) do { if(!(expr)) { OPENMPT_NAMESPACE::AssertHandler(MPT_SOURCE_LOCATION_CURRENT(), #expr); } MPT_CHECKER_ASSUME(expr); } while(0)
|
||||
#define MPT_ASSERT_ALWAYS_MSG(expr, msg) do { if(!(expr)) { OPENMPT_NAMESPACE::AssertHandler(MPT_SOURCE_LOCATION_CURRENT(), #expr, msg); } MPT_CHECKER_ASSUME(expr); } while(0)
|
||||
#ifndef MPT_ASSERT_HANDLER_NEEDED
|
||||
#define MPT_ASSERT_HANDLER_NEEDED
|
||||
#endif
|
||||
|
||||
#else // !NO_ASSERTS
|
||||
|
||||
#define MPT_ASSERT_NOTREACHED() do { if constexpr(!(0)) { OPENMPT_NAMESPACE::AssertHandler(MPT_SOURCE_LOCATION_CURRENT(), "0"); } MPT_CHECKER_ASSUME(0); } while(0)
|
||||
#define MPT_ASSERT(expr) do { if(!(expr)) { OPENMPT_NAMESPACE::AssertHandler(MPT_SOURCE_LOCATION_CURRENT(), #expr); } MPT_CHECKER_ASSUME(expr); } while(0)
|
||||
#define MPT_ASSERT_MSG(expr, msg) do { if(!(expr)) { OPENMPT_NAMESPACE::AssertHandler(MPT_SOURCE_LOCATION_CURRENT(), #expr, msg); } MPT_CHECKER_ASSUME(expr); } while(0)
|
||||
#define MPT_ASSERT_ALWAYS(expr) do { if(!(expr)) { OPENMPT_NAMESPACE::AssertHandler(MPT_SOURCE_LOCATION_CURRENT(), #expr); } MPT_CHECKER_ASSUME(expr); } while(0)
|
||||
#define MPT_ASSERT_ALWAYS_MSG(expr, msg) do { if(!(expr)) { OPENMPT_NAMESPACE::AssertHandler(MPT_SOURCE_LOCATION_CURRENT(), #expr, msg); } MPT_CHECKER_ASSUME(expr); } 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
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
66
Frameworks/OpenMPT/OpenMPT/common/mptBaseMacros.h
Normal file
66
Frameworks/OpenMPT/OpenMPT/common/mptBaseMacros.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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 "openmpt/all/BuildSettings.hpp"
|
||||
|
||||
#include "mpt/base/preprocessor.hpp"
|
||||
#include "mpt/base/compiletime_warning.hpp"
|
||||
#include "mpt/base/macros.hpp"
|
||||
|
||||
#if MPT_CXX_AT_LEAST(20)
|
||||
#include <version>
|
||||
#else // !C++20
|
||||
#include <array>
|
||||
#endif // C++20
|
||||
|
||||
#include <array>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
|
||||
#define MPT_UNREFERENCED_PARAMETER(x) MPT_UNUSED(x)
|
||||
#define MPT_UNUSED_VARIABLE(x) MPT_UNUSED(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
|
54
Frameworks/OpenMPT/OpenMPT/common/mptBaseTypes.h
Normal file
54
Frameworks/OpenMPT/OpenMPT/common/mptBaseTypes.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* 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 "openmpt/all/BuildSettings.hpp"
|
||||
|
||||
#include "mpt/base/integer.hpp"
|
||||
#include "mpt/base/floatingpoint.hpp"
|
||||
#include "mpt/base/pointer.hpp"
|
||||
#include "mpt/base/check_platform.hpp"
|
||||
#include "mpt/base/source_location.hpp"
|
||||
#include "openmpt/base/Types.hpp"
|
||||
|
||||
#include "mptBaseMacros.h"
|
||||
|
||||
#include <array>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
constexpr inline int8 int8_min = std::numeric_limits<int8>::min();
|
||||
constexpr inline int16 int16_min = std::numeric_limits<int16>::min();
|
||||
constexpr inline int32 int32_min = std::numeric_limits<int32>::min();
|
||||
constexpr inline int64 int64_min = std::numeric_limits<int64>::min();
|
||||
|
||||
constexpr inline int8 int8_max = std::numeric_limits<int8>::max();
|
||||
constexpr inline int16 int16_max = std::numeric_limits<int16>::max();
|
||||
constexpr inline int32 int32_max = std::numeric_limits<int32>::max();
|
||||
constexpr inline int64 int64_max = std::numeric_limits<int64>::max();
|
||||
|
||||
constexpr inline uint8 uint8_max = std::numeric_limits<uint8>::max();
|
||||
constexpr inline uint16 uint16_max = std::numeric_limits<uint16>::max();
|
||||
constexpr inline uint32 uint32_max = std::numeric_limits<uint32>::max();
|
||||
constexpr inline uint64 uint64_max = std::numeric_limits<uint64>::max();
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
177
Frameworks/OpenMPT/OpenMPT/common/mptBaseUtils.h
Normal file
177
Frameworks/OpenMPT/OpenMPT/common/mptBaseUtils.h
Normal file
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* 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 "openmpt/all/BuildSettings.hpp"
|
||||
|
||||
|
||||
#include "mpt/base/algorithm.hpp"
|
||||
#include "mpt/base/arithmetic_shift.hpp"
|
||||
#include "mpt/base/array.hpp"
|
||||
#include "mpt/base/bit.hpp"
|
||||
#include "mpt/base/constexpr_throw.hpp"
|
||||
#include "mpt/base/math.hpp"
|
||||
#include "mpt/base/memory.hpp"
|
||||
#include "mpt/base/numeric.hpp"
|
||||
#include "mpt/base/saturate_cast.hpp"
|
||||
#include "mpt/base/saturate_round.hpp"
|
||||
#include "mpt/base/utility.hpp"
|
||||
#include "mpt/base/wrapping_divide.hpp"
|
||||
|
||||
#include "mptBaseMacros.h"
|
||||
#include "mptBaseTypes.h"
|
||||
|
||||
#include <algorithm>
|
||||
#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
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
inline void Clear(T& x)
|
||||
{
|
||||
static_assert(!std::is_pointer<T>::value);
|
||||
mpt::reset(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.");
|
||||
mpt::memclear(a);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Like Limit, but with upperlimit only.
|
||||
template<class T, class C>
|
||||
inline void LimitMax(T& val, const C upperLimit)
|
||||
{
|
||||
if(val > upperLimit)
|
||||
val = upperLimit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
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 Util {
|
||||
|
||||
// Multiply two 32-bit integers, receive 64-bit result.
|
||||
// MSVC generates unnecessarily complicated code for the unoptimized variant using _allmul.
|
||||
MPT_CONSTEXPR20_FUN int64 mul32to64(int32 a, int32 b)
|
||||
{
|
||||
#if MPT_COMPILER_MSVC && (defined(_M_IX86) || defined(_M_X64))
|
||||
MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED20())
|
||||
{
|
||||
return static_cast<int64>(a) * b;
|
||||
} else
|
||||
{
|
||||
return __emul(a, b);
|
||||
}
|
||||
#else
|
||||
return static_cast<int64>(a) * b;
|
||||
#endif
|
||||
}
|
||||
|
||||
MPT_CONSTEXPR20_FUN uint64 mul32to64_unsigned(uint32 a, uint32 b)
|
||||
{
|
||||
#if MPT_COMPILER_MSVC && (defined(_M_IX86) || defined(_M_X64))
|
||||
MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED20())
|
||||
{
|
||||
return static_cast<uint64>(a) * b;
|
||||
} else
|
||||
{
|
||||
return __emulu(a, b);
|
||||
}
|
||||
#else
|
||||
return static_cast<uint64>(a) * b;
|
||||
#endif
|
||||
}
|
||||
|
||||
MPT_CONSTEXPR20_FUN int32 muldiv(int32 a, int32 b, int32 c)
|
||||
{
|
||||
return mpt::saturate_cast<int32>( mul32to64( a, b ) / c );
|
||||
}
|
||||
|
||||
MPT_CONSTEXPR20_FUN 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_CONSTEXPR20_FUN uint32 muldiv_unsigned(uint32 a, uint32 b, uint32 c)
|
||||
{
|
||||
return mpt::saturate_cast<uint32>( mul32to64_unsigned( a, b ) / c );
|
||||
}
|
||||
MPT_CONSTEXPR20_FUN uint32 muldivr_unsigned(uint32 a, uint32 b, uint32 c)
|
||||
{
|
||||
return mpt::saturate_cast<uint32>( ( mul32to64_unsigned( a, b ) + ( c / 2u ) ) / c );
|
||||
}
|
||||
|
||||
constexpr 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);
|
||||
}
|
||||
|
||||
} // namespace Util
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
608
Frameworks/OpenMPT/OpenMPT/common/mptFileIO.cpp
Normal file
608
Frameworks/OpenMPT/OpenMPT/common/mptFileIO.cpp
Normal file
|
@ -0,0 +1,608 @@
|
|||
/*
|
||||
* 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"
|
||||
|
||||
#if defined(MPT_ENABLE_FILEIO)
|
||||
#include "mpt/io/io.hpp"
|
||||
#include "mpt/io/io_stdstream.hpp"
|
||||
#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
|
||||
#include "mpt/system_error/system_error.hpp"
|
||||
#include "FileReader.h"
|
||||
#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS
|
||||
#endif // MPT_ENABLE_FILEIO
|
||||
|
||||
#if defined(MPT_ENABLE_FILEIO)
|
||||
#include <stdexcept>
|
||||
#endif // MPT_ENABLE_FILEIO
|
||||
|
||||
#ifdef MODPLUG_TRACKER
|
||||
#if MPT_OS_WINDOWS
|
||||
#include <windows.h>
|
||||
#include <WinIoCtl.h>
|
||||
#include <io.h>
|
||||
#endif // MPT_OS_WINDOWS
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
#if defined(MPT_ENABLE_FILEIO)
|
||||
#if MPT_COMPILER_MSVC
|
||||
#include <stdio.h>
|
||||
#include <tchar.h>
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
#endif // MPT_ENABLE_FILEIO
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
#if defined(MPT_ENABLE_FILEIO)
|
||||
|
||||
|
||||
|
||||
#if !defined(MPT_BUILD_SILENCE_LIBOPENMPT_CONFIGURATION_WARNINGS)
|
||||
|
||||
#if defined(MPT_COMPILER_QUIRK_WINDOWS_FSTREAM_NO_WCHAR)
|
||||
#if MPT_GCC_BEFORE(9,1,0)
|
||||
MPT_WARNING("Warning: MinGW with GCC earlier than 9.1 detected. Standard library does neither provide std::fstream wchar_t overloads nor std::filesystem with wchar_t support. Unicode filename support is thus unavailable.")
|
||||
#endif // MPT_GCC_AT_LEAST(9,1,0)
|
||||
#endif // MPT_COMPILER_QUIRK_WINDOWS_FSTREAM_NO_WCHAR
|
||||
|
||||
#endif // !MPT_BUILD_SILENCE_LIBOPENMPT_CONFIGURATION_WARNINGS
|
||||
|
||||
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
std::FILE * SafeOutputFile::internal_fopen(const mpt::PathString &filename, std::ios_base::openmode mode, FlushMode flushMode)
|
||||
{
|
||||
m_f = nullptr;
|
||||
mpt::tstring fopen_mode = convert_mode(mode, flushMode);
|
||||
if(fopen_mode.empty())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
std::FILE *f =
|
||||
#ifdef UNICODE
|
||||
_wfopen(filename.AsNativePrefixed().c_str(), fopen_mode.c_str())
|
||||
#else
|
||||
std::fopen(filename.AsNativePrefixed().c_str(), fopen_mode.c_str())
|
||||
#endif
|
||||
;
|
||||
if(!f)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
if(mode & std::ios_base::ate)
|
||||
{
|
||||
if(std::fseek(f, 0, SEEK_END) != 0)
|
||||
{
|
||||
std::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)
|
||||
{
|
||||
std::fclose(m_f);
|
||||
}
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
if(mayThrow && (stream().exceptions() & (std::ios::badbit | std::ios::failbit)))
|
||||
{
|
||||
// cppcheck-suppress exceptThrowInDestructor
|
||||
throw std::ios_base::failure(std::string("Error before flushing file buffers."));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(!stream().rdbuf())
|
||||
{
|
||||
#if MPT_COMPILER_MSVC
|
||||
if(m_f)
|
||||
{
|
||||
std::fclose(m_f);
|
||||
}
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
if(mayThrow && (stream().exceptions() & (std::ios::badbit | std::ios::failbit)))
|
||||
{
|
||||
// cppcheck-suppress exceptThrowInDestructor
|
||||
throw std::ios_base::failure(std::string("Error before flushing file buffers."));
|
||||
}
|
||||
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(std::fflush(m_f) != 0)
|
||||
{
|
||||
errorOnFlush = true;
|
||||
}
|
||||
}
|
||||
if(std::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(std::fflush(m_f) != 0)
|
||||
{
|
||||
errorOnFlush = true;
|
||||
}
|
||||
}
|
||||
if(std::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 mpt::buffer_cast<std::string>(buf);
|
||||
}
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
InputFile::InputFile(const mpt::PathString &filename, bool allowWholeFileCaching)
|
||||
: m_IsValid(false)
|
||||
, m_IsCached(false)
|
||||
{
|
||||
MPT_ASSERT(!filename.empty());
|
||||
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(mpt::in_range<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)).size() != mpt::saturate_cast<std::size_t>(filesize))
|
||||
{
|
||||
m_File.close();
|
||||
return false;
|
||||
}
|
||||
if(!mpt::IO::SeekBegin(m_File))
|
||||
{
|
||||
m_File.close();
|
||||
return false;
|
||||
}
|
||||
m_IsCached = true;
|
||||
m_IsValid = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_IsValid = true;
|
||||
return m_File.good();
|
||||
}
|
||||
|
||||
|
||||
bool InputFile::IsValid() const
|
||||
{
|
||||
return m_IsValid && m_File.good();
|
||||
}
|
||||
|
||||
|
||||
bool InputFile::IsCached() const
|
||||
{
|
||||
return m_IsCached;
|
||||
}
|
||||
|
||||
|
||||
mpt::PathString InputFile::GetFilename() 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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
|
||||
|
||||
|
||||
OnDiskFileWrapper::OnDiskFileWrapper(FileCursor &file, const mpt::PathString &fileNameExtension)
|
||||
: m_IsTempFile(false)
|
||||
{
|
||||
try
|
||||
{
|
||||
file.Rewind();
|
||||
if(!file.GetOptionalFileName())
|
||||
{
|
||||
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("Error creating temporary file.");
|
||||
}
|
||||
while(!file.EndOfFile())
|
||||
{
|
||||
FileCursor::PinnedView view = file.ReadPinnedView(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("Incomplete Write.");
|
||||
}
|
||||
towrite -= chunkSize;
|
||||
written += chunkSize;
|
||||
} while(towrite > 0);
|
||||
}
|
||||
f.close();
|
||||
|
||||
#else // !MPT_ONDISKFILEWRAPPER_NO_CREATEFILE
|
||||
|
||||
HANDLE hFile = NULL;
|
||||
#if MPT_OS_WINDOWS_WINRT
|
||||
hFile = mpt::windows::CheckFileHANDLE(CreateFile2(tempName.AsNative().c_str(), GENERIC_WRITE, FILE_SHARE_READ, CREATE_ALWAYS, NULL));
|
||||
#else
|
||||
hFile = mpt::windows::CheckFileHANDLE(CreateFile(tempName.AsNative().c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL));
|
||||
#endif
|
||||
while(!file.EndOfFile())
|
||||
{
|
||||
FileCursor::PinnedView view = file.ReadPinnedView(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;
|
||||
try
|
||||
{
|
||||
mpt::windows::CheckBOOL(WriteFile(hFile, view.data() + written, chunkSize, &chunkDone, NULL));
|
||||
} catch(...)
|
||||
{
|
||||
CloseHandle(hFile);
|
||||
hFile = NULL;
|
||||
throw;
|
||||
}
|
||||
if(chunkDone != chunkSize)
|
||||
{
|
||||
CloseHandle(hFile);
|
||||
hFile = NULL;
|
||||
throw std::runtime_error("Incomplete WriteFile().");
|
||||
}
|
||||
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.GetOptionalFileName().value();
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
|
||||
|
||||
#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS
|
||||
|
||||
|
||||
#else // !MPT_ENABLE_FILEIO
|
||||
|
||||
MPT_MSVC_WORKAROUND_LNK4221(mptFileIO)
|
||||
|
||||
#endif // MPT_ENABLE_FILEIO
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
398
Frameworks/OpenMPT/OpenMPT/common/mptFileIO.h
Normal file
398
Frameworks/OpenMPT/OpenMPT/common/mptFileIO.h
Normal file
|
@ -0,0 +1,398 @@
|
|||
/*
|
||||
* 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 "openmpt/all/BuildSettings.hpp"
|
||||
|
||||
#if defined(MPT_ENABLE_FILEIO)
|
||||
|
||||
#include "mpt/io_read/filecursor_memory.hpp"
|
||||
#include "mpt/io_read/filecursor_stdstream.hpp"
|
||||
|
||||
#include "../common/mptString.h"
|
||||
#include "../common/mptPathString.h"
|
||||
#include "../common/FileReaderFwd.h"
|
||||
|
||||
#if defined(MPT_COMPILER_QUIRK_WINDOWS_FSTREAM_NO_WCHAR)
|
||||
#if MPT_GCC_AT_LEAST(9,1,0)
|
||||
#include <filesystem>
|
||||
#endif // MPT_GCC_AT_LEAST(9,1,0)
|
||||
#endif // MPT_COMPILER_QUIRK_WINDOWS_FSTREAM_NO_WCHAR
|
||||
#include <fstream>
|
||||
#include <ios>
|
||||
#include <ostream>
|
||||
#include <streambuf>
|
||||
#include <utility>
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
#include <cstdio>
|
||||
#endif // !MPT_COMPILER_MSVC
|
||||
|
||||
#ifdef MODPLUG_TRACKER
|
||||
#if MPT_OS_WINDOWS
|
||||
#include <windows.h>
|
||||
#endif // MPT_OS_WINDOWS
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
#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
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<typename Tbase>
|
||||
inline void fstream_open(Tbase & base, const mpt::PathString & filename, std::ios_base::openmode mode)
|
||||
{
|
||||
#if defined(MPT_COMPILER_QUIRK_WINDOWS_FSTREAM_NO_WCHAR)
|
||||
#if MPT_GCC_AT_LEAST(9,1,0)
|
||||
base.open(static_cast<std::filesystem::path>(filename.AsNative()), mode);
|
||||
#else // !MPT_GCC_AT_LEAST(9,1,0)
|
||||
// Warning: MinGW with GCC earlier than 9.1 detected. Standard library does neither provide std::fstream wchar_t overloads nor std::filesystem with wchar_t support. Unicode filename support is thus unavailable.
|
||||
base.open(mpt::ToCharset(mpt::Charset::Locale, filename.AsNative()).c_str(), mode);
|
||||
#endif // MPT_GCC_AT_LEAST(9,1,0)
|
||||
#else // !MPT_COMPILER_QUIRK_WINDOWS_FSTREAM_NO_WCHAR
|
||||
base.open(filename.AsNativePrefixed().c_str(), mode);
|
||||
#endif // MPT_COMPILER_QUIRK_WINDOWS_FSTREAM_NO_WCHAR
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// We cannot rely on implicit conversion of mpt::PathString to std::filesystem::path when constructing std::fstream
|
||||
// because of broken overload implementation in GCC libstdc++ 8, 9, 10.
|
||||
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95642
|
||||
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90704
|
||||
|
||||
class fstream
|
||||
: public std::fstream
|
||||
{
|
||||
private:
|
||||
typedef std::fstream Tbase;
|
||||
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);
|
||||
}
|
||||
#if MPT_COMPILER_MSVC
|
||||
protected:
|
||||
fstream(std::FILE * file)
|
||||
: std::fstream(file)
|
||||
{
|
||||
}
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
public:
|
||||
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:
|
||||
ifstream() {}
|
||||
ifstream(const mpt::PathString & filename, std::ios_base::openmode mode = std::ios_base::in)
|
||||
{
|
||||
detail::fstream_open<Tbase>(*this, filename, mode);
|
||||
}
|
||||
#if MPT_COMPILER_MSVC
|
||||
protected:
|
||||
ifstream(std::FILE * file)
|
||||
: std::ifstream(file)
|
||||
{
|
||||
}
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
public:
|
||||
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:
|
||||
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(std::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
|
||||
std::FILE *m_f = nullptr;
|
||||
#else // !MPT_COMPILER_MSVC
|
||||
mpt::ofstream m_s;
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
#if MPT_COMPILER_MSVC
|
||||
class FILEostream
|
||||
: public mpt::ofstream
|
||||
{
|
||||
public:
|
||||
FILEostream(std::FILE * file)
|
||||
: mpt::ofstream(file)
|
||||
{
|
||||
return;
|
||||
}
|
||||
};
|
||||
FILEostream m_s;
|
||||
static mpt::tstring convert_mode(std::ios_base::openmode mode, FlushMode flushMode);
|
||||
std::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_IsValid;
|
||||
bool m_IsCached;
|
||||
std::vector<std::byte> m_Cache;
|
||||
public:
|
||||
InputFile(const mpt::PathString &filename, bool allowWholeFileCaching = false);
|
||||
~InputFile();
|
||||
bool IsValid() const;
|
||||
bool IsCached() const;
|
||||
mpt::PathString GetFilename() const;
|
||||
std::istream& GetStream();
|
||||
mpt::const_byte_span GetCache();
|
||||
private:
|
||||
bool Open(const mpt::PathString &filename, bool allowWholeFileCaching = false);
|
||||
};
|
||||
|
||||
|
||||
template <typename Targ1>
|
||||
inline FileCursor make_FileCursor(Targ1 &&arg1)
|
||||
{
|
||||
return mpt::IO::make_FileCursor<mpt::PathString>(std::forward<Targ1>(arg1));
|
||||
}
|
||||
|
||||
template <typename Targ1, typename Targ2>
|
||||
inline FileCursor make_FileCursor(Targ1 &&arg1, Targ2 &&arg2)
|
||||
{
|
||||
return mpt::IO::make_FileCursor<mpt::PathString>(std::forward<Targ1>(arg1), std::forward<Targ2>(arg2));
|
||||
}
|
||||
|
||||
|
||||
// templated in order to reduce header inter-dependencies
|
||||
class InputFile;
|
||||
template <typename TInputFile, std::enable_if_t<std::is_same<TInputFile, InputFile>::value, bool> = true>
|
||||
inline FileCursor make_FileCursor(TInputFile &file)
|
||||
{
|
||||
if(!file.IsValid())
|
||||
{
|
||||
return FileCursor();
|
||||
}
|
||||
if(file.IsCached())
|
||||
{
|
||||
return mpt::IO::make_FileCursor<mpt::PathString>(file.GetCache(), std::make_shared<mpt::PathString>(file.GetFilename()));
|
||||
} else
|
||||
{
|
||||
return mpt::IO::make_FileCursor<mpt::PathString>(file.GetStream(), std::make_shared<mpt::PathString>(file.GetFilename()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename Targ1>
|
||||
inline FileCursor GetFileReader(Targ1 &&arg1)
|
||||
{
|
||||
return make_FileCursor(std::forward<Targ1>(arg1));
|
||||
}
|
||||
|
||||
|
||||
template <typename Targ1, typename Targ2>
|
||||
inline FileCursor GetFileReader(Targ1 &&arg1, Targ2 &&arg2)
|
||||
{
|
||||
return make_FileCursor(std::forward<Targ1>(arg1), std::forward<Targ2>(arg2));
|
||||
}
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
|
||||
|
||||
class OnDiskFileWrapper
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
mpt::PathString m_Filename;
|
||||
bool m_IsTempFile;
|
||||
|
||||
public:
|
||||
|
||||
OnDiskFileWrapper(FileCursor& file, const mpt::PathString& fileNameExtension = P_("tmp"));
|
||||
|
||||
~OnDiskFileWrapper();
|
||||
|
||||
public:
|
||||
|
||||
bool IsValid() const;
|
||||
|
||||
mpt::PathString GetFilename() const;
|
||||
|
||||
}; // class OnDiskFileWrapper
|
||||
|
||||
#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS
|
||||
|
||||
|
||||
#endif // MPT_ENABLE_FILEIO
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
||||
|
872
Frameworks/OpenMPT/OpenMPT/common/mptPathString.cpp
Normal file
872
Frameworks/OpenMPT/OpenMPT/common/mptPathString.cpp
Normal file
|
@ -0,0 +1,872 @@
|
|||
/*
|
||||
* 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 "mpt/uuid/uuid.hpp"
|
||||
|
||||
#include "misc_util.h"
|
||||
|
||||
#include "mptRandom.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 defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
|
||||
|
||||
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 = {};
|
||||
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 = {};
|
||||
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 // MODPLUG_TRACKER && MPT_OS_WINDOWS
|
||||
|
||||
|
||||
#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[0] == PC_('\\') && path[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 = {};
|
||||
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 defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
|
||||
#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 // MODPLUG_TRACKER && MPT_OS_WINDOWS
|
||||
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER) && 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(mpt::global_prng()).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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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 && MPT_OS_WINDOWS
|
||||
|
||||
} // 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;
|
||||
}
|
||||
|
||||
#if MPT_CXX_AT_LEAST(20)
|
||||
static inline char8_t SanitizeFilenameChar(char8_t c)
|
||||
{
|
||||
if( c == u8'\\' ||
|
||||
c == u8'\"' ||
|
||||
c == u8'/' ||
|
||||
c == u8':' ||
|
||||
c == u8'?' ||
|
||||
c == u8'<' ||
|
||||
c == u8'>' ||
|
||||
c == u8'|' ||
|
||||
c == u8'*')
|
||||
{
|
||||
c = u8'_';
|
||||
}
|
||||
return c;
|
||||
}
|
||||
#endif
|
||||
|
||||
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
|
505
Frameworks/OpenMPT/OpenMPT/common/mptPathString.h
Normal file
505
Frameworks/OpenMPT/OpenMPT/common/mptPathString.h
Normal file
|
@ -0,0 +1,505 @@
|
|||
/*
|
||||
* 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 "openmpt/all/BuildSettings.hpp"
|
||||
|
||||
#include "mptString.h"
|
||||
|
||||
#include "mpt/base/namespace.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "openmpt/base/FlagSet.hpp"
|
||||
|
||||
#define MPT_DEPRECATED_PATH
|
||||
//#define MPT_DEPRECATED_PATH [[deprecated]]
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
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(PathString && other) noexcept
|
||||
: path(std::move(other.path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
PathString & assign(const PathString & other)
|
||||
{
|
||||
path = other.path;
|
||||
return *this;
|
||||
}
|
||||
PathString & assign(PathString && other) noexcept
|
||||
{
|
||||
path = std::move(other.path);
|
||||
return *this;
|
||||
}
|
||||
PathString & operator = (const PathString & other)
|
||||
{
|
||||
return assign(other);
|
||||
}
|
||||
PathString &operator = (PathString && other) noexcept
|
||||
{
|
||||
return assign(std::move(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 defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
|
||||
|
||||
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;
|
||||
|
||||
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 ToAString(const mpt::PathString & x) { return mpt::ToCharset(mpt::Charset::Locale, x.ToUnicode()); }
|
||||
#else
|
||||
MPT_DEPRECATED_PATH inline std::string ToAString(const mpt::PathString & x) { return mpt::ToCharset(mpt::Charset::Locale, x.AsNative()); }
|
||||
#endif
|
||||
#else
|
||||
MPT_DEPRECATED_PATH inline std::string ToAString(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 defined(MODPLUG_TRACKER) && MPT_OS_WINDOWS
|
||||
|
||||
// Returns the application executable path or an empty string (if unknown), e.g. "C:\mptrack\"
|
||||
mpt::PathString GetExecutablePath();
|
||||
|
||||
#if !MPT_OS_WINDOWS_WINRT
|
||||
// Returns the system directory path, e.g. "C:\Windows\System32\"
|
||||
mpt::PathString GetSystemPath();
|
||||
#endif // !MPT_OS_WINDOWS_WINRT
|
||||
|
||||
#endif // MODPLUG_TRACKER && MPT_OS_WINDOWS
|
||||
|
||||
#if defined(MODPLUG_TRACKER) && 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();
|
||||
};
|
||||
|
||||
|
||||
// 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 && MPT_OS_WINDOWS
|
||||
|
||||
} // 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)
|
||||
{
|
||||
mpt::append(m_MimeTypes, type.m_MimeTypes);
|
||||
mpt::append(m_Extensions, type.m_Extensions);
|
||||
mpt::append(m_Prefixes, type.m_Prefixes);
|
||||
}
|
||||
}
|
||||
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
|
62
Frameworks/OpenMPT/OpenMPT/common/mptRandom.cpp
Normal file
62
Frameworks/OpenMPT/OpenMPT/common/mptRandom.cpp
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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"
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
#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
|
140
Frameworks/OpenMPT/OpenMPT/common/mptRandom.h
Normal file
140
Frameworks/OpenMPT/OpenMPT/common/mptRandom.h
Normal file
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* 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 "openmpt/all/BuildSettings.hpp"
|
||||
|
||||
#include "mpt/base/bit.hpp"
|
||||
#include "mpt/mutex/mutex.hpp"
|
||||
#ifdef MODPLUG_TRACKER
|
||||
#include "mpt/random/crand.hpp"
|
||||
#endif // MODPLUG_TRACKER
|
||||
#include "mpt/random/default_engines.hpp"
|
||||
#include "mpt/random/device.hpp"
|
||||
#include "mpt/random/engine.hpp"
|
||||
#include "mpt/random/engine_lcg.hpp"
|
||||
#include "mpt/random/seed.hpp"
|
||||
|
||||
#include <limits>
|
||||
#include <random>
|
||||
|
||||
|
||||
|
||||
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
|
||||
{
|
||||
|
||||
|
||||
|
||||
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_CONSTEXPRINLINE typename engine_traits<Trng>::result_type min()
|
||||
{
|
||||
return Trng::min();
|
||||
}
|
||||
static MPT_CONSTEXPRINLINE typename engine_traits<Trng>::result_type max()
|
||||
{
|
||||
return Trng::max();
|
||||
}
|
||||
static MPT_CONSTEXPRINLINE 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()();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#ifdef MPT_BUILD_FUZZER
|
||||
|
||||
// Use deterministic seeding
|
||||
using random_device = deterministc_random_device;
|
||||
|
||||
#else // !MPT_BUILD_FUZZER
|
||||
|
||||
// mpt::random_device always generates 32 bits of entropy
|
||||
using random_device = mpt::sane_random_device;
|
||||
|
||||
#endif // MPT_BUILD_FUZZER
|
||||
|
||||
|
||||
#ifdef MPT_BUILD_FUZZER
|
||||
|
||||
// Use fast PRNGs in order to not waste time fuzzing more complex PRNG
|
||||
// implementations.
|
||||
using fast_prng = deterministic_fast_engine;
|
||||
using good_prng = deterministic_good_engine;
|
||||
|
||||
#else // !MPT_BUILD_FUZZER
|
||||
|
||||
// We cannot use std::minstd_rand here because it has not a power-of-2 sized
|
||||
// output domain which we rely upon.
|
||||
using fast_prng = fast_engine; // about 3 ALU operations, ~32bit of state, suited for inner loops
|
||||
using good_prng = good_engine;
|
||||
|
||||
#endif // MPT_BUILD_FUZZER
|
||||
|
||||
|
||||
using default_prng = mpt::good_prng;
|
||||
|
||||
|
||||
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
|
826
Frameworks/OpenMPT/OpenMPT/common/mptString.cpp
Normal file
826
Frameworks/OpenMPT/OpenMPT/common/mptString.cpp
Normal file
|
@ -0,0 +1,826 @@
|
|||
/*
|
||||
* mptString.cpp
|
||||
* -------------
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "mptString.h"
|
||||
|
||||
#include "mpt/string/types.hpp"
|
||||
#include "mpt/string/utility.hpp"
|
||||
#include "mpt/string_transcode/transcode.hpp"
|
||||
|
||||
#include <locale>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
#include <cwctype>
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
#include <wctype.h>
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
#include <windows.h>
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
|
||||
|
||||
Quick guide to the OpenMPT string type jungle
|
||||
=============================================
|
||||
|
||||
|
||||
|
||||
This quick guide is only meant as a hint. There may be valid reasons to not
|
||||
honor the recommendations found here. Staying consistent with surrounding and/or
|
||||
related code sections may also be important.
|
||||
|
||||
|
||||
|
||||
List of string types
|
||||
--------------------
|
||||
|
||||
* std::string (OpenMPT, libopenmpt)
|
||||
C++ string of unspecifed 8bit encoding. Try to always document the
|
||||
encoding if not clear from context. Do not use unless there is an obvious
|
||||
reason to do so.
|
||||
|
||||
* std::wstring (OpenMPT)
|
||||
UTF16 (on windows) or UTF32 (otherwise). Do not use unless there is an
|
||||
obvious reason to do so.
|
||||
|
||||
* mpt::lstring (OpenMPT)
|
||||
OpenMPT locale string type. The encoding is always CP_ACP. Do not use unless
|
||||
there is an obvious reason to do so.
|
||||
|
||||
* char* (OpenMPT, libopenmpt)
|
||||
C string of unspecified encoding. Use only for static literals or in
|
||||
performance critical inner loops where full control and avoidance of memory
|
||||
allocations is required.
|
||||
|
||||
* wchar_t* (OpenMPT)
|
||||
C wide string. Use only if Unicode is required for static literals or in
|
||||
performance critical inner loops where full control and avoidance of memory
|
||||
allocation is required.
|
||||
|
||||
* mpt::winstring (OpenMPT)
|
||||
OpenMPT type-safe string to interface with native WinAPI, either encoded in
|
||||
locale/CP_ACP (if !UNICODE) or UTF16 (if UNICODE).
|
||||
|
||||
* CString (OpenMPT)
|
||||
MFC string type, either encoded in locale/CP_ACP (if !UNICODE) or UTF16 (if
|
||||
UNICODE). Specify literals with _T(""). Use in MFC GUI code.
|
||||
|
||||
* CStringA (OpenMPT)
|
||||
MFC ANSI string type. The encoding is always CP_ACP. Do not use.
|
||||
|
||||
* CStringW (OpenMPT)
|
||||
MFC Unicode string type. Do not use.
|
||||
|
||||
* mpt::PathString (OpenMPT, libopenmpt)
|
||||
String type representing paths and filenames. Always use for these in order
|
||||
to avoid potentially lossy conversions. Use P_("") macro for
|
||||
literals.
|
||||
|
||||
* mpt::ustring (OpenMPT, libopenmpt)
|
||||
The default unicode string type. Can be encoded in UTF8 or UTF16 or UTF32,
|
||||
depending on MPT_USTRING_MODE_* and sizeof(wchar_t). Literals can written as
|
||||
U_(""). Use as your default string type if no other string type is
|
||||
a measurably better fit.
|
||||
|
||||
* MPT_UTF8 (OpenMPT, libopenmpt)
|
||||
Macro that generates a mpt::ustring from string literals containing
|
||||
non-ascii characters. In order to keep the source code in ascii encoding,
|
||||
always express non-ascii characters using explicit \x23 escaping. Note that
|
||||
depending on the underlying type of mpt::ustring, MPT_UTF8 *requires* a
|
||||
runtime conversion. Only use for string literals containing non-ascii
|
||||
characters (use MPT_USTRING otherwise).
|
||||
|
||||
* MPT_ULITERAL / MPT_UCHAR / mpt::uchar (OpenMPT, libopenmpt)
|
||||
Macros which generate string literals, char literals and the char literal
|
||||
type respectively. These are especially useful in constexpr contexts or
|
||||
global data where MPT_USTRING is either unusable or requires a global
|
||||
contructor to run. Do NOT use as a performance optimization in place of
|
||||
MPT_USTRING however, because MPT_USTRING can be converted to C++11/14 user
|
||||
defined literals eventually, while MPT_ULITERAL cannot because of constexpr
|
||||
requirements.
|
||||
|
||||
* mpt::RawPathString (OpenMPT, libopenmpt)
|
||||
Internal representation of mpt::PathString. Only use for parsing path
|
||||
fragments.
|
||||
|
||||
* mpt::u8string (OpenMPT, libopenmpt)
|
||||
Internal representation of mpt::ustring. Do not use directly. Ever.
|
||||
|
||||
* std::basic_string<char> (OpenMPT)
|
||||
Same as std::string. Do not use std::basic_string in the templated form.
|
||||
|
||||
* std::basic_string<wchar_t> (OpenMPT)
|
||||
Same as std::wstring. Do not use std::basic_string in the templated form.
|
||||
|
||||
The following string types are available in order to avoid the need to overload
|
||||
functions on a huge variety of string types. Use only ever as function argument
|
||||
types.
|
||||
Note that the locale charset is not available on all libopenmpt builds (in which
|
||||
case the option is ignored or a sensible fallback is used; these types are
|
||||
always available).
|
||||
All these types publicly inherit from mpt::ustring and do not contain any
|
||||
additional state. This means that they work the same way as mpt::ustring does
|
||||
and do support type-slicing for both, read and write accesses.
|
||||
These types only add conversion constructors for all string types that have a
|
||||
defined encoding and for all 8bit string types using the specified encoding
|
||||
heuristic.
|
||||
|
||||
* AnyUnicodeString (OpenMPT, libopenmpt)
|
||||
Is constructible from any Unicode string.
|
||||
|
||||
* AnyString (OpenMPT, libopenmpt)
|
||||
Tries to do the smartest auto-magic we can do.
|
||||
|
||||
* AnyStringLocale (OpenMPT, libopenmpt)
|
||||
char-based strings are assumed to be in locale encoding.
|
||||
|
||||
* AnyStringUTF8orLocale (OpenMPT, libopenmpt)
|
||||
char-based strings are tried in UTF8 first, if this fails, locale is used.
|
||||
|
||||
* AnyStringUTF8 (OpenMPT, libopenmpt)
|
||||
char-based strings are assumed to be in UTF8.
|
||||
|
||||
|
||||
|
||||
Encoding of 8bit strings
|
||||
------------------------
|
||||
|
||||
8bit strings have an unspecified encoding. When the string is contained within a
|
||||
CSoundFile object, the encoding is most likely CSoundFile::GetCharsetInternal(),
|
||||
otherwise, try to gather the most probable encoding from surrounding or related
|
||||
code sections.
|
||||
|
||||
|
||||
|
||||
Decision tree to help deciding which string type to use
|
||||
-------------------------------------------------------
|
||||
|
||||
if in libopenmpt
|
||||
if in libopenmpt c++ interface
|
||||
T = std::string, the encoding is utf8
|
||||
elif in libopenmpt c interface
|
||||
T = char*, the encoding is utf8
|
||||
elif performance critical inner loop
|
||||
T = char*, document the encoding if not clear from context
|
||||
elif string literal containing non-ascii characters
|
||||
T = MPT_UTF8
|
||||
elif path or file
|
||||
if parsing path fragments
|
||||
T = mpt::RawPathString
|
||||
template your function on the concrete underlying string type
|
||||
(std::string and std::wstring) or use preprocessor MPT_OS_WINDOWS
|
||||
else
|
||||
T = mpt::PathString
|
||||
fi
|
||||
else
|
||||
T = mpt::ustring
|
||||
fi
|
||||
else
|
||||
if performance critical inner loop
|
||||
if needs unicode support
|
||||
T = mpt::uchar* / MPT_ULITERAL
|
||||
else
|
||||
T = char*, document the encoding if not clear from context
|
||||
fi
|
||||
elif string literal containing non-ascii characters
|
||||
T = MPT_UTF8
|
||||
elif path or file
|
||||
if parsing path fragments
|
||||
T = mpt::RawPathString
|
||||
template your function on the concrete underlying string type
|
||||
(std::string and std::wstring) or use preprocessor MPT_OS_WINDOWS
|
||||
else
|
||||
T = mpt::PathString
|
||||
fi
|
||||
elif winapi interfacing code
|
||||
T = mpt::winstring
|
||||
elif mfc/gui code
|
||||
T = CString
|
||||
else
|
||||
if constexpr context or global data
|
||||
T = mpt::uchar* / MPT_ULITERAL
|
||||
else
|
||||
T = mpt::ustring
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
This boils down to: Prefer mpt::PathString and mpt::ustring, and only use any
|
||||
other string type if there is an obvious reason to do so.
|
||||
|
||||
|
||||
|
||||
Character set conversions
|
||||
-------------------------
|
||||
|
||||
Character set conversions in OpenMPT are always fuzzy.
|
||||
|
||||
Behaviour in case of an invalid source encoding and behaviour in case of an
|
||||
unrepresentable destination encoding can be any of the following:
|
||||
* The character is replaced by some replacement character ('?' or L'\ufffd' in
|
||||
most cases).
|
||||
* The character is replaced by a similar character (either semantically
|
||||
similiar or visually similar).
|
||||
* The character is transcribed with some ASCII text.
|
||||
* The character is discarded.
|
||||
* Conversion stops at this very character.
|
||||
|
||||
Additionally. conversion may stop or continue on \0 characters in the middle of
|
||||
the string.
|
||||
|
||||
Behaviour can vary from one conversion tuple to any other.
|
||||
|
||||
If you need to ensure lossless conversion, do a roundtrip conversion and check
|
||||
for equality.
|
||||
|
||||
|
||||
|
||||
Unicode handling
|
||||
----------------
|
||||
|
||||
OpenMPT is generally not aware of and does not handle different Unicode
|
||||
normalization forms.
|
||||
You should be aware of the following possibilities:
|
||||
* Conversion between UTF8, UTF16, UTF32 may or may not change between NFC and
|
||||
NFD.
|
||||
* Conversion from any non-Unicode 8bit encoding can result in both, NFC or NFD
|
||||
forms.
|
||||
* Conversion to any non-Unicode 8bit encoding may or may not involve
|
||||
conversion to NFC, NFD, NFKC or NFKD during the conversion. This in
|
||||
particular means that conversion of decomposed german umlauts to ISO8859-1
|
||||
may fail.
|
||||
* Changing the normalization form of path strings may render the file
|
||||
inaccessible.
|
||||
|
||||
Unicode BOM may or may not be preserved and/or discarded during conversion.
|
||||
|
||||
Invalid Unicode code points may be treated as invalid or as valid characters
|
||||
when converting between different Unicode encodings.
|
||||
|
||||
|
||||
|
||||
Interfacing with WinAPI
|
||||
-----------------------
|
||||
|
||||
When in MFC code, use CString.
|
||||
When in non MFC code, either use std::wstring when directly interfacing with
|
||||
APIs only available in WCHAR variants, or use mpt::winstring and
|
||||
mpt::WinStringBuf helpers otherwise.
|
||||
Specify TCHAR string literals with _T("foo") in mptrack/, and with TEXT("foo")
|
||||
in common/ or sounddev/. _T() requires <tchar.h> which is specific to the MSVC
|
||||
runtime and not portable across compilers. TEXT() is from <windows.h>. We use
|
||||
_T() in mptrack/ only because it is shorter.
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
namespace mpt { namespace String {
|
||||
|
||||
|
||||
|
||||
#define C(x) (mpt::char_value((x)))
|
||||
|
||||
// AMS1 actually only supports ASCII plus the modified control characters and no high chars at all.
|
||||
// Just default to CP437 for those to keep things simple.
|
||||
static constexpr char32_t CharsetTableCP437AMS[256] = {
|
||||
C(' '),0x0001,0x0002,0x0003,0x00e4,0x0005,0x00e5,0x0007,0x0008,0x0009,0x000a,0x000b,0x000c,0x000d,0x00c4,0x00c5, // differs from CP437
|
||||
0x0010,0x0011,0x0012,0x0013,0x00f6,0x0015,0x0016,0x0017,0x0018,0x00d6,0x001a,0x001b,0x001c,0x001d,0x001e,0x001f, // differs from CP437
|
||||
0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027,0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f,
|
||||
0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f,
|
||||
0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,
|
||||
0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f,
|
||||
0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f,
|
||||
0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x2302,
|
||||
0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7,0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x00ec,0x00c4,0x00c5,
|
||||
0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00f2,0x00fb,0x00f9,0x00ff,0x00d6,0x00dc,0x00a2,0x00a3,0x00a5,0x20a7,0x0192,
|
||||
0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba,0x00bf,0x2310,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb,
|
||||
0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510,
|
||||
0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f,0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567,
|
||||
0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b,0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580,
|
||||
0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4,0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229,
|
||||
0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248,0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0
|
||||
};
|
||||
|
||||
// AMS2: Looking at Velvet Studio's bitmap font (TPIC32.PCX), these appear to be the only supported non-ASCII chars.
|
||||
static constexpr char32_t CharsetTableCP437AMS2[256] = {
|
||||
C(' '),0x00a9,0x221a,0x00b7,C('0'),C('1'),C('2'),C('3'),C('4'),C('5'),C('6'),C('7'),C('8'),C('9'),C('A'),C('B'), // differs from CP437
|
||||
C('C'),C('D'),C('E'),C('F'),C(' '),0x00a7,C(' '),C(' '),C(' '),C(' '),C(' '),C(' '),C(' '),C(' '),C(' '),C(' '), // differs from CP437
|
||||
0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027,0x0028,0x0029,0x002a,0x002b,0x002c,0x002d,0x002e,0x002f,
|
||||
0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,0x003f,
|
||||
0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,
|
||||
0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,0x0058,0x0059,0x005a,0x005b,0x005c,0x005d,0x005e,0x005f,
|
||||
0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f,
|
||||
0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,0x007a,0x007b,0x007c,0x007d,0x007e,0x2302,
|
||||
0x00c7,0x00fc,0x00e9,0x00e2,0x00e4,0x00e0,0x00e5,0x00e7,0x00ea,0x00eb,0x00e8,0x00ef,0x00ee,0x00ec,0x00c4,0x00c5,
|
||||
0x00c9,0x00e6,0x00c6,0x00f4,0x00f6,0x00f2,0x00fb,0x00f9,0x00ff,0x00d6,0x00dc,0x00a2,0x00a3,0x00a5,0x20a7,0x0192,
|
||||
0x00e1,0x00ed,0x00f3,0x00fa,0x00f1,0x00d1,0x00aa,0x00ba,0x00bf,0x2310,0x00ac,0x00bd,0x00bc,0x00a1,0x00ab,0x00bb,
|
||||
0x2591,0x2592,0x2593,0x2502,0x2524,0x2561,0x2562,0x2556,0x2555,0x2563,0x2551,0x2557,0x255d,0x255c,0x255b,0x2510,
|
||||
0x2514,0x2534,0x252c,0x251c,0x2500,0x253c,0x255e,0x255f,0x255a,0x2554,0x2569,0x2566,0x2560,0x2550,0x256c,0x2567,
|
||||
0x2568,0x2564,0x2565,0x2559,0x2558,0x2552,0x2553,0x256b,0x256a,0x2518,0x250c,0x2588,0x2584,0x258c,0x2590,0x2580,
|
||||
0x03b1,0x00df,0x0393,0x03c0,0x03a3,0x03c3,0x00b5,0x03c4,0x03a6,0x0398,0x03a9,0x03b4,0x221e,0x03c6,0x03b5,0x2229,
|
||||
0x2261,0x00b1,0x2265,0x2264,0x2320,0x2321,0x00f7,0x2248,0x00b0,0x2219,0x00b7,0x221a,0x207f,0x00b2,0x25a0,0x00a0
|
||||
};
|
||||
|
||||
#undef C
|
||||
|
||||
|
||||
// templated on 8bit strings because of type-safe variants
|
||||
template<typename Tdststring>
|
||||
static Tdststring EncodeImpl(Charset charset, const mpt::widestring &src)
|
||||
{
|
||||
static_assert(sizeof(typename Tdststring::value_type) == sizeof(char));
|
||||
static_assert(mpt::is_character<typename Tdststring::value_type>::value);
|
||||
switch(charset)
|
||||
{
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
case Charset::Locale: return mpt::encode<Tdststring>(mpt::logical_encoding::locale, src); break;
|
||||
#endif
|
||||
case Charset::UTF8: return mpt::encode<Tdststring>(mpt::common_encoding::utf8, src); break;
|
||||
case Charset::ASCII: return mpt::encode<Tdststring>(mpt::common_encoding::ascii, src); break;
|
||||
case Charset::ISO8859_1: return mpt::encode<Tdststring>(mpt::common_encoding::iso8859_1, src); break;
|
||||
case Charset::ISO8859_15: return mpt::encode<Tdststring>(mpt::common_encoding::iso8859_15, src); break;
|
||||
case Charset::CP850: return mpt::encode<Tdststring>(mpt::common_encoding::cp850, src); break;
|
||||
case Charset::CP437: return mpt::encode<Tdststring>(mpt::common_encoding::cp437, src); break;
|
||||
case Charset::CP437AMS: return mpt::encode<Tdststring>(CharsetTableCP437AMS, src); break;
|
||||
case Charset::CP437AMS2: return mpt::encode<Tdststring>(CharsetTableCP437AMS2, src); break;
|
||||
case Charset::Windows1252: return mpt::encode<Tdststring>(mpt::common_encoding::windows1252, src); break;
|
||||
case Charset::Amiga: return mpt::encode<Tdststring>(mpt::common_encoding::amiga, src); break;
|
||||
case Charset::RISC_OS: return mpt::encode<Tdststring>(mpt::common_encoding::riscos, src); break;
|
||||
case Charset::ISO8859_1_no_C1: return mpt::encode<Tdststring>(mpt::common_encoding::iso8859_1_no_c1, src); break;
|
||||
case Charset::ISO8859_15_no_C1: return mpt::encode<Tdststring>(mpt::common_encoding::iso8859_15_no_c1, src); break;
|
||||
case Charset::Amiga_no_C1: return mpt::encode<Tdststring>(mpt::common_encoding::amiga_no_c1, src); break;
|
||||
}
|
||||
return Tdststring();
|
||||
}
|
||||
|
||||
|
||||
// templated on 8bit strings because of type-safe variants
|
||||
template<typename Tsrcstring>
|
||||
static mpt::widestring DecodeImpl(Charset charset, const Tsrcstring &src)
|
||||
{
|
||||
static_assert(sizeof(typename Tsrcstring::value_type) == sizeof(char));
|
||||
static_assert(mpt::is_character<typename Tsrcstring::value_type>::value);
|
||||
switch(charset)
|
||||
{
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
case Charset::Locale: return mpt::decode<Tsrcstring>(mpt::logical_encoding::locale, src); break;
|
||||
#endif
|
||||
case Charset::UTF8: return mpt::decode<Tsrcstring>(mpt::common_encoding::utf8, src); break;
|
||||
case Charset::ASCII: return mpt::decode<Tsrcstring>(mpt::common_encoding::ascii, src); break;
|
||||
case Charset::ISO8859_1: return mpt::decode<Tsrcstring>(mpt::common_encoding::iso8859_1, src); break;
|
||||
case Charset::ISO8859_15: return mpt::decode<Tsrcstring>(mpt::common_encoding::iso8859_15, src); break;
|
||||
case Charset::CP850: return mpt::decode<Tsrcstring>(mpt::common_encoding::cp850, src); break;
|
||||
case Charset::CP437: return mpt::decode<Tsrcstring>(mpt::common_encoding::cp437, src); break;
|
||||
case Charset::CP437AMS: return mpt::decode<Tsrcstring>(CharsetTableCP437AMS, src); break;
|
||||
case Charset::CP437AMS2: return mpt::decode<Tsrcstring>(CharsetTableCP437AMS2, src); break;
|
||||
case Charset::Windows1252: return mpt::decode<Tsrcstring>(mpt::common_encoding::windows1252, src); break;
|
||||
case Charset::Amiga: return mpt::decode<Tsrcstring>(mpt::common_encoding::amiga, src); break;
|
||||
case Charset::RISC_OS: return mpt::decode<Tsrcstring>(mpt::common_encoding::riscos, src); break;
|
||||
case Charset::ISO8859_1_no_C1: return mpt::decode<Tsrcstring>(mpt::common_encoding::iso8859_1_no_c1, src); break;
|
||||
case Charset::ISO8859_15_no_C1: return mpt::decode<Tsrcstring>(mpt::common_encoding::iso8859_15_no_c1, src); break;
|
||||
case Charset::Amiga_no_C1: return mpt::decode<Tsrcstring>(mpt::common_encoding::amiga_no_c1, src); break;
|
||||
}
|
||||
return mpt::widestring();
|
||||
}
|
||||
|
||||
|
||||
// templated on 8bit strings because of type-safe variants
|
||||
template<typename Tdststring, typename Tsrcstring>
|
||||
static Tdststring ConvertImpl(Charset to, Charset from, const Tsrcstring &src)
|
||||
{
|
||||
static_assert(sizeof(typename Tdststring::value_type) == sizeof(char));
|
||||
static_assert(sizeof(typename Tsrcstring::value_type) == sizeof(char));
|
||||
if(to == from)
|
||||
{
|
||||
const typename Tsrcstring::value_type * src_beg = src.data();
|
||||
const typename Tsrcstring::value_type * src_end = src_beg + src.size();
|
||||
return Tdststring(reinterpret_cast<const typename Tdststring::value_type *>(src_beg), reinterpret_cast<const typename Tdststring::value_type *>(src_end));
|
||||
}
|
||||
return EncodeImpl<Tdststring>(to, DecodeImpl(from, src));
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace String
|
||||
|
||||
|
||||
bool IsUTF8(const std::string &str)
|
||||
{
|
||||
return mpt::is_utf8(str);
|
||||
}
|
||||
|
||||
|
||||
#if MPT_WSTRING_CONVERT
|
||||
std::wstring ToWide(Charset from, const std::string &str)
|
||||
{
|
||||
return String::DecodeImpl(from, str);
|
||||
}
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
std::wstring ToWide(const mpt::lstring &str)
|
||||
{
|
||||
return String::DecodeImpl(Charset::Locale, str);
|
||||
}
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
#endif
|
||||
|
||||
#if MPT_WSTRING_CONVERT
|
||||
std::string ToCharset(Charset to, const std::wstring &str)
|
||||
{
|
||||
return String::EncodeImpl<std::string>(to, str);
|
||||
}
|
||||
#endif
|
||||
std::string ToCharset(Charset to, Charset from, const std::string &str)
|
||||
{
|
||||
return String::ConvertImpl<std::string>(to, from, str);
|
||||
}
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
std::string ToCharset(Charset to, const mpt::lstring &str)
|
||||
{
|
||||
return String::ConvertImpl<std::string>(to, Charset::Locale, str);
|
||||
}
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
#if MPT_WSTRING_CONVERT
|
||||
mpt::lstring ToLocale(const std::wstring &str)
|
||||
{
|
||||
return String::EncodeImpl<mpt::lstring>(Charset::Locale, str);
|
||||
}
|
||||
#endif
|
||||
mpt::lstring ToLocale(Charset from, const std::string &str)
|
||||
{
|
||||
return String::ConvertImpl<mpt::lstring>(Charset::Locale, from, str);
|
||||
}
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
#if MPT_WSTRING_CONVERT
|
||||
mpt::winstring ToWin(const std::wstring &str)
|
||||
{
|
||||
#ifdef UNICODE
|
||||
return str;
|
||||
#else
|
||||
return ToLocale(str);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
mpt::winstring ToWin(Charset from, const std::string &str)
|
||||
{
|
||||
#ifdef UNICODE
|
||||
return ToWide(from, str);
|
||||
#else
|
||||
return ToLocale(from, str);
|
||||
#endif
|
||||
}
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
mpt::winstring ToWin(const mpt::lstring &str)
|
||||
{
|
||||
#ifdef UNICODE
|
||||
return ToWide(str);
|
||||
#else
|
||||
return str;
|
||||
#endif
|
||||
}
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
|
||||
#if defined(MPT_WITH_MFC)
|
||||
|
||||
CString ToCString(const std::wstring &str)
|
||||
{
|
||||
#ifdef UNICODE
|
||||
return str.c_str();
|
||||
#else
|
||||
return ToCharset(Charset::Locale, str).c_str();
|
||||
#endif
|
||||
}
|
||||
CString ToCString(Charset from, const std::string &str)
|
||||
{
|
||||
#ifdef UNICODE
|
||||
return ToWide(from, str).c_str();
|
||||
#else
|
||||
return ToCharset(Charset::Locale, from, str).c_str();
|
||||
#endif
|
||||
}
|
||||
std::wstring ToWide(const CString &str)
|
||||
{
|
||||
#ifdef UNICODE
|
||||
return str.GetString();
|
||||
#else
|
||||
return ToWide(Charset::Locale, str.GetString());
|
||||
#endif
|
||||
}
|
||||
std::string ToCharset(Charset to, const CString &str)
|
||||
{
|
||||
#ifdef UNICODE
|
||||
return ToCharset(to, str.GetString());
|
||||
#else
|
||||
return ToCharset(to, Charset::Locale, str.GetString());
|
||||
#endif
|
||||
}
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
CString ToCString(const mpt::lstring &str)
|
||||
{
|
||||
#ifdef UNICODE
|
||||
return ToWide(str).c_str();
|
||||
#else
|
||||
return str.c_str();
|
||||
#endif
|
||||
}
|
||||
mpt::lstring ToLocale(const CString &str)
|
||||
{
|
||||
#ifdef UNICODE
|
||||
return String::EncodeImpl<mpt::lstring>(Charset::Locale, str.GetString());
|
||||
#else
|
||||
return str.GetString();
|
||||
#endif
|
||||
}
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
#if MPT_OS_WINDOWS
|
||||
mpt::winstring ToWin(const CString &str)
|
||||
{
|
||||
return str.GetString();
|
||||
}
|
||||
#endif // MPT_OS_WINDOWS
|
||||
|
||||
#endif // MPT_WITH_MFC
|
||||
|
||||
|
||||
#if MPT_USTRING_MODE_WIDE
|
||||
// inline
|
||||
#else // !MPT_USTRING_MODE_WIDE
|
||||
#if MPT_WSTRING_CONVERT
|
||||
mpt::ustring ToUnicode(const std::wstring &str)
|
||||
{
|
||||
return String::EncodeImpl<mpt::ustring>(mpt::Charset::UTF8, str);
|
||||
}
|
||||
#endif
|
||||
mpt::ustring ToUnicode(Charset from, const std::string &str)
|
||||
{
|
||||
return String::ConvertImpl<mpt::ustring>(mpt::Charset::UTF8, from, str);
|
||||
}
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
mpt::ustring ToUnicode(const mpt::lstring &str)
|
||||
{
|
||||
return String::ConvertImpl<mpt::ustring>(mpt::Charset::UTF8, mpt::Charset::Locale, str);
|
||||
}
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
#if defined(MPT_WITH_MFC)
|
||||
mpt::ustring ToUnicode(const CString &str)
|
||||
{
|
||||
#ifdef UNICODE
|
||||
return String::EncodeImpl<mpt::ustring>(mpt::Charset::UTF8, str.GetString());
|
||||
#else // !UNICODE
|
||||
return String::ConvertImpl<mpt::ustring, std::string>(mpt::Charset::UTF8, mpt::Charset::Locale, str.GetString());
|
||||
#endif // UNICODE
|
||||
}
|
||||
#endif // MPT_WITH_MFC
|
||||
#endif // MPT_USTRING_MODE_WIDE
|
||||
|
||||
#if MPT_USTRING_MODE_WIDE
|
||||
// nothing, std::wstring overloads will catch all stuff
|
||||
#else // !MPT_USTRING_MODE_WIDE
|
||||
#if MPT_WSTRING_CONVERT
|
||||
std::wstring ToWide(const mpt::ustring &str)
|
||||
{
|
||||
return String::DecodeImpl<mpt::ustring>(mpt::Charset::UTF8, str);
|
||||
}
|
||||
#endif
|
||||
std::string ToCharset(Charset to, const mpt::ustring &str)
|
||||
{
|
||||
return String::ConvertImpl<std::string, mpt::ustring>(to, mpt::Charset::UTF8, str);
|
||||
}
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
mpt::lstring ToLocale(const mpt::ustring &str)
|
||||
{
|
||||
return String::ConvertImpl<mpt::lstring, mpt::ustring>(mpt::Charset::Locale, mpt::Charset::UTF8, str);
|
||||
}
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
#if MPT_OS_WINDOWS
|
||||
mpt::winstring ToWin(const mpt::ustring &str)
|
||||
{
|
||||
#ifdef UNICODE
|
||||
return String::DecodeImpl<mpt::ustring>(mpt::Charset::UTF8, str);
|
||||
#else
|
||||
return String::ConvertImpl<mpt::lstring, mpt::ustring>(mpt::Charset::Locale, mpt::Charset::UTF8, str);
|
||||
#endif
|
||||
}
|
||||
#endif // MPT_OS_WINDOWS
|
||||
#if defined(MPT_WITH_MFC)
|
||||
CString ToCString(const mpt::ustring &str)
|
||||
{
|
||||
#ifdef UNICODE
|
||||
return String::DecodeImpl<mpt::ustring>(mpt::Charset::UTF8, str).c_str();
|
||||
#else // !UNICODE
|
||||
return String::ConvertImpl<std::string, mpt::ustring>(mpt::Charset::Locale, mpt::Charset::UTF8, str).c_str();
|
||||
#endif // UNICODE
|
||||
}
|
||||
#endif // MPT_WITH_MFC
|
||||
#endif // MPT_USTRING_MODE_WIDE
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static mpt::Charset CharsetFromCodePage(uint16 codepage, mpt::Charset fallback, bool * isFallback = nullptr)
|
||||
{
|
||||
mpt::Charset result = fallback;
|
||||
switch(codepage)
|
||||
{
|
||||
case 65001:
|
||||
result = mpt::Charset::UTF8;
|
||||
if(isFallback) *isFallback = false;
|
||||
break;
|
||||
case 20127:
|
||||
result = mpt::Charset::ASCII;
|
||||
if(isFallback) *isFallback = false;
|
||||
break;
|
||||
case 28591:
|
||||
result = mpt::Charset::ISO8859_1;
|
||||
if(isFallback) *isFallback = false;
|
||||
break;
|
||||
case 28605:
|
||||
result = mpt::Charset::ISO8859_15;
|
||||
if(isFallback) *isFallback = false;
|
||||
break;
|
||||
case 437:
|
||||
result = mpt::Charset::CP437;
|
||||
if(isFallback) *isFallback = false;
|
||||
break;
|
||||
case 1252:
|
||||
result = mpt::Charset::Windows1252;
|
||||
if(isFallback) *isFallback = false;
|
||||
break;
|
||||
default:
|
||||
result = fallback;
|
||||
if(isFallback) *isFallback = true;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
mpt::ustring ToUnicode(uint16 codepage, mpt::Charset fallback, const std::string &str)
|
||||
{
|
||||
#if MPT_OS_WINDOWS
|
||||
mpt::ustring result;
|
||||
bool noCharsetMatch = true;
|
||||
mpt::Charset charset = mpt::CharsetFromCodePage(codepage, fallback, &noCharsetMatch);
|
||||
if(noCharsetMatch && mpt::has_codepage(codepage))
|
||||
{
|
||||
result = mpt::ToUnicode(mpt::decode<std::string>(codepage, str));
|
||||
} else
|
||||
{
|
||||
result = mpt::ToUnicode(charset, str);
|
||||
}
|
||||
return result;
|
||||
#else // !MPT_OS_WINDOWS
|
||||
return mpt::ToUnicode(mpt::CharsetFromCodePage(codepage, fallback), str);
|
||||
#endif // MPT_OS_WINDOWS
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
char ToLowerCaseAscii(char c)
|
||||
{
|
||||
return mpt::to_lower_ascii(c);
|
||||
}
|
||||
|
||||
char ToUpperCaseAscii(char c)
|
||||
{
|
||||
return mpt::to_upper_ascii(c);
|
||||
}
|
||||
|
||||
std::string ToLowerCaseAscii(std::string s)
|
||||
{
|
||||
std::transform(s.begin(), s.end(), s.begin(), static_cast<char(*)(char)>(&mpt::ToLowerCaseAscii));
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string ToUpperCaseAscii(std::string s)
|
||||
{
|
||||
std::transform(s.begin(), s.end(), s.begin(), static_cast<char(*)(char)>(&mpt::ToUpperCaseAscii));
|
||||
return s;
|
||||
}
|
||||
|
||||
int CompareNoCaseAscii(const char *a, const char *b, std::size_t n)
|
||||
{
|
||||
while(n--)
|
||||
{
|
||||
unsigned char ac = mpt::char_value(mpt::ToLowerCaseAscii(*a));
|
||||
unsigned char bc = mpt::char_value(mpt::ToLowerCaseAscii(*b));
|
||||
if(ac != bc)
|
||||
{
|
||||
return ac < bc ? -1 : 1;
|
||||
} else if(!ac && !bc)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
++a;
|
||||
++b;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CompareNoCaseAscii(std::string_view a, std::string_view b)
|
||||
{
|
||||
for(std::size_t i = 0; i < std::min(a.length(), b.length()); ++i)
|
||||
{
|
||||
unsigned char ac = mpt::char_value(mpt::ToLowerCaseAscii(a[i]));
|
||||
unsigned char bc = mpt::char_value(mpt::ToLowerCaseAscii(b[i]));
|
||||
if(ac != bc)
|
||||
{
|
||||
return ac < bc ? -1 : 1;
|
||||
} else if(!ac && !bc)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if(a.length() == b.length())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return a.length() < b.length() ? -1 : 1;
|
||||
}
|
||||
|
||||
int CompareNoCaseAscii(const std::string &a, const std::string &b)
|
||||
{
|
||||
return CompareNoCaseAscii(std::string_view(a), std::string_view(b));
|
||||
}
|
||||
|
||||
|
||||
#if defined(MODPLUG_TRACKER)
|
||||
|
||||
mpt::ustring ToLowerCase(const mpt::ustring &s)
|
||||
{
|
||||
#if defined(MPT_WITH_MFC)
|
||||
#if defined(UNICODE)
|
||||
CString tmp = mpt::ToCString(s);
|
||||
tmp.MakeLower();
|
||||
return mpt::ToUnicode(tmp);
|
||||
#else // !UNICODE
|
||||
CStringW tmp = mpt::ToWide(s).c_str();
|
||||
tmp.MakeLower();
|
||||
return mpt::ToUnicode(tmp.GetString());
|
||||
#endif // UNICODE
|
||||
#else // !MPT_WITH_MFC
|
||||
std::wstring ws = mpt::ToWide(s);
|
||||
std::transform(ws.begin(), ws.end(), ws.begin(), &std::towlower);
|
||||
return mpt::ToUnicode(ws);
|
||||
#endif // MPT_WITH_MFC
|
||||
}
|
||||
|
||||
mpt::ustring ToUpperCase(const mpt::ustring &s)
|
||||
{
|
||||
#if defined(MPT_WITH_MFC)
|
||||
#if defined(UNICODE)
|
||||
CString tmp = mpt::ToCString(s);
|
||||
tmp.MakeUpper();
|
||||
return mpt::ToUnicode(tmp);
|
||||
#else // !UNICODE
|
||||
CStringW tmp = mpt::ToWide(s).c_str();
|
||||
tmp.MakeUpper();
|
||||
return mpt::ToUnicode(tmp.GetString());
|
||||
#endif // UNICODE
|
||||
#else // !MPT_WITH_MFC
|
||||
std::wstring ws = mpt::ToWide(s);
|
||||
std::transform(ws.begin(), ws.end(), ws.begin(), &std::towlower);
|
||||
return mpt::ToUnicode(ws);
|
||||
#endif // MPT_WITH_MFC
|
||||
}
|
||||
|
||||
#endif // MODPLUG_TRACKER
|
||||
|
||||
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
446
Frameworks/OpenMPT/OpenMPT/common/mptString.h
Normal file
446
Frameworks/OpenMPT/OpenMPT/common/mptString.h
Normal file
|
@ -0,0 +1,446 @@
|
|||
/*
|
||||
* 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 "openmpt/all/BuildSettings.hpp"
|
||||
|
||||
#include "mpt/base/alloc.hpp"
|
||||
#include "mpt/base/span.hpp"
|
||||
#include "mpt/string/types.hpp"
|
||||
#include "mpt/string/utility.hpp"
|
||||
|
||||
#include "mptBaseTypes.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
|
||||
|
||||
namespace String
|
||||
{
|
||||
|
||||
|
||||
template <typename Tstring, typename Tstring2, typename Tstring3>
|
||||
inline Tstring Replace(Tstring str, const Tstring2 &oldStr, const Tstring3 &newStr)
|
||||
{
|
||||
return mpt::replace(str, oldStr, newStr);
|
||||
}
|
||||
|
||||
|
||||
} // namespace String
|
||||
|
||||
|
||||
enum class Charset {
|
||||
|
||||
UTF8,
|
||||
|
||||
ASCII, // strictly 7-bit ASCII
|
||||
|
||||
ISO8859_1,
|
||||
ISO8859_15,
|
||||
|
||||
CP850,
|
||||
CP437,
|
||||
CP437AMS,
|
||||
CP437AMS2,
|
||||
|
||||
Windows1252,
|
||||
|
||||
Amiga,
|
||||
RISC_OS,
|
||||
|
||||
ISO8859_1_no_C1,
|
||||
ISO8859_15_no_C1,
|
||||
Amiga_no_C1,
|
||||
|
||||
#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
|
||||
|
||||
// getenv
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
inline constexpr Charset CharsetEnvironment = Charset::Locale;
|
||||
#else
|
||||
inline constexpr Charset CharsetEnvironment = 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
|
||||
|
||||
|
||||
|
||||
// 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);
|
||||
|
||||
|
||||
|
||||
#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
|
||||
|
||||
|
||||
|
||||
#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
|
117
Frameworks/OpenMPT/OpenMPT/common/mptStringBuffer.cpp
Normal file
117
Frameworks/OpenMPT/OpenMPT/common/mptStringBuffer.cpp
Normal file
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* mptStringBuffer.cpp
|
||||
* -------------------
|
||||
* Purpose: Various functions for "fixing" char array strings for writing to or
|
||||
* reading from module files, or for securing char arrays in general.
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "mptStringBuffer.h"
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
namespace String
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
std::string ReadStringBuffer(String::ReadWriteMode mode, const char *srcBuffer, std::size_t srcSize)
|
||||
{
|
||||
|
||||
std::string dest;
|
||||
const char *src = srcBuffer;
|
||||
|
||||
if(mode == nullTerminated || mode == spacePaddedNull)
|
||||
{
|
||||
// We assume that the last character of the source buffer is null.
|
||||
if(srcSize > 0)
|
||||
{
|
||||
srcSize -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(mode == nullTerminated || mode == maybeNullTerminated)
|
||||
{
|
||||
|
||||
// Copy null-terminated string, stopping at null.
|
||||
dest.assign(src, std::find(src, src + srcSize, '\0'));
|
||||
|
||||
} else if(mode == spacePadded || mode == spacePaddedNull)
|
||||
{
|
||||
|
||||
// Copy string over.
|
||||
dest.assign(src, src + srcSize);
|
||||
|
||||
// Convert null characters to spaces.
|
||||
std::transform(dest.begin(), dest.end(), dest.begin(), [] (char c) -> char { return (c != '\0') ? c : ' '; });
|
||||
|
||||
// Trim trailing spaces.
|
||||
dest = mpt::trim_right(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
|
299
Frameworks/OpenMPT/OpenMPT/common/mptStringBuffer.h
Normal file
299
Frameworks/OpenMPT/OpenMPT/common/mptStringBuffer.h
Normal file
|
@ -0,0 +1,299 @@
|
|||
/*
|
||||
* 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 "openmpt/all/BuildSettings.hpp"
|
||||
|
||||
#include "mpt/string/buffer.hpp"
|
||||
|
||||
#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
|
||||
|
||||
|
||||
|
||||
namespace String {
|
||||
using mpt::ReadTypedBuf;
|
||||
using mpt::WriteTypedBuf;
|
||||
} // namespace String
|
||||
|
||||
namespace String {
|
||||
using mpt::ReadAutoBuf;
|
||||
using mpt::WriteAutoBuf;
|
||||
} // namespace String
|
||||
|
||||
|
||||
|
||||
template <typename Tchar>
|
||||
class StringModeBufRefImpl
|
||||
{
|
||||
private:
|
||||
Tchar * buf;
|
||||
std::size_t size;
|
||||
String::ReadWriteMode mode;
|
||||
public:
|
||||
// cppcheck false-positive
|
||||
// cppcheck-suppress uninitMemberVar
|
||||
StringModeBufRefImpl(Tchar * buf_, std::size_t size_, String::ReadWriteMode mode_)
|
||||
: buf(buf_)
|
||||
, size(size_)
|
||||
, mode(mode_)
|
||||
{
|
||||
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, const std::array<Tchar, size> &buf)
|
||||
{
|
||||
return StringModeBufRefImpl<typename std::add_const<Tchar>::type>(buf.data(), size, mode);
|
||||
}
|
||||
template <typename Tchar, std::size_t size>
|
||||
inline StringModeBufRefImpl<typename std::add_const<Tchar>::type> ReadBuf(String::ReadWriteMode mode, const 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, const 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, std::array<Tchar, size> &buf)
|
||||
{
|
||||
return StringModeBufRefImpl<Tchar>(buf.data(), 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 modecharbuf
|
||||
{
|
||||
public:
|
||||
typedef char Tchar;
|
||||
using char_type = Tchar;
|
||||
using string_type = std::basic_string<Tchar>;
|
||||
public:
|
||||
Tchar buf[len];
|
||||
public:
|
||||
modecharbuf() = default;
|
||||
modecharbuf(const modecharbuf &) = default;
|
||||
modecharbuf(modecharbuf &&) = default;
|
||||
modecharbuf & operator = (const modecharbuf &) = default;
|
||||
modecharbuf & operator = (modecharbuf &&) = default;
|
||||
operator string_type () const
|
||||
{
|
||||
return mpt::String::ReadBuf(mode, buf);
|
||||
}
|
||||
bool empty() const
|
||||
{
|
||||
return mpt::String::ReadBuf(mode, buf).empty();
|
||||
}
|
||||
modecharbuf & 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>
|
||||
constexpr bool declare_binary_safe(const typename mpt::modecharbuf<len, mode> &) { return true; }
|
||||
//struct is_binary_safe<typename mpt::modecharbuf<len, mode>> : public std::true_type { };
|
||||
static_assert(sizeof(mpt::modecharbuf<7, mpt::String::ReadWriteMode::nullTerminated>) == 7);
|
||||
static_assert(alignof(mpt::modecharbuf<7, mpt::String::ReadWriteMode::nullTerminated>) == 1);
|
||||
static_assert(std::is_standard_layout<mpt::modecharbuf<7, mpt::String::ReadWriteMode::nullTerminated>>::value);
|
||||
|
||||
|
||||
#ifdef MODPLUG_TRACKER
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
|
||||
namespace String {
|
||||
using mpt::ReadWinBuf;
|
||||
using mpt::WriteWinBuf;
|
||||
} // namespace String
|
||||
|
||||
#if defined(MPT_WITH_MFC)
|
||||
|
||||
namespace String {
|
||||
using mpt::ReadCStringBuf;
|
||||
using mpt::WriteCStringBuf;
|
||||
} // 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
|
||||
|
||||
#if MPT_COMPILER_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif // MPT_COMPILER_MSVC
|
||||
|
||||
|
||||
} // namespace String
|
||||
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
143
Frameworks/OpenMPT/OpenMPT/common/mptStringFormat.cpp
Normal file
143
Frameworks/OpenMPT/OpenMPT/common/mptStringFormat.cpp
Normal file
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* 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"
|
||||
|
||||
#include "mpt/format/default_floatingpoint.hpp"
|
||||
#include "mpt/format/default_integer.hpp"
|
||||
#include "mpt/format/helpers.hpp"
|
||||
#include "mpt/format/simple_floatingpoint.hpp"
|
||||
#include "mpt/format/simple_integer.hpp"
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
namespace mpt
|
||||
{
|
||||
|
||||
|
||||
|
||||
std::string ToAString(const bool & x) { return mpt::format_value_default<std::string>(x); }
|
||||
std::string ToAString(const signed char & x) { return mpt::format_value_default<std::string>(x); }
|
||||
std::string ToAString(const unsigned char & x) { return mpt::format_value_default<std::string>(x); }
|
||||
std::string ToAString(const signed short & x) { return mpt::format_value_default<std::string>(x); }
|
||||
std::string ToAString(const unsigned short & x) { return mpt::format_value_default<std::string>(x); }
|
||||
std::string ToAString(const signed int & x) { return mpt::format_value_default<std::string>(x); }
|
||||
std::string ToAString(const unsigned int & x) { return mpt::format_value_default<std::string>(x); }
|
||||
std::string ToAString(const signed long & x) { return mpt::format_value_default<std::string>(x); }
|
||||
std::string ToAString(const unsigned long & x) { return mpt::format_value_default<std::string>(x); }
|
||||
std::string ToAString(const signed long long & x) { return mpt::format_value_default<std::string>(x); }
|
||||
std::string ToAString(const unsigned long long & x) { return mpt::format_value_default<std::string>(x); }
|
||||
std::string ToAString(const float & x) { return mpt::format_value_default<std::string>(x); }
|
||||
std::string ToAString(const double & x) { return mpt::format_value_default<std::string>(x); }
|
||||
std::string ToAString(const long double & x) { return mpt::format_value_default<std::string>(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
|
||||
mpt::ustring ToUString(const bool & x) { return mpt::format_value_default<mpt::ustring>(x); }
|
||||
mpt::ustring ToUString(const signed char & x) { return mpt::format_value_default<mpt::ustring>(x); }
|
||||
mpt::ustring ToUString(const unsigned char & x) { return mpt::format_value_default<mpt::ustring>(x); }
|
||||
mpt::ustring ToUString(const signed short & x) { return mpt::format_value_default<mpt::ustring>(x); }
|
||||
mpt::ustring ToUString(const unsigned short & x) { return mpt::format_value_default<mpt::ustring>(x); }
|
||||
mpt::ustring ToUString(const signed int & x) { return mpt::format_value_default<mpt::ustring>(x); }
|
||||
mpt::ustring ToUString(const unsigned int & x) { return mpt::format_value_default<mpt::ustring>(x); }
|
||||
mpt::ustring ToUString(const signed long & x) { return mpt::format_value_default<mpt::ustring>(x); }
|
||||
mpt::ustring ToUString(const unsigned long & x) { return mpt::format_value_default<mpt::ustring>(x); }
|
||||
mpt::ustring ToUString(const signed long long & x) { return mpt::format_value_default<mpt::ustring>(x); }
|
||||
mpt::ustring ToUString(const unsigned long long & x) { return mpt::format_value_default<mpt::ustring>(x); }
|
||||
mpt::ustring ToUString(const float & x) { return mpt::format_value_default<mpt::ustring>(x); }
|
||||
mpt::ustring ToUString(const double & x) { return mpt::format_value_default<mpt::ustring>(x); }
|
||||
mpt::ustring ToUString(const long double & x) { return mpt::format_value_default<mpt::ustring>(x); }
|
||||
|
||||
#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 mpt::format_value_default<std::wstring>(x); }
|
||||
std::wstring ToWString(const signed char & x) { return mpt::format_value_default<std::wstring>(x); }
|
||||
std::wstring ToWString(const unsigned char & x) { return mpt::format_value_default<std::wstring>(x); }
|
||||
std::wstring ToWString(const signed short & x) { return mpt::format_value_default<std::wstring>(x); }
|
||||
std::wstring ToWString(const unsigned short & x) { return mpt::format_value_default<std::wstring>(x); }
|
||||
std::wstring ToWString(const signed int & x) { return mpt::format_value_default<std::wstring>(x); }
|
||||
std::wstring ToWString(const unsigned int & x) { return mpt::format_value_default<std::wstring>(x); }
|
||||
std::wstring ToWString(const signed long & x) { return mpt::format_value_default<std::wstring>(x); }
|
||||
std::wstring ToWString(const unsigned long & x) { return mpt::format_value_default<std::wstring>(x); }
|
||||
std::wstring ToWString(const signed long long & x) { return mpt::format_value_default<std::wstring>(x); }
|
||||
std::wstring ToWString(const unsigned long long & x) { return mpt::format_value_default<std::wstring>(x); }
|
||||
std::wstring ToWString(const float & x) { return mpt::format_value_default<std::wstring>(x); }
|
||||
std::wstring ToWString(const double & x) { return mpt::format_value_default<std::wstring>(x); }
|
||||
std::wstring ToWString(const long double & x) { return mpt::format_value_default<std::wstring>(x); }
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
std::string FormatValA(const bool & x, const FormatSpec & f) { return mpt::format_simple<std::string>(x, f); }
|
||||
std::string FormatValA(const signed char & x, const FormatSpec & f) { return mpt::format_simple<std::string>(x, f); }
|
||||
std::string FormatValA(const unsigned char & x, const FormatSpec & f) { return mpt::format_simple<std::string>(x, f); }
|
||||
std::string FormatValA(const signed short & x, const FormatSpec & f) { return mpt::format_simple<std::string>(x, f); }
|
||||
std::string FormatValA(const unsigned short & x, const FormatSpec & f) { return mpt::format_simple<std::string>(x, f); }
|
||||
std::string FormatValA(const signed int & x, const FormatSpec & f) { return mpt::format_simple<std::string>(x, f); }
|
||||
std::string FormatValA(const unsigned int & x, const FormatSpec & f) { return mpt::format_simple<std::string>(x, f); }
|
||||
std::string FormatValA(const signed long & x, const FormatSpec & f) { return mpt::format_simple<std::string>(x, f); }
|
||||
std::string FormatValA(const unsigned long & x, const FormatSpec & f) { return mpt::format_simple<std::string>(x, f); }
|
||||
std::string FormatValA(const signed long long & x, const FormatSpec & f) { return mpt::format_simple<std::string>(x, f); }
|
||||
std::string FormatValA(const unsigned long long & x, const FormatSpec & f) { return mpt::format_simple<std::string>(x, f); }
|
||||
std::string FormatValA(const float & x, const FormatSpec & f) { return mpt::format_simple<std::string>(x, f); }
|
||||
std::string FormatValA(const double & x, const FormatSpec & f) { return mpt::format_simple<std::string>(x, f); }
|
||||
std::string FormatValA(const long double & x, const FormatSpec & f) { return mpt::format_simple<std::string>(x, f); }
|
||||
|
||||
mpt::ustring FormatValU(const bool & x, const FormatSpec & f) { return mpt::format_simple<mpt::ustring>(x, f); }
|
||||
mpt::ustring FormatValU(const signed char & x, const FormatSpec & f) { return mpt::format_simple<mpt::ustring>(x, f); }
|
||||
mpt::ustring FormatValU(const unsigned char & x, const FormatSpec & f) { return mpt::format_simple<mpt::ustring>(x, f); }
|
||||
mpt::ustring FormatValU(const signed short & x, const FormatSpec & f) { return mpt::format_simple<mpt::ustring>(x, f); }
|
||||
mpt::ustring FormatValU(const unsigned short & x, const FormatSpec & f) { return mpt::format_simple<mpt::ustring>(x, f); }
|
||||
mpt::ustring FormatValU(const signed int & x, const FormatSpec & f) { return mpt::format_simple<mpt::ustring>(x, f); }
|
||||
mpt::ustring FormatValU(const unsigned int & x, const FormatSpec & f) { return mpt::format_simple<mpt::ustring>(x, f); }
|
||||
mpt::ustring FormatValU(const signed long & x, const FormatSpec & f) { return mpt::format_simple<mpt::ustring>(x, f); }
|
||||
mpt::ustring FormatValU(const unsigned long & x, const FormatSpec & f) { return mpt::format_simple<mpt::ustring>(x, f); }
|
||||
mpt::ustring FormatValU(const signed long long & x, const FormatSpec & f) { return mpt::format_simple<mpt::ustring>(x, f); }
|
||||
mpt::ustring FormatValU(const unsigned long long & x, const FormatSpec & f) { return mpt::format_simple<mpt::ustring>(x, f); }
|
||||
mpt::ustring FormatValU(const float & x, const FormatSpec & f) { return mpt::format_simple<mpt::ustring>(x, f); }
|
||||
mpt::ustring FormatValU(const double & x, const FormatSpec & f) { return mpt::format_simple<mpt::ustring>(x, f); }
|
||||
mpt::ustring FormatValU(const long double & x, const FormatSpec & f) { return mpt::format_simple<mpt::ustring>(x, f); }
|
||||
|
||||
#if MPT_WSTRING_FORMAT
|
||||
std::wstring FormatValW(const bool & x, const FormatSpec & f) { return mpt::format_simple<std::wstring>(x, f); }
|
||||
std::wstring FormatValW(const signed char & x, const FormatSpec & f) { return mpt::format_simple<std::wstring>(x, f); }
|
||||
std::wstring FormatValW(const unsigned char & x, const FormatSpec & f) { return mpt::format_simple<std::wstring>(x, f); }
|
||||
std::wstring FormatValW(const signed short & x, const FormatSpec & f) { return mpt::format_simple<std::wstring>(x, f); }
|
||||
std::wstring FormatValW(const unsigned short & x, const FormatSpec & f) { return mpt::format_simple<std::wstring>(x, f); }
|
||||
std::wstring FormatValW(const signed int & x, const FormatSpec & f) { return mpt::format_simple<std::wstring>(x, f); }
|
||||
std::wstring FormatValW(const unsigned int & x, const FormatSpec & f) { return mpt::format_simple<std::wstring>(x, f); }
|
||||
std::wstring FormatValW(const signed long & x, const FormatSpec & f) { return mpt::format_simple<std::wstring>(x, f); }
|
||||
std::wstring FormatValW(const unsigned long & x, const FormatSpec & f) { return mpt::format_simple<std::wstring>(x, f); }
|
||||
std::wstring FormatValW(const signed long long & x, const FormatSpec & f) { return mpt::format_simple<std::wstring>(x, f); }
|
||||
std::wstring FormatValW(const unsigned long long & x, const FormatSpec & f) { return mpt::format_simple<std::wstring>(x, f); }
|
||||
std::wstring FormatValW(const float & x, const FormatSpec & f) { return mpt::format_simple<std::wstring>(x, f); }
|
||||
std::wstring FormatValW(const double & x, const FormatSpec & f) { return mpt::format_simple<std::wstring>(x, f); }
|
||||
std::wstring FormatValW(const long double & x, const FormatSpec & f) { return mpt::format_simple<std::wstring>(x, f); }
|
||||
#endif
|
||||
|
||||
|
||||
} // namespace mpt
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
554
Frameworks/OpenMPT/OpenMPT/common/mptStringFormat.h
Normal file
554
Frameworks/OpenMPT/OpenMPT/common/mptStringFormat.h
Normal file
|
@ -0,0 +1,554 @@
|
|||
/*
|
||||
* 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 "openmpt/all/BuildSettings.hpp"
|
||||
|
||||
#include "mpt/base/pointer.hpp"
|
||||
#include "mpt/format/message.hpp"
|
||||
#include "mpt/format/simple_spec.hpp"
|
||||
#include "mpt/string/types.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "mptString.h"
|
||||
|
||||
#include "openmpt/base/FlagSet.hpp"
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
|
||||
// The following section demands a rationale.
|
||||
// 1. mpt::afmt::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.
|
||||
// ToAString() 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.
|
||||
// When formatting integers, it is recommended to use mpt::afmt::dec or mpt::afmt::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 FormatValA(int, format) can be
|
||||
// used.
|
||||
// 3. mpt::format(format)(...) provides simplified and type-safe message and localization string formatting.
|
||||
// The only specifier allowed is '{}' enclosing a number 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::afmt mpt::wfmt mpt::ufmt mpt::tfmt mpt::cfmt
|
||||
// MPT_AFORMAT("{}") MPT_WFORMAT("{}") MPT_UFORMAT("{}") MPT_TFORMAT("{}") MPT_CFORMAT("{}")
|
||||
// 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> [[deprecated]] auto ToAString(const T & x) -> decltype(mpt::ToCharset(mpt::Charset::UTF8, x.ToUString())) { return mpt::ToCharset(mpt::Charset::UTF8, x.ToUString()); } // unknown encoding
|
||||
#else
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
template <typename T> [[deprecated]] auto ToAString(const T & x) -> decltype(mpt::ToCharset(mpt::Charset::Locale, x.ToUString())) { return mpt::ToCharset(mpt::Charset::Locale, x.ToUString()); } // unknown encoding
|
||||
#else // !MPT_ENABLE_CHARSET_LOCALE
|
||||
template <typename T> [[deprecated]] auto ToAString(const T & x) -> decltype(mpt::ToCharset(mpt::Charset::UTF8, x.ToUString())) { return mpt::ToCharset(mpt::Charset::UTF8, x.ToUString()); } // unknown encoding
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
#endif
|
||||
|
||||
inline std::string ToAString(const std::string & x) { return x; }
|
||||
inline std::string ToAString(const char * const & x) { return x; }
|
||||
std::string ToAString(const char &x) = delete; // deprecated to catch potential API mis-use, use std::string(1, x) instead
|
||||
#if MPT_WSTRING_FORMAT
|
||||
std::string ToAString(const std::wstring & x) = delete; // Unknown encoding.
|
||||
std::string ToAString(const wchar_t * const & x) = delete; // Unknown encoding.
|
||||
std::string ToAString(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 ToAString(const mpt::ustring & x) = delete; // Unknown encoding.
|
||||
#endif
|
||||
#if defined(MPT_WITH_MFC)
|
||||
std::string ToAString(const CString & x) = delete; // unknown encoding
|
||||
#endif // MPT_WITH_MFC
|
||||
std::string ToAString(const bool & x);
|
||||
std::string ToAString(const signed char & x);
|
||||
std::string ToAString(const unsigned char & x);
|
||||
std::string ToAString(const signed short & x);
|
||||
std::string ToAString(const unsigned short & x);
|
||||
std::string ToAString(const signed int & x);
|
||||
std::string ToAString(const unsigned int & x);
|
||||
std::string ToAString(const signed long & x);
|
||||
std::string ToAString(const unsigned long & x);
|
||||
std::string ToAString(const signed long long & x);
|
||||
std::string ToAString(const unsigned long long & x);
|
||||
std::string ToAString(const float & x);
|
||||
std::string ToAString(const double & x);
|
||||
std::string ToAString(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 ToAString(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 ToStringFormatter {
|
||||
template <typename Tstring, typename T>
|
||||
static inline Tstring format(const T& value) {
|
||||
return ToStringTFunctor<Tstring>()(value);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
using FormatSpec = mpt::format_simple_spec;
|
||||
|
||||
using FormatFlags = mpt::format_simple_flags;
|
||||
|
||||
using fmt_base = mpt::format_simple_base;
|
||||
|
||||
|
||||
std::string FormatValA(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 FormatValA(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 FormatValA(const bool & x, const FormatSpec & f);
|
||||
std::string FormatValA(const signed char & x, const FormatSpec & f);
|
||||
std::string FormatValA(const unsigned char & x, const FormatSpec & f);
|
||||
std::string FormatValA(const signed short & x, const FormatSpec & f);
|
||||
std::string FormatValA(const unsigned short & x, const FormatSpec & f);
|
||||
std::string FormatValA(const signed int & x, const FormatSpec & f);
|
||||
std::string FormatValA(const unsigned int & x, const FormatSpec & f);
|
||||
std::string FormatValA(const signed long & x, const FormatSpec & f);
|
||||
std::string FormatValA(const unsigned long & x, const FormatSpec & f);
|
||||
std::string FormatValA(const signed long long & x, const FormatSpec & f);
|
||||
std::string FormatValA(const unsigned long long & x, const FormatSpec & f);
|
||||
std::string FormatValA(const float & x, const FormatSpec & f);
|
||||
std::string FormatValA(const double & x, const FormatSpec & f);
|
||||
std::string FormatValA(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 FormatValA(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, FormatValA(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, FormatValA(x, f)); } };
|
||||
#endif // UNICODE
|
||||
#endif // MPT_WITH_MFC
|
||||
|
||||
|
||||
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>(mpt::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>(mpt::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> afmt;
|
||||
#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
|
||||
|
||||
|
||||
#define MPT_AFORMAT(f) mpt::format_message<mpt::ToStringFormatter, mpt::parse_format_string_argument_count(f)>(f)
|
||||
|
||||
#if MPT_WSTRING_FORMAT
|
||||
#define MPT_WFORMAT(f) mpt::format_message_typed<mpt::ToStringFormatter, mpt::parse_format_string_argument_count( L ## f ), std::wstring>( L ## f )
|
||||
#endif
|
||||
|
||||
#define MPT_UFORMAT(f) mpt::format_message_typed<mpt::ToStringFormatter, mpt::parse_format_string_argument_count(MPT_ULITERAL(f)), mpt::ustring>(MPT_ULITERAL(f))
|
||||
|
||||
#if defined(MPT_ENABLE_CHARSET_LOCALE)
|
||||
#define MPT_LFORMAT(f) mpt::format_message_typed<mpt::ToStringFormatter, mpt::parse_format_string_argument_count(f), mpt::lstring>(f)
|
||||
#endif // MPT_ENABLE_CHARSET_LOCALE
|
||||
|
||||
#if MPT_OS_WINDOWS
|
||||
#define MPT_TFORMAT(f) mpt::format_message_typed<mpt::ToStringFormatter, mpt::parse_format_string_argument_count(TEXT(f)), mpt::tstring>(TEXT(f))
|
||||
#endif
|
||||
|
||||
#if defined(MPT_WITH_MFC)
|
||||
#define MPT_CFORMAT(f) mpt::format_message_typed<mpt::ToStringFormatter, mpt::parse_format_string_argument_count(TEXT(f)), CString>(TEXT(f))
|
||||
#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::afmt::val(vals[i]);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
} } // namespace mpt::String
|
||||
|
||||
|
||||
|
||||
template <typename enum_t, typename store_t>
|
||||
mpt::ustring ToUString(FlagSet<enum_t, store_t> flagset)
|
||||
{
|
||||
mpt::ustring str(flagset.size_bits(), UC_('0'));
|
||||
|
||||
for(std::size_t x = 0; x < flagset.size_bits(); ++x)
|
||||
{
|
||||
str[flagset.size_bits() - x - 1] = (flagset.value().as_bits() & (static_cast<typename FlagSet<enum_t>::store_type>(1) << x) ? UC_('1') : UC_('0'));
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
98
Frameworks/OpenMPT/OpenMPT/common/mptStringParse.cpp
Normal file
98
Frameworks/OpenMPT/OpenMPT/common/mptStringParse.cpp
Normal file
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* 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 "mpt/parse/parse.hpp"
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
|
||||
template<typename T>
|
||||
inline T ConvertStrToHelper(const std::string &str)
|
||||
{
|
||||
return mpt::ConvertStringTo<T>(str);
|
||||
}
|
||||
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)
|
||||
{
|
||||
return mpt::ConvertStringTo<T>(str);
|
||||
}
|
||||
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)
|
||||
{
|
||||
return mpt::ConvertHexStringTo<T>(str);
|
||||
}
|
||||
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
|
250
Frameworks/OpenMPT/OpenMPT/common/mptStringParse.h
Normal file
250
Frameworks/OpenMPT/OpenMPT/common/mptStringParse.h
Normal file
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
* 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 "openmpt/all/BuildSettings.hpp"
|
||||
|
||||
|
||||
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
|
307
Frameworks/OpenMPT/OpenMPT/common/mptTime.cpp
Normal file
307
Frameworks/OpenMPT/OpenMPT/common/mptTime.cpp
Normal file
|
@ -0,0 +1,307 @@
|
|||
/*
|
||||
* 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 = {};
|
||||
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 = {};
|
||||
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
|
116
Frameworks/OpenMPT/OpenMPT/common/mptTime.h
Normal file
116
Frameworks/OpenMPT/OpenMPT/common/mptTime.h
Normal file
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* 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 "openmpt/all/BuildSettings.hpp"
|
||||
|
||||
#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
|
721
Frameworks/OpenMPT/OpenMPT/common/serialization_utils.cpp
Normal file
721
Frameworks/OpenMPT/OpenMPT/common/serialization_utils.cpp
Normal file
|
@ -0,0 +1,721 @@
|
|||
/*
|
||||
* 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 "mpt/io/io.hpp"
|
||||
#include "mpt/io/io_stdstream.hpp"
|
||||
|
||||
#include <array>
|
||||
#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_GLOBAL(LogDebug, "serialization", x)
|
||||
#else
|
||||
#define SSB_LOG(x) do { } 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(std::numeric_limits<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>((std::numeric_limits<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'};
|
||||
|
||||
|
||||
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_UFORMAT("{}: 0x{}")(U_("Write note: "), mpt::ufmt::hex(s)));
|
||||
}
|
||||
|
||||
void SsbRead::AddReadNote(const SsbStatus s)
|
||||
{
|
||||
m_Status |= s;
|
||||
SSB_LOG(MPT_UFORMAT("{}: 0x{}")(U_("Read note: "), mpt::ufmt::hex(s)));
|
||||
}
|
||||
|
||||
void SsbRead::AddReadNote(const ReadEntry* const pRe, const NumType nNum)
|
||||
{
|
||||
m_Status |= SNT_PROGRESS;
|
||||
SSB_LOG(MPT_UFORMAT("Read entry: {{num, id, rpos, size, desc}} = {{{}, {}, {}, {}, {}}}")(
|
||||
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_UFORMAT("Wrote entry: {{num, id, rpos, size}} = {{{}, {}, {}, {}}}")(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_UFORMAT("Writing map entry: id={}, rpos={}, size={}")(
|
||||
(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 >= static_cast<uint16>(std::numeric_limits<uint16>::max() >> 2))
|
||||
{
|
||||
FinishWrite();
|
||||
AddWriteNote(SNW_MAX_WRITE_COUNT_REACHED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SsbWrite::BeginWrite(const ID &id, const uint64& nVersion)
|
||||
{
|
||||
SSB_LOG(MPT_UFORMAT("Write header with ID = {}")(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_UFORMAT("No entry with id {} found.")(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_UFORMAT("Read header with expected ID = {}")(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);
|
||||
std::array<char, 256> storedIdBuf;
|
||||
storedIdBuf = {};
|
||||
if(storedIdLen > 0)
|
||||
{
|
||||
iStrm.read(storedIdBuf.data(), storedIdLen);
|
||||
}
|
||||
if(!(id == ID(storedIdBuf.data(), storedIdLen)))
|
||||
{
|
||||
AddReadNote(SNR_OBJECTCLASS_IDMISMATCH);
|
||||
}
|
||||
if ((m_Status & SNT_FAILURE) != 0)
|
||||
{
|
||||
SSB_LOG(U_("ID mismatch, terminating read."));
|
||||
return;
|
||||
}
|
||||
|
||||
SSB_LOG(U_("ID match, continuing reading."));
|
||||
|
||||
// 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(U_("No map in the file."));
|
||||
}
|
||||
|
||||
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_UFORMAT("Reading map from rpos: {}")(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_UFORMAT("End of map(rpos): {}")(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_UFORMAT("Writing map to rpos: {}")(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_UFORMAT("End of stream(rpos): {}")(oStrm.tellp() - m_posStart));
|
||||
}
|
||||
|
||||
} // namespace srlztn
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
555
Frameworks/OpenMPT/OpenMPT/common/serialization_utils.h
Normal file
555
Frameworks/OpenMPT/OpenMPT/common/serialization_utils.h
Normal file
|
@ -0,0 +1,555 @@
|
|||
/*
|
||||
* 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 "openmpt/all/BuildSettings.hpp"
|
||||
|
||||
#include "mpt/io/io.hpp"
|
||||
#include "mpt/io/io_stdstream.hpp"
|
||||
#include "openmpt/base/Endian.hpp"
|
||||
|
||||
#include "../common/mptBaseTypes.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 = std::numeric_limits<uint16>::max(),
|
||||
IdSizeMaxFixedSize = (std::numeric_limits<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
|
144
Frameworks/OpenMPT/OpenMPT/common/stdafx.h
Normal file
144
Frameworks/OpenMPT/OpenMPT/common/stdafx.h
Normal file
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* 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 openmpt/all/BuildSettings.hpp.
|
||||
* 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 "openmpt/all/BuildSettings.hpp"
|
||||
|
||||
|
||||
#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
|
||||
|
||||
|
||||
#include "mpt/base/span.hpp"
|
||||
#include "mpt/check/libc.hpp"
|
||||
#if defined(MPT_WITH_MFC)
|
||||
#include "mpt/check/mfc.hpp"
|
||||
#endif
|
||||
#if MPT_OS_WINDOWS
|
||||
#include "mpt/check/windows.hpp"
|
||||
#endif
|
||||
#include "mpt/exception_text/exception_text.hpp"
|
||||
#include "mpt/out_of_memory/out_of_memory.hpp"
|
||||
#include "mpt/system_error/system_error.hpp"
|
||||
|
||||
#include "openmpt/base/Types.hpp"
|
||||
#include "openmpt/logging/Logger.hpp"
|
||||
|
||||
|
||||
#include <memory>
|
||||
#include <new>
|
||||
|
||||
|
||||
// this will be available everywhere
|
||||
|
||||
#include "../common/mptBaseMacros.h"
|
||||
// <version>
|
||||
// <array>
|
||||
// <iterator>
|
||||
// <type_traits>
|
||||
// <cstddef>
|
||||
// <cstdint>
|
||||
|
||||
#include "../common/mptBaseTypes.h"
|
||||
// "openmpt/base/Types.hpp"
|
||||
// "mptBaseMacros.h"
|
||||
// <array>
|
||||
// <limits>
|
||||
// <type_traits>
|
||||
// <cstdint>
|
||||
|
||||
#include "../common/mptAssert.h"
|
||||
// "mptBaseMacros.h"
|
||||
|
||||
#include "../common/mptBaseUtils.h"
|
||||
// <algorithm>
|
||||
// <bit>
|
||||
// <limits>
|
||||
// <numeric>
|
||||
// <utility>
|
||||
|
||||
#include "../common/mptString.h"
|
||||
// <algorithm>
|
||||
// <limits>
|
||||
// <string>
|
||||
// <string_view>
|
||||
// <type_traits>
|
||||
// <cstring>
|
||||
|
||||
#include "../common/mptStringBuffer.h"
|
||||
|
||||
#include "../common/mptStringFormat.h"
|
||||
// <stdexcept>
|
||||
|
||||
#include "../common/mptPathString.h"
|
||||
|
||||
#include "../common/Logging.h"
|
||||
// "openmpt/logging/Logger.hpp"
|
||||
// <atomic>
|
||||
|
||||
#include "../common/misc_util.h"
|
||||
// <stdexcept>
|
||||
// <optional>
|
||||
// <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
|
827
Frameworks/OpenMPT/OpenMPT/common/version.cpp
Normal file
827
Frameworks/OpenMPT/OpenMPT/common/version.cpp
Normal file
|
@ -0,0 +1,827 @@
|
|||
/*
|
||||
* 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_UFORMAT("{}.{}")(mpt::ufmt::HEX((v >> 24) & 0xFF), mpt::ufmt::HEX0<2>((v >> 16) & 0xFF));
|
||||
} else
|
||||
{
|
||||
// Full version info available
|
||||
return MPT_UFORMAT("{}.{}.{}.{}")(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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
VersionWithRevision VersionWithRevision::Current()
|
||||
{
|
||||
return {Version::Current(), static_cast<uint64>(SourceInfo::Current().Revision())};
|
||||
}
|
||||
|
||||
VersionWithRevision VersionWithRevision::Parse(const mpt::ustring &s)
|
||||
{
|
||||
Version version = Version::Parse(mpt::ustring());
|
||||
uint64 revision = 0;
|
||||
const auto tokens = mpt::String::Split<mpt::ustring>(s, U_("-"));
|
||||
if(tokens.size() >= 1)
|
||||
{
|
||||
version = Version::Parse(tokens[0]);
|
||||
}
|
||||
if(tokens.size() >= 2)
|
||||
{
|
||||
revision = ConvertStrTo<uint64>(tokens[1].substr(1));
|
||||
}
|
||||
return {version, revision};
|
||||
}
|
||||
|
||||
mpt::ustring VersionWithRevision::ToUString() const
|
||||
{
|
||||
if(!HasRevision())
|
||||
{
|
||||
return mpt::ufmt::val(version);
|
||||
}
|
||||
if(!version.IsTestVersion())
|
||||
{
|
||||
return mpt::ufmt::val(version);
|
||||
}
|
||||
return MPT_UFORMAT("{}-r{}")(version, revision);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
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 defined(MPT_BUILD_RETRO)
|
||||
retval += UL_(" RETRO");
|
||||
#endif // MPT_BUILD_RETRO
|
||||
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
|
||||
#ifndef MPT_WITH_VST
|
||||
UL_(" NO_VST")
|
||||
#endif
|
||||
#ifndef MPT_WITH_DMO
|
||||
UL_(" NO_DMO")
|
||||
#endif
|
||||
#ifdef NO_PLUGINS
|
||||
UL_(" NO_PLUGINS")
|
||||
#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_UFORMAT("Microsoft Compiler {}.{}.{}.{}")
|
||||
( _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_UFORMAT("Microsoft Compiler {}.{}.{}")
|
||||
( _MSC_FULL_VER / 10000000
|
||||
, mpt::ufmt::dec0<2>((_MSC_FULL_VER / 100000) % 100)
|
||||
, mpt::ufmt::dec0<5>(_MSC_FULL_VER % 100000)
|
||||
);
|
||||
#else
|
||||
retval += MPT_UFORMAT("Microsoft Compiler {}.{}")(MPT_COMPILER_MSVC_VERSION / 100, MPT_COMPILER_MSVC_VERSION % 100);
|
||||
#endif
|
||||
#elif MPT_COMPILER_GCC
|
||||
retval += MPT_UFORMAT("GNU Compiler Collection {}.{}.{}")(MPT_COMPILER_GCC_VERSION / 10000, (MPT_COMPILER_GCC_VERSION / 100) % 100, MPT_COMPILER_GCC_VERSION % 100);
|
||||
#elif MPT_COMPILER_CLANG
|
||||
retval += MPT_UFORMAT("Clang {}.{}.{}")(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[StringSourceInfo])
|
||||
{
|
||||
const SourceInfo sourceInfo = SourceInfo::Current();
|
||||
if(!sourceInfo.GetUrlWithRevision().empty())
|
||||
{
|
||||
result.push_back(MPT_UFORMAT(" {}")(sourceInfo.GetUrlWithRevision()));
|
||||
}
|
||||
if(!sourceInfo.Date().empty())
|
||||
{
|
||||
result.push_back(MPT_UFORMAT(" ({})")(sourceInfo.Date()));
|
||||
}
|
||||
if(!sourceInfo.GetStateString().empty())
|
||||
{
|
||||
result.push_back(MPT_UFORMAT(" {}")(sourceInfo.GetStateString()));
|
||||
}
|
||||
}
|
||||
if(strings[StringBuildFlags])
|
||||
{
|
||||
if(!IsReleasedBuild())
|
||||
{
|
||||
result.push_back(GetBuildFlagsString());
|
||||
}
|
||||
}
|
||||
if(strings[StringBuildFeatures])
|
||||
{
|
||||
result.push_back(GetBuildFeaturesString());
|
||||
}
|
||||
return mpt::trim(mpt::String::Combine<mpt::ustring>(result, U_("")));
|
||||
}
|
||||
|
||||
mpt::ustring GetVersionStringPure()
|
||||
{
|
||||
FlagSet<Build::Strings> strings;
|
||||
strings |= Build::StringVersion;
|
||||
strings |= Build::StringRevision;
|
||||
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;
|
||||
#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 / Open ModPlug Tracker\n"
|
||||
#else
|
||||
"libopenmpt (based on OpenMPT / Open ModPlug Tracker)\n"
|
||||
#endif
|
||||
"\n"
|
||||
"Copyright \xC2\xA9 2004-2022 OpenMPT Project Developers and Contributors\n"
|
||||
"Copyright \xC2\xA9 1997-2003 Olivier Lapicque\n"
|
||||
"\n"
|
||||
"Developers:\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 contributors:\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
|
||||
#ifdef MPT_WITH_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_ANCIENT
|
||||
"Teemu Suutari for ancient\n"
|
||||
"https://github.com/temisu/ancient\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 for RtAudio\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"
|
||||
#ifdef MPT_WITH_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 Project Developers and 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"" "\n"
|
||||
"AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE" "\n"
|
||||
"IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE" "\n"
|
||||
"DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE" "\n"
|
||||
"FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL" "\n"
|
||||
"DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR" "\n"
|
||||
"SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER" "\n"
|
||||
"CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY," "\n"
|
||||
"OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE" "\n"
|
||||
"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." "\n"
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace Build
|
||||
|
||||
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
397
Frameworks/OpenMPT/OpenMPT/common/version.h
Normal file
397
Frameworks/OpenMPT/OpenMPT/common/version.h
Normal file
|
@ -0,0 +1,397 @@
|
|||
/*
|
||||
* 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 "openmpt/all/BuildSettings.hpp"
|
||||
|
||||
#include "mptString.h"
|
||||
#include "openmpt/base/FlagSet.hpp"
|
||||
|
||||
#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_CONSTEXPRINLINE Version() noexcept
|
||||
: m_Version(0)
|
||||
{}
|
||||
|
||||
explicit MPT_CONSTEXPRINLINE Version(uint32 version) noexcept
|
||||
: m_Version(version)
|
||||
{}
|
||||
|
||||
explicit MPT_CONSTEXPRINLINE 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_CONSTEXPRINLINE operator bool () const noexcept
|
||||
{
|
||||
return m_Version != 0;
|
||||
}
|
||||
MPT_CONSTEXPRINLINE bool operator ! () const noexcept
|
||||
{
|
||||
return m_Version == 0;
|
||||
}
|
||||
|
||||
MPT_CONSTEXPRINLINE uint32 GetRawVersion() const noexcept
|
||||
{
|
||||
return m_Version;
|
||||
}
|
||||
|
||||
MPT_FORCEINLINE Version Masked(uint32 mask) const noexcept
|
||||
{
|
||||
return Version(m_Version & mask);
|
||||
}
|
||||
|
||||
MPT_CONSTEXPRINLINE 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_CONSTEXPRINLINE 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_CONSTEXPRINLINE 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_CONSTEXPRINLINE bool operator == (const Version &a, const Version &b) noexcept
|
||||
{
|
||||
return a.GetRawVersion() == b.GetRawVersion();
|
||||
}
|
||||
MPT_CONSTEXPRINLINE bool operator != (const Version &a, const Version &b) noexcept
|
||||
{
|
||||
return a.GetRawVersion() != b.GetRawVersion();
|
||||
}
|
||||
MPT_CONSTEXPRINLINE bool operator <= (const Version &a, const Version &b) noexcept
|
||||
{
|
||||
return a.GetRawVersion() <= b.GetRawVersion();
|
||||
}
|
||||
MPT_CONSTEXPRINLINE bool operator >= (const Version &a, const Version &b) noexcept
|
||||
{
|
||||
return a.GetRawVersion() >= b.GetRawVersion();
|
||||
}
|
||||
MPT_CONSTEXPRINLINE bool operator < (const Version &a, const Version &b) noexcept
|
||||
{
|
||||
return a.GetRawVersion() < b.GetRawVersion();
|
||||
}
|
||||
MPT_CONSTEXPRINLINE bool operator > (const Version &a, const Version &b) noexcept
|
||||
{
|
||||
return a.GetRawVersion() > b.GetRawVersion();
|
||||
}
|
||||
|
||||
|
||||
MPT_CONSTEXPRINLINE 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) MPT_FORCE_CONSTEXPR(Version{( 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"
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct VersionWithRevision
|
||||
{
|
||||
Version version;
|
||||
uint64 revision;
|
||||
static VersionWithRevision Current();
|
||||
static VersionWithRevision Parse(const mpt::ustring &s);
|
||||
mpt::ustring ToUString() const;
|
||||
constexpr bool HasRevision() const noexcept
|
||||
{
|
||||
return revision != 0;
|
||||
}
|
||||
constexpr bool IsEqualTo(VersionWithRevision other) const noexcept
|
||||
{
|
||||
return version == other.version && revision == other.revision;
|
||||
}
|
||||
constexpr bool IsEquivalentTo(VersionWithRevision other) const noexcept
|
||||
{
|
||||
if(version == other.version && revision == other.revision)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if(HasRevision() && other.HasRevision())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return version == other.version;
|
||||
}
|
||||
constexpr bool IsNewerThan(VersionWithRevision other) const noexcept
|
||||
{
|
||||
if(version < other.version)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(version > other.version)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if(!HasRevision() && !other.HasRevision())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(HasRevision() && other.HasRevision())
|
||||
{
|
||||
if(revision < other.revision)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(revision > other.revision)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
constexpr bool IsOlderThan(VersionWithRevision other) const noexcept
|
||||
{
|
||||
if(version < other.version)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if(version > other.version)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(!HasRevision() && !other.HasRevision())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(HasRevision() && other.HasRevision())
|
||||
{
|
||||
if(revision < other.revision)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if(revision > other.revision)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
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+"
|
||||
StringSourceInfo = 1<<5, // "https://source.openmpt.org/svn/openmpt/trunk/OpenMPT@1234 (2016-01-02) +dirty"
|
||||
StringBuildFlags = 1<<6, // "TEST DEBUG"
|
||||
StringBuildFeatures = 1<<7, // "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+"
|
||||
|
||||
// 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+ 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
|
23
Frameworks/OpenMPT/OpenMPT/common/versionNumber.h
Normal file
23
Frameworks/OpenMPT/OpenMPT/common/versionNumber.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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 "openmpt/all/BuildSettings.hpp"
|
||||
|
||||
OPENMPT_NAMESPACE_BEGIN
|
||||
|
||||
// Version definitions. The only thing that needs to be changed when changing version number.
|
||||
#define VER_MAJORMAJOR 1
|
||||
#define VER_MAJOR 30
|
||||
#define VER_MINOR 05
|
||||
#define VER_MINORMINOR 01
|
||||
|
||||
OPENMPT_NAMESPACE_END
|
325
Frameworks/OpenMPT/OpenMPT/contrib/fuzzing/all_formats.dict
Normal file
325
Frameworks/OpenMPT/OpenMPT/contrib/fuzzing/all_formats.dict
Normal file
|
@ -0,0 +1,325 @@
|
|||
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"
|
||||
|
||||
dsym="\x02\x01\x13\x13\x14\x12\x01\x0B\x01"
|
||||
|
||||
dtm="D.T."
|
||||
dtm="S.Q."
|
||||
#dtm="PATT"
|
||||
#dtm="INST"
|
||||
dtm="DAPT"
|
||||
dtm="DAIT"
|
||||
|
||||
far="FAR\xFE"
|
||||
far="\x0D\x0A\x1A"
|
||||
|
||||
fmt="FMTracker\x01\x01"
|
||||
|
||||
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"
|
||||
|
||||
symmod="SymM\x00\x00\x00\x01\xFF\xFF\xFF\xFF\x00\x00\x00"
|
||||
|
||||
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"
|
||||
plugin_symmodecho="SymMEcho"
|
||||
|
||||
midi="MThd\x00\x00\x00\x06\x00\x01\x00\x01\x01\xE0MTrk"
|
||||
|
||||
wave="WAVEfmt "
|
||||
wave="data"
|
||||
|
||||
# IFF / AIFF (for SymMOD loader)
|
||||
iff="FORM"
|
||||
iff="AIFF"
|
||||
iff="AIFC"
|
||||
iff="8SVX"
|
||||
iff="16SV"
|
||||
iff="MAUD"
|
||||
iff="VHDR"
|
||||
iff="BODY"
|
||||
iff="CHAN"
|
||||
iff="MHDR"
|
||||
iff="MDAT"
|
||||
iff="NAME"
|
4
Frameworks/OpenMPT/OpenMPT/contrib/fuzzing/build.sh
Executable file
4
Frameworks/OpenMPT/OpenMPT/contrib/fuzzing/build.sh
Executable file
|
@ -0,0 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
cd "${0%/*}"
|
||||
cd ../..
|
||||
AFL_HARDEN=1 CONFIG=afl make clean all EXAMPLES=0 TEST=0 OPENMPT123=0 NO_VORBIS=1 NO_VORBISFILE=1 NO_MPG123=1 CHECKED_ADDRESS=1
|
13
Frameworks/OpenMPT/OpenMPT/contrib/fuzzing/fuzz-main.sh
Normal file
13
Frameworks/OpenMPT/OpenMPT/contrib/fuzzing/fuzz-main.sh
Normal file
|
@ -0,0 +1,13 @@
|
|||
#!/usr/bin/env bash
|
||||
cd "${0%/*}"
|
||||
. ./fuzz-settings.sh
|
||||
|
||||
# Create tmpfs for storing temporary fuzzing data
|
||||
mkdir $FUZZING_TEMPDIR
|
||||
sudo mount -t tmpfs -o size=300M none $FUZZING_TEMPDIR
|
||||
rm -rf $FUZZING_TEMPDIR/bin
|
||||
mkdir $FUZZING_TEMPDIR/bin
|
||||
cp -d ../../bin/* $FUZZING_TEMPDIR/bin/
|
||||
|
||||
#export AFL_PRELOAD=$AFL_DIR/libdislocator.so
|
||||
LD_LIBRARY_PATH=$FUZZING_TEMPDIR/bin $AFL_DIR/afl-fuzz -p exploit -f $FUZZING_TEMPDIR/infile01 -x all_formats.dict -t $FUZZING_TIMEOUT $FUZZING_INPUT -o $FUZZING_FINDINGS_DIR -D -M fuzzer01 $FUZZING_TEMPDIR/bin/fuzz $FUZZING_TEMPDIR/infile01
|
|
@ -0,0 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
cd "${0%/*}"
|
||||
. ./fuzz-settings.sh
|
||||
|
||||
#export AFL_PRELOAD=$AFL_DIR/libdislocator.so
|
||||
LD_LIBRARY_PATH=$FUZZING_TEMPDIR/bin $AFL_DIR/afl-fuzz -p coe -f $FUZZING_TEMPDIR/infile02 -x all_formats.dict -t $FUZZING_TIMEOUT $FUZZING_INPUT -o $FUZZING_FINDINGS_DIR -S fuzzer02 $FUZZING_TEMPDIR/bin/fuzz $FUZZING_TEMPDIR/infile02
|
|
@ -0,0 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
cd "${0%/*}"
|
||||
. ./fuzz-settings.sh
|
||||
|
||||
#export AFL_PRELOAD=$AFL_DIR/libdislocator.so
|
||||
LD_LIBRARY_PATH=$FUZZING_TEMPDIR/bin $AFL_DIR/afl-fuzz -p explore -f $FUZZING_TEMPDIR/infile03 -x all_formats.dict -t $FUZZING_TIMEOUT $FUZZING_INPUT -o $FUZZING_FINDINGS_DIR -S fuzzer03 $FUZZING_TEMPDIR/bin/fuzz $FUZZING_TEMPDIR/infile03
|
18
Frameworks/OpenMPT/OpenMPT/contrib/fuzzing/fuzz-settings.sh
Executable file
18
Frameworks/OpenMPT/OpenMPT/contrib/fuzzing/fuzz-settings.sh
Executable file
|
@ -0,0 +1,18 @@
|
|||
#!/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
|
59
Frameworks/OpenMPT/OpenMPT/contrib/fuzzing/fuzz.c
Normal file
59
Frameworks/OpenMPT/OpenMPT/contrib/fuzzing/fuzz.c
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
18
Frameworks/OpenMPT/OpenMPT/contrib/fuzzing/get-afl.sh
Executable file
18
Frameworks/OpenMPT/OpenMPT/contrib/fuzzing/get-afl.sh
Executable file
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env bash
|
||||
cd "${0%/*}"
|
||||
|
||||
if [ -z "${GET_AFL_VERSION}" ]; then
|
||||
GET_AFL_VERSION="$(wget --quiet -O - "https://api.github.com/repos/AFLplusplus/AFLplusplus/releases/latest" | grep -Po '"tag_name": "\K.*?(?=")')"
|
||||
fi
|
||||
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
|
51
Frameworks/OpenMPT/OpenMPT/contrib/fuzzing/readme.md
Normal file
51
Frameworks/OpenMPT/OpenMPT/contrib/fuzzing/readme.md
Normal file
|
@ -0,0 +1,51 @@
|
|||
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.
|
|
@ -0,0 +1,25 @@
|
|||
Copyright (c) 2004-2022, OpenMPT Project Developers and 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 COPYRIGHT HOLDERS AND 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 COPYRIGHT HOLDER OR 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.
|
|
@ -0,0 +1,46 @@
|
|||
|
||||
ACLOCAL_AMFLAGS = -I m4 --install
|
||||
EXTRA_DIST =
|
||||
EXTRA_DIST += LICENSE
|
||||
EXTRA_DIST += libopenmpt_modplug.pc.in
|
||||
EXTRA_DIST += libmodplug.pc.in
|
||||
EXTRA_DIST += test.sh
|
||||
MOSTLYCLEANFILES =
|
||||
|
||||
dist_doc_DATA =
|
||||
dist_doc_DATA += LICENSE
|
||||
nobase_dist_doc_DATA =
|
||||
|
||||
bin_PROGRAMS =
|
||||
check_PROGRAMS =
|
||||
lib_LTLIBRARIES =
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA =
|
||||
nobase_include_HEADERS =
|
||||
|
||||
if ENABLE_LIBOPENMPT_MODPLUG
|
||||
lib_LTLIBRARIES += libopenmpt_modplug.la
|
||||
libopenmpt_modplug_la_LDFLAGS = -version-info 1:0:0 -no-undefined
|
||||
libopenmpt_modplug_la_CPPFLAGS = -I$(srcdir)/ $(LIBOPENMPT_CPPFLAGS)
|
||||
libopenmpt_modplug_la_CXXFLAGS = $(LIBOPENMPT_CFLAGS)
|
||||
libopenmpt_modplug_la_CFLAGS = $(LIBOPENMPT_CFLAGS)
|
||||
libopenmpt_modplug_la_LIBADD = $(LIBOPENMPT_LIBS)
|
||||
libopenmpt_modplug_la_SOURCES =
|
||||
libopenmpt_modplug_la_SOURCES += libopenmpt_modplug.c
|
||||
libopenmpt_modplug_la_SOURCES += libopenmpt_modplug_cpp.cpp
|
||||
endif
|
||||
|
||||
if ENABLE_LIBMODPLUG
|
||||
pkgconfig_DATA += libmodplug.pc
|
||||
lib_LTLIBRARIES += libmodplug.la
|
||||
libmodplug_la_LDFLAGS = -version-info 1:0:0 -no-undefined
|
||||
nobase_include_HEADERS += libmodplug/modplug.h libmodplug/sndfile.h libmodplug/stdafx.h
|
||||
libmodplug_la_CPPFLAGS = -I$(srcdir)/ $(LIBOPENMPT_CPPFLAGS)
|
||||
libmodplug_la_CXXFLAGS = $(LIBOPENMPT_CFLAGS)
|
||||
libmodplug_la_CFLAGS = $(LIBOPENMPT_CFLAGS)
|
||||
libmodplug_la_LIBADD = $(LIBOPENMPT_LIBS)
|
||||
libmodplug_la_SOURCES =
|
||||
libmodplug_la_SOURCES += libopenmpt_modplug.c
|
||||
libmodplug_la_SOURCES += libopenmpt_modplug_cpp.cpp
|
||||
endif
|
2
Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.8.5/autogen.sh
Executable file
2
Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.8.5/autogen.sh
Executable file
|
@ -0,0 +1,2 @@
|
|||
#!/usr/bin/env sh
|
||||
autoreconf -i
|
7
Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.8.5/clean.sh
Executable file
7
Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.8.5/clean.sh
Executable file
|
@ -0,0 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
./autogen.sh
|
||||
./configure
|
||||
make distclean
|
|
@ -0,0 +1,81 @@
|
|||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* define if the compiler supports basic C++11 syntax */
|
||||
#undef HAVE_CXX11
|
||||
|
||||
/* define if the compiler supports basic C++14 syntax */
|
||||
#undef HAVE_CXX14
|
||||
|
||||
/* define if the compiler supports basic C++17 syntax */
|
||||
#undef HAVE_CXX17
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#undef HAVE_DLFCN_H
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Define to the sub-directory where libtool stores uninstalled libraries. */
|
||||
#undef LT_OBJDIR
|
||||
|
||||
/* Name of package */
|
||||
#undef PACKAGE
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#undef PACKAGE_URL
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Version number of package */
|
||||
#undef VERSION
|
||||
|
||||
/* Enable large inode numbers on Mac OS X 10.5. */
|
||||
#ifndef _DARWIN_USE_64_BIT_INODE
|
||||
# define _DARWIN_USE_64_BIT_INODE 1
|
||||
#endif
|
||||
|
||||
/* Number of bits in a file offset, on hosts where this is settable. */
|
||||
#undef _FILE_OFFSET_BITS
|
||||
|
||||
/* Define for large files, on AIX-style hosts. */
|
||||
#undef _LARGE_FILES
|
|
@ -0,0 +1,66 @@
|
|||
AC_INIT([libopenmpt-modplug], [0.8.8.5-openmpt1], [https://bugs.openmpt.org/], [libopenmpt-modplug], [https://lib.openmpt.org/])
|
||||
AC_PREREQ([2.68])
|
||||
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_AUX_DIR([build-aux])
|
||||
AC_CONFIG_FILES([Makefile libopenmpt_modplug.pc libmodplug.pc])
|
||||
|
||||
AM_INIT_AUTOMAKE([1.11 -Wall -Werror foreign subdir-objects])
|
||||
|
||||
AM_PROG_AR
|
||||
|
||||
LT_INIT
|
||||
|
||||
AC_SYS_LARGEFILE
|
||||
|
||||
PKG_PROG_PKG_CONFIG([0.24])
|
||||
AC_PROG_CC
|
||||
AM_PROG_CC_C_O
|
||||
AC_PROG_CXX
|
||||
AC_PROG_INSTALL
|
||||
|
||||
LIBOPENMPT_REQUIRES_PRIVATE=
|
||||
LIBOPENMPT_LIBS_PRIVATE=
|
||||
|
||||
# We want a modern C compiler
|
||||
AC_PROG_CC_STDC
|
||||
#AC_PROG_CC_C99
|
||||
|
||||
# We need C++11 support
|
||||
AX_CXX_COMPILE_STDCXX(17, [noext], [optional])
|
||||
AS_IF([test "x$HAVE_CXX17" != "x1"],
|
||||
[
|
||||
AX_CXX_COMPILE_STDCXX(14, [noext], [optional])
|
||||
AS_IF([test "x$HAVE_CXX14" != "x1"],
|
||||
[
|
||||
AX_CXX_COMPILE_STDCXX(11, [noext], [mandatory])
|
||||
],[]
|
||||
)
|
||||
],[]
|
||||
)
|
||||
|
||||
AC_LANG_PUSH([C])
|
||||
AX_CHECK_COMPILE_FLAG([-fvisibility=hidden], [CFLAGS="$CFLAGS -fvisibility=hidden"])
|
||||
AX_CFLAGS_WARN_ALL
|
||||
AC_LANG_POP([C])
|
||||
|
||||
AC_LANG_PUSH([C++])
|
||||
AX_CHECK_COMPILE_FLAG([-fvisibility=hidden], [CXXFLAGS="$CXXFLAGS -fvisibility=hidden"])
|
||||
AX_CXXFLAGS_WARN_ALL
|
||||
AC_LANG_POP([C++])
|
||||
|
||||
PKG_CHECK_MODULES([LIBOPENMPT], [libopenmpt])
|
||||
|
||||
# libmodplug emulation
|
||||
AC_ARG_ENABLE([libopenmpt_modplug], AS_HELP_STRING([--disable-libopenmpt_modplug], [Disable the libopenmpt_modplug emulation library of the libmodplug interface.]))
|
||||
AM_CONDITIONAL([ENABLE_LIBOPENMPT_MODPLUG], [test "x$enable_libopenmpt_modplug" != "xno"])
|
||||
|
||||
# libmodplug replacement
|
||||
AC_ARG_ENABLE([libmodplug], AS_HELP_STRING([--enable-libmodplug], [Enable libmodplug replacement library based on libopenmpt.
|
||||
WARNING: This will replace your current libmodplug installation.
|
||||
CAUTION: The emulation of the libmodplug interface is not complete as libmodplug exposes lots of internal implementation details. If any of those is used by an application, the emulation via libopenmpt will fail and/or crash.
|
||||
]))
|
||||
AM_CONDITIONAL([ENABLE_LIBMODPLUG], [test "x$enable_libmodplug" = "xyes"])
|
||||
|
||||
AC_OUTPUT
|
9
Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.8.5/dist.sh
Executable file
9
Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.8.5/dist.sh
Executable file
|
@ -0,0 +1,9 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
./test.sh
|
||||
|
||||
./autogen.sh
|
||||
./configure
|
||||
make dist
|
|
@ -0,0 +1,13 @@
|
|||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=${prefix}/include
|
||||
|
||||
Name: libmodplug
|
||||
Description: The ModPlug mod file playing library (emulated via libopenmpt).
|
||||
Version: @PACKAGE_VERSION@
|
||||
Requires.private: libopenmpt
|
||||
Libs: -L${libdir} -lmodplug
|
||||
Libs.private:
|
||||
Cflags: -I${includedir}
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
* This source code is public domain.
|
||||
*
|
||||
* Authors: Kenton Varda <temporal@gauge3d.org> (C interface wrapper)
|
||||
*/
|
||||
|
||||
#ifndef MODPLUG_MODPLUG_H
|
||||
#define MODPLUG_MODPLUG_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
# if defined(MODPLUG_BUILD) && defined(DLL_EXPORT) /* building libmodplug as a dll for windows */
|
||||
# define MODPLUG_EXPORT __declspec(dllexport)
|
||||
# elif defined(MODPLUG_BUILD) || defined(MODPLUG_STATIC) /* building or using static libmodplug for windows */
|
||||
# define MODPLUG_EXPORT
|
||||
# else
|
||||
# define MODPLUG_EXPORT __declspec(dllimport) /* using libmodplug dll for windows */
|
||||
# endif
|
||||
/* FIXME: USE VISIBILITY ATTRIBUTES HERE */
|
||||
#elif defined(MODPLUG_BUILD)
|
||||
#define MODPLUG_EXPORT
|
||||
#else
|
||||
#define MODPLUG_EXPORT
|
||||
#endif
|
||||
|
||||
struct _ModPlugFile;
|
||||
typedef struct _ModPlugFile ModPlugFile;
|
||||
|
||||
struct _ModPlugNote {
|
||||
unsigned char Note;
|
||||
unsigned char Instrument;
|
||||
unsigned char VolumeEffect;
|
||||
unsigned char Effect;
|
||||
unsigned char Volume;
|
||||
unsigned char Parameter;
|
||||
};
|
||||
typedef struct _ModPlugNote ModPlugNote;
|
||||
|
||||
typedef void (*ModPlugMixerProc)(int*, unsigned long, unsigned long);
|
||||
|
||||
/* Load a mod file. [data] should point to a block of memory containing the complete
|
||||
* file, and [size] should be the size of that block.
|
||||
* Return the loaded mod file on success, or NULL on failure. */
|
||||
MODPLUG_EXPORT ModPlugFile* ModPlug_Load(const void* data, int size);
|
||||
/* Unload a mod file. */
|
||||
MODPLUG_EXPORT void ModPlug_Unload(ModPlugFile* file);
|
||||
|
||||
/* Read sample data into the buffer. Returns the number of bytes read. If the end
|
||||
* of the mod has been reached, zero is returned. */
|
||||
MODPLUG_EXPORT int ModPlug_Read(ModPlugFile* file, void* buffer, int size);
|
||||
|
||||
/* Get the name of the mod. The returned buffer is stored within the ModPlugFile
|
||||
* structure and will remain valid until you unload the file. */
|
||||
MODPLUG_EXPORT const char* ModPlug_GetName(ModPlugFile* file);
|
||||
|
||||
/* Get the length of the mod, in milliseconds. Note that this result is not always
|
||||
* accurate, especially in the case of mods with loops. */
|
||||
MODPLUG_EXPORT int ModPlug_GetLength(ModPlugFile* file);
|
||||
|
||||
/* Seek to a particular position in the song. Note that seeking and MODs don't mix very
|
||||
* well. Some mods will be missing instruments for a short time after a seek, as ModPlug
|
||||
* does not scan the sequence backwards to find out which instruments were supposed to be
|
||||
* playing at that time. (Doing so would be difficult and not very reliable.) Also,
|
||||
* note that seeking is not very exact in some mods -- especially those for which
|
||||
* ModPlug_GetLength() does not report the full length. */
|
||||
MODPLUG_EXPORT void ModPlug_Seek(ModPlugFile* file, int millisecond);
|
||||
|
||||
enum _ModPlug_Flags
|
||||
{
|
||||
MODPLUG_ENABLE_OVERSAMPLING = 1 << 0, /* Enable oversampling (*highly* recommended) */
|
||||
MODPLUG_ENABLE_NOISE_REDUCTION = 1 << 1, /* Enable noise reduction */
|
||||
MODPLUG_ENABLE_REVERB = 1 << 2, /* Enable reverb */
|
||||
MODPLUG_ENABLE_MEGABASS = 1 << 3, /* Enable megabass */
|
||||
MODPLUG_ENABLE_SURROUND = 1 << 4 /* Enable surround sound. */
|
||||
};
|
||||
|
||||
enum _ModPlug_ResamplingMode
|
||||
{
|
||||
MODPLUG_RESAMPLE_NEAREST = 0, /* No interpolation (very fast, extremely bad sound quality) */
|
||||
MODPLUG_RESAMPLE_LINEAR = 1, /* Linear interpolation (fast, good quality) */
|
||||
MODPLUG_RESAMPLE_SPLINE = 2, /* Cubic spline interpolation (high quality) */
|
||||
MODPLUG_RESAMPLE_FIR = 3 /* 8-tap fir filter (extremely high quality) */
|
||||
};
|
||||
|
||||
typedef struct _ModPlug_Settings
|
||||
{
|
||||
int mFlags; /* One or more of the MODPLUG_ENABLE_* flags above, bitwise-OR'ed */
|
||||
|
||||
/* Note that ModPlug always decodes sound at 44100kHz, 32 bit, stereo and then
|
||||
* down-mixes to the settings you choose. */
|
||||
int mChannels; /* Number of channels - 1 for mono or 2 for stereo */
|
||||
int mBits; /* Bits per sample - 8, 16, or 32 */
|
||||
int mFrequency; /* Sampling rate - 11025, 22050, or 44100 */
|
||||
int mResamplingMode; /* One of MODPLUG_RESAMPLE_*, above */
|
||||
|
||||
int mStereoSeparation; /* Stereo separation, 1 - 256 */
|
||||
int mMaxMixChannels; /* Maximum number of mixing channels (polyphony), 32 - 256 */
|
||||
|
||||
int mReverbDepth; /* Reverb level 0(quiet)-100(loud) */
|
||||
int mReverbDelay; /* Reverb delay in ms, usually 40-200ms */
|
||||
int mBassAmount; /* XBass level 0(quiet)-100(loud) */
|
||||
int mBassRange; /* XBass cutoff in Hz 10-100 */
|
||||
int mSurroundDepth; /* Surround level 0(quiet)-100(heavy) */
|
||||
int mSurroundDelay; /* Surround delay in ms, usually 5-40ms */
|
||||
int mLoopCount; /* Number of times to loop. Zero prevents looping.
|
||||
-1 loops forever. */
|
||||
} ModPlug_Settings;
|
||||
|
||||
/* Get and set the mod decoder settings. All options, except for channels, bits-per-sample,
|
||||
* sampling rate, and loop count, will take effect immediately. Those options which don't
|
||||
* take effect immediately will take effect the next time you load a mod. */
|
||||
MODPLUG_EXPORT void ModPlug_GetSettings(ModPlug_Settings* settings);
|
||||
MODPLUG_EXPORT void ModPlug_SetSettings(const ModPlug_Settings* settings);
|
||||
|
||||
/* New ModPlug API Functions */
|
||||
/* NOTE: Master Volume (1-512) */
|
||||
MODPLUG_EXPORT unsigned int ModPlug_GetMasterVolume(ModPlugFile* file) ;
|
||||
MODPLUG_EXPORT void ModPlug_SetMasterVolume(ModPlugFile* file,unsigned int cvol) ;
|
||||
|
||||
MODPLUG_EXPORT int ModPlug_GetCurrentSpeed(ModPlugFile* file);
|
||||
MODPLUG_EXPORT int ModPlug_GetCurrentTempo(ModPlugFile* file);
|
||||
MODPLUG_EXPORT int ModPlug_GetCurrentOrder(ModPlugFile* file);
|
||||
MODPLUG_EXPORT int ModPlug_GetCurrentPattern(ModPlugFile* file);
|
||||
MODPLUG_EXPORT int ModPlug_GetCurrentRow(ModPlugFile* file);
|
||||
MODPLUG_EXPORT int ModPlug_GetPlayingChannels(ModPlugFile* file);
|
||||
|
||||
MODPLUG_EXPORT void ModPlug_SeekOrder(ModPlugFile* file,int order);
|
||||
MODPLUG_EXPORT int ModPlug_GetModuleType(ModPlugFile* file);
|
||||
MODPLUG_EXPORT char* ModPlug_GetMessage(ModPlugFile* file);
|
||||
|
||||
|
||||
#ifndef MODPLUG_NO_FILESAVE
|
||||
/*
|
||||
* EXPERIMENTAL Export Functions
|
||||
*/
|
||||
/*Export to a Scream Tracker 3 S3M module. EXPERIMENTAL (only works on Little-Endian platforms)*/
|
||||
MODPLUG_EXPORT char ModPlug_ExportS3M(ModPlugFile* file, const char* filepath);
|
||||
|
||||
/*Export to a Extended Module (XM). EXPERIMENTAL (only works on Little-Endian platforms)*/
|
||||
MODPLUG_EXPORT char ModPlug_ExportXM(ModPlugFile* file, const char* filepath);
|
||||
|
||||
/*Export to a Amiga MOD file. EXPERIMENTAL.*/
|
||||
MODPLUG_EXPORT char ModPlug_ExportMOD(ModPlugFile* file, const char* filepath);
|
||||
|
||||
/*Export to a Impulse Tracker IT file. Should work OK in Little-Endian & Big-Endian platforms :-) */
|
||||
MODPLUG_EXPORT char ModPlug_ExportIT(ModPlugFile* file, const char* filepath);
|
||||
#endif // MODPLUG_NO_FILESAVE
|
||||
|
||||
MODPLUG_EXPORT unsigned int ModPlug_NumInstruments(ModPlugFile* file);
|
||||
MODPLUG_EXPORT unsigned int ModPlug_NumSamples(ModPlugFile* file);
|
||||
MODPLUG_EXPORT unsigned int ModPlug_NumPatterns(ModPlugFile* file);
|
||||
MODPLUG_EXPORT unsigned int ModPlug_NumChannels(ModPlugFile* file);
|
||||
MODPLUG_EXPORT unsigned int ModPlug_SampleName(ModPlugFile* file, unsigned int qual, char* buff);
|
||||
MODPLUG_EXPORT unsigned int ModPlug_InstrumentName(ModPlugFile* file, unsigned int qual, char* buff);
|
||||
|
||||
/*
|
||||
* Retrieve pattern note-data
|
||||
*/
|
||||
MODPLUG_EXPORT ModPlugNote* ModPlug_GetPattern(ModPlugFile* file, int pattern, unsigned int* numrows);
|
||||
|
||||
/*
|
||||
* =================
|
||||
* Mixer callback
|
||||
* =================
|
||||
*
|
||||
* Use this callback if you want to 'modify' the mixed data of LibModPlug.
|
||||
*
|
||||
* void proc(int* buffer,unsigned long channels,unsigned long nsamples) ;
|
||||
*
|
||||
* 'buffer': A buffer of mixed samples
|
||||
* 'channels': N. of channels in the buffer
|
||||
* 'nsamples': N. of samples in the buffeer (without taking care of n.channels)
|
||||
*
|
||||
* (Samples are signed 32-bit integers)
|
||||
*/
|
||||
MODPLUG_EXPORT void ModPlug_InitMixerCallback(ModPlugFile* file,ModPlugMixerProc proc) ;
|
||||
MODPLUG_EXPORT void ModPlug_UnloadMixerCallback(ModPlugFile* file) ;
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* This source code is public domain.
|
||||
*
|
||||
* Authors: Rani Assaf <rani@magic.metawire.com>,
|
||||
* Olivier Lapicque <olivierl@jps.net>,
|
||||
* Adam Goode <adam@evdebs.org> (endian and char fixes for PPC)
|
||||
*/
|
||||
|
||||
#ifndef MODPLUG_STDAFX_H
|
||||
#define MODPLUG_STDAFX_H
|
||||
|
||||
/* Autoconf detection of stdint/inttypes */
|
||||
#if defined(HAVE_CONFIG_H) && !defined(CONFIG_H_INCLUDED)
|
||||
# include "config.h"
|
||||
# define CONFIG_H_INCLUDED 1
|
||||
#endif
|
||||
#ifdef HAVE_INTTYPES_H
|
||||
# include <inttypes.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDINT_H
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#ifdef MSC_VER
|
||||
#pragma warning (disable:4201)
|
||||
#pragma warning (disable:4514)
|
||||
#endif
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
#include <mmsystem.h>
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define srandom(_seed) srand(_seed)
|
||||
#define random() rand()
|
||||
#define sleep(_ms) Sleep(_ms)
|
||||
|
||||
inline void ProcessPlugins(int n) {}
|
||||
|
||||
#define strncasecmp(a,b,c) strncmp(a,b,c)
|
||||
#define strcasecmp(a,b) strcmp(a,b)
|
||||
#define strnicmp(a,b,c) strncasecmp(a,b,c)
|
||||
#define HAVE_SINF 1
|
||||
|
||||
#ifndef isblank
|
||||
#define isblank(c) ((c) == ' ' || (c) == '\t')
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#ifdef HAVE_MALLOC_H
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
typedef int8_t CHAR;
|
||||
typedef uint8_t UCHAR;
|
||||
typedef uint8_t* PUCHAR;
|
||||
typedef uint16_t USHORT;
|
||||
typedef uint32_t ULONG;
|
||||
typedef uint32_t UINT;
|
||||
typedef uint32_t DWORD;
|
||||
typedef int32_t LONG;
|
||||
typedef int64_t LONGLONG;
|
||||
typedef int32_t* LPLONG;
|
||||
typedef uint32_t* LPDWORD;
|
||||
typedef uint16_t WORD;
|
||||
typedef uint8_t BYTE;
|
||||
typedef uint8_t* LPBYTE;
|
||||
typedef bool BOOL;
|
||||
typedef char* LPSTR;
|
||||
typedef void* LPVOID;
|
||||
typedef uint16_t* LPWORD;
|
||||
typedef const char* LPCSTR;
|
||||
typedef void* PVOID;
|
||||
typedef void VOID;
|
||||
|
||||
inline LONG MulDiv (long a, long b, long c)
|
||||
{
|
||||
// if (!c) return 0;
|
||||
return ((uint64_t) a * (uint64_t) b ) / c;
|
||||
}
|
||||
|
||||
#define MODPLUG_NO_FILESAVE
|
||||
#define NO_AGC
|
||||
#define LPCTSTR LPCSTR
|
||||
#define lstrcpyn strncpy
|
||||
#define lstrcpy strcpy
|
||||
#define lstrcmp strcmp
|
||||
#define WAVE_FORMAT_PCM 1
|
||||
//#define ENABLE_EQ
|
||||
|
||||
#define GHND 0
|
||||
|
||||
inline int8_t * GlobalAllocPtr(unsigned int, size_t size)
|
||||
{
|
||||
int8_t * p = (int8_t *) malloc(size);
|
||||
|
||||
if (p != NULL) memset(p, 0, size);
|
||||
return p;
|
||||
}
|
||||
|
||||
inline void ProcessPlugins(int /* n */ ) {}
|
||||
|
||||
#define GlobalFreePtr(p) free((void *)(p))
|
||||
|
||||
#define strnicmp(a,b,c) strncasecmp(a,b,c)
|
||||
#define wsprintf sprintf
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE false
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE true
|
||||
#endif
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
# if defined(MODPLUG_BUILD) && defined(DLL_EXPORT) /* building libmodplug as a dll for windows */
|
||||
# define MODPLUG_EXPORT __declspec(dllexport)
|
||||
# elif defined(MODPLUG_BUILD) || defined(MODPLUG_STATIC) /* building or using static libmodplug for windows */
|
||||
# define MODPLUG_EXPORT
|
||||
# else
|
||||
# define MODPLUG_EXPORT __declspec(dllimport) /* using libmodplug dll for windows */
|
||||
# endif
|
||||
/* FIXME: USE VISIBILITY ATTRIBUTES HERE */
|
||||
#elif defined(MODPLUG_BUILD)
|
||||
#define MODPLUG_EXPORT
|
||||
#else
|
||||
#define MODPLUG_EXPORT
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,604 @@
|
|||
/*
|
||||
* libopenmpt_modplug.c
|
||||
* --------------------
|
||||
* Purpose: libopenmpt emulation of the libmodplug interface
|
||||
* Notes : (currently none)
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
#ifndef NO_LIBMODPLUG
|
||||
|
||||
#ifdef LIBOPENMPT_BUILD_DLL
|
||||
#undef LIBOPENMPT_BUILD_DLL
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#include <libopenmpt/libopenmpt.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <memory.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define MODPLUG_BUILD
|
||||
#ifdef _MSC_VER
|
||||
#ifdef MPT_BUILD_MSVC_SHARED
|
||||
#define DLL_EXPORT
|
||||
#endif /* MPT_BUILD_MSVC_SHARED */
|
||||
#ifdef MPT_BUILD_MSVC_STATIC
|
||||
#define MODPLUG_STATIC
|
||||
#endif /* MPT_BUILD_MSVC_STATIC */
|
||||
#endif /* _MSC_VER */
|
||||
#ifdef _MSC_VER
|
||||
#define LIBOPENMPT_MODPLUG_API
|
||||
#else /* !_MSC_VER */
|
||||
#define LIBOPENMPT_MODPLUG_API LIBOPENMPT_API_HELPER_EXPORT
|
||||
#endif /* _MSC_VER */
|
||||
#include "libmodplug/modplug.h"
|
||||
|
||||
/* from libmodplug/sndfile.h */
|
||||
/* header is not c clean */
|
||||
#define MIXING_ATTENUATION 4
|
||||
#define MOD_TYPE_NONE 0x0
|
||||
#define MOD_TYPE_MOD 0x1
|
||||
#define MOD_TYPE_S3M 0x2
|
||||
#define MOD_TYPE_XM 0x4
|
||||
#define MOD_TYPE_MED 0x8
|
||||
#define MOD_TYPE_MTM 0x10
|
||||
#define MOD_TYPE_IT 0x20
|
||||
#define MOD_TYPE_669 0x40
|
||||
#define MOD_TYPE_ULT 0x80
|
||||
#define MOD_TYPE_STM 0x100
|
||||
#define MOD_TYPE_FAR 0x200
|
||||
#define MOD_TYPE_WAV 0x400
|
||||
#define MOD_TYPE_AMF 0x800
|
||||
#define MOD_TYPE_AMS 0x1000
|
||||
#define MOD_TYPE_DSM 0x2000
|
||||
#define MOD_TYPE_MDL 0x4000
|
||||
#define MOD_TYPE_OKT 0x8000
|
||||
#define MOD_TYPE_MID 0x10000
|
||||
#define MOD_TYPE_DMF 0x20000
|
||||
#define MOD_TYPE_PTM 0x40000
|
||||
#define MOD_TYPE_DBM 0x80000
|
||||
#define MOD_TYPE_MT2 0x100000
|
||||
#define MOD_TYPE_AMF0 0x200000
|
||||
#define MOD_TYPE_PSM 0x400000
|
||||
#define MOD_TYPE_J2B 0x800000
|
||||
#define MOD_TYPE_ABC 0x1000000
|
||||
#define MOD_TYPE_PAT 0x2000000
|
||||
#define MOD_TYPE_UMX 0x80000000 // Fake type
|
||||
|
||||
#define BUFFER_COUNT 1024
|
||||
|
||||
struct _ModPlugFile {
|
||||
openmpt_module* mod;
|
||||
signed short* buf;
|
||||
signed int* mixerbuf;
|
||||
char* name;
|
||||
char* message;
|
||||
ModPlug_Settings settings;
|
||||
ModPlugMixerProc mixerproc;
|
||||
ModPlugNote** patterns;
|
||||
};
|
||||
|
||||
static ModPlug_Settings globalsettings = {
|
||||
MODPLUG_ENABLE_OVERSAMPLING|MODPLUG_ENABLE_NOISE_REDUCTION,
|
||||
2,
|
||||
16,
|
||||
44100,
|
||||
MODPLUG_RESAMPLE_LINEAR,
|
||||
128,
|
||||
256,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
static int32_t modplugresamplingmode_to_filterlength(int mode)
|
||||
{
|
||||
if(mode<0){
|
||||
return 1;
|
||||
}
|
||||
switch(mode){
|
||||
case MODPLUG_RESAMPLE_NEAREST: return 1; break;
|
||||
case MODPLUG_RESAMPLE_LINEAR: return 2; break;
|
||||
case MODPLUG_RESAMPLE_SPLINE: return 4; break;
|
||||
case MODPLUG_RESAMPLE_FIR: return 8; break;
|
||||
}
|
||||
return 8;
|
||||
}
|
||||
|
||||
LIBOPENMPT_MODPLUG_API ModPlugFile* ModPlug_Load(const void* data, int size)
|
||||
{
|
||||
ModPlugFile* file = malloc(sizeof(ModPlugFile));
|
||||
const char* name = NULL;
|
||||
const char* message = NULL;
|
||||
if(!file) return NULL;
|
||||
memset(file,0,sizeof(ModPlugFile));
|
||||
memcpy(&file->settings,&globalsettings,sizeof(ModPlug_Settings));
|
||||
file->mod = openmpt_module_create_from_memory2(data,size,NULL,NULL,NULL,NULL,NULL,NULL,NULL);
|
||||
if(!file->mod){
|
||||
free(file);
|
||||
return NULL;
|
||||
}
|
||||
file->buf = malloc(BUFFER_COUNT*sizeof(signed short)*4);
|
||||
if(!file->buf){
|
||||
openmpt_module_destroy(file->mod);
|
||||
free(file);
|
||||
return NULL;
|
||||
}
|
||||
openmpt_module_set_repeat_count(file->mod,file->settings.mLoopCount);
|
||||
name = openmpt_module_get_metadata(file->mod,"title");
|
||||
if(name){
|
||||
file->name = malloc(strlen(name)+1);
|
||||
if(file->name){
|
||||
strcpy(file->name,name);
|
||||
}
|
||||
openmpt_free_string(name);
|
||||
name = NULL;
|
||||
}else{
|
||||
file->name = malloc(strlen("")+1);
|
||||
if(file->name){
|
||||
strcpy(file->name,"");
|
||||
}
|
||||
}
|
||||
message = openmpt_module_get_metadata(file->mod,"message");
|
||||
if(message){
|
||||
file->message = malloc(strlen(message)+1);
|
||||
if(file->message){
|
||||
strcpy(file->message,message);
|
||||
}
|
||||
openmpt_free_string(message);
|
||||
message = NULL;
|
||||
}else{
|
||||
file->message = malloc(strlen("")+1);
|
||||
if(file->message){
|
||||
strcpy(file->message,"");
|
||||
}
|
||||
}
|
||||
openmpt_module_set_render_param(file->mod,OPENMPT_MODULE_RENDER_STEREOSEPARATION_PERCENT,file->settings.mStereoSeparation*100/128);
|
||||
openmpt_module_set_render_param(file->mod,OPENMPT_MODULE_RENDER_INTERPOLATIONFILTER_LENGTH,modplugresamplingmode_to_filterlength(file->settings.mResamplingMode));
|
||||
return file;
|
||||
}
|
||||
|
||||
LIBOPENMPT_MODPLUG_API void ModPlug_Unload(ModPlugFile* file)
|
||||
{
|
||||
int p;
|
||||
if(!file) return;
|
||||
if(file->patterns){
|
||||
for(p=0;p<openmpt_module_get_num_patterns(file->mod);p++){
|
||||
if(file->patterns[p]){
|
||||
free(file->patterns[p]);
|
||||
file->patterns[p] = NULL;
|
||||
}
|
||||
}
|
||||
free(file->patterns);
|
||||
file->patterns = NULL;
|
||||
}
|
||||
if(file->mixerbuf){
|
||||
free(file->mixerbuf);
|
||||
file->mixerbuf = NULL;
|
||||
}
|
||||
openmpt_module_destroy(file->mod);
|
||||
file->mod = NULL;
|
||||
free(file->name);
|
||||
file->name = NULL;
|
||||
free(file->message);
|
||||
file->message = NULL;
|
||||
free(file->buf);
|
||||
file->buf = NULL;
|
||||
free(file);
|
||||
}
|
||||
|
||||
LIBOPENMPT_MODPLUG_API int ModPlug_Read(ModPlugFile* file, void* buffer, int size)
|
||||
{
|
||||
int framesize;
|
||||
int framecount;
|
||||
int frames;
|
||||
int rendered;
|
||||
int frame;
|
||||
int channel;
|
||||
int totalrendered;
|
||||
signed short* in;
|
||||
signed int* mixbuf;
|
||||
unsigned char* buf8;
|
||||
signed short* buf16;
|
||||
signed int* buf32;
|
||||
if(!file) return 0;
|
||||
framesize = file->settings.mBits/8*file->settings.mChannels;
|
||||
framecount = size/framesize;
|
||||
buf8 = buffer;
|
||||
buf16 = buffer;
|
||||
buf32 = buffer;
|
||||
totalrendered = 0;
|
||||
while(framecount>0){
|
||||
frames = framecount;
|
||||
if(frames>BUFFER_COUNT){
|
||||
frames = BUFFER_COUNT;
|
||||
}
|
||||
if(file->settings.mChannels==1){
|
||||
rendered = (int)openmpt_module_read_mono(file->mod,file->settings.mFrequency,frames,&file->buf[frames*0]);
|
||||
}else if(file->settings.mChannels==2){
|
||||
rendered = (int)openmpt_module_read_stereo(file->mod,file->settings.mFrequency,frames,&file->buf[frames*0],&file->buf[frames*1]);
|
||||
}else if(file->settings.mChannels==4){
|
||||
rendered = (int)openmpt_module_read_quad(file->mod,file->settings.mFrequency,frames,&file->buf[frames*0],&file->buf[frames*1],&file->buf[frames*2],&file->buf[frames*3]);
|
||||
}else{
|
||||
return 0;
|
||||
}
|
||||
in = file->buf;
|
||||
if(file->mixerproc&&file->mixerbuf){
|
||||
mixbuf=file->mixerbuf;
|
||||
for(frame=0;frame<frames;frame++){
|
||||
for(channel=0;channel<file->settings.mChannels;channel++){
|
||||
*mixbuf = in[frames*channel+frame]<<(32-16-1-MIXING_ATTENUATION);
|
||||
mixbuf++;
|
||||
}
|
||||
}
|
||||
file->mixerproc(file->mixerbuf,file->settings.mChannels*frames,file->settings.mChannels);
|
||||
mixbuf=file->mixerbuf;
|
||||
for(frame=0;frame<frames;frame++){
|
||||
for(channel=0;channel<file->settings.mChannels;channel++){
|
||||
in[frames*channel+frame] = *mixbuf>>(32-16-1-MIXING_ATTENUATION);
|
||||
mixbuf++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(file->settings.mBits==8){
|
||||
for(frame=0;frame<frames;frame++){
|
||||
for(channel=0;channel<file->settings.mChannels;channel++){
|
||||
*buf8 = in[frames*channel+frame]/256+0x80;
|
||||
buf8++;
|
||||
}
|
||||
}
|
||||
}else if(file->settings.mBits==16){
|
||||
for(frame=0;frame<frames;frame++){
|
||||
for(channel=0;channel<file->settings.mChannels;channel++){
|
||||
*buf16 = in[frames*channel+frame];
|
||||
buf16++;
|
||||
}
|
||||
}
|
||||
}else if(file->settings.mBits==32){
|
||||
for(frame=0;frame<frames;frame++){
|
||||
for(channel=0;channel<file->settings.mChannels;channel++){
|
||||
*buf32 = in[frames*channel+frame] << (32-16-1-MIXING_ATTENUATION);
|
||||
buf32++;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
return 0;
|
||||
}
|
||||
totalrendered += rendered;
|
||||
framecount -= frames;
|
||||
if(!rendered) break;
|
||||
}
|
||||
memset(((char*)buffer)+totalrendered*framesize,0,size-totalrendered*framesize);
|
||||
return totalrendered*framesize;
|
||||
}
|
||||
|
||||
LIBOPENMPT_MODPLUG_API const char* ModPlug_GetName(ModPlugFile* file)
|
||||
{
|
||||
if(!file) return NULL;
|
||||
return file->name;
|
||||
}
|
||||
|
||||
LIBOPENMPT_MODPLUG_API int ModPlug_GetLength(ModPlugFile* file)
|
||||
{
|
||||
if(!file) return 0;
|
||||
return (int)(openmpt_module_get_duration_seconds(file->mod)*1000.0);
|
||||
}
|
||||
|
||||
LIBOPENMPT_MODPLUG_API void ModPlug_Seek(ModPlugFile* file, int millisecond)
|
||||
{
|
||||
if(!file) return;
|
||||
openmpt_module_set_position_seconds(file->mod,(double)millisecond*0.001);
|
||||
}
|
||||
|
||||
LIBOPENMPT_MODPLUG_API void ModPlug_GetSettings(ModPlug_Settings* settings)
|
||||
{
|
||||
if(!settings) return;
|
||||
memcpy(settings,&globalsettings,sizeof(ModPlug_Settings));
|
||||
}
|
||||
|
||||
LIBOPENMPT_MODPLUG_API void ModPlug_SetSettings(const ModPlug_Settings* settings)
|
||||
{
|
||||
if(!settings) return;
|
||||
memcpy(&globalsettings,settings,sizeof(ModPlug_Settings));
|
||||
}
|
||||
|
||||
LIBOPENMPT_MODPLUG_API unsigned int ModPlug_GetMasterVolume(ModPlugFile* file)
|
||||
{
|
||||
int32_t val;
|
||||
if(!file) return 0;
|
||||
val = 0;
|
||||
if(!openmpt_module_get_render_param(file->mod,OPENMPT_MODULE_RENDER_MASTERGAIN_MILLIBEL,&val)) return 128;
|
||||
return (unsigned int)(128.0*pow(10.0,val*0.0005));
|
||||
}
|
||||
|
||||
LIBOPENMPT_MODPLUG_API void ModPlug_SetMasterVolume(ModPlugFile* file,unsigned int cvol)
|
||||
{
|
||||
if(!file) return;
|
||||
openmpt_module_set_render_param(file->mod,OPENMPT_MODULE_RENDER_MASTERGAIN_MILLIBEL,(int32_t)(2000.0*log10(cvol/128.0)));
|
||||
}
|
||||
|
||||
LIBOPENMPT_MODPLUG_API int ModPlug_GetCurrentSpeed(ModPlugFile* file)
|
||||
{
|
||||
if(!file) return 0;
|
||||
return openmpt_module_get_current_speed(file->mod);
|
||||
}
|
||||
|
||||
LIBOPENMPT_MODPLUG_API int ModPlug_GetCurrentTempo(ModPlugFile* file)
|
||||
{
|
||||
if(!file) return 0;
|
||||
return openmpt_module_get_current_tempo(file->mod);
|
||||
}
|
||||
|
||||
LIBOPENMPT_MODPLUG_API int ModPlug_GetCurrentOrder(ModPlugFile* file)
|
||||
{
|
||||
if(!file) return 0;
|
||||
return openmpt_module_get_current_order(file->mod);
|
||||
}
|
||||
|
||||
LIBOPENMPT_MODPLUG_API int ModPlug_GetCurrentPattern(ModPlugFile* file)
|
||||
{
|
||||
if(!file) return 0;
|
||||
return openmpt_module_get_current_pattern(file->mod);
|
||||
}
|
||||
|
||||
LIBOPENMPT_MODPLUG_API int ModPlug_GetCurrentRow(ModPlugFile* file)
|
||||
{
|
||||
if(!file) return 0;
|
||||
return openmpt_module_get_current_row(file->mod);
|
||||
}
|
||||
|
||||
LIBOPENMPT_MODPLUG_API int ModPlug_GetPlayingChannels(ModPlugFile* file)
|
||||
{
|
||||
if(!file) return 0;
|
||||
return openmpt_module_get_current_playing_channels(file->mod);
|
||||
}
|
||||
|
||||
LIBOPENMPT_MODPLUG_API void ModPlug_SeekOrder(ModPlugFile* file,int order)
|
||||
{
|
||||
if(!file) return;
|
||||
openmpt_module_set_position_order_row(file->mod,order,0);
|
||||
}
|
||||
|
||||
LIBOPENMPT_MODPLUG_API int ModPlug_GetModuleType(ModPlugFile* file)
|
||||
{
|
||||
const char* type;
|
||||
int retval;
|
||||
if(!file) return 0;
|
||||
type = openmpt_module_get_metadata(file->mod,"type");
|
||||
retval = MOD_TYPE_NONE;
|
||||
if(!type){
|
||||
return retval;
|
||||
}
|
||||
if(!strcmp(type,"mod")){
|
||||
retval = MOD_TYPE_MOD;
|
||||
}else if(!strcmp(type,"s3m")){
|
||||
retval = MOD_TYPE_S3M;
|
||||
}else if(!strcmp(type,"xm")){
|
||||
retval = MOD_TYPE_XM;
|
||||
}else if(!strcmp(type,"med")){
|
||||
retval = MOD_TYPE_MED;
|
||||
}else if(!strcmp(type,"mtm")){
|
||||
retval = MOD_TYPE_MTM;
|
||||
}else if(!strcmp(type,"it")){
|
||||
retval = MOD_TYPE_IT;
|
||||
}else if(!strcmp(type,"669")){
|
||||
retval = MOD_TYPE_669;
|
||||
}else if(!strcmp(type,"ult")){
|
||||
retval = MOD_TYPE_ULT;
|
||||
}else if(!strcmp(type,"stm")){
|
||||
retval = MOD_TYPE_STM;
|
||||
}else if(!strcmp(type,"far")){
|
||||
retval = MOD_TYPE_FAR;
|
||||
}else if(!strcmp(type,"s3m")){
|
||||
retval = MOD_TYPE_WAV;
|
||||
}else if(!strcmp(type,"amf")){
|
||||
retval = MOD_TYPE_AMF;
|
||||
}else if(!strcmp(type,"ams")){
|
||||
retval = MOD_TYPE_AMS;
|
||||
}else if(!strcmp(type,"dsm")){
|
||||
retval = MOD_TYPE_DSM;
|
||||
}else if(!strcmp(type,"mdl")){
|
||||
retval = MOD_TYPE_MDL;
|
||||
}else if(!strcmp(type,"okt")){
|
||||
retval = MOD_TYPE_OKT;
|
||||
}else if(!strcmp(type,"mid")){
|
||||
retval = MOD_TYPE_MID;
|
||||
}else if(!strcmp(type,"dmf")){
|
||||
retval = MOD_TYPE_DMF;
|
||||
}else if(!strcmp(type,"ptm")){
|
||||
retval = MOD_TYPE_PTM;
|
||||
}else if(!strcmp(type,"dbm")){
|
||||
retval = MOD_TYPE_DBM;
|
||||
}else if(!strcmp(type,"mt2")){
|
||||
retval = MOD_TYPE_MT2;
|
||||
}else if(!strcmp(type,"amf0")){
|
||||
retval = MOD_TYPE_AMF0;
|
||||
}else if(!strcmp(type,"psm")){
|
||||
retval = MOD_TYPE_PSM;
|
||||
}else if(!strcmp(type,"j2b")){
|
||||
retval = MOD_TYPE_J2B;
|
||||
}else if(!strcmp(type,"abc")){
|
||||
retval = MOD_TYPE_ABC;
|
||||
}else if(!strcmp(type,"pat")){
|
||||
retval = MOD_TYPE_PAT;
|
||||
}else if(!strcmp(type,"umx")){
|
||||
retval = MOD_TYPE_UMX;
|
||||
}else{
|
||||
retval = MOD_TYPE_IT; /* fallback, most complex type */
|
||||
}
|
||||
openmpt_free_string(type);
|
||||
return retval;
|
||||
}
|
||||
|
||||
LIBOPENMPT_MODPLUG_API char* ModPlug_GetMessage(ModPlugFile* file)
|
||||
{
|
||||
if(!file) return NULL;
|
||||
return file->message;
|
||||
}
|
||||
|
||||
LIBOPENMPT_MODPLUG_API unsigned int ModPlug_NumInstruments(ModPlugFile* file)
|
||||
{
|
||||
if(!file) return 0;
|
||||
return openmpt_module_get_num_instruments(file->mod);
|
||||
}
|
||||
|
||||
LIBOPENMPT_MODPLUG_API unsigned int ModPlug_NumSamples(ModPlugFile* file)
|
||||
{
|
||||
if(!file) return 0;
|
||||
return openmpt_module_get_num_samples(file->mod);
|
||||
}
|
||||
|
||||
LIBOPENMPT_MODPLUG_API unsigned int ModPlug_NumPatterns(ModPlugFile* file)
|
||||
{
|
||||
if(!file) return 0;
|
||||
return openmpt_module_get_num_patterns(file->mod);
|
||||
}
|
||||
|
||||
LIBOPENMPT_MODPLUG_API unsigned int ModPlug_NumChannels(ModPlugFile* file)
|
||||
{
|
||||
if(!file) return 0;
|
||||
return openmpt_module_get_num_channels(file->mod);
|
||||
}
|
||||
|
||||
LIBOPENMPT_MODPLUG_API unsigned int ModPlug_SampleName(ModPlugFile* file, unsigned int qual, char* buff)
|
||||
{
|
||||
const char* str;
|
||||
char buf[32];
|
||||
if(!file) return 0;
|
||||
str = openmpt_module_get_sample_name(file->mod,qual-1);
|
||||
memset(buf,0,32);
|
||||
if(str){
|
||||
strncpy(buf,str,31);
|
||||
openmpt_free_string(str);
|
||||
}
|
||||
if(buff){
|
||||
strncpy(buff,buf,32);
|
||||
}
|
||||
return (unsigned int)strlen(buf);
|
||||
}
|
||||
|
||||
LIBOPENMPT_MODPLUG_API unsigned int ModPlug_InstrumentName(ModPlugFile* file, unsigned int qual, char* buff)
|
||||
{
|
||||
const char* str;
|
||||
char buf[32];
|
||||
if(!file) return 0;
|
||||
str = openmpt_module_get_instrument_name(file->mod,qual-1);
|
||||
memset(buf,0,32);
|
||||
if(str){
|
||||
strncpy(buf,str,31);
|
||||
openmpt_free_string(str);
|
||||
}
|
||||
if(buff){
|
||||
strncpy(buff,buf,32);
|
||||
}
|
||||
return (unsigned int)strlen(buf);
|
||||
}
|
||||
|
||||
LIBOPENMPT_MODPLUG_API ModPlugNote* ModPlug_GetPattern(ModPlugFile* file, int pattern, unsigned int* numrows)
|
||||
{
|
||||
int c;
|
||||
int r;
|
||||
int numr;
|
||||
int numc;
|
||||
ModPlugNote note;
|
||||
if(!file) return NULL;
|
||||
if(numrows){
|
||||
*numrows = openmpt_module_get_pattern_num_rows(file->mod,pattern);
|
||||
}
|
||||
if(pattern<0||pattern>=openmpt_module_get_num_patterns(file->mod)){
|
||||
return NULL;
|
||||
}
|
||||
if(!file->patterns){
|
||||
file->patterns = malloc(sizeof(ModPlugNote*)*openmpt_module_get_pattern_num_rows(file->mod,pattern));
|
||||
if(!file->patterns) return NULL;
|
||||
memset(file->patterns,0,sizeof(ModPlugNote*)*openmpt_module_get_pattern_num_rows(file->mod,pattern));
|
||||
}
|
||||
if(!file->patterns[pattern]){
|
||||
file->patterns[pattern] = malloc(sizeof(ModPlugNote)*openmpt_module_get_pattern_num_rows(file->mod,pattern)*openmpt_module_get_num_channels(file->mod));
|
||||
if(!file->patterns[pattern]) return NULL;
|
||||
memset(file->patterns[pattern],0,sizeof(ModPlugNote)*openmpt_module_get_pattern_num_rows(file->mod,pattern)*openmpt_module_get_num_channels(file->mod));
|
||||
}
|
||||
numr = openmpt_module_get_pattern_num_rows(file->mod,pattern);
|
||||
numc = openmpt_module_get_num_channels(file->mod);
|
||||
for(r=0;r<numr;r++){
|
||||
for(c=0;c<numc;c++){
|
||||
memset(¬e,0,sizeof(ModPlugNote));
|
||||
note.Note = openmpt_module_get_pattern_row_channel_command(file->mod,pattern,r,c,OPENMPT_MODULE_COMMAND_NOTE);
|
||||
note.Instrument = openmpt_module_get_pattern_row_channel_command(file->mod,pattern,r,c,OPENMPT_MODULE_COMMAND_INSTRUMENT);
|
||||
note.VolumeEffect = openmpt_module_get_pattern_row_channel_command(file->mod,pattern,r,c,OPENMPT_MODULE_COMMAND_VOLUMEEFFECT);
|
||||
note.Effect = openmpt_module_get_pattern_row_channel_command(file->mod,pattern,r,c,OPENMPT_MODULE_COMMAND_EFFECT);
|
||||
note.Volume = openmpt_module_get_pattern_row_channel_command(file->mod,pattern,r,c,OPENMPT_MODULE_COMMAND_VOLUME);
|
||||
note.Parameter = openmpt_module_get_pattern_row_channel_command(file->mod,pattern,r,c,OPENMPT_MODULE_COMMAND_PARAMETER);
|
||||
memcpy(&file->patterns[pattern][r*numc+c],¬e,sizeof(ModPlugNote));
|
||||
}
|
||||
}
|
||||
return file->patterns[pattern];
|
||||
}
|
||||
|
||||
LIBOPENMPT_MODPLUG_API void ModPlug_InitMixerCallback(ModPlugFile* file,ModPlugMixerProc proc)
|
||||
{
|
||||
if(!file) return;
|
||||
if(!file->mixerbuf){
|
||||
file->mixerbuf = malloc(BUFFER_COUNT*sizeof(signed int)*4);
|
||||
}
|
||||
file->mixerproc = proc;
|
||||
}
|
||||
|
||||
LIBOPENMPT_MODPLUG_API void ModPlug_UnloadMixerCallback(ModPlugFile* file)
|
||||
{
|
||||
if(!file) return;
|
||||
file->mixerproc = NULL;
|
||||
if(file->mixerbuf){
|
||||
free(file->mixerbuf);
|
||||
file->mixerbuf = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
LIBOPENMPT_MODPLUG_API char ModPlug_ExportS3M(ModPlugFile* file, const char* filepath)
|
||||
{
|
||||
(void)file;
|
||||
/* not implemented */
|
||||
fprintf(stderr,"libopenmpt-modplug: error: ModPlug_ExportS3M(%s) not implemented.\n",filepath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LIBOPENMPT_MODPLUG_API char ModPlug_ExportXM(ModPlugFile* file, const char* filepath)
|
||||
{
|
||||
(void)file;
|
||||
/* not implemented */
|
||||
fprintf(stderr,"libopenmpt-modplug: error: ModPlug_ExportXM(%s) not implemented.\n",filepath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LIBOPENMPT_MODPLUG_API char ModPlug_ExportMOD(ModPlugFile* file, const char* filepath)
|
||||
{
|
||||
(void)file;
|
||||
/* not implemented */
|
||||
fprintf(stderr,"libopenmpt-modplug: error: ModPlug_ExportMOD(%s) not implemented.\n",filepath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LIBOPENMPT_MODPLUG_API char ModPlug_ExportIT(ModPlugFile* file, const char* filepath)
|
||||
{
|
||||
(void)file;
|
||||
/* not implemented */
|
||||
fprintf(stderr,"libopenmpt-modplug: error: ModPlug_ExportIT(%s) not implemented.\n",filepath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* NO_LIBMODPLUG */
|
|
@ -0,0 +1,12 @@
|
|||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=${prefix}/include
|
||||
|
||||
Name: libopenmpt_modplug
|
||||
Description: The ModPlug mod file playing library (emulated via libopenmpt).
|
||||
Version: @PACKAGE_VERSION@
|
||||
Requires.private: libopenmpt
|
||||
Libs: -L${libdir} -lopenmpt_modplug
|
||||
Libs.private:
|
||||
Cflags: -I${includedir}
|
|
@ -0,0 +1,887 @@
|
|||
/*
|
||||
* libopenmpt_modplug_cpp.cpp
|
||||
* --------------------------
|
||||
* Purpose: libopenmpt emulation of the libmodplug c++ interface
|
||||
* Notes : WARNING! THIS IS A HACK!
|
||||
* Authors: OpenMPT Devs
|
||||
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
||||
*/
|
||||
|
||||
#ifndef NO_LIBMODPLUG
|
||||
|
||||
/*
|
||||
|
||||
***********************************************************************
|
||||
WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
|
||||
***********************************************************************
|
||||
|
||||
This is a dirty hack to emulate just so much of the libmodplug c++
|
||||
interface so that the current known users (mainly xmms-modplug itself,
|
||||
gstreamer modplug, audacious, and stuff based on those) work. This is
|
||||
neither a complete nor a correct implementation.
|
||||
Metadata and other state is not provided or updated.
|
||||
|
||||
*/
|
||||
|
||||
#ifdef UNICODE
|
||||
#undef UNICODE
|
||||
#endif
|
||||
#ifdef _UNICODE
|
||||
#undef _UNICODE
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#include <libopenmpt/libopenmpt.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#define MODPLUG_BUILD
|
||||
#ifdef _MSC_VER
|
||||
/* libmodplug C++ header is broken for MSVC DLL builds */
|
||||
#define MODPLUG_STATIC
|
||||
#endif /* _MSC_VER */
|
||||
#ifdef _MSC_VER
|
||||
#define LIBOPENMPT_MODPLUG_API
|
||||
#else /* !_MSC_VER */
|
||||
#define LIBOPENMPT_MODPLUG_API LIBOPENMPT_API_HELPER_EXPORT
|
||||
#endif /* _MSC_VER */
|
||||
class LIBOPENMPT_MODPLUG_API CSoundFile;
|
||||
#include "libmodplug/stdafx.h"
|
||||
#include "libmodplug/sndfile.h"
|
||||
|
||||
namespace {
|
||||
template <class T>
|
||||
void Clear( T & x )
|
||||
{
|
||||
std::memset( &x, 0, sizeof(T) );
|
||||
}
|
||||
}
|
||||
|
||||
//#define mpcpplog() fprintf(stderr, "%s %i\n", __func__, __LINE__)
|
||||
#define mpcpplog() do{}while(0)
|
||||
|
||||
#define UNUSED(x) (void)((x))
|
||||
|
||||
union self_t {
|
||||
CHAR CompressionTable[16];
|
||||
openmpt::module * self_;
|
||||
};
|
||||
|
||||
static void set_self( CSoundFile * that, openmpt::module * self_ ) {
|
||||
self_t self_union;
|
||||
Clear(self_union);
|
||||
self_union.self_ = self_;
|
||||
std::memcpy( that->CompressionTable, self_union.CompressionTable, sizeof( self_union.CompressionTable ) );
|
||||
}
|
||||
|
||||
static openmpt::module * get_self( const CSoundFile * that ) {
|
||||
self_t self_union;
|
||||
Clear(self_union);
|
||||
std::memcpy( self_union.CompressionTable, that->CompressionTable, sizeof( self_union.CompressionTable ) );
|
||||
return self_union.self_;
|
||||
}
|
||||
|
||||
#define mod ( get_self( this ) )
|
||||
|
||||
#define update_state() \
|
||||
if ( mod ) m_nCurrentPattern = mod->get_current_order(); \
|
||||
if ( mod ) m_nPattern = mod->get_current_pattern(); \
|
||||
if ( mod ) m_nMusicSpeed = mod->get_current_speed(); \
|
||||
if ( mod ) m_nMusicTempo = mod->get_current_tempo(); \
|
||||
/**/
|
||||
|
||||
UINT CSoundFile::m_nXBassDepth = 0;
|
||||
UINT CSoundFile::m_nXBassRange = 0;
|
||||
UINT CSoundFile::m_nReverbDepth = 0;
|
||||
UINT CSoundFile::m_nReverbDelay = 0;
|
||||
UINT CSoundFile::gnReverbType = 0;
|
||||
UINT CSoundFile::m_nProLogicDepth = 0;
|
||||
UINT CSoundFile::m_nProLogicDelay = 0;
|
||||
UINT CSoundFile::m_nStereoSeparation = 128;
|
||||
UINT CSoundFile::m_nMaxMixChannels = 256;
|
||||
LONG CSoundFile::m_nStreamVolume = 0x8000;
|
||||
DWORD CSoundFile::gdwSysInfo = 0;
|
||||
DWORD CSoundFile::gdwSoundSetup = 0;
|
||||
DWORD CSoundFile::gdwMixingFreq = 44100;
|
||||
DWORD CSoundFile::gnBitsPerSample = 16;
|
||||
DWORD CSoundFile::gnChannels = 2;
|
||||
UINT CSoundFile::gnAGC = 0;
|
||||
UINT CSoundFile::gnVolumeRampSamples = 0;
|
||||
UINT CSoundFile::gnVUMeter = 0;
|
||||
UINT CSoundFile::gnCPUUsage = 0;
|
||||
LPSNDMIXHOOKPROC CSoundFile::gpSndMixHook = 0;
|
||||
PMIXPLUGINCREATEPROC CSoundFile::gpMixPluginCreateProc = 0;
|
||||
|
||||
CSoundFile::CSoundFile() {
|
||||
mpcpplog();
|
||||
Clear(Chn);
|
||||
Clear(ChnMix);
|
||||
Clear(Ins);
|
||||
Clear(Headers);
|
||||
Clear(ChnSettings);
|
||||
Clear(Patterns);
|
||||
Clear(PatternSize);
|
||||
Clear(Order);
|
||||
Clear(m_MidiCfg);
|
||||
Clear(m_MixPlugins);
|
||||
Clear(m_nDefaultSpeed);
|
||||
Clear(m_nDefaultTempo);
|
||||
Clear(m_nDefaultGlobalVolume);
|
||||
Clear(m_dwSongFlags);
|
||||
Clear(m_nChannels);
|
||||
Clear(m_nMixChannels);
|
||||
Clear(m_nMixStat);
|
||||
Clear(m_nBufferCount);
|
||||
Clear(m_nType);
|
||||
Clear(m_nSamples);
|
||||
Clear(m_nInstruments);
|
||||
Clear(m_nTickCount);
|
||||
Clear(m_nTotalCount);
|
||||
Clear(m_nPatternDelay);
|
||||
Clear(m_nFrameDelay);
|
||||
Clear(m_nMusicSpeed);
|
||||
Clear(m_nMusicTempo);
|
||||
Clear(m_nNextRow);
|
||||
Clear(m_nRow);
|
||||
Clear(m_nPattern);
|
||||
Clear(m_nCurrentPattern);
|
||||
Clear(m_nNextPattern);
|
||||
Clear(m_nRestartPos);
|
||||
Clear(m_nMasterVolume);
|
||||
Clear(m_nGlobalVolume);
|
||||
Clear(m_nSongPreAmp);
|
||||
Clear(m_nFreqFactor);
|
||||
Clear(m_nTempoFactor);
|
||||
Clear(m_nOldGlbVolSlide);
|
||||
Clear(m_nMinPeriod);
|
||||
Clear(m_nMaxPeriod);
|
||||
Clear(m_nRepeatCount);
|
||||
Clear(m_nInitialRepeatCount);
|
||||
Clear(m_nGlobalFadeSamples);
|
||||
Clear(m_nGlobalFadeMaxSamples);
|
||||
Clear(m_nMaxOrderPosition);
|
||||
Clear(m_nPatternNames);
|
||||
Clear(m_lpszSongComments);
|
||||
Clear(m_lpszPatternNames);
|
||||
Clear(m_szNames);
|
||||
Clear(CompressionTable);
|
||||
}
|
||||
|
||||
CSoundFile::~CSoundFile() {
|
||||
mpcpplog();
|
||||
Destroy();
|
||||
}
|
||||
|
||||
BOOL CSoundFile::Create( LPCBYTE lpStream, DWORD dwMemLength ) {
|
||||
mpcpplog();
|
||||
try {
|
||||
openmpt::module * m = new openmpt::module( lpStream, dwMemLength );
|
||||
set_self( this, m );
|
||||
std::strncpy( m_szNames[0], mod->get_metadata("title").c_str(), sizeof( m_szNames[0] ) - 1 );
|
||||
m_szNames[0][ sizeof( m_szNames[0] ) - 1 ] = '\0';
|
||||
std::string type = mod->get_metadata("type");
|
||||
m_nType = MOD_TYPE_NONE;
|
||||
if ( type == "mod" ) {
|
||||
m_nType = MOD_TYPE_MOD;
|
||||
} else if ( type == "s3m" ) {
|
||||
m_nType = MOD_TYPE_S3M;
|
||||
} else if ( type == "xm" ) {
|
||||
m_nType = MOD_TYPE_XM;
|
||||
} else if ( type == "med" ) {
|
||||
m_nType = MOD_TYPE_MED;
|
||||
} else if ( type == "mtm" ) {
|
||||
m_nType = MOD_TYPE_MTM;
|
||||
} else if ( type == "it" ) {
|
||||
m_nType = MOD_TYPE_IT;
|
||||
} else if ( type == "669" ) {
|
||||
m_nType = MOD_TYPE_669;
|
||||
} else if ( type == "ult" ) {
|
||||
m_nType = MOD_TYPE_ULT;
|
||||
} else if ( type == "stm" ) {
|
||||
m_nType = MOD_TYPE_STM;
|
||||
} else if ( type == "far" ) {
|
||||
m_nType = MOD_TYPE_FAR;
|
||||
} else if ( type == "s3m" ) {
|
||||
m_nType = MOD_TYPE_WAV;
|
||||
} else if ( type == "amf" ) {
|
||||
m_nType = MOD_TYPE_AMF;
|
||||
} else if ( type == "ams" ) {
|
||||
m_nType = MOD_TYPE_AMS;
|
||||
} else if ( type == "dsm" ) {
|
||||
m_nType = MOD_TYPE_DSM;
|
||||
} else if ( type == "mdl" ) {
|
||||
m_nType = MOD_TYPE_MDL;
|
||||
} else if ( type == "okt" ) {
|
||||
m_nType = MOD_TYPE_OKT;
|
||||
} else if ( type == "mid" ) {
|
||||
m_nType = MOD_TYPE_MID;
|
||||
} else if ( type == "dmf" ) {
|
||||
m_nType = MOD_TYPE_DMF;
|
||||
} else if ( type == "ptm" ) {
|
||||
m_nType = MOD_TYPE_PTM;
|
||||
} else if ( type == "dbm" ) {
|
||||
m_nType = MOD_TYPE_DBM;
|
||||
} else if ( type == "mt2" ) {
|
||||
m_nType = MOD_TYPE_MT2;
|
||||
} else if ( type == "amf0" ) {
|
||||
m_nType = MOD_TYPE_AMF0;
|
||||
} else if ( type == "psm" ) {
|
||||
m_nType = MOD_TYPE_PSM;
|
||||
} else if ( type == "j2b" ) {
|
||||
m_nType = MOD_TYPE_J2B;
|
||||
} else if ( type == "abc" ) {
|
||||
m_nType = MOD_TYPE_ABC;
|
||||
} else if ( type == "pat" ) {
|
||||
m_nType = MOD_TYPE_PAT;
|
||||
} else if ( type == "umx" ) {
|
||||
m_nType = MOD_TYPE_UMX;
|
||||
} else {
|
||||
m_nType = MOD_TYPE_IT; // fallback, most complex type
|
||||
}
|
||||
m_nChannels = mod->get_num_channels();
|
||||
m_nMasterVolume = 128;
|
||||
m_nSamples = mod->get_num_samples();
|
||||
update_state();
|
||||
return TRUE;
|
||||
} catch ( ... ) {
|
||||
Destroy();
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL CSoundFile::Destroy() {
|
||||
mpcpplog();
|
||||
if ( mod ) {
|
||||
delete mod;
|
||||
set_self( this, 0 );
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
UINT CSoundFile::GetNumChannels() const {
|
||||
mpcpplog();
|
||||
return mod->get_num_channels();
|
||||
}
|
||||
|
||||
static std::int32_t vol128_To_millibel( unsigned int vol ) {
|
||||
return static_cast<std::int32_t>( 2000.0 * std::log10( static_cast<int>( vol ) / 128.0 ) );
|
||||
}
|
||||
|
||||
BOOL CSoundFile::SetMasterVolume( UINT vol, BOOL bAdjustAGC ) {
|
||||
UNUSED(bAdjustAGC);
|
||||
mpcpplog();
|
||||
m_nMasterVolume = vol;
|
||||
mod->set_render_param( openmpt::module::RENDER_MASTERGAIN_MILLIBEL, vol128_To_millibel( m_nMasterVolume ) );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
UINT CSoundFile::GetNumPatterns() const {
|
||||
mpcpplog();
|
||||
return mod->get_num_patterns();
|
||||
}
|
||||
|
||||
UINT CSoundFile::GetNumInstruments() const {
|
||||
mpcpplog();
|
||||
return mod->get_num_instruments();
|
||||
}
|
||||
|
||||
void CSoundFile::SetCurrentOrder( UINT nOrder ) {
|
||||
mpcpplog();
|
||||
mod->set_position_order_row( nOrder, 0 );
|
||||
update_state();
|
||||
}
|
||||
|
||||
UINT CSoundFile::GetSampleName( UINT nSample, LPSTR s ) const {
|
||||
mpcpplog();
|
||||
char buf[32];
|
||||
std::memset( buf, 0, 32 );
|
||||
if ( mod ) {
|
||||
std::vector<std::string> names = mod->get_sample_names();
|
||||
if ( 1 <= nSample && nSample <= names.size() ) {
|
||||
std::strncpy( buf, names[ nSample - 1 ].c_str(), 31 );
|
||||
}
|
||||
}
|
||||
if ( s ) {
|
||||
std::strncpy( s, buf, 32 );
|
||||
}
|
||||
return static_cast<UINT>( std::strlen( buf ) );
|
||||
}
|
||||
|
||||
UINT CSoundFile::GetInstrumentName( UINT nInstr, LPSTR s ) const {
|
||||
mpcpplog();
|
||||
char buf[32];
|
||||
std::memset( buf, 0, 32 );
|
||||
if ( mod ) {
|
||||
std::vector<std::string> names = mod->get_instrument_names();
|
||||
if ( 1 <= nInstr && nInstr <= names.size() ) {
|
||||
std::strncpy( buf, names[ nInstr - 1 ].c_str(), 31 );
|
||||
}
|
||||
}
|
||||
if ( s ) {
|
||||
std::strncpy( s, buf, 32 );
|
||||
}
|
||||
return static_cast<UINT>( std::strlen( buf ) );
|
||||
}
|
||||
|
||||
void CSoundFile::LoopPattern( int nPat, int nRow ) {
|
||||
UNUSED(nPat);
|
||||
UNUSED(nRow);
|
||||
mpcpplog();
|
||||
// todo
|
||||
}
|
||||
|
||||
void CSoundFile::CheckCPUUsage( UINT nCPU ) {
|
||||
UNUSED(nCPU);
|
||||
mpcpplog();
|
||||
}
|
||||
|
||||
BOOL CSoundFile::SetPatternName( UINT nPat, LPCSTR lpszName ) {
|
||||
UNUSED(nPat);
|
||||
mpcpplog();
|
||||
if ( !lpszName ) {
|
||||
return FALSE;
|
||||
}
|
||||
// todo
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CSoundFile::GetPatternName( UINT nPat, LPSTR lpszName, UINT cbSize ) const {
|
||||
UNUSED(nPat);
|
||||
mpcpplog();
|
||||
if ( !lpszName || cbSize <= 0 ) {
|
||||
return FALSE;
|
||||
}
|
||||
std::memset( lpszName, 0, cbSize );
|
||||
// todo
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CSoundFile::ReadXM(LPCBYTE lpStream, DWORD dwMemLength) { UNUSED(lpStream); UNUSED(dwMemLength); mpcpplog(); return FALSE; }
|
||||
BOOL CSoundFile::ReadS3M(LPCBYTE lpStream, DWORD dwMemLength) { UNUSED(lpStream); UNUSED(dwMemLength); mpcpplog(); return FALSE; }
|
||||
BOOL CSoundFile::ReadMod(LPCBYTE lpStream, DWORD dwMemLength) { UNUSED(lpStream); UNUSED(dwMemLength); mpcpplog(); return FALSE; }
|
||||
BOOL CSoundFile::ReadMed(LPCBYTE lpStream, DWORD dwMemLength) { UNUSED(lpStream); UNUSED(dwMemLength); mpcpplog(); return FALSE; }
|
||||
BOOL CSoundFile::ReadMTM(LPCBYTE lpStream, DWORD dwMemLength) { UNUSED(lpStream); UNUSED(dwMemLength); mpcpplog(); return FALSE; }
|
||||
BOOL CSoundFile::ReadSTM(LPCBYTE lpStream, DWORD dwMemLength) { UNUSED(lpStream); UNUSED(dwMemLength); mpcpplog(); return FALSE; }
|
||||
BOOL CSoundFile::ReadIT(LPCBYTE lpStream, DWORD dwMemLength) { UNUSED(lpStream); UNUSED(dwMemLength); mpcpplog(); return FALSE; }
|
||||
BOOL CSoundFile::Read669(LPCBYTE lpStream, DWORD dwMemLength) { UNUSED(lpStream); UNUSED(dwMemLength); mpcpplog(); return FALSE; }
|
||||
BOOL CSoundFile::ReadUlt(LPCBYTE lpStream, DWORD dwMemLength) { UNUSED(lpStream); UNUSED(dwMemLength); mpcpplog(); return FALSE; }
|
||||
BOOL CSoundFile::ReadWav(LPCBYTE lpStream, DWORD dwMemLength) { UNUSED(lpStream); UNUSED(dwMemLength); mpcpplog(); return FALSE; }
|
||||
BOOL CSoundFile::ReadDSM(LPCBYTE lpStream, DWORD dwMemLength) { UNUSED(lpStream); UNUSED(dwMemLength); mpcpplog(); return FALSE; }
|
||||
BOOL CSoundFile::ReadFAR(LPCBYTE lpStream, DWORD dwMemLength) { UNUSED(lpStream); UNUSED(dwMemLength); mpcpplog(); return FALSE; }
|
||||
BOOL CSoundFile::ReadAMS(LPCBYTE lpStream, DWORD dwMemLength) { UNUSED(lpStream); UNUSED(dwMemLength); mpcpplog(); return FALSE; }
|
||||
BOOL CSoundFile::ReadAMS2(LPCBYTE lpStream, DWORD dwMemLength) { UNUSED(lpStream); UNUSED(dwMemLength); mpcpplog(); return FALSE; }
|
||||
BOOL CSoundFile::ReadMDL(LPCBYTE lpStream, DWORD dwMemLength) { UNUSED(lpStream); UNUSED(dwMemLength); mpcpplog(); return FALSE; }
|
||||
BOOL CSoundFile::ReadOKT(LPCBYTE lpStream, DWORD dwMemLength) { UNUSED(lpStream); UNUSED(dwMemLength); mpcpplog(); return FALSE; }
|
||||
BOOL CSoundFile::ReadDMF(LPCBYTE lpStream, DWORD dwMemLength) { UNUSED(lpStream); UNUSED(dwMemLength); mpcpplog(); return FALSE; }
|
||||
BOOL CSoundFile::ReadPTM(LPCBYTE lpStream, DWORD dwMemLength) { UNUSED(lpStream); UNUSED(dwMemLength); mpcpplog(); return FALSE; }
|
||||
BOOL CSoundFile::ReadDBM(LPCBYTE lpStream, DWORD dwMemLength) { UNUSED(lpStream); UNUSED(dwMemLength); mpcpplog(); return FALSE; }
|
||||
BOOL CSoundFile::ReadAMF(LPCBYTE lpStream, DWORD dwMemLength) { UNUSED(lpStream); UNUSED(dwMemLength); mpcpplog(); return FALSE; }
|
||||
BOOL CSoundFile::ReadMT2(LPCBYTE lpStream, DWORD dwMemLength) { UNUSED(lpStream); UNUSED(dwMemLength); mpcpplog(); return FALSE; }
|
||||
BOOL CSoundFile::ReadPSM(LPCBYTE lpStream, DWORD dwMemLength) { UNUSED(lpStream); UNUSED(dwMemLength); mpcpplog(); return FALSE; }
|
||||
BOOL CSoundFile::ReadJ2B(LPCBYTE lpStream, DWORD dwMemLength) { UNUSED(lpStream); UNUSED(dwMemLength); mpcpplog(); return FALSE; }
|
||||
BOOL CSoundFile::ReadUMX(LPCBYTE lpStream, DWORD dwMemLength) { UNUSED(lpStream); UNUSED(dwMemLength); mpcpplog(); return FALSE; }
|
||||
BOOL CSoundFile::ReadABC(LPCBYTE lpStream, DWORD dwMemLength) { UNUSED(lpStream); UNUSED(dwMemLength); mpcpplog(); return FALSE; }
|
||||
BOOL CSoundFile::TestABC(LPCBYTE lpStream, DWORD dwMemLength) { UNUSED(lpStream); UNUSED(dwMemLength); mpcpplog(); return FALSE; }
|
||||
BOOL CSoundFile::ReadMID(LPCBYTE lpStream, DWORD dwMemLength) { UNUSED(lpStream); UNUSED(dwMemLength); mpcpplog(); return FALSE; }
|
||||
BOOL CSoundFile::TestMID(LPCBYTE lpStream, DWORD dwMemLength) { UNUSED(lpStream); UNUSED(dwMemLength); mpcpplog(); return FALSE; }
|
||||
BOOL CSoundFile::ReadPAT(LPCBYTE lpStream, DWORD dwMemLength) { UNUSED(lpStream); UNUSED(dwMemLength); mpcpplog(); return FALSE; }
|
||||
BOOL CSoundFile::TestPAT(LPCBYTE lpStream, DWORD dwMemLength) { UNUSED(lpStream); UNUSED(dwMemLength); mpcpplog(); return FALSE; }
|
||||
|
||||
#ifndef MODPLUG_NO_FILESAVE
|
||||
|
||||
UINT CSoundFile::WriteSample( FILE * f, MODINSTRUMENT * pins, UINT nFlags, UINT nMaxLen ) {
|
||||
UNUSED(f);
|
||||
UNUSED(pins);
|
||||
UNUSED(nFlags);
|
||||
UNUSED(nMaxLen);
|
||||
mpcpplog();
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOL CSoundFile::SaveXM( LPCSTR lpszFileName, UINT nPacking ) {
|
||||
UNUSED(lpszFileName);
|
||||
UNUSED(nPacking);
|
||||
mpcpplog();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL CSoundFile::SaveS3M( LPCSTR lpszFileName, UINT nPacking ) {
|
||||
UNUSED(lpszFileName);
|
||||
UNUSED(nPacking);
|
||||
mpcpplog();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL CSoundFile::SaveMod( LPCSTR lpszFileName, UINT nPacking ) {
|
||||
UNUSED(lpszFileName);
|
||||
UNUSED(nPacking);
|
||||
mpcpplog();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL CSoundFile::SaveIT( LPCSTR lpszFileName, UINT nPacking ) {
|
||||
UNUSED(lpszFileName);
|
||||
UNUSED(nPacking);
|
||||
mpcpplog();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
UINT CSoundFile::GetBestSaveFormat() const {
|
||||
mpcpplog();
|
||||
return MOD_TYPE_IT;
|
||||
}
|
||||
|
||||
UINT CSoundFile::GetSaveFormats() const {
|
||||
mpcpplog();
|
||||
return MOD_TYPE_IT;
|
||||
}
|
||||
|
||||
void CSoundFile::ConvertModCommand( MODCOMMAND * ) const {
|
||||
mpcpplog();
|
||||
}
|
||||
|
||||
void CSoundFile::S3MConvert( MODCOMMAND * m, BOOL bIT ) const {
|
||||
UNUSED(m);
|
||||
UNUSED(bIT);
|
||||
mpcpplog();
|
||||
}
|
||||
|
||||
void CSoundFile::S3MSaveConvert( UINT * pcmd, UINT * pprm, BOOL bIT ) const {
|
||||
UNUSED(pcmd);
|
||||
UNUSED(pprm);
|
||||
UNUSED(bIT);
|
||||
mpcpplog();
|
||||
}
|
||||
|
||||
WORD CSoundFile::ModSaveCommand( const MODCOMMAND * m, BOOL bXM ) const {
|
||||
UNUSED(m);
|
||||
UNUSED(bXM);
|
||||
mpcpplog();
|
||||
return 0;
|
||||
}
|
||||
|
||||
VOID CSoundFile::ResetChannels() {
|
||||
mpcpplog();
|
||||
}
|
||||
|
||||
UINT CSoundFile::CreateStereoMix( int count ) {
|
||||
UNUSED(count);
|
||||
mpcpplog();
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOL CSoundFile::FadeSong( UINT msec ) {
|
||||
UNUSED(msec);
|
||||
mpcpplog();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CSoundFile::GlobalFadeSong( UINT msec ) {
|
||||
UNUSED(msec);
|
||||
mpcpplog();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CSoundFile::InitPlayer( BOOL bReset ) {
|
||||
UNUSED(bReset);
|
||||
mpcpplog();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CSoundFile::SetMixConfig( UINT nStereoSeparation, UINT nMaxMixChannels ) {
|
||||
UNUSED(nMaxMixChannels);
|
||||
mpcpplog();
|
||||
m_nStereoSeparation = nStereoSeparation;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
DWORD CSoundFile::InitSysInfo() {
|
||||
mpcpplog();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CSoundFile::SetAGC( BOOL b ) {
|
||||
UNUSED(b);
|
||||
mpcpplog();
|
||||
}
|
||||
|
||||
void CSoundFile::ResetAGC() {
|
||||
mpcpplog();
|
||||
}
|
||||
|
||||
void CSoundFile::ProcessAGC( int count ) {
|
||||
UNUSED(count);
|
||||
mpcpplog();
|
||||
}
|
||||
|
||||
BOOL CSoundFile::SetWaveConfig( UINT nRate, UINT nBits, UINT nChannels, BOOL bMMX ) {
|
||||
UNUSED(bMMX);
|
||||
mpcpplog();
|
||||
gdwMixingFreq = nRate;
|
||||
gnBitsPerSample = nBits;
|
||||
gnChannels = nChannels;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CSoundFile::SetWaveConfigEx( BOOL bSurround, BOOL bNoOverSampling, BOOL bReverb, BOOL hqido, BOOL bMegaBass, BOOL bNR, BOOL bEQ ) {
|
||||
UNUSED(bSurround);
|
||||
UNUSED(bReverb);
|
||||
UNUSED(hqido);
|
||||
UNUSED(bMegaBass);
|
||||
UNUSED(bEQ);
|
||||
mpcpplog();
|
||||
DWORD d = gdwSoundSetup & ~(SNDMIX_NORESAMPLING|SNDMIX_HQRESAMPLER|SNDMIX_ULTRAHQSRCMODE);
|
||||
if ( bNoOverSampling ) {
|
||||
d |= SNDMIX_NORESAMPLING;
|
||||
} else if ( !hqido ) {
|
||||
d |= 0;
|
||||
} else if ( !bNR ) {
|
||||
d |= SNDMIX_HQRESAMPLER;
|
||||
} else {
|
||||
d |= (SNDMIX_HQRESAMPLER|SNDMIX_ULTRAHQSRCMODE);
|
||||
}
|
||||
gdwSoundSetup = d;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CSoundFile::SetResamplingMode( UINT nMode ) {
|
||||
mpcpplog();
|
||||
DWORD d = gdwSoundSetup & ~(SNDMIX_NORESAMPLING|SNDMIX_HQRESAMPLER|SNDMIX_ULTRAHQSRCMODE);
|
||||
switch ( nMode ) {
|
||||
case SRCMODE_NEAREST:
|
||||
d |= SNDMIX_NORESAMPLING;
|
||||
break;
|
||||
case SRCMODE_LINEAR:
|
||||
break;
|
||||
case SRCMODE_SPLINE:
|
||||
d |= SNDMIX_HQRESAMPLER;
|
||||
break;
|
||||
case SRCMODE_POLYPHASE:
|
||||
d |= (SNDMIX_HQRESAMPLER|SNDMIX_ULTRAHQSRCMODE);
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
break;
|
||||
}
|
||||
gdwSoundSetup = d;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CSoundFile::SetReverbParameters( UINT nDepth, UINT nDelay ) {
|
||||
UNUSED(nDepth);
|
||||
UNUSED(nDelay);
|
||||
mpcpplog();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CSoundFile::SetXBassParameters( UINT nDepth, UINT nRange ) {
|
||||
UNUSED(nDepth);
|
||||
UNUSED(nRange);
|
||||
mpcpplog();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CSoundFile::SetSurroundParameters( UINT nDepth, UINT nDelay ) {
|
||||
UNUSED(nDepth);
|
||||
UNUSED(nDelay);
|
||||
mpcpplog();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
UINT CSoundFile::GetMaxPosition() const {
|
||||
mpcpplog();
|
||||
// rows in original, just use seconds here
|
||||
if ( mod ) return static_cast<UINT>( mod->get_duration_seconds() + 0.5 );
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD CSoundFile::GetLength( BOOL bAdjust, BOOL bTotal ) {
|
||||
UNUSED(bAdjust);
|
||||
UNUSED(bTotal);
|
||||
mpcpplog();
|
||||
if ( mod ) return static_cast<DWORD>( mod->get_duration_seconds() + 0.5 );
|
||||
return 0;
|
||||
}
|
||||
|
||||
UINT CSoundFile::GetSongComments( LPSTR s, UINT cbsize, UINT linesize ) {
|
||||
UNUSED(linesize);
|
||||
mpcpplog();
|
||||
if ( !s ) {
|
||||
return 0;
|
||||
}
|
||||
if ( cbsize <= 0 ) {
|
||||
return 0;
|
||||
}
|
||||
if ( !mod ) {
|
||||
s[0] = '\0';
|
||||
return 1;
|
||||
}
|
||||
std::strncpy( s, mod->get_metadata("message").c_str(), cbsize );
|
||||
s[ cbsize - 1 ] = '\0';
|
||||
return static_cast<UINT>( std::strlen( s ) + 1 );
|
||||
}
|
||||
|
||||
UINT CSoundFile::GetRawSongComments( LPSTR s, UINT cbsize, UINT linesize ) {
|
||||
UNUSED(linesize);
|
||||
mpcpplog();
|
||||
if ( !s ) {
|
||||
return 0;
|
||||
}
|
||||
if ( cbsize <= 0 ) {
|
||||
return 0;
|
||||
}
|
||||
if ( !mod ) {
|
||||
s[0] = '\0';
|
||||
return 1;
|
||||
}
|
||||
std::strncpy( s, mod->get_metadata("message_raw").c_str(), cbsize );
|
||||
s[ cbsize - 1 ] = '\0';
|
||||
return static_cast<UINT>( std::strlen( s ) + 1 );
|
||||
}
|
||||
|
||||
void CSoundFile::SetCurrentPos( UINT nPos ) {
|
||||
mpcpplog();
|
||||
if ( mod ) mod->set_position_seconds( nPos );
|
||||
update_state();
|
||||
}
|
||||
|
||||
UINT CSoundFile::GetCurrentPos() const {
|
||||
mpcpplog();
|
||||
if ( mod ) return static_cast<UINT>( mod->get_position_seconds() + 0.5 );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_stereo_separation() {
|
||||
mpcpplog();
|
||||
return CSoundFile::m_nStereoSeparation * 100 / 128;
|
||||
}
|
||||
|
||||
static int get_filter_length() {
|
||||
mpcpplog();
|
||||
if ( ( CSoundFile::gdwSoundSetup & (SNDMIX_HQRESAMPLER|SNDMIX_ULTRAHQSRCMODE) ) == (SNDMIX_HQRESAMPLER|SNDMIX_ULTRAHQSRCMODE) ) {
|
||||
return 8;
|
||||
} else if ( ( CSoundFile::gdwSoundSetup & SNDMIX_HQRESAMPLER ) == SNDMIX_HQRESAMPLER ) {
|
||||
return 4;
|
||||
} else if ( ( CSoundFile::gdwSoundSetup & SNDMIX_NORESAMPLING ) == SNDMIX_NORESAMPLING ) {
|
||||
return 1;
|
||||
} else {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
static std::size_t get_sample_size() {
|
||||
return (CSoundFile::gnBitsPerSample/8);
|
||||
}
|
||||
|
||||
static std::size_t get_num_channels() {
|
||||
return CSoundFile::gnChannels;
|
||||
}
|
||||
|
||||
static std::size_t get_frame_size() {
|
||||
return get_sample_size() * get_num_channels();
|
||||
}
|
||||
|
||||
static int get_samplerate() {
|
||||
return CSoundFile::gdwMixingFreq;
|
||||
}
|
||||
|
||||
UINT CSoundFile::Read( LPVOID lpBuffer, UINT cbBuffer ) {
|
||||
mpcpplog();
|
||||
if ( !mod ) {
|
||||
return 0;
|
||||
}
|
||||
mpcpplog();
|
||||
if ( !lpBuffer ) {
|
||||
return 0;
|
||||
}
|
||||
mpcpplog();
|
||||
if ( cbBuffer <= 0 ) {
|
||||
return 0;
|
||||
}
|
||||
mpcpplog();
|
||||
if ( get_samplerate() <= 0 ) {
|
||||
return 0;
|
||||
}
|
||||
mpcpplog();
|
||||
if ( get_sample_size() != 1 && get_sample_size() != 2 && get_sample_size() != 4 ) {
|
||||
return 0;
|
||||
}
|
||||
mpcpplog();
|
||||
if ( get_num_channels() != 1 && get_num_channels() != 2 && get_num_channels() != 4 ) {
|
||||
return 0;
|
||||
}
|
||||
mpcpplog();
|
||||
std::memset( lpBuffer, 0, cbBuffer );
|
||||
const std::size_t frames_torender = cbBuffer / get_frame_size();
|
||||
short * out = reinterpret_cast<short*>( lpBuffer );
|
||||
std::vector<short> tmpbuf;
|
||||
if ( get_sample_size() == 1 || get_sample_size() == 4 ) {
|
||||
tmpbuf.resize( frames_torender * get_num_channels() );
|
||||
out = &tmpbuf[0];
|
||||
}
|
||||
|
||||
mod->set_render_param( openmpt::module::RENDER_STEREOSEPARATION_PERCENT, get_stereo_separation() );
|
||||
mod->set_render_param( openmpt::module::RENDER_INTERPOLATIONFILTER_LENGTH, get_filter_length() );
|
||||
std::size_t frames_rendered = 0;
|
||||
if ( get_num_channels() == 1 ) {
|
||||
frames_rendered = mod->read( get_samplerate(), frames_torender, out );
|
||||
} else if ( get_num_channels() == 4 ) {
|
||||
frames_rendered = mod->read_interleaved_quad( get_samplerate(), frames_torender, out );
|
||||
} else {
|
||||
frames_rendered = mod->read_interleaved_stereo( get_samplerate(), frames_torender, out );
|
||||
}
|
||||
|
||||
if ( get_sample_size() == 1 ) {
|
||||
unsigned char * dst = reinterpret_cast<unsigned char*>( lpBuffer );
|
||||
for ( std::size_t sample = 0; sample < frames_rendered * get_num_channels(); ++sample ) {
|
||||
dst[sample] = ( tmpbuf[sample] / 0x100 ) + 0x80;
|
||||
}
|
||||
} else if ( get_sample_size() == 4 ) {
|
||||
int * dst = reinterpret_cast<int*>( lpBuffer );
|
||||
for ( std::size_t sample = 0; sample < frames_rendered * get_num_channels(); ++sample ) {
|
||||
dst[sample] = tmpbuf[sample] << (32-16-1-MIXING_ATTENUATION);
|
||||
}
|
||||
}
|
||||
update_state();
|
||||
return static_cast<UINT>( frames_rendered );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
gstreamer modplug calls:
|
||||
|
||||
mSoundFile->Create
|
||||
mSoundFile->Destroy
|
||||
|
||||
mSoundFile->SetWaveConfig
|
||||
mSoundFile->SetWaveConfigEx
|
||||
mSoundFile->SetResamplingMode
|
||||
mSoundFile->SetSurroundParameters
|
||||
mSoundFile->SetXBassParameters
|
||||
mSoundFile->SetReverbParameters
|
||||
|
||||
mSoundFile->GetMaxPosition (inline, -> GetLength)
|
||||
mSoundFile->GetSongTime
|
||||
|
||||
mSoundFile->GetTitle (inline)
|
||||
mSoundFile->GetSongComments
|
||||
|
||||
mSoundFile->SetCurrentPos
|
||||
mSoundFile->Read
|
||||
|
||||
mSoundFile->GetCurrentPos
|
||||
mSoundFile->GetMusicTempo (inline)
|
||||
|
||||
*/
|
||||
|
||||
|
||||
// really very internal symbols, probably nothing calls these directly
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunknown-pragmas"
|
||||
#pragma clang diagnostic ignored "-Wunused-parameter"
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunknown-pragmas"
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4100)
|
||||
#endif
|
||||
|
||||
BOOL CSoundFile::ReadNote() { mpcpplog(); return 0; }
|
||||
BOOL CSoundFile::ProcessRow() { mpcpplog(); return 0; }
|
||||
BOOL CSoundFile::ProcessEffects() { mpcpplog(); return 0; }
|
||||
UINT CSoundFile::GetNNAChannel(UINT nChn) const { mpcpplog(); return 0; }
|
||||
void CSoundFile::CheckNNA(UINT nChn, UINT instr, int note, BOOL bForceCut) { mpcpplog(); }
|
||||
void CSoundFile::NoteChange(UINT nChn, int note, BOOL bPorta, BOOL bResetEnv) { mpcpplog(); }
|
||||
void CSoundFile::InstrumentChange(MODCHANNEL *pChn, UINT instr, BOOL bPorta,BOOL bUpdVol,BOOL bResetEnv) { mpcpplog(); }
|
||||
void CSoundFile::PortamentoUp(MODCHANNEL *pChn, UINT param) { mpcpplog(); }
|
||||
void CSoundFile::PortamentoDown(MODCHANNEL *pChn, UINT param) { mpcpplog(); }
|
||||
void CSoundFile::FinePortamentoUp(MODCHANNEL *pChn, UINT param) { mpcpplog(); }
|
||||
void CSoundFile::FinePortamentoDown(MODCHANNEL *pChn, UINT param) { mpcpplog(); }
|
||||
void CSoundFile::ExtraFinePortamentoUp(MODCHANNEL *pChn, UINT param) { mpcpplog(); }
|
||||
void CSoundFile::ExtraFinePortamentoDown(MODCHANNEL *pChn, UINT param) { mpcpplog(); }
|
||||
void CSoundFile::TonePortamento(MODCHANNEL *pChn, UINT param) { mpcpplog(); }
|
||||
void CSoundFile::Vibrato(MODCHANNEL *pChn, UINT param) { mpcpplog(); }
|
||||
void CSoundFile::FineVibrato(MODCHANNEL *pChn, UINT param) { mpcpplog(); }
|
||||
void CSoundFile::VolumeSlide(MODCHANNEL *pChn, UINT param) { mpcpplog(); }
|
||||
void CSoundFile::PanningSlide(MODCHANNEL *pChn, UINT param) { mpcpplog(); }
|
||||
void CSoundFile::ChannelVolSlide(MODCHANNEL *pChn, UINT param) { mpcpplog(); }
|
||||
void CSoundFile::FineVolumeUp(MODCHANNEL *pChn, UINT param) { mpcpplog(); }
|
||||
void CSoundFile::FineVolumeDown(MODCHANNEL *pChn, UINT param) { mpcpplog(); }
|
||||
void CSoundFile::Tremolo(MODCHANNEL *pChn, UINT param) { mpcpplog(); }
|
||||
void CSoundFile::Panbrello(MODCHANNEL *pChn, UINT param) { mpcpplog(); }
|
||||
void CSoundFile::RetrigNote(UINT nChn, UINT param) { mpcpplog(); }
|
||||
void CSoundFile::NoteCut(UINT nChn, UINT nTick) { mpcpplog(); }
|
||||
void CSoundFile::KeyOff(UINT nChn) { mpcpplog(); }
|
||||
int CSoundFile::PatternLoop(MODCHANNEL *, UINT param) { mpcpplog(); return 0; }
|
||||
void CSoundFile::ExtendedMODCommands(UINT nChn, UINT param) { mpcpplog(); }
|
||||
void CSoundFile::ExtendedS3MCommands(UINT nChn, UINT param) { mpcpplog(); }
|
||||
void CSoundFile::ExtendedChannelEffect(MODCHANNEL *, UINT param) { mpcpplog(); }
|
||||
void CSoundFile::ProcessMidiMacro(UINT nChn, LPCSTR pszMidiMacro, UINT param) { mpcpplog(); }
|
||||
void CSoundFile::SetupChannelFilter(MODCHANNEL *pChn, BOOL bReset, int flt_modifier) const { mpcpplog(); }
|
||||
void CSoundFile::DoFreqSlide(MODCHANNEL *pChn, LONG nFreqSlide) { mpcpplog(); }
|
||||
void CSoundFile::SetTempo(UINT param) { mpcpplog(); }
|
||||
void CSoundFile::SetSpeed(UINT param) { mpcpplog(); }
|
||||
void CSoundFile::GlobalVolSlide(UINT param) { mpcpplog(); }
|
||||
DWORD CSoundFile::IsSongFinished(UINT nOrder, UINT nRow) const { mpcpplog(); return 0; }
|
||||
BOOL CSoundFile::IsValidBackwardJump(UINT nStartOrder, UINT nStartRow, UINT nJumpOrder, UINT nJumpRow) const { mpcpplog(); return 0; }
|
||||
UINT CSoundFile::PackSample(int &sample, int next) { mpcpplog(); return 0; }
|
||||
BOOL CSoundFile::CanPackSample(LPSTR pSample, UINT nLen, UINT nPacking, BYTE *result) { mpcpplog(); return 0; }
|
||||
UINT CSoundFile::ReadSample(MODINSTRUMENT *pIns, UINT nFlags, LPCSTR pMemFile, DWORD dwMemLength) { mpcpplog(); return 0; }
|
||||
BOOL CSoundFile::DestroySample(UINT nSample) { mpcpplog(); return 0; }
|
||||
BOOL CSoundFile::DestroyInstrument(UINT nInstr) { mpcpplog(); return 0; }
|
||||
BOOL CSoundFile::IsSampleUsed(UINT nSample) { mpcpplog(); return 0; }
|
||||
BOOL CSoundFile::IsInstrumentUsed(UINT nInstr) { mpcpplog(); return 0; }
|
||||
BOOL CSoundFile::RemoveInstrumentSamples(UINT nInstr) { mpcpplog(); return 0; }
|
||||
UINT CSoundFile::DetectUnusedSamples(BOOL *) { mpcpplog(); return 0; }
|
||||
BOOL CSoundFile::RemoveSelectedSamples(BOOL *) { mpcpplog(); return 0; }
|
||||
void CSoundFile::AdjustSampleLoop(MODINSTRUMENT *pIns) { mpcpplog(); }
|
||||
BOOL CSoundFile::ReadInstrumentFromSong(UINT nInstr, CSoundFile *, UINT nSrcInstrument) { mpcpplog(); return 0; }
|
||||
BOOL CSoundFile::ReadSampleFromSong(UINT nSample, CSoundFile *, UINT nSrcSample) { mpcpplog(); return 0; }
|
||||
UINT CSoundFile::GetNoteFromPeriod(UINT period) const { mpcpplog(); return 0; }
|
||||
UINT CSoundFile::GetPeriodFromNote(UINT note, int nFineTune, UINT nC4Speed) const { mpcpplog(); return 0; }
|
||||
UINT CSoundFile::GetFreqFromPeriod(UINT period, UINT nC4Speed, int nPeriodFrac) const { mpcpplog(); return 0; }
|
||||
void CSoundFile::ResetMidiCfg() { mpcpplog(); }
|
||||
UINT CSoundFile::MapMidiInstrument(DWORD dwProgram, UINT nChannel, UINT nNote) { mpcpplog(); return 0; }
|
||||
BOOL CSoundFile::ITInstrToMPT(const void *p, INSTRUMENTHEADER *penv, UINT trkvers) { mpcpplog(); return 0; }
|
||||
UINT CSoundFile::SaveMixPlugins(FILE *f, BOOL bUpdate) { mpcpplog(); return 0; }
|
||||
UINT CSoundFile::LoadMixPlugins(const void *pData, UINT nLen) { mpcpplog(); return 0; }
|
||||
#ifndef NO_FILTER
|
||||
DWORD CSoundFile::CutOffToFrequency(UINT nCutOff, int flt_modifier) const { mpcpplog(); return 0; }
|
||||
#endif
|
||||
DWORD CSoundFile::TransposeToFrequency(int transp, int ftune) { mpcpplog(); return 0; }
|
||||
int CSoundFile::FrequencyToTranspose(DWORD freq) { mpcpplog(); return 0; }
|
||||
void CSoundFile::FrequencyToTranspose(MODINSTRUMENT *psmp) { mpcpplog(); }
|
||||
MODCOMMAND *CSoundFile::AllocatePattern(UINT rows, UINT nchns) { mpcpplog(); return 0; }
|
||||
signed char* CSoundFile::AllocateSample(UINT nbytes) { mpcpplog(); return 0; }
|
||||
void CSoundFile::FreePattern(LPVOID pat) { mpcpplog(); }
|
||||
void CSoundFile::FreeSample(LPVOID p) { mpcpplog(); }
|
||||
UINT CSoundFile::Normalize24BitBuffer(LPBYTE pbuffer, UINT cbsizebytes, DWORD lmax24, DWORD dwByteInc) { mpcpplog(); return 0; }
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
#endif // NO_LIBMODPLUG
|
|
@ -0,0 +1,972 @@
|
|||
# ===========================================================================
|
||||
# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Check for baseline language coverage in the compiler for the specified
|
||||
# version of the C++ standard. If necessary, add switches to CXX and
|
||||
# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard)
|
||||
# or '14' (for the C++14 standard).
|
||||
#
|
||||
# The second argument, if specified, indicates whether you insist on an
|
||||
# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
|
||||
# -std=c++11). If neither is specified, you get whatever works, with
|
||||
# preference for an extended mode.
|
||||
#
|
||||
# The third argument, if specified 'mandatory' or if left unspecified,
|
||||
# indicates that baseline support for the specified C++ standard is
|
||||
# required and that the macro should error out if no mode with that
|
||||
# support is found. If specified 'optional', then configuration proceeds
|
||||
# regardless, after defining HAVE_CXX${VERSION} if and only if a
|
||||
# supporting mode is found.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
|
||||
# Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
|
||||
# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
|
||||
# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
|
||||
# Copyright (c) 2015 Paul Norman <penorman@mac.com>
|
||||
# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
|
||||
# Copyright (c) 2016, 2018 Krzesimir Nowak <qdlacz@gmail.com>
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 9
|
||||
|
||||
dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
|
||||
dnl (serial version number 13).
|
||||
|
||||
AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
|
||||
m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"],
|
||||
[$1], [14], [ax_cxx_compile_alternatives="14 1y"],
|
||||
[$1], [17], [ax_cxx_compile_alternatives="17 1z"],
|
||||
[m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
|
||||
m4_if([$2], [], [],
|
||||
[$2], [ext], [],
|
||||
[$2], [noext], [],
|
||||
[m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl
|
||||
m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true],
|
||||
[$3], [mandatory], [ax_cxx_compile_cxx$1_required=true],
|
||||
[$3], [optional], [ax_cxx_compile_cxx$1_required=false],
|
||||
[m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
|
||||
AC_LANG_PUSH([C++])dnl
|
||||
ac_success=no
|
||||
|
||||
m4_if([$2], [noext], [], [dnl
|
||||
if test x$ac_success = xno; then
|
||||
for alternative in ${ax_cxx_compile_alternatives}; do
|
||||
switch="-std=gnu++${alternative}"
|
||||
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
|
||||
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
|
||||
$cachevar,
|
||||
[ac_save_CXX="$CXX"
|
||||
CXX="$CXX $switch"
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
|
||||
[eval $cachevar=yes],
|
||||
[eval $cachevar=no])
|
||||
CXX="$ac_save_CXX"])
|
||||
if eval test x\$$cachevar = xyes; then
|
||||
CXX="$CXX $switch"
|
||||
if test -n "$CXXCPP" ; then
|
||||
CXXCPP="$CXXCPP $switch"
|
||||
fi
|
||||
ac_success=yes
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi])
|
||||
|
||||
m4_if([$2], [ext], [], [dnl
|
||||
if test x$ac_success = xno; then
|
||||
dnl HP's aCC needs +std=c++11 according to:
|
||||
dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
|
||||
dnl Cray's crayCC needs "-h std=c++11"
|
||||
for alternative in ${ax_cxx_compile_alternatives}; do
|
||||
for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do
|
||||
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
|
||||
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
|
||||
$cachevar,
|
||||
[ac_save_CXX="$CXX"
|
||||
CXX="$CXX $switch"
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
|
||||
[eval $cachevar=yes],
|
||||
[eval $cachevar=no])
|
||||
CXX="$ac_save_CXX"])
|
||||
if eval test x\$$cachevar = xyes; then
|
||||
CXX="$CXX $switch"
|
||||
if test -n "$CXXCPP" ; then
|
||||
CXXCPP="$CXXCPP $switch"
|
||||
fi
|
||||
ac_success=yes
|
||||
break
|
||||
fi
|
||||
done
|
||||
if test x$ac_success = xyes; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi])
|
||||
AC_LANG_POP([C++])
|
||||
if test x$ax_cxx_compile_cxx$1_required = xtrue; then
|
||||
if test x$ac_success = xno; then
|
||||
AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.])
|
||||
fi
|
||||
fi
|
||||
if test x$ac_success = xno; then
|
||||
HAVE_CXX$1=0
|
||||
AC_MSG_NOTICE([No compiler with C++$1 support was found])
|
||||
else
|
||||
HAVE_CXX$1=1
|
||||
AC_DEFINE(HAVE_CXX$1,1,
|
||||
[define if the compiler supports basic C++$1 syntax])
|
||||
fi
|
||||
AC_SUBST(HAVE_CXX$1)
|
||||
])
|
||||
|
||||
|
||||
dnl Test body for checking C++11 support
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
|
||||
)
|
||||
|
||||
|
||||
dnl Test body for checking C++14 support
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
|
||||
)
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17],
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_17
|
||||
)
|
||||
|
||||
dnl Tests for new features in C++11
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
|
||||
|
||||
// If the compiler admits that it is not ready for C++11, why torture it?
|
||||
// Hopefully, this will speed up the test.
|
||||
|
||||
#ifndef __cplusplus
|
||||
|
||||
#error "This is not a C++ compiler"
|
||||
|
||||
#elif __cplusplus < 201103L
|
||||
|
||||
#error "This is not a C++11 compiler"
|
||||
|
||||
#else
|
||||
|
||||
namespace cxx11
|
||||
{
|
||||
|
||||
namespace test_static_assert
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
struct check
|
||||
{
|
||||
static_assert(sizeof(int) <= sizeof(T), "not big enough");
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace test_final_override
|
||||
{
|
||||
|
||||
struct Base
|
||||
{
|
||||
virtual void f() {}
|
||||
};
|
||||
|
||||
struct Derived : public Base
|
||||
{
|
||||
virtual void f() override {}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace test_double_right_angle_brackets
|
||||
{
|
||||
|
||||
template < typename T >
|
||||
struct check {};
|
||||
|
||||
typedef check<void> single_type;
|
||||
typedef check<check<void>> double_type;
|
||||
typedef check<check<check<void>>> triple_type;
|
||||
typedef check<check<check<check<void>>>> quadruple_type;
|
||||
|
||||
}
|
||||
|
||||
namespace test_decltype
|
||||
{
|
||||
|
||||
int
|
||||
f()
|
||||
{
|
||||
int a = 1;
|
||||
decltype(a) b = 2;
|
||||
return a + b;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace test_type_deduction
|
||||
{
|
||||
|
||||
template < typename T1, typename T2 >
|
||||
struct is_same
|
||||
{
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
template < typename T >
|
||||
struct is_same<T, T>
|
||||
{
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
template < typename T1, typename T2 >
|
||||
auto
|
||||
add(T1 a1, T2 a2) -> decltype(a1 + a2)
|
||||
{
|
||||
return a1 + a2;
|
||||
}
|
||||
|
||||
int
|
||||
test(const int c, volatile int v)
|
||||
{
|
||||
static_assert(is_same<int, decltype(0)>::value == true, "");
|
||||
static_assert(is_same<int, decltype(c)>::value == false, "");
|
||||
static_assert(is_same<int, decltype(v)>::value == false, "");
|
||||
auto ac = c;
|
||||
auto av = v;
|
||||
auto sumi = ac + av + 'x';
|
||||
auto sumf = ac + av + 1.0;
|
||||
static_assert(is_same<int, decltype(ac)>::value == true, "");
|
||||
static_assert(is_same<int, decltype(av)>::value == true, "");
|
||||
static_assert(is_same<int, decltype(sumi)>::value == true, "");
|
||||
static_assert(is_same<int, decltype(sumf)>::value == false, "");
|
||||
static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
|
||||
return (sumf > 0.0) ? sumi : add(c, v);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace test_noexcept
|
||||
{
|
||||
|
||||
int f() { return 0; }
|
||||
int g() noexcept { return 0; }
|
||||
|
||||
static_assert(noexcept(f()) == false, "");
|
||||
static_assert(noexcept(g()) == true, "");
|
||||
|
||||
}
|
||||
|
||||
namespace test_constexpr
|
||||
{
|
||||
|
||||
template < typename CharT >
|
||||
unsigned long constexpr
|
||||
strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
|
||||
{
|
||||
return *s ? strlen_c_r(s + 1, acc + 1) : acc;
|
||||
}
|
||||
|
||||
template < typename CharT >
|
||||
unsigned long constexpr
|
||||
strlen_c(const CharT *const s) noexcept
|
||||
{
|
||||
return strlen_c_r(s, 0UL);
|
||||
}
|
||||
|
||||
static_assert(strlen_c("") == 0UL, "");
|
||||
static_assert(strlen_c("1") == 1UL, "");
|
||||
static_assert(strlen_c("example") == 7UL, "");
|
||||
static_assert(strlen_c("another\0example") == 7UL, "");
|
||||
|
||||
}
|
||||
|
||||
namespace test_rvalue_references
|
||||
{
|
||||
|
||||
template < int N >
|
||||
struct answer
|
||||
{
|
||||
static constexpr int value = N;
|
||||
};
|
||||
|
||||
answer<1> f(int&) { return answer<1>(); }
|
||||
answer<2> f(const int&) { return answer<2>(); }
|
||||
answer<3> f(int&&) { return answer<3>(); }
|
||||
|
||||
void
|
||||
test()
|
||||
{
|
||||
int i = 0;
|
||||
const int c = 0;
|
||||
static_assert(decltype(f(i))::value == 1, "");
|
||||
static_assert(decltype(f(c))::value == 2, "");
|
||||
static_assert(decltype(f(0))::value == 3, "");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace test_uniform_initialization
|
||||
{
|
||||
|
||||
struct test
|
||||
{
|
||||
static const int zero {};
|
||||
static const int one {1};
|
||||
};
|
||||
|
||||
static_assert(test::zero == 0, "");
|
||||
static_assert(test::one == 1, "");
|
||||
|
||||
}
|
||||
|
||||
namespace test_lambdas
|
||||
{
|
||||
|
||||
void
|
||||
test1()
|
||||
{
|
||||
auto lambda1 = [](){};
|
||||
auto lambda2 = lambda1;
|
||||
lambda1();
|
||||
lambda2();
|
||||
}
|
||||
|
||||
int
|
||||
test2()
|
||||
{
|
||||
auto a = [](int i, int j){ return i + j; }(1, 2);
|
||||
auto b = []() -> int { return '0'; }();
|
||||
auto c = [=](){ return a + b; }();
|
||||
auto d = [&](){ return c; }();
|
||||
auto e = [a, &b](int x) mutable {
|
||||
const auto identity = [](int y){ return y; };
|
||||
for (auto i = 0; i < a; ++i)
|
||||
a += b--;
|
||||
return x + identity(a + b);
|
||||
}(0);
|
||||
return a + b + c + d + e;
|
||||
}
|
||||
|
||||
int
|
||||
test3()
|
||||
{
|
||||
const auto nullary = [](){ return 0; };
|
||||
const auto unary = [](int x){ return x; };
|
||||
using nullary_t = decltype(nullary);
|
||||
using unary_t = decltype(unary);
|
||||
const auto higher1st = [](nullary_t f){ return f(); };
|
||||
const auto higher2nd = [unary](nullary_t f1){
|
||||
return [unary, f1](unary_t f2){ return f2(unary(f1())); };
|
||||
};
|
||||
return higher1st(nullary) + higher2nd(nullary)(unary);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace test_variadic_templates
|
||||
{
|
||||
|
||||
template <int...>
|
||||
struct sum;
|
||||
|
||||
template <int N0, int... N1toN>
|
||||
struct sum<N0, N1toN...>
|
||||
{
|
||||
static constexpr auto value = N0 + sum<N1toN...>::value;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct sum<>
|
||||
{
|
||||
static constexpr auto value = 0;
|
||||
};
|
||||
|
||||
static_assert(sum<>::value == 0, "");
|
||||
static_assert(sum<1>::value == 1, "");
|
||||
static_assert(sum<23>::value == 23, "");
|
||||
static_assert(sum<1, 2>::value == 3, "");
|
||||
static_assert(sum<5, 5, 11>::value == 21, "");
|
||||
static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
|
||||
|
||||
}
|
||||
|
||||
// http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
|
||||
// Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
|
||||
// because of this.
|
||||
namespace test_template_alias_sfinae
|
||||
{
|
||||
|
||||
struct foo {};
|
||||
|
||||
template<typename T>
|
||||
using member = typename T::member_type;
|
||||
|
||||
template<typename T>
|
||||
void func(...) {}
|
||||
|
||||
template<typename T>
|
||||
void func(member<T>*) {}
|
||||
|
||||
void test();
|
||||
|
||||
void test() { func<foo>(0); }
|
||||
|
||||
}
|
||||
|
||||
} // namespace cxx11
|
||||
|
||||
#endif // __cplusplus >= 201103L
|
||||
|
||||
]])
|
||||
|
||||
|
||||
dnl Tests for new features in C++14
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[
|
||||
|
||||
// If the compiler admits that it is not ready for C++14, why torture it?
|
||||
// Hopefully, this will speed up the test.
|
||||
|
||||
#ifndef __cplusplus
|
||||
|
||||
#error "This is not a C++ compiler"
|
||||
|
||||
#elif __cplusplus < 201402L
|
||||
|
||||
#error "This is not a C++14 compiler"
|
||||
|
||||
#else
|
||||
|
||||
namespace cxx14
|
||||
{
|
||||
|
||||
namespace test_polymorphic_lambdas
|
||||
{
|
||||
|
||||
int
|
||||
test()
|
||||
{
|
||||
const auto lambda = [](auto&&... args){
|
||||
const auto istiny = [](auto x){
|
||||
return (sizeof(x) == 1UL) ? 1 : 0;
|
||||
};
|
||||
const int aretiny[] = { istiny(args)... };
|
||||
return aretiny[0];
|
||||
};
|
||||
return lambda(1, 1L, 1.0f, '1');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace test_binary_literals
|
||||
{
|
||||
|
||||
constexpr auto ivii = 0b0000000000101010;
|
||||
static_assert(ivii == 42, "wrong value");
|
||||
|
||||
}
|
||||
|
||||
namespace test_generalized_constexpr
|
||||
{
|
||||
|
||||
template < typename CharT >
|
||||
constexpr unsigned long
|
||||
strlen_c(const CharT *const s) noexcept
|
||||
{
|
||||
auto length = 0UL;
|
||||
for (auto p = s; *p; ++p)
|
||||
++length;
|
||||
return length;
|
||||
}
|
||||
|
||||
static_assert(strlen_c("") == 0UL, "");
|
||||
static_assert(strlen_c("x") == 1UL, "");
|
||||
static_assert(strlen_c("test") == 4UL, "");
|
||||
static_assert(strlen_c("another\0test") == 7UL, "");
|
||||
|
||||
}
|
||||
|
||||
namespace test_lambda_init_capture
|
||||
{
|
||||
|
||||
int
|
||||
test()
|
||||
{
|
||||
auto x = 0;
|
||||
const auto lambda1 = [a = x](int b){ return a + b; };
|
||||
const auto lambda2 = [a = lambda1(x)](){ return a; };
|
||||
return lambda2();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace test_digit_separators
|
||||
{
|
||||
|
||||
constexpr auto ten_million = 100'000'000;
|
||||
static_assert(ten_million == 100000000, "");
|
||||
|
||||
}
|
||||
|
||||
namespace test_return_type_deduction
|
||||
{
|
||||
|
||||
auto f(int& x) { return x; }
|
||||
decltype(auto) g(int& x) { return x; }
|
||||
|
||||
template < typename T1, typename T2 >
|
||||
struct is_same
|
||||
{
|
||||
static constexpr auto value = false;
|
||||
};
|
||||
|
||||
template < typename T >
|
||||
struct is_same<T, T>
|
||||
{
|
||||
static constexpr auto value = true;
|
||||
};
|
||||
|
||||
int
|
||||
test()
|
||||
{
|
||||
auto x = 0;
|
||||
static_assert(is_same<int, decltype(f(x))>::value, "");
|
||||
static_assert(is_same<int&, decltype(g(x))>::value, "");
|
||||
return x;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace cxx14
|
||||
|
||||
#endif // __cplusplus >= 201402L
|
||||
|
||||
]])
|
||||
|
||||
|
||||
dnl Tests for new features in C++17
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[
|
||||
|
||||
// If the compiler admits that it is not ready for C++17, why torture it?
|
||||
// Hopefully, this will speed up the test.
|
||||
|
||||
#ifndef __cplusplus
|
||||
|
||||
#error "This is not a C++ compiler"
|
||||
|
||||
#elif __cplusplus <= 201402L
|
||||
|
||||
#error "This is not a C++17 compiler"
|
||||
|
||||
#else
|
||||
|
||||
#if defined(__clang__)
|
||||
#define REALLY_CLANG
|
||||
#else
|
||||
#if defined(__GNUC__)
|
||||
#define REALLY_GCC
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <initializer_list>
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
|
||||
namespace cxx17
|
||||
{
|
||||
|
||||
#if !defined(REALLY_CLANG)
|
||||
namespace test_constexpr_lambdas
|
||||
{
|
||||
|
||||
// TODO: test it with clang++ from git
|
||||
|
||||
constexpr int foo = [](){return 42;}();
|
||||
|
||||
}
|
||||
#endif // !defined(REALLY_CLANG)
|
||||
|
||||
namespace test::nested_namespace::definitions
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
namespace test_fold_expression
|
||||
{
|
||||
|
||||
template<typename... Args>
|
||||
int multiply(Args... args)
|
||||
{
|
||||
return (args * ... * 1);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
bool all(Args... args)
|
||||
{
|
||||
return (args && ...);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace test_extended_static_assert
|
||||
{
|
||||
|
||||
static_assert (true);
|
||||
|
||||
}
|
||||
|
||||
namespace test_auto_brace_init_list
|
||||
{
|
||||
|
||||
auto foo = {5};
|
||||
auto bar {5};
|
||||
|
||||
static_assert(std::is_same<std::initializer_list<int>, decltype(foo)>::value);
|
||||
static_assert(std::is_same<int, decltype(bar)>::value);
|
||||
}
|
||||
|
||||
namespace test_typename_in_template_template_parameter
|
||||
{
|
||||
|
||||
template<template<typename> typename X> struct D;
|
||||
|
||||
}
|
||||
|
||||
namespace test_fallthrough_nodiscard_maybe_unused_attributes
|
||||
{
|
||||
|
||||
int f1()
|
||||
{
|
||||
return 42;
|
||||
}
|
||||
|
||||
[[nodiscard]] int f2()
|
||||
{
|
||||
[[maybe_unused]] auto unused = f1();
|
||||
|
||||
switch (f1())
|
||||
{
|
||||
case 17:
|
||||
f1();
|
||||
[[fallthrough]];
|
||||
case 42:
|
||||
f1();
|
||||
}
|
||||
return f1();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace test_extended_aggregate_initialization
|
||||
{
|
||||
|
||||
struct base1
|
||||
{
|
||||
int b1, b2 = 42;
|
||||
};
|
||||
|
||||
struct base2
|
||||
{
|
||||
base2() {
|
||||
b3 = 42;
|
||||
}
|
||||
int b3;
|
||||
};
|
||||
|
||||
struct derived : base1, base2
|
||||
{
|
||||
int d;
|
||||
};
|
||||
|
||||
derived d1 {{1, 2}, {}, 4}; // full initialization
|
||||
derived d2 {{}, {}, 4}; // value-initialized bases
|
||||
|
||||
}
|
||||
|
||||
namespace test_general_range_based_for_loop
|
||||
{
|
||||
|
||||
struct iter
|
||||
{
|
||||
int i;
|
||||
|
||||
int& operator* ()
|
||||
{
|
||||
return i;
|
||||
}
|
||||
|
||||
const int& operator* () const
|
||||
{
|
||||
return i;
|
||||
}
|
||||
|
||||
iter& operator++()
|
||||
{
|
||||
++i;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
struct sentinel
|
||||
{
|
||||
int i;
|
||||
};
|
||||
|
||||
bool operator== (const iter& i, const sentinel& s)
|
||||
{
|
||||
return i.i == s.i;
|
||||
}
|
||||
|
||||
bool operator!= (const iter& i, const sentinel& s)
|
||||
{
|
||||
return !(i == s);
|
||||
}
|
||||
|
||||
struct range
|
||||
{
|
||||
iter begin() const
|
||||
{
|
||||
return {0};
|
||||
}
|
||||
|
||||
sentinel end() const
|
||||
{
|
||||
return {5};
|
||||
}
|
||||
};
|
||||
|
||||
void f()
|
||||
{
|
||||
range r {};
|
||||
|
||||
for (auto i : r)
|
||||
{
|
||||
[[maybe_unused]] auto v = i;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace test_lambda_capture_asterisk_this_by_value
|
||||
{
|
||||
|
||||
struct t
|
||||
{
|
||||
int i;
|
||||
int foo()
|
||||
{
|
||||
return [*this]()
|
||||
{
|
||||
return i;
|
||||
}();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace test_enum_class_construction
|
||||
{
|
||||
|
||||
enum class byte : unsigned char
|
||||
{};
|
||||
|
||||
byte foo {42};
|
||||
|
||||
}
|
||||
|
||||
namespace test_constexpr_if
|
||||
{
|
||||
|
||||
template <bool cond>
|
||||
int f ()
|
||||
{
|
||||
if constexpr(cond)
|
||||
{
|
||||
return 13;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 42;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace test_selection_statement_with_initializer
|
||||
{
|
||||
|
||||
int f()
|
||||
{
|
||||
return 13;
|
||||
}
|
||||
|
||||
int f2()
|
||||
{
|
||||
if (auto i = f(); i > 0)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
switch (auto i = f(); i + 4)
|
||||
{
|
||||
case 17:
|
||||
return 2;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if !defined(REALLY_CLANG)
|
||||
namespace test_template_argument_deduction_for_class_templates
|
||||
{
|
||||
|
||||
// TODO: test it with clang++ from git
|
||||
|
||||
template <typename T1, typename T2>
|
||||
struct pair
|
||||
{
|
||||
pair (T1 p1, T2 p2)
|
||||
: m1 {p1},
|
||||
m2 {p2}
|
||||
{}
|
||||
|
||||
T1 m1;
|
||||
T2 m2;
|
||||
};
|
||||
|
||||
void f()
|
||||
{
|
||||
[[maybe_unused]] auto p = pair{13, 42u};
|
||||
}
|
||||
|
||||
}
|
||||
#endif // !defined(REALLY_CLANG)
|
||||
|
||||
namespace test_non_type_auto_template_parameters
|
||||
{
|
||||
|
||||
template <auto n>
|
||||
struct B
|
||||
{};
|
||||
|
||||
B<5> b1;
|
||||
B<'a'> b2;
|
||||
|
||||
}
|
||||
|
||||
#if !defined(REALLY_CLANG)
|
||||
namespace test_structured_bindings
|
||||
{
|
||||
|
||||
// TODO: test it with clang++ from git
|
||||
|
||||
int arr[2] = { 1, 2 };
|
||||
std::pair<int, int> pr = { 1, 2 };
|
||||
|
||||
auto f1() -> int(&)[2]
|
||||
{
|
||||
return arr;
|
||||
}
|
||||
|
||||
auto f2() -> std::pair<int, int>&
|
||||
{
|
||||
return pr;
|
||||
}
|
||||
|
||||
struct S
|
||||
{
|
||||
int x1 : 2;
|
||||
volatile double y1;
|
||||
};
|
||||
|
||||
S f3()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
auto [ x1, y1 ] = f1();
|
||||
auto& [ xr1, yr1 ] = f1();
|
||||
auto [ x2, y2 ] = f2();
|
||||
auto& [ xr2, yr2 ] = f2();
|
||||
const auto [ x3, y3 ] = f3();
|
||||
|
||||
}
|
||||
#endif // !defined(REALLY_CLANG)
|
||||
|
||||
#if !defined(REALLY_CLANG)
|
||||
namespace test_exception_spec_type_system
|
||||
{
|
||||
|
||||
// TODO: test it with clang++ from git
|
||||
|
||||
struct Good {};
|
||||
struct Bad {};
|
||||
|
||||
void g1() noexcept;
|
||||
void g2();
|
||||
|
||||
template<typename T>
|
||||
Bad
|
||||
f(T*, T*);
|
||||
|
||||
template<typename T1, typename T2>
|
||||
Good
|
||||
f(T1*, T2*);
|
||||
|
||||
static_assert (std::is_same_v<Good, decltype(f(g1, g2))>);
|
||||
|
||||
}
|
||||
#endif // !defined(REALLY_CLANG)
|
||||
|
||||
namespace test_inline_variables
|
||||
{
|
||||
|
||||
template<class T> void f(T)
|
||||
{}
|
||||
|
||||
template<class T> inline T g(T)
|
||||
{
|
||||
return T{};
|
||||
}
|
||||
|
||||
template<> inline void f<>(int)
|
||||
{}
|
||||
|
||||
template<> int g<>(int)
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace cxx17
|
||||
|
||||
#endif // __cplusplus <= 201402L
|
||||
|
||||
]])
|
10
Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.8.5/test.sh
Executable file
10
Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.8.5/test.sh
Executable file
|
@ -0,0 +1,10 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
./autogen.sh
|
||||
|
||||
./configure
|
||||
make
|
||||
make distcheck
|
||||
make distclean
|
|
@ -0,0 +1,25 @@
|
|||
Copyright (c) 2004-2022, OpenMPT Project Developers and 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 COPYRIGHT HOLDERS AND 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 COPYRIGHT HOLDER OR 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.
|
|
@ -0,0 +1,46 @@
|
|||
|
||||
ACLOCAL_AMFLAGS = -I m4 --install
|
||||
EXTRA_DIST =
|
||||
EXTRA_DIST += LICENSE
|
||||
EXTRA_DIST += libopenmpt_modplug.pc.in
|
||||
EXTRA_DIST += libmodplug.pc.in
|
||||
EXTRA_DIST += test.sh
|
||||
MOSTLYCLEANFILES =
|
||||
|
||||
dist_doc_DATA =
|
||||
dist_doc_DATA += LICENSE
|
||||
nobase_dist_doc_DATA =
|
||||
|
||||
bin_PROGRAMS =
|
||||
check_PROGRAMS =
|
||||
lib_LTLIBRARIES =
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA =
|
||||
nobase_include_HEADERS =
|
||||
|
||||
if ENABLE_LIBOPENMPT_MODPLUG
|
||||
lib_LTLIBRARIES += libopenmpt_modplug.la
|
||||
libopenmpt_modplug_la_LDFLAGS = -version-info 1:0:0 -no-undefined
|
||||
libopenmpt_modplug_la_CPPFLAGS = -I$(srcdir)/ $(LIBOPENMPT_CPPFLAGS)
|
||||
libopenmpt_modplug_la_CXXFLAGS = $(LIBOPENMPT_CFLAGS)
|
||||
libopenmpt_modplug_la_CFLAGS = $(LIBOPENMPT_CFLAGS)
|
||||
libopenmpt_modplug_la_LIBADD = $(LIBOPENMPT_LIBS)
|
||||
libopenmpt_modplug_la_SOURCES =
|
||||
libopenmpt_modplug_la_SOURCES += libopenmpt_modplug.c
|
||||
libopenmpt_modplug_la_SOURCES += libopenmpt_modplug_cpp.cpp
|
||||
endif
|
||||
|
||||
if ENABLE_LIBMODPLUG
|
||||
pkgconfig_DATA += libmodplug.pc
|
||||
lib_LTLIBRARIES += libmodplug.la
|
||||
libmodplug_la_LDFLAGS = -version-info 1:0:0 -no-undefined
|
||||
nobase_include_HEADERS += libmodplug/modplug.h libmodplug/sndfile.h libmodplug/stdafx.h
|
||||
libmodplug_la_CPPFLAGS = -I$(srcdir)/ $(LIBOPENMPT_CPPFLAGS)
|
||||
libmodplug_la_CXXFLAGS = $(LIBOPENMPT_CFLAGS)
|
||||
libmodplug_la_CFLAGS = $(LIBOPENMPT_CFLAGS)
|
||||
libmodplug_la_LIBADD = $(LIBOPENMPT_LIBS)
|
||||
libmodplug_la_SOURCES =
|
||||
libmodplug_la_SOURCES += libopenmpt_modplug.c
|
||||
libmodplug_la_SOURCES += libopenmpt_modplug_cpp.cpp
|
||||
endif
|
2
Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.9.0/autogen.sh
Executable file
2
Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.9.0/autogen.sh
Executable file
|
@ -0,0 +1,2 @@
|
|||
#!/usr/bin/env sh
|
||||
autoreconf -i
|
7
Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.9.0/clean.sh
Executable file
7
Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.9.0/clean.sh
Executable file
|
@ -0,0 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
./autogen.sh
|
||||
./configure
|
||||
make distclean
|
|
@ -0,0 +1,81 @@
|
|||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* define if the compiler supports basic C++11 syntax */
|
||||
#undef HAVE_CXX11
|
||||
|
||||
/* define if the compiler supports basic C++14 syntax */
|
||||
#undef HAVE_CXX14
|
||||
|
||||
/* define if the compiler supports basic C++17 syntax */
|
||||
#undef HAVE_CXX17
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#undef HAVE_DLFCN_H
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#undef HAVE_INTTYPES_H
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#undef HAVE_STDLIB_H
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#undef HAVE_STRINGS_H
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#undef HAVE_STRING_H
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#undef HAVE_SYS_STAT_H
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#undef HAVE_SYS_TYPES_H
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#undef HAVE_UNISTD_H
|
||||
|
||||
/* Define to the sub-directory where libtool stores uninstalled libraries. */
|
||||
#undef LT_OBJDIR
|
||||
|
||||
/* Name of package */
|
||||
#undef PACKAGE
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#undef PACKAGE_BUGREPORT
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#undef PACKAGE_NAME
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#undef PACKAGE_STRING
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#undef PACKAGE_TARNAME
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#undef PACKAGE_URL
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#undef PACKAGE_VERSION
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#undef STDC_HEADERS
|
||||
|
||||
/* Version number of package */
|
||||
#undef VERSION
|
||||
|
||||
/* Enable large inode numbers on Mac OS X 10.5. */
|
||||
#ifndef _DARWIN_USE_64_BIT_INODE
|
||||
# define _DARWIN_USE_64_BIT_INODE 1
|
||||
#endif
|
||||
|
||||
/* Number of bits in a file offset, on hosts where this is settable. */
|
||||
#undef _FILE_OFFSET_BITS
|
||||
|
||||
/* Define for large files, on AIX-style hosts. */
|
||||
#undef _LARGE_FILES
|
|
@ -0,0 +1,66 @@
|
|||
AC_INIT([libopenmpt-modplug], [0.8.9.0-openmpt1], [https://bugs.openmpt.org/], [libopenmpt-modplug], [https://lib.openmpt.org/])
|
||||
AC_PREREQ([2.68])
|
||||
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_AUX_DIR([build-aux])
|
||||
AC_CONFIG_FILES([Makefile libopenmpt_modplug.pc libmodplug.pc])
|
||||
|
||||
AM_INIT_AUTOMAKE([1.11 -Wall -Werror foreign subdir-objects])
|
||||
|
||||
AM_PROG_AR
|
||||
|
||||
LT_INIT
|
||||
|
||||
AC_SYS_LARGEFILE
|
||||
|
||||
PKG_PROG_PKG_CONFIG([0.24])
|
||||
AC_PROG_CC
|
||||
AM_PROG_CC_C_O
|
||||
AC_PROG_CXX
|
||||
AC_PROG_INSTALL
|
||||
|
||||
LIBOPENMPT_REQUIRES_PRIVATE=
|
||||
LIBOPENMPT_LIBS_PRIVATE=
|
||||
|
||||
# We want a modern C compiler
|
||||
AC_PROG_CC_STDC
|
||||
#AC_PROG_CC_C99
|
||||
|
||||
# We need C++11 support
|
||||
AX_CXX_COMPILE_STDCXX(17, [noext], [optional])
|
||||
AS_IF([test "x$HAVE_CXX17" != "x1"],
|
||||
[
|
||||
AX_CXX_COMPILE_STDCXX(14, [noext], [optional])
|
||||
AS_IF([test "x$HAVE_CXX14" != "x1"],
|
||||
[
|
||||
AX_CXX_COMPILE_STDCXX(11, [noext], [mandatory])
|
||||
],[]
|
||||
)
|
||||
],[]
|
||||
)
|
||||
|
||||
AC_LANG_PUSH([C])
|
||||
AX_CHECK_COMPILE_FLAG([-fvisibility=hidden], [CFLAGS="$CFLAGS -fvisibility=hidden -DSYM_VISIBILITY"])
|
||||
AX_CFLAGS_WARN_ALL
|
||||
AC_LANG_POP([C])
|
||||
|
||||
AC_LANG_PUSH([C++])
|
||||
AX_CHECK_COMPILE_FLAG([-fvisibility=hidden], [CXXFLAGS="$CXXFLAGS -fvisibility=hidden -DSYM_VISIBILITY"])
|
||||
AX_CXXFLAGS_WARN_ALL
|
||||
AC_LANG_POP([C++])
|
||||
|
||||
PKG_CHECK_MODULES([LIBOPENMPT], [libopenmpt])
|
||||
|
||||
# libmodplug emulation
|
||||
AC_ARG_ENABLE([libopenmpt_modplug], AS_HELP_STRING([--disable-libopenmpt_modplug], [Disable the libopenmpt_modplug emulation library of the libmodplug interface.]))
|
||||
AM_CONDITIONAL([ENABLE_LIBOPENMPT_MODPLUG], [test "x$enable_libopenmpt_modplug" != "xno"])
|
||||
|
||||
# libmodplug replacement
|
||||
AC_ARG_ENABLE([libmodplug], AS_HELP_STRING([--enable-libmodplug], [Enable libmodplug replacement library based on libopenmpt.
|
||||
WARNING: This will replace your current libmodplug installation.
|
||||
CAUTION: The emulation of the libmodplug interface is not complete as libmodplug exposes lots of internal implementation details. If any of those is used by an application, the emulation via libopenmpt will fail and/or crash.
|
||||
]))
|
||||
AM_CONDITIONAL([ENABLE_LIBMODPLUG], [test "x$enable_libmodplug" = "xyes"])
|
||||
|
||||
AC_OUTPUT
|
9
Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.9.0/dist.sh
Executable file
9
Frameworks/OpenMPT/OpenMPT/contrib/libmodplug-0.8.9.0/dist.sh
Executable file
|
@ -0,0 +1,9 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
./test.sh
|
||||
|
||||
./autogen.sh
|
||||
./configure
|
||||
make dist
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue