Compare commits
1 Commits
master
...
libarchive
Author | SHA1 | Date |
---|---|---|
Martchus | a5b0b0b1e1 |
|
@ -96,6 +96,10 @@ set(CMAKE_TEMPLATE_FILES
|
|||
cmake/templates/global.h.in
|
||||
cmake/templates/version.h.in
|
||||
cmake/templates/template.pc.in)
|
||||
set(SCRIPT_FILES)
|
||||
if (MINGW)
|
||||
list(APPEND SCRIPT_FILES scripts/wine.sh)
|
||||
endif ()
|
||||
if (WIN32)
|
||||
list(APPEND CMAKE_TEMPLATE_FILES cmake/templates/windows.rc.in cmake/templates/windows-cli-wrapper.rc.in
|
||||
cmake/templates/cli-wrapper.cpp)
|
||||
|
@ -117,7 +121,7 @@ set(META_APP_URL "https://github.com/${META_APP_AUTHOR}/${META_PROJECT_NAME}")
|
|||
set(META_APP_DESCRIPTION "Useful C++ classes and routines such as argument parser, IO and conversion utilities")
|
||||
set(META_VERSION_MAJOR 5)
|
||||
set(META_VERSION_MINOR 24)
|
||||
set(META_VERSION_PATCH 9)
|
||||
set(META_VERSION_PATCH 7)
|
||||
|
||||
# find required 3rd party libraries
|
||||
include(3rdParty)
|
||||
|
@ -187,13 +191,27 @@ if (REQUIRED_BOOST_COMPONENTS)
|
|||
endif ()
|
||||
|
||||
# configure required libraries for std::filesystem
|
||||
option(USE_STANDARD_FILESYSTEM "uses std::filesystem; if disabled Bash completion for files and directories is not working"
|
||||
option(USE_STANDARD_FILESYSTEM "uses std::filesystem; if disabled Bash completion for files and directories and archiving utilities are disabled"
|
||||
ON)
|
||||
if (USE_STANDARD_FILESYSTEM)
|
||||
list(APPEND META_PRIVATE_COMPILE_DEFINITIONS ${META_PROJECT_VARNAME}_USE_STANDARD_FILESYSTEM)
|
||||
use_standard_filesystem()
|
||||
else ()
|
||||
message(WARNING "The use of std::filesystem has been disabled. Bash completion for files and directories will not work.")
|
||||
message(WARNING "The use of std::filesystem has been disabled. Bash completion for files and directories will not work and archiving utilities are disabled.")
|
||||
endif ()
|
||||
|
||||
# configure usage of libarchive
|
||||
option(USE_LIBARCHIVE "uses libarchive; if disabled archiving utilities will not be available" OFF)
|
||||
if (USE_LIBARCHIVE)
|
||||
if (NOT USE_STANDARD_FILESYSTEM)
|
||||
message(FATAL_ERROR "Unable to use USE_LIBARCHIVE without USE_STANDARD_FILESYSTEM.")
|
||||
endif ()
|
||||
use_package(TARGET_NAME LibArchive::LibArchive PACKAGE_NAME LibArchive)
|
||||
list(APPEND HEADER_FILES io/archive.h)
|
||||
list(APPEND SRC_FILES io/archive.cpp)
|
||||
list(APPEND META_PUBLIC_COMPILE_DEFINITIONS ${META_PROJECT_VARNAME}_USE_LIBARCHIVE)
|
||||
else ()
|
||||
set(EXCLUDED_FILES io/archive.h io/archive.cpp)
|
||||
endif ()
|
||||
|
||||
# configure whether escape codes should be enabled by default
|
||||
|
|
|
@ -22,23 +22,14 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"name": "clang",
|
||||
"name": "libc++",
|
||||
"inherits": "default",
|
||||
"displayName": "Use clang/clang++",
|
||||
"description": "Enforces use of clang/clang++ even when it is not the system default",
|
||||
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/default-clang",
|
||||
"displayName": "Use clang++ and libc++",
|
||||
"description": "Enforces use of clang++ and libc++ even when it is not the system default",
|
||||
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/default-no-webview",
|
||||
"cacheVariables": {
|
||||
"CMAKE_C_COMPILER": {"type": "STRING", "value": "clang"},
|
||||
"CMAKE_CXX_COMPILER": {"type": "STRING", "value": "clang++"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "libc++",
|
||||
"inherits": "clang",
|
||||
"displayName": "Use clang/clang++ and libc++",
|
||||
"description": "Enforces use of clang/clang++ and libc++ even when it is not the system default",
|
||||
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/default-clang-libc++",
|
||||
"cacheVariables": {
|
||||
"CMAKE_CXX_COMPILER": {"type": "STRING", "value": "clang++"},
|
||||
"CMAKE_CXX_FLAGS": {"type": "STRING", "value": "$env{CXXFLAGS} -stdlib=libc++"}
|
||||
}
|
||||
},
|
||||
|
@ -90,13 +81,6 @@
|
|||
"CONFIGURATION_TARGET_SUFFIX": {"type": "STRING", "value": "devel"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "devel-clang",
|
||||
"inherits": ["devel", "clang"],
|
||||
"displayName": "Development config using clang",
|
||||
"description": "Combination of devel and libc++",
|
||||
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/devel-clang"
|
||||
},
|
||||
{
|
||||
"name": "devel-libc++",
|
||||
"inherits": ["devel", "libc++"],
|
||||
|
@ -132,13 +116,6 @@
|
|||
"CMAKE_UNITY_BUILD": {"type": "BOOL", "value": "ON"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "devel-clang-qt6",
|
||||
"inherits": ["qt6", "devel-clang"],
|
||||
"displayName": "Development config using clang and Qt 6",
|
||||
"description": "Combination of qt6 and devel-clang",
|
||||
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/devel-clang-qt6"
|
||||
},
|
||||
{
|
||||
"name": "devel-libc++-qt6",
|
||||
"inherits": ["qt6", "devel-libc++"],
|
||||
|
@ -185,42 +162,9 @@
|
|||
"CMAKE_INSTALL_PREFIX": {"type": "PATH", "value": "$env{KDE_INSTALL_DIR}"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "arch-*-w64-mingw32",
|
||||
"inherits": ["no-webview", "no-kde"],
|
||||
"environment": {
|
||||
"CPPFLAGS": "-D_FORTIFY_SOURCE=3 -D_GLIBCXX_ASSERTIONS",
|
||||
"CFLAGS": "$env{CPPFLAGS} -O2 -pipe -fno-plt -fexceptions --param=ssp-buffer-size=4 -Wformat -Werror=format-security -fcf-protection",
|
||||
"CXXFLAGS": "$env{CPPFLAGS} -O2 -pipe -fno-plt -fexceptions --param=ssp-buffer-size=4 -Wformat -Werror=format-security -fcf-protection",
|
||||
"LDFLAGS": "-Wl,-O1,--sort-common,--as-needed -fstack-protector"
|
||||
},
|
||||
"cacheVariables": {
|
||||
"BUILD_SHARED_LIBS": {"type": "BOOL", "value": "ON"},
|
||||
"VERSIONED_MINGW_LIBRARIES": {"type": "BOOL", "value": "ON"},
|
||||
"ENABLE_TARGETS_FOR_MINGW_CROSS_PACKAGING": {"type": "BOOL", "value": "ON"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "arch-i686-w64-mingw32",
|
||||
"inherits": "arch-*-w64-mingw32",
|
||||
"displayName": "Target i686-w64-mingw32 using Arch Linux's mingw-w64 packaging",
|
||||
"description": "Build targeting i686-w64-mingw32, paths and flags are specific to Arch Linux's mingw-w64 packaging",
|
||||
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/arch-i686-w64-mingw32",
|
||||
"toolchainFile": "/usr/share/mingw/toolchain-i686-w64-mingw32.cmake",
|
||||
"environment": {
|
||||
"CROSS_TOOL_PREFIX": "i686-w64-mingw32-",
|
||||
"CROSS_INSTALL_PREFIX": "/usr/i686-w64-mingw32",
|
||||
"PATH": "$env{CROSS_INSTALL_PREFIX}/bin:$penv{PATH}"
|
||||
},
|
||||
"cacheVariables": {
|
||||
"CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES": {"type": "PATH", "value": "$env{CROSS_INSTALL_PREFIX}/include"},
|
||||
"CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES": {"type": "PATH", "value": "$env{CROSS_INSTALL_PREFIX}/include"},
|
||||
"CMAKE_CROSSCOMPILING_EMULATOR": {"type": "PATH", "value": "/usr/bin/i686-w64-mingw32-wine"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "arch-x86_64-w64-mingw32",
|
||||
"inherits": "arch-*-w64-mingw32",
|
||||
"inherits": ["no-webview", "no-kde"],
|
||||
"displayName": "Target x86_64-w64-mingw32 using Arch Linux's mingw-w64 packaging",
|
||||
"description": "Build targeting x86_64-w64-mingw32, paths and flags are specific to Arch Linux's mingw-w64 packaging",
|
||||
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/arch-x86_64-w64-mingw32",
|
||||
|
@ -228,28 +172,20 @@
|
|||
"environment": {
|
||||
"CROSS_TOOL_PREFIX": "x86_64-w64-mingw32-",
|
||||
"CROSS_INSTALL_PREFIX": "/usr/x86_64-w64-mingw32",
|
||||
"CPPFLAGS": "-D_FORTIFY_SOURCE=3 -D_GLIBCXX_ASSERTIONS",
|
||||
"CFLAGS": "$env{CPPFLAGS} -O2 -pipe -fno-plt -fexceptions --param=ssp-buffer-size=4 -Wformat -Werror=format-security -fcf-protection",
|
||||
"CXXFLAGS": "$env{CPPFLAGS} -O2 -pipe -fno-plt -fexceptions --param=ssp-buffer-size=4 -Wformat -Werror=format-security -fcf-protection",
|
||||
"LDFLAGS": "-Wl,-O1,--sort-common,--as-needed -fstack-protector",
|
||||
"PATH": "$env{CROSS_INSTALL_PREFIX}/bin:$penv{PATH}"
|
||||
},
|
||||
"cacheVariables": {
|
||||
"BUILD_SHARED_LIBS": {"type": "BOOL", "value": "ON"},
|
||||
"VERSIONED_MINGW_LIBRARIES": {"type": "BOOL", "value": "ON"},
|
||||
"CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES": {"type": "PATH", "value": "$env{CROSS_INSTALL_PREFIX}/include"},
|
||||
"CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES": {"type": "PATH", "value": "$env{CROSS_INSTALL_PREFIX}/include"},
|
||||
"CMAKE_CROSSCOMPILING_EMULATOR": {"type": "PATH", "value": "/usr/bin/x86_64-w64-mingw32-wine"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "arch-i686-w64-mingw32-static",
|
||||
"inherits": "arch-i686-w64-mingw32",
|
||||
"displayName": "Target i686-w64-mingw32 using Arch Linux's mingw-w64 packaging (static)",
|
||||
"description": "Build targeting i686-w64-mingw32, paths and flags are specific to Arch Linux's mingw-w64 packaging",
|
||||
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/arch-i686-w64-mingw32-static",
|
||||
"toolchainFile": "/usr/share/mingw/toolchain-i686-w64-mingw32-static.cmake",
|
||||
"cacheVariables": {
|
||||
"BUILD_SHARED_LIBS": {"type": "BOOL", "value": "OFF"},
|
||||
"CMAKE_FIND_LIBRARY_SUFFIXES": {"type": "STRING", "value": ".a;.lib"},
|
||||
"STATIC_LIBRARY_LINKAGE": {"type": "BOOL", "value": "ON"},
|
||||
"STATIC_LINKAGE": {"type": "BOOL", "value": "ON"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "arch-x86_64-w64-mingw32-static",
|
||||
"inherits": "arch-x86_64-w64-mingw32",
|
||||
|
@ -258,19 +194,9 @@
|
|||
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/arch-x86_64-w64-mingw32-static",
|
||||
"toolchainFile": "/usr/share/mingw/toolchain-x86_64-w64-mingw32-static.cmake",
|
||||
"cacheVariables": {
|
||||
"BUILD_SHARED_LIBS": {"type": "BOOL", "value": "OFF"},
|
||||
"CMAKE_FIND_LIBRARY_SUFFIXES": {"type": "STRING", "value": ".a;.lib"},
|
||||
"STATIC_LIBRARY_LINKAGE": {"type": "BOOL", "value": "ON"},
|
||||
"STATIC_LINKAGE": {"type": "BOOL", "value": "ON"}
|
||||
"BUILD_SHARED_LIBS": {"type": "BOOL", "value": "OFF"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "arch-i686-w64-mingw32-qt6",
|
||||
"inherits": ["qt6", "arch-i686-w64-mingw32"],
|
||||
"displayName": "Combination of qt6 and arch-i686-w64-mingw32",
|
||||
"description": "See description of qt6 and arch-i686-w64-mingw32",
|
||||
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/arch-i686-w64-mingw32-qt6"
|
||||
},
|
||||
{
|
||||
"name": "arch-x86_64-w64-mingw32-qt6",
|
||||
"inherits": ["qt6", "arch-x86_64-w64-mingw32"],
|
||||
|
@ -278,13 +204,6 @@
|
|||
"description": "See description of qt6 and arch-x86_64-w64-mingw32",
|
||||
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/arch-x86_64-w64-mingw32-qt6"
|
||||
},
|
||||
{
|
||||
"name": "arch-i686-w64-mingw32-static-qt6",
|
||||
"inherits": ["qt6", "arch-i686-w64-mingw32-static"],
|
||||
"displayName": "Combination of qt6 and arch-i686-w64-mingw32-static",
|
||||
"description": "See description of qt6 and arch-i686-w64-mingw32-static",
|
||||
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/arch-i686-w64-mingw32-static-qt6"
|
||||
},
|
||||
{
|
||||
"name": "arch-x86_64-w64-mingw32-static-qt6",
|
||||
"inherits": ["qt6", "arch-x86_64-w64-mingw32-static"],
|
||||
|
@ -292,13 +211,6 @@
|
|||
"description": "See description of qt6 and arch-x86_64-w64-mingw32-static",
|
||||
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/arch-x86_64-w64-mingw32-static-qt6"
|
||||
},
|
||||
{
|
||||
"name": "arch-i686-w64-mingw32-devel",
|
||||
"inherits": ["devel", "arch-i686-w64-mingw32"],
|
||||
"displayName": "Combination of devel and arch-i686-w64-mingw32",
|
||||
"description": "See descriptions of devel and arch-i686-w64-mingw32",
|
||||
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/arch-i686-w64-mingw32-devel"
|
||||
},
|
||||
{
|
||||
"name": "arch-x86_64-w64-mingw32-devel",
|
||||
"inherits": ["devel", "arch-x86_64-w64-mingw32"],
|
||||
|
@ -306,34 +218,6 @@
|
|||
"description": "See descriptions of devel and arch-x86_64-w64-mingw32",
|
||||
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/arch-x86_64-w64-mingw32-devel"
|
||||
},
|
||||
{
|
||||
"name": "arch-i686-w64-mingw32-devel-qt6",
|
||||
"inherits": ["qt6", "devel", "arch-i686-w64-mingw32"],
|
||||
"displayName": "Combination of qt6, devel and arch-i686-w64-mingw32",
|
||||
"description": "See descriptions of devel and arch-i686-w64-mingw32",
|
||||
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/arch-i686-w64-mingw32-devel"
|
||||
},
|
||||
{
|
||||
"name": "arch-x86_64-w64-mingw32-devel-qt6",
|
||||
"inherits": ["qt6", "devel", "arch-x86_64-w64-mingw32"],
|
||||
"displayName": "Combination of qt6, devel and arch-x86_64-w64-mingw32",
|
||||
"description": "See descriptions of devel and arch-x86_64-w64-mingw32",
|
||||
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/arch-x86_64-w64-mingw32-devel"
|
||||
},
|
||||
{
|
||||
"name": "arch-i686-w64-mingw32-static-devel-qt6",
|
||||
"inherits": ["qt6", "devel", "arch-i686-w64-mingw32-static"],
|
||||
"displayName": "Combination of qt6, devel and arch-i686-w64-mingw32-static",
|
||||
"description": "See descriptions of devel and arch-i686-w64-mingw32-static",
|
||||
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/arch-i686-w64-mingw32-devel"
|
||||
},
|
||||
{
|
||||
"name": "arch-x86_64-w64-mingw32-static-devel-qt6",
|
||||
"inherits": ["qt6", "devel", "arch-x86_64-w64-mingw32-static"],
|
||||
"displayName": "Combination of qt6, devel and arch-x86_64-w64-mingw32-static",
|
||||
"description": "See descriptions of devel and arch-x86_64-w64-mingw32-static",
|
||||
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/arch-x86_64-w64-mingw32-devel"
|
||||
},
|
||||
{
|
||||
"name": "arch-static-compat",
|
||||
"inherits": ["no-webview", "no-kde", "qt6"],
|
||||
|
@ -382,10 +266,10 @@
|
|||
"description": "Build on Windows targeting x64-windows-static using MSVC, Qt 6 (for Qt libs and CMake/Ninja), vcpkg (for other dependencies) and MSYS2 (for Perl, Go, ffmpeg and other tools)",
|
||||
"binaryDir": "$env{BUILD_DIR}/${sourceDirName}/win-x64-msvc-static",
|
||||
"environment": {
|
||||
|
||||
"INCLUDE": "$env{MSVC_ROOT}/include;$env{MSVC_ROOT}/ATLMFC/include;$env{WIN_KITS_ROOT}/include/$env{WIN_KITS_VERSION}/ucrt;$env{WIN_KITS_ROOT}//include/$env{WIN_KITS_VERSION}//um;$env{WIN_KITS_ROOT}//include/$env{WIN_KITS_VERSION}//shared;$env{WIN_KITS_ROOT}/include/$env{WIN_KITS_VERSION}//winrt;$env{WIN_KITS_ROOT}/include/$env{WIN_KITS_VERSION}//cppwinrt",
|
||||
"LIB": "$env{MSVC_ROOT}/ATLMFC/lib/x64;$env{MSVC_ROOT}/lib/x64;$env{WIN_KITS_ROOT}/lib/$env{WIN_KITS_VERSION}/ucrt/x64;$env{WIN_KITS_ROOT}/lib/$env{WIN_KITS_VERSION}//um/x64",
|
||||
"LIBPATH": "$env{MSVC_ROOT}/ATLMFC/lib/x64;$env{MSVC_ROOT}/lib/x64;$env{WIN_KITS_ROOT}/lib/$env{WIN_KITS_VERSION}/ucrt/x64;$env{WIN_KITS_ROOT}/lib/$env{WIN_KITS_VERSION}/um/x64",
|
||||
"GOROOT": "$env{MSYS2_ROOT}/mingw64/lib/go"
|
||||
"LIBPATH": "$env{MSVC_ROOT}/ATLMFC/lib/x64;$env{MSVC_ROOT}/lib/x64;$env{WIN_KITS_ROOT}/lib/$env{WIN_KITS_VERSION}/ucrt/x64;$env{WIN_KITS_ROOT}/lib/$env{WIN_KITS_VERSION}/um/x64"
|
||||
},
|
||||
"cacheVariables": {
|
||||
"BUILD_SHARED_LIBS": {"type": "BOOL", "value": "OFF"},
|
||||
|
@ -410,6 +294,7 @@
|
|||
"DOXYGEN_BIN": {"type": "FILEPATH", "value": "$env{MSYS2_ROOT}/mingw64/bin/doxygen.exe"},
|
||||
"CLANG_FORMAT_BIN": {"type": "FILEPATH", "value": "$env{MSYS2_ROOT}/mingw64/bin/clang-format.exe"},
|
||||
"GO_BIN": {"type": "FILEPATH", "value": "$env{MSYS2_ROOT}/mingw64/bin/go.exe"},
|
||||
"GOROOT": {"type": "PATH", "value": "$env{MSYS2_ROOT}/mingw64/lib/go"},
|
||||
"FFMPEG_BIN": {"type": "FILEPATH", "value": "$env{MSYS2_ROOT}/mingw64/bin/ffmpeg.exe"},
|
||||
"REALPATH_BIN": {"type": "FILEPATH", "value": "$env{MSYS2_ROOT}/usr/bin/realpath.exe"},
|
||||
"FORCE_EXTERNAL_ICONV": {"type": "BOOL", "value": "ON"},
|
||||
|
@ -449,30 +334,19 @@
|
|||
{"name": "libc++", "configurePreset": "libc++"},
|
||||
{"name": "qt6", "configurePreset": "qt6"},
|
||||
{"name": "devel", "configurePreset": "devel"},
|
||||
{"name": "devel-clang", "configurePreset": "devel-clang"},
|
||||
{"name": "devel-libc++", "configurePreset": "devel-libc++"},
|
||||
{"name": "devel-qt6", "configurePreset": "devel-qt6"},
|
||||
{"name": "devel-unity", "configurePreset": "devel-unity"},
|
||||
{"name": "devel-clang-qt6", "configurePreset": "devel-clang-qt6"},
|
||||
{"name": "devel-libc++-qt6", "configurePreset": "devel-libc++-qt6"},
|
||||
{"name": "debug", "configurePreset": "debug"},
|
||||
{"name": "debug-qt6", "configurePreset": "debug-qt6"},
|
||||
{"name": "debug-kde", "configurePreset": "debug-kde"},
|
||||
{"name": "debug-kde-custom", "configurePreset": "debug-kde-custom"},
|
||||
{"name": "arch-i686-w64-mingw32", "configurePreset": "arch-i686-w64-mingw32"},
|
||||
{"name": "arch-x86_64-w64-mingw32", "configurePreset": "arch-x86_64-w64-mingw32"},
|
||||
{"name": "arch-i686-w64-mingw32-static", "configurePreset": "arch-i686-w64-mingw32-static"},
|
||||
{"name": "arch-x86_64-w64-mingw32-static", "configurePreset": "arch-x86_64-w64-mingw32-static"},
|
||||
{"name": "arch-i686-w64-mingw32-qt6", "configurePreset": "arch-i686-w64-mingw32-qt6"},
|
||||
{"name": "arch-x86_64-w64-mingw32-qt6", "configurePreset": "arch-x86_64-w64-mingw32-qt6"},
|
||||
{"name": "arch-i686-w64-mingw32-static-qt6", "configurePreset": "arch-i686-w64-mingw32-static-qt6"},
|
||||
{"name": "arch-x86_64-w64-mingw32-static-qt6", "configurePreset": "arch-x86_64-w64-mingw32-static-qt6"},
|
||||
{"name": "arch-i686-w64-mingw32-devel", "configurePreset": "arch-i686-w64-mingw32-devel"},
|
||||
{"name": "arch-x86_64-w64-mingw32-devel", "configurePreset": "arch-x86_64-w64-mingw32-devel"},
|
||||
{"name": "arch-i686-w64-mingw32-devel-qt6", "configurePreset": "arch-i686-w64-mingw32-devel-qt6"},
|
||||
{"name": "arch-x86_64-w64-mingw32-devel-qt6", "configurePreset": "arch-x86_64-w64-mingw32-devel-qt6"},
|
||||
{"name": "arch-i686-w64-mingw32-static-devel-qt6", "configurePreset": "arch-i686-w64-mingw32-static-devel-qt6"},
|
||||
{"name": "arch-x86_64-w64-mingw32-static-devel-qt6", "configurePreset": "arch-x86_64-w64-mingw32-static-devel-qt6"},
|
||||
{"name": "arch-static-compat", "configurePreset": "arch-static-compat"},
|
||||
{"name": "arch-static-compat-devel", "configurePreset": "arch-static-compat-devel"},
|
||||
{"name": "win-x64-msvc-static", "configurePreset": "win-x64-msvc-static"},
|
||||
|
|
10
README.md
10
README.md
|
@ -78,6 +78,7 @@ These build instructions apply to `c++utilities` but also to my other projects u
|
|||
* glibc with iconv support or standalone iconv library
|
||||
* libstdc++ or Boost.Iostreams for `NativeFileStream` (optional, use `USE_NATIVE_FILE_BUFFER=OFF` to disable)
|
||||
* Boost.Process for `execApp()` test helper under Windows (optional, use `USE_BOOST_PROCESS=OFF` to disable)
|
||||
* libarchive (optional, for archiving utilities only, use `USE_LIBARCHIVE=ON` to enable)
|
||||
* My other projects have further dependencies such as Qt. Checkout the README of these
|
||||
projects for further details.
|
||||
|
||||
|
@ -117,8 +118,9 @@ building on Windows.
|
|||
* If thread local storage is not supported by your compiler/platform (might be the case on MacOS), you can
|
||||
disable making use of it via `ENABLE_THREAD_LOCAL=OFF`.
|
||||
* To disable use of `std::filesystem`, set `USE_STANDARD_FILESYSTEM=OFF`. Note that the Bash completion will
|
||||
not be able to suggest files and directories with `USE_STANDARD_FILESYSTEM=OFF`. Note that this will only
|
||||
help with `c++utilities` itself. My other projects might use `std::filesystem` unconditionally.
|
||||
not be able to suggest files and directories and the archiving utilities cannot be enabled with
|
||||
`USE_STANDARD_FILESYSTEM=OFF`. Note that this will only help with `c++utilities` itself. My other projects
|
||||
might use `std::filesystem` unconditionally.
|
||||
* To disable `NativeFileStream` (and make it just a regular `std::fstream`), set `USE_NATIVE_FILE_BUFFER=OFF`.
|
||||
Note that handling paths with non-ASCII characters will then cease to work on Windows.
|
||||
* The Qt-based applications support bundeling icon themes by specifying e.g.
|
||||
|
@ -202,7 +204,7 @@ Run the following commands to build one of my applications and its `c++utilities
|
|||
in one go (in this example Syncthing Tray):
|
||||
```
|
||||
# install dependencies; you may strip down this list depending on the application and features to enable
|
||||
pacman -Syu git perl-YAML mingw-w64-x86_64-gcc mingw-w64-x86_64-ccache mingw-w64-x86_64-cmake mingw-w64-x86_64-boost mingw-w64-x86_64-cppunit mingw-w64-x86_64-qt6-base mingw-w64-x86_64-qt6-declarative mingw-w64-x86_64-qt6-tools mingw-w64-x86_64-qt6-svg mingw-w64-x86_64-clang-tools-extra mingw-w64-x86_64-doxygen mingw-w64-x86_64-ffmpeg mingw-w64-x86_64-go
|
||||
pacman -Syu git perl-YAML mingw-w64-x86_64-gcc mingw-w64-x86_64-ccache mingw-w64-x86_64-cmake mingw-w64-x86_64-boost mingw-w64-x86_64-cppunit mingw-w64-x86_64-qt6-base mingw-w64-x86_64-qt6-declarative mingw-w64-x86_64-qt6-tools mingw-w64-x86_64-qt6-svg mingw-w64-x86_64-clang-tools-extra mingw-w64-x86_64-doxygen mingw-w64-x86_64-ffmpeg mingw-w64-x86_64-go mingw-w64-x86_64-libarchive
|
||||
|
||||
# clone repositories as mentioned under "Building this straight" in the application's README file
|
||||
cd /path/to/store/sources
|
||||
|
@ -268,7 +270,7 @@ various additional environment variables to be set and you need to install depen
|
|||
* `QT_TOOLS`: for additional build tools provided by the official Qt installer, e.g. `D:/programming/qt/Tools`
|
||||
* `VCPKG_ROOT`: directory of VCPKG checkout used for other dependencies; install the following packages:
|
||||
```
|
||||
vcpkg install boost-system:x64-windows-static boost-iostreams:x64-windows-static boost-filesystem:x64-windows-static boost-hana:x64-windows-static boost-process:x64-windows-static boost-asio:x64-windows-static libiconv:x64-windows-static zlib:x64-windows-static openssl:x64-windows-static cppunit:x64-windows-static
|
||||
vcpkg install boost-system:x64-windows-static boost-iostreams:x64-windows-static boost-filesystem:x64-windows-static boost-hana:x64-windows-static boost-process:x64-windows-static boost-asio:x64-windows-static libiconv:x64-windows-static zlib:x64-windows-static openssl:x64-windows-static cppunit:x64-windows-static libarchive'[bzip2,crypto,zstd]':x64-windows-static
|
||||
```
|
||||
|
||||
When building with MSVC, do *not* use any of the MSYS2 shells. The environment of those shells leads to
|
||||
|
|
|
@ -1799,7 +1799,7 @@ void ValueConversion::Helper::ArgumentValueConversionError::throwFailure(const s
|
|||
throw ParseError(argumentPath.empty()
|
||||
? argsToString("Conversion of top-level value \"", valueToConvert, "\" to type \"", targetTypeName, "\" failed: ", errorMessage)
|
||||
: argsToString("Conversion of value \"", valueToConvert, "\" (for argument --", argumentPath.back()->name(), ") to type \"",
|
||||
targetTypeName, "\" failed: ", errorMessage));
|
||||
targetTypeName, "\" failed: ", errorMessage));
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -1810,7 +1810,7 @@ void ArgumentOccurrence::throwNumberOfValuesNotSufficient(unsigned long valuesTo
|
|||
throw ParseError(path.empty()
|
||||
? argsToString("Expected ", valuesToConvert, " top-level values to be present but only ", values.size(), " have been specified.")
|
||||
: argsToString("Expected ", valuesToConvert, " values for argument --", path.back()->name(), " to be present but only ", values.size(),
|
||||
" have been specified."));
|
||||
" have been specified."));
|
||||
}
|
||||
|
||||
} // namespace CppUtilities
|
||||
|
|
|
@ -881,7 +881,7 @@ inline void Argument::setFlags(Argument::Flags flags, bool add)
|
|||
{
|
||||
m_flags = add ? (m_flags | flags)
|
||||
: static_cast<Argument::Flags>(static_cast<std::underlying_type<Argument::Flags>::type>(m_flags)
|
||||
& ~static_cast<std::underlying_type<Argument::Flags>::type>(flags));
|
||||
& ~static_cast<std::underlying_type<Argument::Flags>::type>(flags));
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace CppUtilities {
|
|||
*/
|
||||
FakeQtConfigArguments::FakeQtConfigArguments()
|
||||
: m_qtWidgetsGuiArg(
|
||||
"qt-widgets-gui", 'g', "shows a Qt widgets based graphical user interface (the application has not been built with Qt widgets support)")
|
||||
"qt-widgets-gui", 'g', "shows a Qt widgets based graphical user interface (the application has not been built with Qt widgets support)")
|
||||
, m_qtQuickGuiArg(
|
||||
"qt-quick-gui", 'q', "shows a Qt quick based graphical user interface (the application has not been built with Qt quick support)")
|
||||
{
|
||||
|
|
|
@ -63,7 +63,7 @@ function (add_appstream_file)
|
|||
endif ()
|
||||
|
||||
# create appstream desktop file from template
|
||||
set(APPSTREAM_FILE "${CMAKE_CURRENT_BINARY_DIR}/resources/${META_ID}.metainfo.xml")
|
||||
set(APPSTREAM_FILE "${CMAKE_CURRENT_BINARY_DIR}/resources/${META_ID}.appdata.xml")
|
||||
configure_file("${APP_APPSTREAM_TEMPLATE_FILE}" "${APPSTREAM_FILE}" @ONLY)
|
||||
|
||||
# add install for the appstream file
|
||||
|
|
|
@ -191,39 +191,18 @@ if (NOT META_PROJECT_LICENSE)
|
|||
endif ()
|
||||
endif ()
|
||||
|
||||
# determine RDNS automatically from other meta-data and allow override
|
||||
set(${META_PROJECT_VARNAME_UPPER}_RDNS_OVERRIDE
|
||||
""
|
||||
CACHE STRING "overrides the RDNS used in AppStream meta-data files for ${META_PROJECT_NAME}")
|
||||
if (${META_PROJECT_VARNAME_UPPER}_RDNS_OVERRIDE)
|
||||
set(META_PROJECT_RDNS ${${META_PROJECT_VARNAME_UPPER}_RDNS_OVERRIDE})
|
||||
endif ()
|
||||
set(${META_PROJECT_VARNAME_UPPER}_DEVELOPER_ID_OVERRIDE
|
||||
""
|
||||
CACHE STRING "overrides the developer ID used in AppStream meta-data files for ${META_PROJECT_NAME}")
|
||||
if (${META_PROJECT_VARNAME_UPPER}_DEVELOPER_ID_OVERRIDE)
|
||||
set(META_DEVELOPER_ID ${${META_PROJECT_VARNAME_UPPER}_DEVELOPER_ID_OVERRIDE})
|
||||
endif ()
|
||||
if (${META_PROJECT_VARNAME_UPPER}_RDNS_OVERRIDE OR ${META_PROJECT_VARNAME_UPPER}_DEVELOPER_ID_OVERRIDE)
|
||||
message(
|
||||
WARNING
|
||||
"Overriding the RDNS or developer ID is NOT recommended. This feature is only intended to ease "
|
||||
"transitioning when a change is required and to create alternative packaging for development and private use.")
|
||||
endif ()
|
||||
if (NOT META_PROJECT_RDNS OR NOT META_DEVELOPER_ID)
|
||||
string(TOLOWER "${META_APP_AUTHOR}" META_APP_AUTHOR_LOWER)
|
||||
# determine RDNS automatically from other meta-data
|
||||
if (NOT META_PROJECT_RDNS)
|
||||
if (NOT META_PROJECT_RDNS_BASE)
|
||||
if (META_APP_URL MATCHES ".*github\\.(com|io).*")
|
||||
if (META_APP_URL MATCHES ".*github\\.com.*")
|
||||
set(META_PROJECT_RDNS_BASE "io.github") # assume GitHub pages
|
||||
else ()
|
||||
set(META_PROJECT_RDNS_BASE "org")
|
||||
endif ()
|
||||
endif ()
|
||||
string(TOLOWER "${META_APP_AUTHOR}" META_APP_AUTHOR_LOWER)
|
||||
set(META_PROJECT_RDNS "${META_PROJECT_RDNS_BASE}.${META_APP_AUTHOR_LOWER}.${META_PROJECT_NAME}${TARGET_SUFFIX}")
|
||||
endif ()
|
||||
if (NOT META_DEVELOPER_ID)
|
||||
set(META_DEVELOPER_ID "${META_PROJECT_RDNS_BASE}.${META_APP_AUTHOR_LOWER}")
|
||||
endif ()
|
||||
|
||||
# provide variables for other projects built as part of the same subdirs project to access files from this project
|
||||
get_directory_property(HAS_PARENT PARENT_DIRECTORY)
|
||||
|
|
|
@ -59,7 +59,7 @@ function (configure_development_warnings)
|
|||
option(TREAT_WARNINGS_AS_ERRORS "adds additional compiler flag to treat warnings as errors" "${ENABLE_DEVEL_DEFAULTS}")
|
||||
if (TREAT_WARNINGS_AS_ERRORS)
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES ".*Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
list(APPEND COMPILE_OPTIONS_TO_CONFIGURE -Werror -Wno-error=address)
|
||||
list(APPEND COMPILE_OPTIONS_TO_CONFIGURE -Werror)
|
||||
else ()
|
||||
message(AUTHOR_WARNING "Treating warnings as errors is not supported for compiler '${CMAKE_CXX_COMPILER_ID}'.")
|
||||
endif ()
|
||||
|
|
|
@ -52,10 +52,9 @@ function (configure_test_target)
|
|||
PRIVATE "${ARGS_LIBRARIES}" "${PRIVATE_LIBRARIES}")
|
||||
target_include_directories(
|
||||
"${TEST_TARGET_NAME}"
|
||||
PUBLIC $<BUILD_INTERFACE:${TARGET_INCLUDE_DIRECTORY_BUILD_INTERFACE}>
|
||||
$<BUILD_INTERFACE:${TARGET_GENERATED_INCLUDE_DIRECTORY}> $<INSTALL_INTERFACE:${HEADER_INSTALL_DESTINATION}>
|
||||
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> $<INSTALL_INTERFACE:${HEADER_INSTALL_DESTINATION}>
|
||||
${PUBLIC_INCLUDE_DIRS}
|
||||
PRIVATE ${TEST_INCLUDE_DIRS} ${PRIVATE_INCLUDE_DIRS})
|
||||
PRIVATE ${TEST_INCLUDE_DIRS} "${PRIVATE_INCLUDE_DIRS}")
|
||||
target_compile_definitions(
|
||||
"${TEST_TARGET_NAME}"
|
||||
PUBLIC "${META_PUBLIC_COMPILE_DEFINITIONS}"
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<url type="homepage">@META_APP_URL@</url>
|
||||
<url type="bugtracker">@META_APP_BUGTRACKER_URL@</url>
|
||||
<launchable type="desktop-id">@META_ID@.desktop</launchable>
|
||||
<developer id="@META_DEVELOPER_ID@"><name>@META_APP_AUTHOR@</name></developer>
|
||||
<developer><name>@META_APP_AUTHOR@</name></developer>
|
||||
<provides>
|
||||
<binary>@META_TARGET_NAME@</binary>
|
||||
</provides>
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#define PROJECT_CONFIG_SUFFIX "@META_CONFIG_SUFFIX@"
|
||||
#define PROJECT_CONFIG_TARGET_SUFFIX "@TARGET_SUFFIX@"
|
||||
#define APP_NAME "@META_APP_NAME@"
|
||||
#define APP_ID "@META_ID@"
|
||||
#define APP_VERSION "@META_APP_VERSION@"
|
||||
#define APP_VERSION_MAJOR @META_VERSION_MAJOR@
|
||||
#define APP_VERSION_MINOR @META_VERSION_MINOR@
|
||||
|
|
|
@ -168,11 +168,11 @@ CPP_UTILITIES_EXPORT inline void getBytes24(std::uint32_t value, char *outputbuf
|
|||
#if CONVERSION_UTILITIES_BINARY_CONVERSION_INTERNAL == 0
|
||||
outputbuffer[0] = static_cast<char>((value >> 16) & 0xFF);
|
||||
outputbuffer[1] = static_cast<char>((value >> 8) & 0xFF);
|
||||
outputbuffer[2] = static_cast<char>((value) & 0xFF);
|
||||
outputbuffer[2] = static_cast<char>((value)&0xFF);
|
||||
#else
|
||||
outputbuffer[2] = static_cast<char>((value >> 16) & 0xFF);
|
||||
outputbuffer[1] = static_cast<char>((value >> 8) & 0xFF);
|
||||
outputbuffer[0] = static_cast<char>((value) & 0xFF);
|
||||
outputbuffer[0] = static_cast<char>((value)&0xFF);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -16,16 +16,16 @@ template <class StringType, class ViewType> using IsStringViewType = std::is_sam
|
|||
template <class StringType, class CharType> using IsCharType = std::is_same<typename StringType::value_type, CharType>;
|
||||
namespace Detail {
|
||||
template <typename StringType, typename T>
|
||||
auto IsStringType(
|
||||
int) -> decltype(std::declval<StringType &>().append(std::declval<const T &>()), std::declval<const T &>().size(), Traits::Bool<true>{});
|
||||
auto IsStringType(int)
|
||||
-> decltype(std::declval<StringType &>().append(std::declval<const T &>()), std::declval<const T &>().size(), Traits::Bool<true>{});
|
||||
template <typename StringType, typename T> Traits::Bool<false> IsStringType(...);
|
||||
template <typename StringType> void functionTakingConstStringRef(const StringType &str);
|
||||
template <typename StringType, typename T>
|
||||
auto IsConvertibleToConstStringRef(int) -> decltype(functionTakingConstStringRef<StringType>(std::declval<const T &>()), Traits::Bool<true>{});
|
||||
template <typename StringType, typename T> Traits::Bool<false> IsConvertibleToConstStringRef(...);
|
||||
template <typename StringType, typename T>
|
||||
auto IsConvertibleToConstStringRefViaNative(
|
||||
int) -> decltype(functionTakingConstStringRef<StringType>(std::declval<const T &>().native()), Traits::Bool<true>{});
|
||||
auto IsConvertibleToConstStringRefViaNative(int)
|
||||
-> decltype(functionTakingConstStringRef<StringType>(std::declval<const T &>().native()), Traits::Bool<true>{});
|
||||
template <typename StringType, typename T> Traits::Bool<false> IsConvertibleToConstStringRefViaNative(...);
|
||||
} // namespace Detail
|
||||
template <typename StringType, typename StringType2>
|
||||
|
|
|
@ -0,0 +1,225 @@
|
|||
#include "./archive.h"
|
||||
|
||||
#include "../conversion/stringbuilder.h"
|
||||
#include "../io/misc.h"
|
||||
|
||||
#include <archive.h>
|
||||
#include <archive_entry.h>
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
using namespace CppUtilities;
|
||||
|
||||
namespace CppUtilities {
|
||||
|
||||
/*!
|
||||
* \brief Destroys the ArchiveException.
|
||||
*/
|
||||
ArchiveException::~ArchiveException()
|
||||
{
|
||||
}
|
||||
|
||||
/// \cond
|
||||
///
|
||||
struct AddDirectoryToFileMap {
|
||||
bool operator()(std::string_view path)
|
||||
{
|
||||
fileMap[std::string(path)];
|
||||
return false;
|
||||
}
|
||||
FileMap &fileMap;
|
||||
};
|
||||
|
||||
struct AddFileToFileMap {
|
||||
bool operator()(std::string_view directoryPath, ArchiveFile &&file)
|
||||
{
|
||||
fileMap[std::string(directoryPath)].emplace_back(std::move(file));
|
||||
return false;
|
||||
}
|
||||
FileMap &fileMap;
|
||||
};
|
||||
|
||||
void walkThroughArchiveInternal(struct archive *ar, std::string_view archiveName, const FilePredicate &isFileRelevant, FileHandler &&fileHandler,
|
||||
DirectoryHandler &&directoryHandler)
|
||||
{
|
||||
// iterate through all archive entries
|
||||
struct archive_entry *const entry = archive_entry_new();
|
||||
auto fileContent = std::string();
|
||||
while (archive_read_next_header2(ar, entry) == ARCHIVE_OK) {
|
||||
// check entry type (only dirs, files and symlinks relevant here)
|
||||
const auto entryType(archive_entry_filetype(entry));
|
||||
if (entryType != AE_IFDIR && entryType != AE_IFREG && entryType != AE_IFLNK) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// get file path
|
||||
const char *filePath = archive_entry_pathname_utf8(entry);
|
||||
if (!filePath) {
|
||||
filePath = archive_entry_pathname(entry);
|
||||
}
|
||||
if (!filePath) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// get permissions
|
||||
const mode_t perm = archive_entry_perm(entry);
|
||||
|
||||
// add directories explicitly to get the entire tree though skipping irrelevant files
|
||||
if (entryType == AE_IFDIR) {
|
||||
// remove trailing slashes
|
||||
const char *dirEnd = filePath;
|
||||
for (const char *i = filePath; *i; ++i) {
|
||||
if (*i != '/') {
|
||||
dirEnd = i + 1;
|
||||
}
|
||||
}
|
||||
if (directoryHandler(std::string_view(filePath, static_cast<std::size_t>(dirEnd - filePath)))) {
|
||||
goto free;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// split the path into dir and fileName
|
||||
const char *fileName = filePath, *dirEnd = filePath;
|
||||
for (const char *i = filePath; *i; ++i) {
|
||||
if (*i == '/') {
|
||||
fileName = i + 1;
|
||||
dirEnd = i;
|
||||
}
|
||||
}
|
||||
|
||||
// prevent looking into irrelevant files
|
||||
if (isFileRelevant && !isFileRelevant(filePath, fileName, perm)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// read timestamps
|
||||
const auto creationTime = DateTime::fromTimeStampGmt(archive_entry_ctime(entry));
|
||||
const auto modificationTime = DateTime::fromTimeStampGmt(archive_entry_mtime(entry));
|
||||
|
||||
// read symlink
|
||||
if (entryType == AE_IFLNK) {
|
||||
if (fileHandler(std::string_view(filePath, static_cast<std::string::size_type>(dirEnd - filePath)),
|
||||
ArchiveFile(fileName, std::string(archive_entry_symlink_utf8(entry)), ArchiveFileType::Link, creationTime, modificationTime))) {
|
||||
goto free;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// determine file size to pre-allocate buffer for file content
|
||||
const la_int64_t fileSize = archive_entry_size(entry);
|
||||
fileContent.clear();
|
||||
if (fileSize > 0) {
|
||||
fileContent.reserve(static_cast<std::string::size_type>(fileSize));
|
||||
}
|
||||
|
||||
// read file content
|
||||
const char *buff;
|
||||
auto size = std::size_t();
|
||||
auto offset = la_int64_t();
|
||||
for (;;) {
|
||||
const auto returnCode = archive_read_data_block(ar, reinterpret_cast<const void **>(&buff), &size, &offset);
|
||||
if (returnCode == ARCHIVE_EOF || returnCode < ARCHIVE_OK) {
|
||||
break;
|
||||
}
|
||||
fileContent.append(buff, size);
|
||||
}
|
||||
|
||||
// move it to results
|
||||
if (fileHandler(std::string_view(filePath, static_cast<std::string::size_type>(dirEnd - filePath)),
|
||||
ArchiveFile(fileName, std::move(fileContent), ArchiveFileType::Regular, creationTime, modificationTime))) {
|
||||
goto free;
|
||||
}
|
||||
}
|
||||
|
||||
// free resources used by libarchive
|
||||
free:
|
||||
archive_entry_free(entry);
|
||||
const auto returnCode = archive_read_free(ar);
|
||||
if (returnCode != ARCHIVE_OK) {
|
||||
throw ArchiveException(argsToString("Unable to free archive: ", archiveName));
|
||||
}
|
||||
}
|
||||
|
||||
/// \endcond
|
||||
|
||||
/*!
|
||||
* \brief Invokes callbacks for files and directories in the specified archive.
|
||||
*/
|
||||
void walkThroughArchiveFromBuffer(std::string_view archiveData, std::string_view archiveName, const FilePredicate &isFileRelevant,
|
||||
FileHandler &&fileHandler, DirectoryHandler &&directoryHandler)
|
||||
{
|
||||
// refuse opening empty buffer
|
||||
if (archiveData.empty()) {
|
||||
throw ArchiveException("Unable to open archive \"" % archiveName + "\": archive data is empty");
|
||||
}
|
||||
// open archive buffer using libarchive
|
||||
struct archive *ar = archive_read_new();
|
||||
archive_read_support_filter_all(ar);
|
||||
archive_read_support_format_all(ar);
|
||||
const auto returnCode = archive_read_open_memory(ar, archiveData.data(), archiveData.size());
|
||||
if (returnCode != ARCHIVE_OK) {
|
||||
archive_read_free(ar);
|
||||
if (const char *const error = archive_error_string(ar)) {
|
||||
throw ArchiveException("Unable to open/read archive \"" % archiveName % "\": " + error);
|
||||
} else {
|
||||
throw ArchiveException("Unable to open/read archive \"" % archiveName + "\": unable to open archive from memory");
|
||||
}
|
||||
}
|
||||
walkThroughArchiveInternal(ar, archiveName, isFileRelevant, std::move(fileHandler), std::move(directoryHandler));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Extracts the specified archive.
|
||||
*/
|
||||
FileMap extractFilesFromBuffer(std::string_view archiveData, std::string_view archiveName, const FilePredicate &isFileRelevant)
|
||||
{
|
||||
auto results = FileMap();
|
||||
walkThroughArchiveFromBuffer(archiveData, archiveName, isFileRelevant, AddFileToFileMap{ results }, AddDirectoryToFileMap{ results });
|
||||
return results;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Invokes callbacks for files and directories in the specified archive.
|
||||
*/
|
||||
void walkThroughArchive(
|
||||
std::string_view archivePath, const FilePredicate &isFileRelevant, FileHandler &&fileHandler, DirectoryHandler &&directoryHandler)
|
||||
{
|
||||
// open archive file using libarchive
|
||||
if (archivePath.empty()) {
|
||||
throw ArchiveException("Unable to open archive: no path specified");
|
||||
}
|
||||
auto ec = std::error_code();
|
||||
auto size = std::filesystem::file_size(archivePath, ec);
|
||||
if (ec) {
|
||||
throw ArchiveException("Unable to determine size of \"" % archivePath % "\": " + ec.message());
|
||||
}
|
||||
if (!size) {
|
||||
throw ArchiveException("Unable to open archive \"" % archivePath + "\": file is empty");
|
||||
}
|
||||
struct archive *ar = archive_read_new();
|
||||
archive_read_support_filter_all(ar);
|
||||
archive_read_support_format_all(ar);
|
||||
const auto returnCode = archive_read_open_filename(ar, archivePath.data(), 10240);
|
||||
if (returnCode != ARCHIVE_OK) {
|
||||
archive_read_free(ar);
|
||||
if (const char *const error = archive_error_string(ar)) {
|
||||
throw ArchiveException("Unable to open/read archive \"" % archivePath % "\": " + error);
|
||||
} else {
|
||||
throw ArchiveException("Unable to open/read archive \"" % archivePath + "\": unable to open archive from file");
|
||||
}
|
||||
}
|
||||
walkThroughArchiveInternal(ar, archivePath, isFileRelevant, std::move(fileHandler), std::move(directoryHandler));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Extracts the specified archive.
|
||||
*/
|
||||
FileMap extractFiles(std::string_view archivePath, const FilePredicate &isFileRelevant)
|
||||
{
|
||||
auto results = FileMap();
|
||||
walkThroughArchive(archivePath, isFileRelevant, AddFileToFileMap{ results }, AddDirectoryToFileMap{ results });
|
||||
return results;
|
||||
}
|
||||
|
||||
} // namespace CppUtilities
|
|
@ -0,0 +1,88 @@
|
|||
#ifndef CPP_UTILITIES_ARCHIVE_H
|
||||
#define CPP_UTILITIES_ARCHIVE_H
|
||||
|
||||
#include "../chrono/datetime.h"
|
||||
#include "../global.h"
|
||||
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
namespace CppUtilities {
|
||||
|
||||
/*!
|
||||
* \class ArchiveException
|
||||
* \brief The ArchiveException class is thrown by the various archiving-related
|
||||
* functions of this library when a conversion error occurs.
|
||||
*/
|
||||
class CPP_UTILITIES_EXPORT ArchiveException : public std::runtime_error {
|
||||
public:
|
||||
explicit ArchiveException() noexcept;
|
||||
explicit ArchiveException(std::string_view what) noexcept;
|
||||
~ArchiveException() override;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Constructs a new ArchiveException.
|
||||
*/
|
||||
inline ArchiveException::ArchiveException() noexcept
|
||||
: std::runtime_error("unable to convert")
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructs a new ArchiveException.
|
||||
*/
|
||||
inline ArchiveException::ArchiveException(std::string_view what) noexcept
|
||||
: std::runtime_error(what.data())
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief The ArchiveFileType enum specifies the type of a file within an archive.
|
||||
*/
|
||||
enum class ArchiveFileType { Regular, Link };
|
||||
|
||||
/*!
|
||||
* \brief The ArchiveFile class holds data about a file within an archive.
|
||||
*/
|
||||
struct CPP_UTILITIES_EXPORT ArchiveFile {
|
||||
explicit ArchiveFile(
|
||||
std::string &&name, std::string &&content, ArchiveFileType type, CppUtilities::DateTime creationTime, CppUtilities::DateTime modificationTime)
|
||||
: name(name)
|
||||
, content(content)
|
||||
, creationTime(creationTime)
|
||||
, modificationTime(modificationTime)
|
||||
, type(type)
|
||||
{
|
||||
}
|
||||
std::string name;
|
||||
std::string content;
|
||||
CppUtilities::DateTime creationTime;
|
||||
CppUtilities::DateTime modificationTime;
|
||||
ArchiveFileType type;
|
||||
};
|
||||
|
||||
/// \brief A map of files extracted from an archive. Keys represent directories and values files within those directories.
|
||||
using FileMap = std::map<std::string, std::vector<ArchiveFile>>;
|
||||
/// \brief A function that is invoked for each file within an archive. If it returns true, the file is considered; otherwise the file is ignored.
|
||||
using FilePredicate = std::function<bool(const char *, const char *, mode_t)>;
|
||||
/// \brief A function that is invoked by the walk-through-functions to return a directory.
|
||||
using DirectoryHandler = std::function<bool(std::string_view path)>;
|
||||
/// \brief A function that is invoked by the walk-through-functions to return a file.
|
||||
using FileHandler = std::function<bool(std::string_view path, ArchiveFile &&file)>;
|
||||
|
||||
CPP_UTILITIES_EXPORT FileMap extractFiles(std::string_view archivePath, const FilePredicate &isFileRelevant = FilePredicate());
|
||||
CPP_UTILITIES_EXPORT void walkThroughArchive(std::string_view archivePath, const FilePredicate &isFileRelevant = FilePredicate(),
|
||||
FileHandler &&fileHandler = FileHandler(), DirectoryHandler &&directoryHandler = DirectoryHandler());
|
||||
CPP_UTILITIES_EXPORT FileMap extractFilesFromBuffer(std::string_view archiveData, std::string_view archiveName, const FilePredicate &isFileRelevant = FilePredicate());
|
||||
CPP_UTILITIES_EXPORT void walkThroughArchiveFromBuffer(std::string_view archiveData, std::string_view archiveName,
|
||||
const FilePredicate &isFileRelevant = FilePredicate(), FileHandler &&fileHandler = FileHandler(),
|
||||
DirectoryHandler &&directoryHandler = DirectoryHandler());
|
||||
|
||||
} // namespace CppUtilities
|
||||
|
||||
#endif // CPP_UTILITIES_ARCHIVE_H
|
Binary file not shown.
|
@ -1,5 +1,7 @@
|
|||
#include "./testutils.h"
|
||||
|
||||
using namespace CppUtilities;
|
||||
|
||||
#include "../conversion/stringconversion.h"
|
||||
|
||||
/*!
|
||||
|
@ -32,6 +34,10 @@ std::ostream &operator<<(std::ostream &out, const std::wstring &s)
|
|||
#include "../io/nativefilestream.h"
|
||||
#include "../io/path.h"
|
||||
|
||||
#ifdef CPP_UTILITIES_USE_LIBARCHIVE
|
||||
#include "../io/archive.h"
|
||||
#endif
|
||||
|
||||
#include <cppunit/TestFixture.h>
|
||||
#include <cppunit/extensions/HelperMacros.h>
|
||||
|
||||
|
@ -50,7 +56,6 @@ std::ostream &operator<<(std::ostream &out, const std::wstring &s)
|
|||
#endif
|
||||
|
||||
using namespace std;
|
||||
using namespace CppUtilities;
|
||||
using namespace CppUtilities::Literals;
|
||||
using namespace CPPUNIT_NS;
|
||||
|
||||
|
@ -73,6 +78,9 @@ class IoTests : public TestFixture {
|
|||
CPPUNIT_TEST(testAnsiEscapeCodes);
|
||||
#ifdef CPP_UTILITIES_USE_NATIVE_FILE_BUFFER
|
||||
CPPUNIT_TEST(testNativeFileStream);
|
||||
#endif
|
||||
#ifdef CPP_UTILITIES_USE_LIBARCHIVE
|
||||
CPPUNIT_TEST(testExtractingArchive);
|
||||
#endif
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
|
@ -95,6 +103,9 @@ public:
|
|||
#ifdef CPP_UTILITIES_USE_NATIVE_FILE_BUFFER
|
||||
void testNativeFileStream();
|
||||
#endif
|
||||
#ifdef CPP_UTILITIES_USE_LIBARCHIVE
|
||||
void testExtractingArchive();
|
||||
#endif
|
||||
};
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(IoTests);
|
||||
|
@ -769,3 +780,31 @@ void IoTests::testNativeFileStream()
|
|||
CPPUNIT_ASSERT_EQUAL("barfoo"s, readFile(txtFilePath, 7));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CPP_UTILITIES_USE_LIBARCHIVE
|
||||
void IoTests::testExtractingArchive()
|
||||
{
|
||||
const auto archivePath = testFilePath("test.zip");
|
||||
const auto archiveContents = extractFiles(archivePath);
|
||||
const auto &root = archiveContents.at(std::string());
|
||||
const auto &subdir = archiveContents.at("subdir");
|
||||
const auto &subsubdir = archiveContents.at("subdir/foo");
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(1_st, root.size());
|
||||
CPPUNIT_ASSERT_EQUAL("test.txt"s, root.at(0).name);
|
||||
CPPUNIT_ASSERT_EQUAL(ArchiveFileType::Regular, root.at(0).type);
|
||||
CPPUNIT_ASSERT_EQUAL(DateTime::fromDate(1970, 1, 1), root.at(0).creationTime);
|
||||
CPPUNIT_ASSERT_EQUAL(DateTime::fromDateAndTime(2024, 3, 3, 19, 46, 42), root.at(0).modificationTime);
|
||||
CPPUNIT_ASSERT_EQUAL("testfile\n"s, root.at(0).content);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(1_st, subdir.size());
|
||||
CPPUNIT_ASSERT_EQUAL("nested-testfile.txt"s, subdir.at(0).name);
|
||||
CPPUNIT_ASSERT_EQUAL(ArchiveFileType::Regular, subdir.at(0).type);
|
||||
CPPUNIT_ASSERT_EQUAL("some file\n"s, subdir.at(0).content);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(1_st, subsubdir.size());
|
||||
CPPUNIT_ASSERT_EQUAL("bar"s, subsubdir.at(0).name);
|
||||
CPPUNIT_ASSERT_EQUAL(ArchiveFileType::Regular, subsubdir.at(0).type);
|
||||
CPPUNIT_ASSERT_EQUAL(std::string(), subsubdir.at(0).content);
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue