From 7ee008e150bc5bcf76082d726f719ee0fdfda982 Mon Sep 17 00:00:00 2001 From: SulfurNitride Date: Wed, 11 Feb 2026 02:37:39 -0600 Subject: Fluorine Manager: full Linux port of Mod Organizer 2 Complete native Linux port with FUSE-based virtual filesystem, Proton/umu-run integration, and Flatpak packaging. Key features: - FUSE VFS replacing Windows USVFS (in-process + standalone helper for Flatpak) - Proton/GE-Proton/umu-run launcher with env var forwarding - Flatpak support (sandbox-aware VFS, NXM handler, umu-run) - Wine prefix management UI - Case-insensitive path resolution for Linux filesystems - QSettings-safe INI handling (avoids Bethesda INI corruption) - Portable instance support with auto-generated launcher scripts Co-Authored-By: Claude Opus 4.6 --- libs/archive/.clang-format | 41 ++ libs/archive/.git-blame-ignore-revs | 1 + libs/archive/.gitattributes | 7 + libs/archive/.github/workflows/build.yml | 39 ++ libs/archive/.github/workflows/linting.yml | 16 + libs/archive/.gitignore | 5 + libs/archive/.pre-commit-config.yaml | 20 + libs/archive/CMakeLists.txt | 37 + libs/archive/CMakePresets.json | 74 ++ libs/archive/LICENSE | 165 +++++ libs/archive/README.md | 239 +++++++ libs/archive/cmake/config.cmake.in | 7 + libs/archive/include/archive/archive.h | 280 ++++++++ libs/archive/src/CMakeLists.txt | 101 +++ libs/archive/src/archive.cpp | 609 +++++++++++++++++ libs/archive/src/compat.h | 87 +++ libs/archive/src/extractcallback.cpp | 364 ++++++++++ libs/archive/src/extractcallback.h | 133 ++++ libs/archive/src/fileio.cpp | 449 ++++++++++++ libs/archive/src/fileio.h | 343 ++++++++++ libs/archive/src/formatter.h | 121 ++++ libs/archive/src/inputstream.cpp | 70 ++ libs/archive/src/inputstream.h | 54 ++ libs/archive/src/instrument.h | 111 +++ libs/archive/src/interfaceguids.cpp | 37 + libs/archive/src/library.h | 164 +++++ libs/archive/src/multioutputstream.cpp | 142 ++++ libs/archive/src/multioutputstream.h | 106 +++ libs/archive/src/opencallback.cpp | 168 +++++ libs/archive/src/opencallback.h | 75 ++ libs/archive/src/propertyvariant.cpp | 214 ++++++ libs/archive/src/propertyvariant.h | 56 ++ libs/archive/src/unknown_impl.h | 191 ++++++ libs/archive/src/version.rc | 28 + libs/archive/thirdparty/C/7zTypes.h | 597 ++++++++++++++++ libs/archive/thirdparty/C/7zWindows.h | 101 +++ libs/archive/thirdparty/C/Compiler.h | 236 +++++++ libs/archive/thirdparty/C/Precomp.h | 127 ++++ .../archive/thirdparty/CPP/7zip/Archive/IArchive.h | 754 +++++++++++++++++++++ libs/archive/thirdparty/CPP/7zip/ICoder.h | 477 +++++++++++++ libs/archive/thirdparty/CPP/7zip/IDecl.h | 76 +++ libs/archive/thirdparty/CPP/7zip/IPassword.h | 54 ++ libs/archive/thirdparty/CPP/7zip/IProgress.h | 20 + libs/archive/thirdparty/CPP/7zip/IStream.h | 210 ++++++ libs/archive/thirdparty/CPP/7zip/MyVersion.h | 2 + libs/archive/thirdparty/CPP/7zip/PropID.h | 178 +++++ libs/archive/thirdparty/CPP/Common/Common.h | 28 + libs/archive/thirdparty/CPP/Common/Common0.h | 330 +++++++++ libs/archive/thirdparty/CPP/Common/MyGuidDef.h | 63 ++ libs/archive/thirdparty/CPP/Common/MyTypes.h | 38 ++ libs/archive/thirdparty/CPP/Common/MyUnknown.h | 8 + libs/archive/thirdparty/CPP/Common/MyWindows.cpp | 292 ++++++++ libs/archive/thirdparty/CPP/Common/MyWindows.h | 325 +++++++++ libs/archive/thirdparty/CPP/Common/NewHandler.h | 121 ++++ libs/archive/thirdparty/CPP/Common/StdAfx.h | 8 + libs/archive/vcpkg.json | 10 + 56 files changed, 8609 insertions(+) create mode 100644 libs/archive/.clang-format create mode 100644 libs/archive/.git-blame-ignore-revs create mode 100644 libs/archive/.gitattributes create mode 100644 libs/archive/.github/workflows/build.yml create mode 100644 libs/archive/.github/workflows/linting.yml create mode 100644 libs/archive/.gitignore create mode 100644 libs/archive/.pre-commit-config.yaml create mode 100644 libs/archive/CMakeLists.txt create mode 100644 libs/archive/CMakePresets.json create mode 100644 libs/archive/LICENSE create mode 100644 libs/archive/README.md create mode 100644 libs/archive/cmake/config.cmake.in create mode 100644 libs/archive/include/archive/archive.h create mode 100644 libs/archive/src/CMakeLists.txt create mode 100644 libs/archive/src/archive.cpp create mode 100644 libs/archive/src/compat.h create mode 100644 libs/archive/src/extractcallback.cpp create mode 100644 libs/archive/src/extractcallback.h create mode 100644 libs/archive/src/fileio.cpp create mode 100644 libs/archive/src/fileio.h create mode 100644 libs/archive/src/formatter.h create mode 100644 libs/archive/src/inputstream.cpp create mode 100644 libs/archive/src/inputstream.h create mode 100644 libs/archive/src/instrument.h create mode 100644 libs/archive/src/interfaceguids.cpp create mode 100644 libs/archive/src/library.h create mode 100644 libs/archive/src/multioutputstream.cpp create mode 100644 libs/archive/src/multioutputstream.h create mode 100644 libs/archive/src/opencallback.cpp create mode 100644 libs/archive/src/opencallback.h create mode 100644 libs/archive/src/propertyvariant.cpp create mode 100644 libs/archive/src/propertyvariant.h create mode 100644 libs/archive/src/unknown_impl.h create mode 100644 libs/archive/src/version.rc create mode 100644 libs/archive/thirdparty/C/7zTypes.h create mode 100644 libs/archive/thirdparty/C/7zWindows.h create mode 100644 libs/archive/thirdparty/C/Compiler.h create mode 100644 libs/archive/thirdparty/C/Precomp.h create mode 100644 libs/archive/thirdparty/CPP/7zip/Archive/IArchive.h create mode 100644 libs/archive/thirdparty/CPP/7zip/ICoder.h create mode 100644 libs/archive/thirdparty/CPP/7zip/IDecl.h create mode 100644 libs/archive/thirdparty/CPP/7zip/IPassword.h create mode 100644 libs/archive/thirdparty/CPP/7zip/IProgress.h create mode 100644 libs/archive/thirdparty/CPP/7zip/IStream.h create mode 100644 libs/archive/thirdparty/CPP/7zip/MyVersion.h create mode 100644 libs/archive/thirdparty/CPP/7zip/PropID.h create mode 100644 libs/archive/thirdparty/CPP/Common/Common.h create mode 100644 libs/archive/thirdparty/CPP/Common/Common0.h create mode 100644 libs/archive/thirdparty/CPP/Common/MyGuidDef.h create mode 100644 libs/archive/thirdparty/CPP/Common/MyTypes.h create mode 100644 libs/archive/thirdparty/CPP/Common/MyUnknown.h create mode 100644 libs/archive/thirdparty/CPP/Common/MyWindows.cpp create mode 100644 libs/archive/thirdparty/CPP/Common/MyWindows.h create mode 100644 libs/archive/thirdparty/CPP/Common/NewHandler.h create mode 100644 libs/archive/thirdparty/CPP/Common/StdAfx.h create mode 100644 libs/archive/vcpkg.json (limited to 'libs/archive') diff --git a/libs/archive/.clang-format b/libs/archive/.clang-format new file mode 100644 index 0000000..6098e1f --- /dev/null +++ b/libs/archive/.clang-format @@ -0,0 +1,41 @@ +--- +# We'll use defaults from the LLVM style, but with 4 columns indentation. +BasedOnStyle: LLVM +IndentWidth: 2 +--- +Language: Cpp +DeriveLineEnding: false +UseCRLF: true +DerivePointerAlignment: false +PointerAlignment: Left +AlignConsecutiveAssignments: true +AllowShortFunctionsOnASingleLine: Inline +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: Empty +AlwaysBreakTemplateDeclarations: Yes +AccessModifierOffset: -2 +AlignTrailingComments: true +SpacesBeforeTrailingComments: 2 +NamespaceIndentation: Inner +MaxEmptyLinesToKeep: 1 +BreakBeforeBraces: Custom +BraceWrapping: + AfterCaseLabel: false + AfterClass: true + AfterControlStatement: false + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterStruct: true + AfterUnion: true + AfterExternBlock: true + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: true +ColumnLimit: 88 +ForEachMacros: ['Q_FOREACH', 'foreach'] diff --git a/libs/archive/.git-blame-ignore-revs b/libs/archive/.git-blame-ignore-revs new file mode 100644 index 0000000..be37b84 --- /dev/null +++ b/libs/archive/.git-blame-ignore-revs @@ -0,0 +1 @@ +bc77d2a270cc24fd69a8b46ccad4cca2b334a19d diff --git a/libs/archive/.gitattributes b/libs/archive/.gitattributes new file mode 100644 index 0000000..f869712 --- /dev/null +++ b/libs/archive/.gitattributes @@ -0,0 +1,7 @@ +# Set the default behavior, in case people don't have core.autocrlf set. +* text=auto + +# Explicitly declare text files you want to always be normalized and converted +# to native line endings on checkout. +*.cpp text eol=crlf +*.h text eol=crlf diff --git a/libs/archive/.github/workflows/build.yml b/libs/archive/.github/workflows/build.yml new file mode 100644 index 0000000..f476ad1 --- /dev/null +++ b/libs/archive/.github/workflows/build.yml @@ -0,0 +1,39 @@ +name: Build Archive + +on: + push: + branches: [master] + pull_request: + types: [opened, synchronize, reopened] + +env: + VCPKG_BINARY_SOURCES: clear;x-azblob,${{ vars.AZ_BLOB_VCPKG_URL }},${{ secrets.AZ_BLOB_SAS }},readwrite + +jobs: + build: + runs-on: windows-2022 + steps: + # set VCPKG Root + - name: "Set environmental variables" + shell: bash + run: | + echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - uses: actions/checkout@v4 + + - name: Configure Archive build + shell: pwsh + run: | + cmake --preset vs2022-windows-shared "-DCMAKE_INSTALL_PREFIX=install" + + - name: Build Archive + run: cmake --build vsbuild --config RelWithDebInfo + + - name: Install Archive + run: cmake --install vsbuild --config RelWithDebInfo + + - name: Upload Archive artifact + uses: actions/upload-artifact@master + with: + name: archive + path: ./install diff --git a/libs/archive/.github/workflows/linting.yml b/libs/archive/.github/workflows/linting.yml new file mode 100644 index 0000000..22eb21a --- /dev/null +++ b/libs/archive/.github/workflows/linting.yml @@ -0,0 +1,16 @@ +name: Lint Archive + +on: + push: + pull_request: + types: [opened, synchronize, reopened] + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Check format + uses: ModOrganizer2/check-formatting-action@master + with: + check-path: "." diff --git a/libs/archive/.gitignore b/libs/archive/.gitignore new file mode 100644 index 0000000..cf71be7 --- /dev/null +++ b/libs/archive/.gitignore @@ -0,0 +1,5 @@ +edit +CMakeLists.txt.user +/msbuild.log +/*std*.log +/*build diff --git a/libs/archive/.pre-commit-config.yaml b/libs/archive/.pre-commit-config.yaml new file mode 100644 index 0000000..eb8969c --- /dev/null +++ b/libs/archive/.pre-commit-config.yaml @@ -0,0 +1,20 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v6.0.0 + hooks: + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-merge-conflict + - id: check-case-conflict + - repo: https://github.com/pre-commit/mirrors-clang-format + rev: v21.1.8 + hooks: + - id: clang-format + 'types_or': [c++, c] + +ci: + autofix_commit_msg: "[pre-commit.ci] Auto fixes from pre-commit.com hooks." + autofix_prs: true + autoupdate_commit_msg: "[pre-commit.ci] Pre-commit autoupdate." + autoupdate_schedule: quarterly + submodules: false diff --git a/libs/archive/CMakeLists.txt b/libs/archive/CMakeLists.txt new file mode 100644 index 0000000..fa5d783 --- /dev/null +++ b/libs/archive/CMakeLists.txt @@ -0,0 +1,37 @@ +cmake_minimum_required(VERSION 3.16) + +include(CMakePackageConfigHelpers) + +project(archive) + +set_property(GLOBAL PROPERTY USE_FOLDERS ON) +option(BUILD_SHARED_LIBS "Build using shared libraries" ON) + +add_subdirectory(src) + +configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/config.cmake.in + "${CMAKE_CURRENT_BINARY_DIR}/mo2-archive-config.cmake" + INSTALL_DESTINATION "lib/cmake/mo2-archive" + NO_SET_AND_CHECK_MACRO + NO_CHECK_REQUIRED_COMPONENTS_MACRO +) + +file(READ "${CMAKE_CURRENT_SOURCE_DIR}/src/version.rc" archive_version) +string(REGEX MATCH "#define VER_FILEVERSION[ \t]*([0-9]+),([0-9]+),([0-9]+)" _ ${archive_version}) +set(archive_version_major ${CMAKE_MATCH_1}) +set(archive_version_minor ${CMAKE_MATCH_2}) +set(archive_version_patch ${CMAKE_MATCH_3}) + +message(STATUS "[MO2] Found version '${archive_version_major}.${archive_version_minor}.${archive_version_patch}'.") + +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/mo2-archive-config-version.cmake" + VERSION "${archive_version_major}.${archive_version_minor}.${archive_version_patch}" + COMPATIBILITY AnyNewerVersion +) + +install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/mo2-archive-config.cmake + ${CMAKE_CURRENT_BINARY_DIR}/mo2-archive-config-version.cmake + DESTINATION lib/cmake/mo2-archive +) diff --git a/libs/archive/CMakePresets.json b/libs/archive/CMakePresets.json new file mode 100644 index 0000000..ed1f0cc --- /dev/null +++ b/libs/archive/CMakePresets.json @@ -0,0 +1,74 @@ +{ + "configurePresets": [ + { + "errors": { + "deprecated": true + }, + "hidden": true, + "name": "cmake-dev", + "warnings": { + "deprecated": true, + "dev": true + } + }, + { + "cacheVariables": { + "VCPKG_MANIFEST_NO_DEFAULT_FEATURES": { + "type": "BOOL", + "value": "ON" + } + }, + "toolchainFile": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", + "hidden": true, + "name": "vcpkg" + }, + { + "binaryDir": "${sourceDir}/vsbuild", + "architecture": { + "strategy": "set", + "value": "x64" + }, + "cacheVariables": { + "CMAKE_CXX_FLAGS": "/EHsc /MP /W4", + "VCPKG_TARGET_TRIPLET": { + "type": "STRING", + "value": "x64-windows-static-md" + }, + "BUILD_SHARED_LIBS": { + "type": "BOOL", + "value": "OFF" + } + }, + "generator": "Visual Studio 17 2022", + "inherits": ["cmake-dev", "vcpkg"], + "name": "vs2022-windows-static", + "toolset": "v143" + }, + { + "cacheVariables": { + "BUILD_SHARED_LIBS": { + "type": "BOOL", + "value": "ON" + }, + "VCPKG_TARGET_TRIPLET": { + "type": "STRING", + "value": "x64-windows" + } + }, + "inherits": "vs2022-windows-static", + "name": "vs2022-windows-shared" + }, + { + "inherits": "vs2022-windows-shared", + "name": "vs2022-windows" + } + ], + "buildPresets": [ + { + "name": "vs2022-windows", + "resolvePackageReferences": "on", + "configurePreset": "vs2022-windows" + } + ], + "version": 4 +} diff --git a/libs/archive/LICENSE b/libs/archive/LICENSE new file mode 100644 index 0000000..0a04128 --- /dev/null +++ b/libs/archive/LICENSE @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/libs/archive/README.md b/libs/archive/README.md new file mode 100644 index 0000000..e389081 --- /dev/null +++ b/libs/archive/README.md @@ -0,0 +1,239 @@ +[![Build status](https://ci.appveyor.com/api/projects/status/hdthueiiuedeb38f?svg=true)](https://ci.appveyor.com/project/Modorganizer2/modorganizer-archive) + +# modorganizer-archive + +This module provides a wrapper round the 7zip `7z.dll` allowing easy(ish) access to the contents of an archive. + +## How to build? + +If you want to build this as par of ModOrganizer2, simply use ModOrganizer2 build system. + +If you want to build this as a standalone DLL, you can run the following (requires `cmake >= 3.16`): + +```batch +mkdir build +cd build +cmake .. +cmake --build . --config Release +``` + +This will download the two required dependencies (7z sources and [`fmtlib`](https://github.com/fmtlib/fmt)), and +build the DLL under `build/src/Release`. + +In order to use the DLL, you need to have the `7z.dll` available in your path, otherwize `CreateArchive()` will +always fail. You can get the `7z.dll` by installing `7z.exe` or by building 7z yourself (building `archive` does +not build `7z`). + +## The `Archive` class + +The first thing to do is to create an archive wrapper: + +```cpp +#include + +std::unique_ptr CreateArchive(); +``` + +This creates an archive handler. + +You can check the [src/archive.h](src/archive.h) header for more details but here are some +of the available methods: + +```cpp +/** + * @brief Check if this Archive wrapper is in a valid state. + * + * A non-valid Archive instance usually means that the 7z DLLs could not be loaded properly. Failures + * to open or extract archives do not invalidate the Archive, so this should only be used to check + * if the Archive object has been initialized properly. + * + * @return true if this instance is valid, false otherwise. + */ +bool Archive::isValid() const; +``` + +If this returns `false`, this probably means the system cannot find `7z.dll` or it is corrupt, very old (or possibly too new). +**You should check this before calling `open`.** + +```cpp +/** + * @brief Open the given archive. + * + * @param archivePath Path to the archive to open. + * @param passwordCallback Callback to use to ask user for password. This callback must remain + * valid until extraction is complete since some types of archives only requires password when + * extracting. + * + * @return true if the archive was open properly, false otherwise. + */ +bool Archive::open(std::wstring const &archiveName, ArchiveCallbacks::PasswordCallback passwordCallback) +``` + +This attempts to open the specified archive file. It should manage to open pretty much anything 7zip recognises. It returns `true` on success. +If an error occurs, it returns `false` and `getLastError()` can be used to check the cause of the failure (see the `Archive.h` header for the +list of possible errors): + +```cpp +Archive::Error getLastError() const; +``` + +If `std::wstring passwordChangeCallback()` is not empty, it is called if when password is needed and should return the password to use. + +**Note:** this may be called during `extract` rather than during `open`, so should remain usable until the end of the extraction. +If you do not supply this callback, archives with passwords will be unreadable. + +Once the archive is opned, you can retrieve the list of files inside using `getFileList()`: + +```cpp +const std::vector& getFileList() const; +``` + +This will return a reference to a vector containing `FileData`. The vector contains non-const pointers so you can actually modify (not assign) +the pointed `FileData` to indicate which files to extract and the path to extract them to. + +Once you have updated the `FileData` (see below) you want to extract, you can then perform the extraction using: + +```cpp +/** + * @brief Extract the content of the archive. + * + * This function uses the filenames from FileData to obtain the extraction paths of file. + * + * @param outputDirectory Path to the directory where the archive should be extracted. If not empty, + * conflicting files will be replaced by the extracted ones. + * @param progressCallback Function called to notify extraction progress. This function is called + * when new data is written to the disk, not when the archive is read, so it may take a little + * time to start. + * @param fileChangeCallback Function called when the file currently being extracted changes. + * @param errorCallback Function called when an error occurs. + * + * @return true if the archive was extracted, false otherwise. + */ +bool extract(std::wstring const &outputDirectory, ArchiveCallbacks::ProgressCallback progressCallback, + ArchiveCallbacks::FileChangeCallback fileChangeCallback, ArchiveCallbacks::ErrorCallback errorCallback) +``` + +All callbacks are optional, you can pass an empty `std::function` instead (either `nullptr` or `{}`). The purpose of the callbacks: + +- `progressCallback(float)` is called during extraction to notify progress. +- `fileChangeCallback(std::wstring const&)` is called when a file starts being extracted. +- `errorCallback(std::wstring const&)` is called if an error occurred, with an appropriate error message. There is not much you can do + here beyond displaying the message. This will also result in a failure return from `extract`. + +Once `extract()` is done, you can call `getFileList()` again and perform a different extractions. `extract()` will clean the list of +`FileData` (unless an error occurred). + +You can cancel the extraction at any time by calling: + +```cpp +void Archive::cancel(); +``` + +This will cause `extract` to return `false` and `getLastError` to return `ERROR_EXTRACT_CANCELLED`. + +Once you are done, do not forget to close the currently opened `Archive`: + +```cpp +void Archive::close(); +``` + +## The `FileData` class + +As you have seen above, the `getFileList` method returns a reference to a vector of entries about all the files in the archive. +You can see the full declaration of `FileData` in [src/archive.h](src/archive.h). The following methods are the most important +ones: + +```cpp +void FileData::addOutputFileName(std::wstring const& filepath) +``` + +Adds a new output path for this file. The given `filepath` should be relative to the extraction folder specified in `Archive::extract`. +Initially, the list of output paths is empty, so if you do not call `addOutputFileName`, the corresponding file will not be extracted. +You can extract a file in the archive to as many files as you want. + +```cpp +std::vector FileData::getAndClearOutputFileNames() +``` + +Returns the list of output paths (relative to the extraction folder) for this file and clears it. This is normally only used inside +`extract` but can be used to clear the output filenames after a failure. + +Depending on the type of archives, you may have entries corresponding to directories, in which case `FileData::isDirectory()` will +return `true`. +You can "extract" those like normal files, but directories will be automatically created for files if necessary anyway. + +## Full example + +Below is a full example on how to extract an archive to a given folder: + +```cpp +#include + +#include "archive.h" + +int main() { + + // Path to the archive and to the output folder: + const std::wstring archivePath = L"archive.7z"; + const std::wstring outputFolder = L"output"; + + auto archive = CreateArchive(); + + if (!archive->isValid()) { + std::wcerr << "Failed to load the archive module: " << archive->getLastError() << '\n'; + return -1; + } + + // You can set a log callback if you want: + archive->setLogCallback([](auto level, auto const& message) { + std::wcout << message << '\n'; + }); + + // Open the archive: + if (!archive->open(archivePath, nullptr)) { + std::wcerr << "Failed to open the archive: " << archive->getLastError() << '\n'; + return -1; + } + + // Get the list of files: + auto const& files = archive->getFileList(); + + // Mark all files for extraction to their path in the archive: + for (auto *fileData: files) { + fileData->addOutputFileName(fileData->getFileName()); + } + + // Extract everything (without callbacks): + auto result = archive->extract(outputFolder, nullptr, nullptr, nullptr); + + if (!result) { + std::wcerr << "Failed to extract the archive: " << archive->getLastError() << '\n'; + return -1; + } + + // Close the archive: + archive->close(); + + return 0; +} +``` + +# Copyright + +Copyright (C) 2012 Sebastian Herbord, (C) 2020 MO2 Team. All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +See [LICENSE](LICENSE) for more details. diff --git a/libs/archive/cmake/config.cmake.in b/libs/archive/cmake/config.cmake.in new file mode 100644 index 0000000..4bf70e6 --- /dev/null +++ b/libs/archive/cmake/config.cmake.in @@ -0,0 +1,7 @@ +@PACKAGE_INIT@ + +if(WIN32) + find_package(7zip CONFIG REQUIRED) +endif() + +include ( "${CMAKE_CURRENT_LIST_DIR}/mo2-archive-targets.cmake" ) diff --git a/libs/archive/include/archive/archive.h b/libs/archive/include/archive/archive.h new file mode 100644 index 0000000..3985427 --- /dev/null +++ b/libs/archive/include/archive/archive.h @@ -0,0 +1,280 @@ +/* +Mod Organizer archive handling + +Copyright (C) 2012 Sebastian Herbord, 2020 MO2 Team. All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef ARCHIVE_H +#define ARCHIVE_H + +#include +#include +#include +#include + +#if defined(MO2_ARCHIVE_BUILD_STATIC) +#define DLLEXPORT +#elif defined(_WIN32) + #if defined(MO2_ARCHIVE_BUILD_EXPORT) + #define DLLEXPORT __declspec(dllexport) + #else + #define DLLEXPORT __declspec(dllimport) + #endif +#else + #if defined(MO2_ARCHIVE_BUILD_EXPORT) + #define DLLEXPORT __attribute__((visibility("default"))) + #else + #define DLLEXPORT + #endif +#endif + +class FileData +{ +public: + /** + * @return the path of this entry in the archive (usually relative, unless the archive + * contains absolute path). + */ + virtual std::wstring getArchiveFilePath() const = 0; + + /** + * @return the size of this entry in bytes (uncompressed). + */ + virtual uint64_t getSize() const = 0; + + /** + * @brief Add the given filepath to the list of files to create from this + * entry when extracting. + * + * @param filepath The filepath to add, relative to the output folder. + */ + virtual void addOutputFilePath(std::wstring const& filepath) = 0; + + /** + * @brief Retrieve the list of filepaths to extract this entry to. + * + * @return the list of paths this entry should be extracted to, relative to the + * output folder. + */ + virtual const std::vector& getOutputFilePaths() const = 0; + + /** + * @brief Clear the list of output file paths for this entry. + */ + virtual void clearOutputFilePaths() = 0; + + /** + * @return the CRC of this file. + */ + virtual uint64_t getCRC() const = 0; + + /** + * @return true if this entry is a directory, false otherwize. + */ + virtual bool isDirectory() const = 0; + + virtual ~FileData() = default; +}; + +class Archive +{ +public: // Declarations + enum class LogLevel + { + Debug, + Info, + Warning, + Error + }; + + enum class ProgressType + { + + // Indicates the 7z progression in the archive (related to reading the archive. When + // extracting + // a lot of files, this may reach 100% way before the extraction is complete since + // most of the + // time will be spend writing data and not reading it (use EXTRACTION in this case). + // When + // extracting few small files, this may be useful for solid archives since most of + // the time + // will be spent in reading and decompressing the archive rather than in writing the + // actual files. + ARCHIVE, + + // Progress about extraction. If this reach 100%, it means that the extraction of + // all files is + // complete. The EXTRACTION progress may not start immediately, and might be kind of + // chaotic when + // extracting few files from an archive, but is much more representative of the + // actual progress + // than ARCHIVE. + EXTRACTION + }; + + enum class FileChangeType + { + EXTRACTION_START, + EXTRACTION_END + }; + + static constexpr int MAX_PASSWORD_LENGTH = 256; + + /** + * List of callbacks: + */ + using LogCallback = std::function; + using ProgressCallback = std::function; + using PasswordCallback = std::function; + using FileChangeCallback = std::function; + using ErrorCallback = std::function; + + /** + * + */ + enum class Error + { + ERROR_NONE, + ERROR_EXTRACT_CANCELLED, + ERROR_LIBRARY_NOT_FOUND, + ERROR_LIBRARY_INVALID, + ERROR_ARCHIVE_NOT_FOUND, + ERROR_FAILED_TO_OPEN_ARCHIVE, + ERROR_INVALID_ARCHIVE_FORMAT, + ERROR_LIBRARY_ERROR, + ERROR_ARCHIVE_INVALID, + ERROR_OUT_OF_MEMORY + }; + +public: // Special member functions: + virtual ~Archive() {} + +public: + /** + * @brief Check if this Archive wrapper is in a valid state. + * + * A non-valid Archive instance usually means that the 7z DLLs could not be loaded + * properly. Failures to open or extract archives do not invalidate the Archive, so + * this should only be used to check if the Archive object has been initialized + * properly. + * + * @return true if this instance is valid, false otherwise. + */ + virtual bool isValid() const = 0; + + /** + * @return retrieve the error-code of the last error that occurred. + */ + virtual Error getLastError() const = 0; + + /** + * @brief Set the callback used to log messages. + * + * To remove the callback, you can pass a default-constructed LogCallback object. + * + * @param logCallback The new callback to use for logging message. + */ + virtual void setLogCallback(LogCallback logCallback) = 0; + + /** + * @brief Open the given archive. + * + * @param archivePath Path to the archive to open. + * @param passwordCallback Callback to use to ask user for password. This callback + * must remain valid until extraction is complete since some types of archives only + * requires password when extracting. + * + * @return true if the archive was open properly, false otherwise. + */ + virtual bool open(std::wstring const& archivePath, + PasswordCallback passwordCallback) = 0; + + /** + * @brief Close the currently opened archive. + */ + virtual void close() = 0; + + /** + * @return the list of files in the currently opened archive. + */ + virtual const std::vector& getFileList() const = 0; + + /** + * @brief Extract the content of the archive. + * + * This function uses the filenames from FileData to obtain the extraction paths of + * file. All the callbacks are optional (you can specify default-constructed + * std::function). Overloads with one or two callbacks are also provided. + * + * @param outputDirectory Path to the directory where the archive should be extracted. + * If not empty, conflicting files will be replaced by the extracted ones. + * @param progressCallback Function called to notify extraction progress. + * @param fileChangeCallback Function called when the file currently being extracted + * changes. + * @param errorCallback Function called when an error occurs. + * + * @return true if the archive was extracted, false otherwise. + */ + virtual bool extract(std::wstring const& outputDirectory, + ProgressCallback progressCallback, + FileChangeCallback fileChangeCallback, + ErrorCallback errorCallback) = 0; + + /** + * @brief Cancel the current extraction process. + */ + virtual void cancel() = 0; + + // A bunch of useful overloads (with one or two callbacks): + bool extract(std::wstring const& outputDirectory, ErrorCallback errorCallback) + { + return extract(outputDirectory, {}, {}, errorCallback); + } + bool extract(std::wstring const& outputDirectory, ProgressCallback progressCallback) + { + return extract(outputDirectory, progressCallback, {}, {}); + } + bool extract(std::wstring const& outputDirectory, + FileChangeCallback fileChangeCallback) + { + return extract(outputDirectory, {}, fileChangeCallback, {}); + } + bool extract(std::wstring const& outputDirectory, ProgressCallback progressCallback, + ErrorCallback errorCallback) + { + return extract(outputDirectory, progressCallback, {}, errorCallback); + } + bool extract(std::wstring const& outputDirectory, ProgressCallback progressCallback, + FileChangeCallback fileChangeCallback) + { + return extract(outputDirectory, progressCallback, fileChangeCallback, {}); + } + bool extract(std::wstring const& outputDirectory, + FileChangeCallback fileChangeCallback, ErrorCallback errorCallback) + { + return extract(outputDirectory, {}, fileChangeCallback, errorCallback); + } +}; + +/** + * @brief Factory function for archive-objects. + * + * @return a pointer to a new Archive object that can be used to manipulate archives. + */ +DLLEXPORT std::unique_ptr CreateArchive(); + +#endif // ARCHIVE_H diff --git a/libs/archive/src/CMakeLists.txt b/libs/archive/src/CMakeLists.txt new file mode 100644 index 0000000..75e9b53 --- /dev/null +++ b/libs/archive/src/CMakeLists.txt @@ -0,0 +1,101 @@ +cmake_minimum_required(VERSION 3.16) + +if(WIN32) + find_package(7zip CONFIG REQUIRED) +endif() + +add_library(archive) + +set_target_properties(archive PROPERTIES CXX_STANDARD 20) + +# On Linux, we use the bundled 7zip SDK headers and dlopen the 7z.so at runtime +# On Windows, we use the vcpkg 7zip package +if(WIN32) + target_link_libraries(archive PRIVATE 7zip::7zip) +else() + # Add 7zip SDK headers from thirdparty + target_include_directories(archive PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/../thirdparty/CPP + ) + # We need to compile MyWindows.cpp for BSTR/Variant support on Linux + target_sources(archive PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/../thirdparty/CPP/Common/MyWindows.cpp + ) + target_link_libraries(archive PRIVATE dl) + target_compile_definitions(archive PRIVATE -DARCHIVE_LINUX_PORT) +endif() + +set(ARCHIVE_SOURCES + archive.cpp + compat.h + extractcallback.cpp + extractcallback.h + fileio.cpp + fileio.h + formatter.h + inputstream.cpp + inputstream.h + instrument.h + interfaceguids.cpp + library.h + multioutputstream.cpp + multioutputstream.h + opencallback.cpp + opencallback.h + propertyvariant.cpp + propertyvariant.h + unknown_impl.h +) + +if(WIN32) + list(APPEND ARCHIVE_SOURCES version.rc) +endif() + +target_sources(archive + PRIVATE + ${ARCHIVE_SOURCES} + PUBLIC + FILE_SET HEADERS + BASE_DIRS ${CMAKE_CURRENT_LIST_DIR}/../include + FILES ${CMAKE_CURRENT_LIST_DIR}/../include/archive/archive.h +) + +target_include_directories(archive PRIVATE ${CMAKE_CURRENT_LIST_DIR}/../include/archive) + +if (MSVC) + target_compile_options(archive + PRIVATE + "/MP" + "/W4" + "/external:anglebrackets" + "/external:W0" + ) + target_link_options(archive + PRIVATE + $<$:/LTCG /INCREMENTAL:NO /OPT:REF /OPT:ICF> + ) + + set_target_properties(archive PROPERTIES VS_STARTUP_PROJECT archive) +endif() + +if(NOT MSVC) + target_compile_options(archive PRIVATE -Wall -Wextra -Wno-unused-parameter) +endif() + +if (BUILD_STATIC) + target_compile_definitions(archive PUBLIC -DMO2_ARCHIVE_BUILD_STATIC) +else() + target_compile_definitions(archive PRIVATE -DMO2_ARCHIVE_BUILD_EXPORT) +endif() + +add_library(mo2::archive ALIAS archive) + +install(TARGETS archive EXPORT archiveTargets FILE_SET HEADERS) +if (NOT BUILD_STATIC AND WIN32) + install(FILES $ DESTINATION pdb OPTIONAL) +endif() +install(EXPORT archiveTargets + FILE mo2-archive-targets.cmake + NAMESPACE mo2:: + DESTINATION lib/cmake/mo2-archive +) diff --git a/libs/archive/src/archive.cpp b/libs/archive/src/archive.cpp new file mode 100644 index 0000000..6d35366 --- /dev/null +++ b/libs/archive/src/archive.cpp @@ -0,0 +1,609 @@ +/* +Mod Organizer archive handling + +Copyright (C) 2012 Sebastian Herbord, 2020 MO2 Team. All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "archive.h" +#include "compat.h" + +#include "extractcallback.h" +#include "inputstream.h" +#include "library.h" +#include "opencallback.h" +#include "propertyvariant.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace PropID = NArchive::NHandlerPropID; + +class FileDataImpl : public FileData +{ + friend class Archive; + +public: + FileDataImpl(std::wstring const& fileName, UInt64 size, UInt64 crc, bool isDirectory) + : m_FileName(fileName), m_Size(size), m_CRC(crc), m_IsDirectory(isDirectory) + {} + + virtual std::wstring getArchiveFilePath() const override { return m_FileName; } + virtual uint64_t getSize() const override { return m_Size; } + + virtual void addOutputFilePath(std::wstring const& fileName) override + { + m_OutputFilePaths.push_back(fileName); + } + virtual const std::vector& getOutputFilePaths() const override + { + return m_OutputFilePaths; + } + + virtual void clearOutputFilePaths() override { m_OutputFilePaths.clear(); } + + bool isEmpty() const { return m_OutputFilePaths.empty(); } + virtual bool isDirectory() const override { return m_IsDirectory; } + virtual uint64_t getCRC() const override { return m_CRC; } + +private: + std::wstring m_FileName; + UInt64 m_Size; + UInt64 m_CRC; + std::vector m_OutputFilePaths; + bool m_IsDirectory; +}; + +/// represents the connection to one archive and provides common functionality +class ArchiveImpl : public Archive +{ + + // Callback that does nothing but avoid having to check if the callback is present + // everytime. + static LogCallback DefaultLogCallback; + +public: + ArchiveImpl(); + virtual ~ArchiveImpl(); + + virtual bool isValid() const { return m_Valid; } + + virtual Error getLastError() const { return m_LastError; } + virtual void setLogCallback(LogCallback logCallback) override + { + // Wrap the callback so that we do not have to check if it is set everywhere: + m_LogCallback = logCallback ? logCallback : DefaultLogCallback; + } + + virtual bool open(std::wstring const& archiveName, + PasswordCallback passwordCallback) override; + virtual void close() override; + const std::vector& getFileList() const override { return m_FileList; } + virtual bool extract(std::wstring const& outputDirectory, + ProgressCallback progressCallback, + FileChangeCallback fileChangeCallback, + ErrorCallback errorCallback) override; + + virtual void cancel() override; + +private: + void clearFileList(); + void resetFileList(); + + HRESULT loadFormats(); + +private: + typedef UINT32(WINAPI* CreateObjectFunc)(const GUID* clsID, const GUID* interfaceID, + void** outObject); + CreateObjectFunc m_CreateObjectFunc; + + // A note: In 7zip source code this not is what this typedef is called, the old + // GetHandlerPropertyFunc appears to be deprecated. + typedef UInt32(WINAPI* GetPropertyFunc)(UInt32 index, PROPID propID, + PROPVARIANT* value); + GetPropertyFunc m_GetHandlerPropertyFunc; + + template + T readHandlerProperty(UInt32 index, PROPID propID) const; + + template + T readProperty(UInt32 index, PROPID propID) const; + + bool m_Valid; + Error m_LastError; + + ALibrary m_Library; + std::wstring m_ArchiveName; // TBH I don't think this is required + CComPtr m_ArchivePtr; + CArchiveExtractCallback* m_ExtractCallback; + + LogCallback m_LogCallback; + PasswordCallback m_PasswordCallback; + + std::vector m_FileList; + + std::wstring m_Password; + + struct ArchiveFormatInfo + { + CLSID m_ClassID; + std::wstring m_Name; + std::vector m_Signatures; + std::wstring m_Extensions; + std::wstring m_AdditionalExtensions; + UInt32 m_SignatureOffset; + }; + + typedef std::vector Formats; + Formats m_Formats; + + typedef std::unordered_map FormatMap; + FormatMap m_FormatMap; + + // I don't think one signature could possibly describe two formats. + typedef std::map SignatureMap; + SignatureMap m_SignatureMap; + + std::size_t m_MaxSignatureLen = 0; +}; + +Archive::LogCallback ArchiveImpl::DefaultLogCallback([](LogLevel, std::wstring const&) { +}); + +template +T ArchiveImpl::readHandlerProperty(UInt32 index, PROPID propID) const +{ + PropertyVariant prop; + if (m_GetHandlerPropertyFunc(index, propID, &prop) != S_OK) { + throw std::runtime_error("Failed to read property"); + } + return static_cast(prop); +} + +template +T ArchiveImpl::readProperty(UInt32 index, PROPID propID) const +{ + PropertyVariant prop; + if (m_ArchivePtr->GetProperty(index, propID, &prop) != S_OK) { + throw std::runtime_error("Failed to read property"); + } + return static_cast(prop); +} + +// Seriously, there is one format returned in the list that has no registered +// extension and no signature. WTF? +HRESULT ArchiveImpl::loadFormats() +{ + typedef UInt32(WINAPI * GetNumberOfFormatsFunc)(UInt32 * numFormats); + GetNumberOfFormatsFunc getNumberOfFormats = + m_Library.resolve("GetNumberOfFormats"); + if (getNumberOfFormats == nullptr) { + return E_FAIL; + } + + UInt32 numFormats; + RINOK(getNumberOfFormats(&numFormats)); + + for (UInt32 i = 0; i < numFormats; ++i) { + ArchiveFormatInfo item; + + item.m_Name = readHandlerProperty(i, PropID::kName); + + item.m_ClassID = readHandlerProperty(i, PropID::kClassID); + + // Should split up the extensions and map extension to type, and see what we get + // from that for preference then try all extensions anyway... + item.m_Extensions = readHandlerProperty(i, PropID::kExtension); + + // This is unnecessary currently for our purposes. Basically, for each + // extension, there's an 'addext' which, if set (to other than *) means that + // theres a double encoding going on. For instance, the bzip format is like this + // addext = "* * .tar .tar" + // ext = "bz2 bzip2 tbz2 tbz" + // which means that tbz2 and tbz should uncompress to a tar file which can be + // further processed as if it were a tar file. Having said which, we don't + // need to support this at all, so I'm storing it but ignoring it. + item.m_AdditionalExtensions = + readHandlerProperty(i, PropID::kAddExtension); + + std::string signature = readHandlerProperty(i, PropID::kSignature); + if (!signature.empty()) { + item.m_Signatures.push_back(signature); + if (m_MaxSignatureLen < signature.size()) { + m_MaxSignatureLen = signature.size(); + } + m_SignatureMap[signature] = item; + } + + std::string multiSig = readHandlerProperty(i, PropID::kMultiSignature); + const char* multiSigBytes = multiSig.c_str(); + std::size_t size = multiSig.length(); + while (size > 0) { + unsigned len = *multiSigBytes++; + size--; + if (len > size) + break; + std::string sig(multiSigBytes, multiSigBytes + len); + multiSigBytes = multiSigBytes + len; + size -= len; + item.m_Signatures.push_back(sig); + if (m_MaxSignatureLen < sig.size()) { + m_MaxSignatureLen = sig.size(); + } + m_SignatureMap[sig] = item; + } + + UInt32 offset = readHandlerProperty(i, PropID::kSignatureOffset); + item.m_SignatureOffset = offset; + + // Now split the extension up from the space separated string and create + // a map from each extension to the possible formats + // We could make these pointers but it's not a massive overhead and nobody + // should be changing this + std::wistringstream s(item.m_Extensions); + std::wstring t; + while (s >> t) { + m_FormatMap[t].push_back(item); + } + m_Formats.push_back(item); + } + return S_OK; +} + +ArchiveImpl::ArchiveImpl() + : m_Valid(false), m_LastError(Error::ERROR_NONE), m_Library("dlls/7zip.dll"), + m_PasswordCallback{} +{ + // Reset the log callback: + setLogCallback({}); + + if (!m_Library) { + m_LastError = Error::ERROR_LIBRARY_NOT_FOUND; + return; + } + + m_CreateObjectFunc = m_Library.resolve("CreateObject"); + if (m_CreateObjectFunc == nullptr) { + m_LastError = Error::ERROR_LIBRARY_INVALID; + return; + } + + m_GetHandlerPropertyFunc = m_Library.resolve("GetHandlerProperty2"); + if (m_GetHandlerPropertyFunc == nullptr) { + m_LastError = Error::ERROR_LIBRARY_INVALID; + return; + } + + try { + if (loadFormats() != S_OK) { + m_LastError = Error::ERROR_LIBRARY_INVALID; + return; + } + + m_Valid = true; + return; + } catch (std::exception const& e) { + m_LogCallback(LogLevel::Error, std::format(L"Caught exception {}.", e)); + m_LastError = Error::ERROR_LIBRARY_INVALID; + } +} + +ArchiveImpl::~ArchiveImpl() +{ + close(); +} + +bool ArchiveImpl::open(std::wstring const& archiveName, + PasswordCallback passwordCallback) +{ + m_ArchiveName = archiveName; // Just for debugging, not actually used... + + Formats formatList = m_Formats; + + // Convert to long path if it's not already: + std::filesystem::path filepath = IO::make_path(archiveName); + + // If it doesn't exist or is a directory, error + if (!exists(filepath) || is_directory(filepath)) { + m_LastError = Error::ERROR_ARCHIVE_NOT_FOUND; + return false; + } + + // in rars the password seems to be requested during extraction, not on open, so we + // need to hold on to the callback for now + m_PasswordCallback = passwordCallback; + + CComPtr file(new InputStream); + + if (!file->Open(filepath)) { + m_LastError = Error::ERROR_FAILED_TO_OPEN_ARCHIVE; + return false; + } + + CComPtr openCallbackPtr; + try { + openCallbackPtr = + new CArchiveOpenCallback(passwordCallback, m_LogCallback, filepath); + } catch (std::runtime_error const&) { + m_LastError = Error::ERROR_FAILED_TO_OPEN_ARCHIVE; + return false; + } + + // Try to open the archive + + bool sigMismatch = false; + + { + // Get the first iterator that is strictly > the signature we're looking for. + for (auto signatureInfo : m_SignatureMap) { + // Read the signature of the file and look that up. + std::vector buff; + buff.reserve(m_MaxSignatureLen); + UInt32 act; + file->Seek(0, STREAM_SEEK_SET, nullptr); + file->Read(buff.data(), static_cast(m_MaxSignatureLen), &act); + file->Seek(0, STREAM_SEEK_SET, nullptr); + std::string signature = std::string(buff.data(), act); + if (signatureInfo.first == std::string(buff.data(), signatureInfo.first.size())) { + if (m_CreateObjectFunc(&signatureInfo.second.m_ClassID, &IID_IInArchive, + (void**)&m_ArchivePtr) != S_OK) { + m_LastError = Error::ERROR_LIBRARY_ERROR; + return false; + } + + if (m_ArchivePtr->Open(file, 0, openCallbackPtr) != S_OK) { + m_LogCallback(LogLevel::Debug, + std::format(L"Failed to open {} using {} (from signature).", + archiveName, signatureInfo.second.m_Name)); + m_ArchivePtr.Release(); + } else { + m_LogCallback(LogLevel::Debug, + std::format(L"Opened {} using {} (from signature).", + archiveName, signatureInfo.second.m_Name)); + + // Retrieve the extension (warning: .extension() contains the dot): + std::wstring ext = + ArchiveStrings::towlower(filepath.extension().wstring().substr(1)); + std::wistringstream s(signatureInfo.second.m_Extensions); + std::wstring t; + bool found = false; + while (s >> t) { + if (t == ext) { + found = true; + break; + } + } + if (!found) { + m_LogCallback(LogLevel::Warning, + L"The extension of this file did not match the expected " + L"extensions for this format."); + sigMismatch = true; + } + } + // Arguably we should give up here if it's not OK if 7zip can't even start + // to decode even though we've found the format from the signature. + // Sadly, the 7zip API documentation is pretty well non-existant. + break; + } + std::vector::iterator iter = std::find_if( + formatList.begin(), formatList.end(), [=](ArchiveFormatInfo a) -> bool { + return a.m_Name == signatureInfo.second.m_Name; + }); + if (iter != formatList.end()) + formatList.erase(iter); + } + } + + { + // determine archive type based on extension + Formats const* formats = nullptr; + std::wstring ext = + ArchiveStrings::towlower(filepath.extension().wstring().substr(1)); + FormatMap::const_iterator map_iter = m_FormatMap.find(ext); + if (map_iter != m_FormatMap.end()) { + formats = &map_iter->second; + if (formats != nullptr) { + if (m_ArchivePtr == nullptr) { + // OK, we have some potential formats. If there is only one, try it now. If + // there are multiple formats, we'll try by signature lookup first. + for (ArchiveFormatInfo format : *formats) { + if (m_CreateObjectFunc(&format.m_ClassID, &IID_IInArchive, + (void**)&m_ArchivePtr) != S_OK) { + m_LastError = Error::ERROR_LIBRARY_ERROR; + return false; + } + + if (m_ArchivePtr->Open(file, 0, openCallbackPtr) != S_OK) { + m_LogCallback(LogLevel::Debug, + std::format(L"Failed to open {} using {} (from signature).", + archiveName, format.m_Name)); + m_ArchivePtr.Release(); + } else { + m_LogCallback(LogLevel::Debug, + std::format(L"Opened {} using {} (from signature).", + archiveName, format.m_Name)); + break; + } + + std::vector::iterator iter = std::find_if( + formatList.begin(), formatList.end(), [=](ArchiveFormatInfo a) -> bool { + return a.m_Name == format.m_Name; + }); + if (iter != formatList.end()) + formatList.erase(iter); + } + } else if (sigMismatch) { + std::vector vformats; + for (ArchiveFormatInfo format : *formats) { + vformats.push_back(format.m_Name); + } + m_LogCallback( + LogLevel::Warning, + std::format(L"The format(s) expected for this extension are: {}.", + ArchiveStrings::join(vformats, L", "))); + } + } + } + } + + if (m_ArchivePtr == nullptr) { + m_LogCallback(LogLevel::Warning, L"Trying to open an archive but could not " + L"recognize the extension or signature."); + m_LogCallback( + LogLevel::Debug, + L"Attempting to open the file with the remaining formats as a fallback..."); + for (auto format : formatList) { + if (m_CreateObjectFunc(&format.m_ClassID, &IID_IInArchive, + (void**)&m_ArchivePtr) != S_OK) { + m_LastError = Error::ERROR_LIBRARY_ERROR; + return false; + } + if (m_ArchivePtr->Open(file, 0, openCallbackPtr) == S_OK) { + m_LogCallback(LogLevel::Debug, + std::format(L"Opened {} using {} (from signature).", archiveName, + format.m_Name)); + m_LogCallback(LogLevel::Warning, + L"This archive likely has an incorrect extension."); + break; + } else + m_ArchivePtr.Release(); + } + } + + if (m_ArchivePtr == nullptr) { + m_LastError = Error::ERROR_INVALID_ARCHIVE_FORMAT; + return false; + } + + m_Password = openCallbackPtr->GetPassword(); + /* + UInt32 subFile = ULONG_MAX; + { + NCOM::CPropVariant prop; + if (m_ArchivePtr->GetArchiveProperty(kpidMainSubfile, &prop) != S_OK) { + throw std::runtime_error("failed to get property kpidMainSubfile"); + } + + if (prop.vt == VT_UI4) { + subFile = prop.ulVal; + } + } + + if (subFile != ULONG_MAX) { + std::wstring subPath = GetArchiveItemPath(m_ArchivePtr, subFile); + + CMyComPtr setSubArchiveName; + openCallbackPtr.QueryInterface(IID_IArchiveOpenSetSubArchiveName, (void + **)&setSubArchiveName); if (setSubArchiveName) { + setSubArchiveName->SetSubArchiveName(subPath.c_str()); + } + }*/ + + m_LastError = Error::ERROR_NONE; + + resetFileList(); + return true; +} + +void ArchiveImpl::close() +{ + if (m_ArchivePtr != nullptr) { + m_ArchivePtr->Close(); + } + clearFileList(); + m_ArchivePtr.Release(); + m_PasswordCallback = {}; +} + +void ArchiveImpl::clearFileList() +{ + for (std::vector::iterator iter = m_FileList.begin(); + iter != m_FileList.end(); ++iter) { + delete *iter; + } + m_FileList.clear(); +} + +void ArchiveImpl::resetFileList() +{ + UInt32 numItems = 0; + clearFileList(); + + m_ArchivePtr->GetNumberOfItems(&numItems); + + for (UInt32 i = 0; i < numItems; ++i) { + m_FileList.push_back(new FileDataImpl( + readProperty(i, kpidPath), readProperty(i, kpidSize), + readProperty(i, kpidCRC), readProperty(i, kpidIsDir))); + } +} + +bool ArchiveImpl::extract(std::wstring const& outputDirectory, + ProgressCallback progressCallback, + FileChangeCallback fileChangeCallback, + ErrorCallback errorCallback) + +{ + // Retrieve the list of indices we want to extract: + std::vector indices; + UInt64 totalSize = 0; + for (std::size_t i = 0; i < m_FileList.size(); ++i) { + FileDataImpl* fileData = static_cast(m_FileList[i]); + if (!fileData->isEmpty()) { + indices.push_back(static_cast(i)); + totalSize += fileData->getSize(); + } + } + + m_ExtractCallback = new CArchiveExtractCallback( + progressCallback, fileChangeCallback, errorCallback, m_PasswordCallback, + m_LogCallback, m_ArchivePtr, outputDirectory, &m_FileList[0], m_FileList.size(), + totalSize, &m_Password); + HRESULT result = m_ArchivePtr->Extract( + indices.data(), static_cast(indices.size()), false, m_ExtractCallback); + // Note: m_ExtractCallBack is deleted by Extract + switch (result) { + case S_OK: { + // nop + } break; + case E_ABORT: { + m_LastError = Error::ERROR_EXTRACT_CANCELLED; + } break; + case E_OUTOFMEMORY: { + m_LastError = Error::ERROR_OUT_OF_MEMORY; + } break; + default: { + m_LastError = Error::ERROR_LIBRARY_ERROR; + } break; + } + + return result == S_OK; +} + +void ArchiveImpl::cancel() +{ + m_ExtractCallback->SetCanceled(true); +} + +std::unique_ptr CreateArchive() +{ + return std::make_unique(); +} diff --git a/libs/archive/src/compat.h b/libs/archive/src/compat.h new file mode 100644 index 0000000..65c2ec5 --- /dev/null +++ b/libs/archive/src/compat.h @@ -0,0 +1,87 @@ +/* +Mod Organizer archive handling - Linux compatibility header + +Copyright (C) 2024 MO2 Team. All rights reserved. + +This header provides Windows COM compatibility types for Linux builds. +On Windows, the real Windows headers are used instead. +*/ + +#ifndef ARCHIVE_COMPAT_H +#define ARCHIVE_COMPAT_H + +#ifdef _WIN32 + +#include +#include +#include +#include +#include + +#else // Linux + +#include +#include + +// PropVariantInit / PropVariantClear - map to VariantClear from 7zip SDK +inline HRESULT PropVariantInit(PROPVARIANT* pvar) { + pvar->vt = VT_EMPTY; + return S_OK; +} + +inline HRESULT PropVariantClear(PROPVARIANT* pvar) { + return VariantClear(pvar); +} + +// A minimal CComPtr replacement for Linux +template +class CComPtr +{ +public: + CComPtr() : p(nullptr) {} + CComPtr(T* lp) : p(lp) { if (p) p->AddRef(); } + CComPtr(const CComPtr& other) : p(other.p) { if (p) p->AddRef(); } + ~CComPtr() { Release(); } + + CComPtr& operator=(T* lp) { + if (lp) lp->AddRef(); + Release(); + p = lp; + return *this; + } + + CComPtr& operator=(const CComPtr& other) { + if (this != &other) { + if (other.p) other.p->AddRef(); + Release(); + p = other.p; + } + return *this; + } + + void Release() { + if (p) { + p->Release(); + p = nullptr; + } + } + + T* Detach() { + T* pt = p; + p = nullptr; + return pt; + } + + operator T*() const { return p; } + T* operator->() const { return p; } + T** operator&() { return &p; } + bool operator!() const { return p == nullptr; } + bool operator==(std::nullptr_t) const { return p == nullptr; } + bool operator!=(std::nullptr_t) const { return p != nullptr; } + + T* p; +}; + +#endif // _WIN32 + +#endif // ARCHIVE_COMPAT_H diff --git a/libs/archive/src/extractcallback.cpp b/libs/archive/src/extractcallback.cpp new file mode 100644 index 0000000..7629298 --- /dev/null +++ b/libs/archive/src/extractcallback.cpp @@ -0,0 +1,364 @@ +/* +Mod Organizer archive handling + +Copyright (C) 2012 Sebastian Herbord, 2020 MO2 Team. All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "compat.h" + +#include +#include +#include +#include +#include + +#include "archive.h" +#include "extractcallback.h" +#include "propertyvariant.h" + +std::wstring operationResultToString(Int32 operationResult) +{ + namespace R = NArchive::NExtract::NOperationResult; + + switch (operationResult) { + case R::kOK: + return {}; + + case R::kUnsupportedMethod: + return L"Encoding method unsupported"; + + case R::kDataError: + return L"Data error"; + + case R::kCRCError: + return L"CRC error"; + + case R::kUnavailable: + return L"Unavailable"; + + case R::kUnexpectedEnd: + return L"Unexpected end of archive"; + + case R::kDataAfterEnd: + return L"Data after end of archive"; + + case R::kIsNotArc: + return L"Not an ARC"; + + case R::kHeadersError: + return L"Bad headers"; + + case R::kWrongPassword: + return L"Wrong password"; + + default: + return std::format(L"Unknown error {}", operationResult); + } +} + +CArchiveExtractCallback::CArchiveExtractCallback( + Archive::ProgressCallback progressCallback, + Archive::FileChangeCallback fileChangeCallback, + Archive::ErrorCallback errorCallback, Archive::PasswordCallback passwordCallback, + Archive::LogCallback logCallback, IInArchive* archiveHandler, + std::wstring const& directoryPath, FileData* const* fileData, std::size_t nbFiles, + UInt64 totalFileSize, std::wstring* password) + : m_ArchiveHandler(archiveHandler), m_Total(0), m_DirectoryPath(), + m_Extracting(false), m_Canceled(false), m_Timers{}, m_ProcessedFileInfo{}, + m_OutputFileStream{}, m_OutFileStreamCom{}, m_FileData(fileData), + m_NbFiles(nbFiles), m_TotalFileSize(totalFileSize), m_LastCallbackFileSize(0), + m_ExtractedFileSize(0), m_ProgressCallback(progressCallback), + m_FileChangeCallback(fileChangeCallback), m_ErrorCallback(errorCallback), + m_PasswordCallback(passwordCallback), m_LogCallback(logCallback), + m_Password(password) +{ + m_DirectoryPath = IO::make_path(directoryPath); +} + +CArchiveExtractCallback::~CArchiveExtractCallback() +{ +#ifdef INSTRUMENT_ARCHIVE + m_LogCallback(Archive::LogLevel::Debug, m_Timers.GetStream.toString(L"GetStream")); + m_LogCallback(Archive::LogLevel::Debug, m_Timers.SetOperationResult.SetMTime.toString( + L"SetOperationResult.SetMTime")); + m_LogCallback(Archive::LogLevel::Debug, m_Timers.SetOperationResult.Close.toString( + L"SetOperationResult.Close")); + m_LogCallback(Archive::LogLevel::Debug, m_Timers.SetOperationResult.Release.toString( + L"SetOperationResult.Release")); + m_LogCallback(Archive::LogLevel::Debug, + m_Timers.SetOperationResult.SetFileAttributesW.toString( + L"SetOperationResult.SetFileAttributesW")); +#endif +} + +STDMETHODIMP CArchiveExtractCallback::SetTotal(UInt64 size) throw() +{ + m_Total = size; + return S_OK; +} + +STDMETHODIMP CArchiveExtractCallback::SetCompleted(const UInt64* completed) throw() +{ + if (m_ProgressCallback) { + m_ProgressCallback(Archive::ProgressType::ARCHIVE, *completed, m_Total); + } + return m_Canceled ? E_ABORT : S_OK; +} + +template +bool CArchiveExtractCallback::getOptionalProperty(UInt32 index, int property, + T* result) const +{ + PropertyVariant prop; + if (m_ArchiveHandler->GetProperty(index, property, &prop) != S_OK) { + m_LogCallback(Archive::LogLevel::Error, + std::format(L"Error getting property {}.", property)); + return false; + } + if (prop.is_empty()) { + return false; + } + *result = static_cast(prop); + return true; +} + +template +bool CArchiveExtractCallback::getProperty(UInt32 index, int property, T* result) const +{ + PropertyVariant prop; + if (m_ArchiveHandler->GetProperty(index, property, &prop) != S_OK) { + m_LogCallback(Archive::LogLevel::Error, + std::format(L"Error getting property {}.", property)); + return false; + } + + *result = static_cast(prop); + return true; +} + +STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, + ISequentialOutStream** outStream, + Int32 askExtractMode) throw() +{ + [[maybe_unused]] auto guard = m_Timers.GetStream.instrument(); + namespace fs = std::filesystem; + + *outStream = nullptr; + m_OutFileStreamCom.Release(); + + m_FullProcessedPaths.clear(); + m_Extracting = false; + + if (askExtractMode != NArchive::NExtract::NAskMode::kExtract) { + return S_OK; + } + + std::vector filenames = m_FileData[index]->getOutputFilePaths(); + m_FileData[index]->clearOutputFilePaths(); + if (filenames.empty()) { + return S_OK; + } + +#ifndef _WIN32 + // Archives from Windows contain backslash path separators which are valid + // filename characters on Linux - convert them to forward slashes. + for (auto& fn : filenames) { + std::replace(fn.begin(), fn.end(), L'\\', L'/'); + } +#endif + + try { + m_ProcessedFileInfo.AttribDefined = + getOptionalProperty(index, kpidAttrib, &m_ProcessedFileInfo.Attrib); + + if (!getProperty(index, kpidIsDir, &m_ProcessedFileInfo.isDir)) { + return E_ABORT; + } + + // Why do we do this? And if we are doing this, shouldn't we copy the created + // and accessed times (kpidATime, kpidCTime) as well? + m_ProcessedFileInfo.MTimeDefined = + getOptionalProperty(index, kpidMTime, &m_ProcessedFileInfo.MTime); + + if (m_ProcessedFileInfo.isDir) { + for (auto const& filename : filenames) { + auto fullpath = m_DirectoryPath / fs::path(filename).make_preferred(); + std::error_code ec; + std::filesystem::create_directories(fullpath, ec); + if (ec) { + reportError(L"cannot created directory '{}': {}", fullpath, ec); + return E_ABORT; + } + m_FullProcessedPaths.push_back(fullpath); + } + } else { + for (auto const& filename : filenames) { + auto fullProcessedPath = m_DirectoryPath / fs::path(filename).make_preferred(); + // If the filename contains a '/' we want to make the directory + auto directoryPath = fullProcessedPath.parent_path(); + if (!fs::exists(directoryPath)) { + // Make the containing directory + std::error_code ec; + std::filesystem::create_directories(directoryPath, ec); + if (ec) { + reportError(L"cannot created directory '{}': {}", directoryPath, ec); + return E_ABORT; + } + // m_DirectoryPath.mkpath(filename.left(slashPos)); + } + // If the file already exists, delete it + if (fs::exists(fullProcessedPath)) { + std::error_code ec; + if (!fs::remove(fullProcessedPath, ec)) { + reportError(L"cannot delete output file '{}': {}", fullProcessedPath, ec); + return E_ABORT; + } + } + m_FullProcessedPaths.push_back(fullProcessedPath); + } + + m_OutputFileStream = new MultiOutputStream([this](UInt32 size, UInt64) { + m_ExtractedFileSize += size; + if (m_ProgressCallback) { + m_ProgressCallback(Archive::ProgressType::EXTRACTION, m_ExtractedFileSize, + m_TotalFileSize); + } + }); + CComPtr outStreamCom(m_OutputFileStream); + + if (!m_OutputFileStream->Open(m_FullProcessedPaths)) { + reportError(L"cannot open output file '{}': {}", m_FullProcessedPaths[0], + ::GetLastError()); + return E_ABORT; + } + + UInt64 fileSize; + auto fileSizeFound = getOptionalProperty(index, kpidSize, &fileSize); + if (fileSizeFound && m_OutputFileStream->SetSize(fileSize) != S_OK) { + m_LogCallback(Archive::LogLevel::Error, + std::format(L"SetSize() failed on {}.", m_FullProcessedPaths[0])); + } + + // This is messy but I can't find another way of doing it. A simple + // assignment of m_outFileStream to *outStream doesn't increase the + // reference count. + m_OutFileStreamCom = outStreamCom; + *outStream = outStreamCom.Detach(); + } + + if (m_FileChangeCallback) { + m_FileChangeCallback(Archive::FileChangeType::EXTRACTION_START, filenames[0]); + } + + return S_OK; + } catch (std::exception const& e) { + m_LogCallback(Archive::LogLevel::Error, + std::format(L"Caught exception {} in GetStream.", e)); + } + return E_FAIL; +} + +STDMETHODIMP CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode) throw() +{ + if (m_Canceled) { + return E_ABORT; + } + m_Extracting = askExtractMode == NArchive::NExtract::NAskMode::kExtract; + return S_OK; +} + +STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 operationResult) throw() +{ + if (operationResult != NArchive::NExtract::NOperationResult::kOK) { + reportError(operationResultToString(operationResult)); + } + + if (m_OutFileStreamCom) { + if (m_ProcessedFileInfo.MTimeDefined) { + [[maybe_unused]] auto guard = m_Timers.SetOperationResult.SetMTime.instrument(); + m_OutputFileStream->SetMTime(&m_ProcessedFileInfo.MTime); + } + [[maybe_unused]] auto guard = m_Timers.SetOperationResult.Close.instrument(); + RINOK(m_OutputFileStream->Close()) + } + + { + [[maybe_unused]] auto guard = m_Timers.SetOperationResult.Release.instrument(); + m_OutFileStreamCom.Release(); + } + + [[maybe_unused]] auto guard2 = m_Timers.SetOperationResult.SetFileAttributesW.instrument(); + if (m_Extracting && m_ProcessedFileInfo.AttribDefined) { + // this is moderately annoying. I can't do this on the file handle because if + // the file in question is a directory there isn't a file handle. + // Also I'd like to convert the attributes to QT attributes but I'm not sure + // if that's possible. Hence the conversions and strange string. + for (auto& path : m_FullProcessedPaths) { +#ifdef _WIN32 + std::wstring const fn = L"\\\\?\\" + path.native(); + // If the attributes are POSIX-based, fix that + if (m_ProcessedFileInfo.Attrib & 0xF0000000) + m_ProcessedFileInfo.Attrib &= 0x7FFF; + + // Should probably log any errors here somehow + ::SetFileAttributesW(fn.c_str(), m_ProcessedFileInfo.Attrib); +#else + // On Linux, we could set file permissions based on the attributes, + // but Windows file attributes don't map well to POSIX permissions. + // For now, we only handle the read-only attribute and only for files. + // Applying read-only to directories can break extraction when later + // files need to be created inside those directories. + if (!m_ProcessedFileInfo.isDir && + (m_ProcessedFileInfo.Attrib & FILE_ATTRIBUTE_READONLY)) { + std::filesystem::permissions(path, + std::filesystem::perms::owner_write, + std::filesystem::perm_options::remove); + } else if (m_ProcessedFileInfo.isDir) { + // Keep extracted directories writable for the owner. + std::filesystem::permissions(path, + std::filesystem::perms::owner_write, + std::filesystem::perm_options::add); + } +#endif + } + } + + return S_OK; +} + +STDMETHODIMP CArchiveExtractCallback::CryptoGetTextPassword(BSTR* passwordOut) throw() +{ + // if we've already got a password, don't ask again (and again...) + if (m_Password->empty() && m_PasswordCallback) { + *m_Password = m_PasswordCallback(); + } + + *passwordOut = ::SysAllocString(m_Password->c_str()); + return *passwordOut != 0 ? S_OK : E_OUTOFMEMORY; +} + +void CArchiveExtractCallback::SetCanceled(bool aCanceled) +{ + m_Canceled = aCanceled; +} + +void CArchiveExtractCallback::reportError(std::wstring const& message) +{ + if (m_ErrorCallback) { + m_ErrorCallback(message); + } +} diff --git a/libs/archive/src/extractcallback.h b/libs/archive/src/extractcallback.h new file mode 100644 index 0000000..f95fc86 --- /dev/null +++ b/libs/archive/src/extractcallback.h @@ -0,0 +1,133 @@ +/* +Mod Organizer archive handling + +Copyright (C) 2012 Sebastian Herbord, 2020 MO2 Team. All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef EXTRACTCALLBACK_H +#define EXTRACTCALLBACK_H + +#include +#include +#include +#include + +#include <7zip/Archive/IArchive.h> +#include <7zip/IPassword.h> + +#include "compat.h" + +#include "archive.h" +#include "formatter.h" +#include "instrument.h" +#include "multioutputstream.h" +#include "unknown_impl.h" + +class FileData; + +class CArchiveExtractCallback : public IArchiveExtractCallback, + public ICryptoGetTextPassword +{ + + // A note: It appears that the IArchiveExtractCallback interface includes the + // IProgress interface, swo we need to respond to it + UNKNOWN_3_INTERFACE(IArchiveExtractCallback, ICryptoGetTextPassword, IProgress); + +public: + CArchiveExtractCallback(Archive::ProgressCallback progressCallback, + Archive::FileChangeCallback fileChangeCallback, + Archive::ErrorCallback errorCallback, + Archive::PasswordCallback passwordCallback, + Archive::LogCallback logCallback, IInArchive* archiveHandler, + std::wstring const& directoryPath, FileData* const* fileData, + std::size_t nbFiles, UInt64 totalFileSize, + std::wstring* password); + + virtual ~CArchiveExtractCallback(); + + void SetCanceled(bool aCanceled); + + Z7_IFACE_COM7_IMP(IProgress) + Z7_IFACE_COM7_IMP(IArchiveExtractCallback) + + // ICryptoGetTextPassword + STDMETHOD(CryptoGetTextPassword)(BSTR* aPassword) throw(); + +private: + void reportError(const std::wstring& message); + + template + void reportError(std::wformat_string format, Args&&... args) + { + reportError(std::format(format, std::forward(args)...)); + } + + template + bool getOptionalProperty(UInt32 index, int property, T* result) const; + template + bool getProperty(UInt32 index, int property, T* result) const; + +private: + CComPtr m_ArchiveHandler; + + UInt64 m_Total; + + std::filesystem::path m_DirectoryPath; + bool m_Extracting; + std::atomic m_Canceled; + + struct + { + ArchiveTimers::Timer GetStream; + struct + { + ArchiveTimers::Timer SetMTime; + ArchiveTimers::Timer Close; + ArchiveTimers::Timer Release; + ArchiveTimers::Timer SetFileAttributesW; + } SetOperationResult; + } m_Timers; + + struct CProcessedFileInfo + { + FILETIME MTime; + UInt32 Attrib; + bool isDir; + bool AttribDefined; + bool MTimeDefined; + } m_ProcessedFileInfo; + + MultiOutputStream* m_OutputFileStream; + CComPtr m_OutFileStreamCom; + + std::vector m_FullProcessedPaths; + + FileData* const* m_FileData; + std::size_t m_NbFiles; + UInt64 m_TotalFileSize; + UInt64 m_LastCallbackFileSize; + UInt64 m_ExtractedFileSize; + + Archive::ProgressCallback m_ProgressCallback; + Archive::FileChangeCallback m_FileChangeCallback; + Archive::ErrorCallback m_ErrorCallback; + Archive::PasswordCallback m_PasswordCallback; + Archive::LogCallback m_LogCallback; + std::wstring* m_Password; +}; + +#endif // EXTRACTCALLBACK_H diff --git a/libs/archive/src/fileio.cpp b/libs/archive/src/fileio.cpp new file mode 100644 index 0000000..83d0665 --- /dev/null +++ b/libs/archive/src/fileio.cpp @@ -0,0 +1,449 @@ +/* +Mod Organizer archive handling + +Copyright (C) 2020 MO2 Team. All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "fileio.h" + +#ifdef _WIN32 + +inline bool BOOLToBool(BOOL v) +{ + return (v != FALSE); +} + +namespace IO +{ + +// FileBase + +bool FileBase::Close() noexcept +{ + if (m_Handle == INVALID_HANDLE_VALUE) + return true; + if (!::CloseHandle(m_Handle)) + return false; + m_Handle = INVALID_HANDLE_VALUE; + return true; +} + +bool FileBase::GetPosition(UInt64& position) noexcept +{ + return Seek(0, FILE_CURRENT, position); +} + +bool FileBase::GetLength(UInt64& length) const noexcept +{ + DWORD sizeHigh; + DWORD sizeLow = ::GetFileSize(m_Handle, &sizeHigh); + if (sizeLow == 0xFFFFFFFF) + if (::GetLastError() != NO_ERROR) + return false; + length = (((UInt64)sizeHigh) << 32) + sizeLow; + return true; +} + +bool FileBase::Seek(Int64 distanceToMove, DWORD moveMethod, + UInt64& newPosition) noexcept +{ + LONG high = (LONG)(distanceToMove >> 32); + DWORD low = ::SetFilePointer(m_Handle, (LONG)(distanceToMove & 0xFFFFFFFF), &high, + moveMethod); + if (low == 0xFFFFFFFF) + if (::GetLastError() != NO_ERROR) + return false; + newPosition = (((UInt64)(UInt32)high) << 32) + low; + return true; +} +bool FileBase::Seek(UInt64 position, UInt64& newPosition) noexcept +{ + return Seek(position, FILE_BEGIN, newPosition); +} + +bool FileBase::SeekToBegin() noexcept +{ + UInt64 newPosition; + return Seek(0, newPosition); +} + +bool FileBase::SeekToEnd(UInt64& newPosition) noexcept +{ + return Seek(0, FILE_END, newPosition); +} + +bool FileBase::Create(std::filesystem::path const& path, DWORD desiredAccess, + DWORD shareMode, DWORD creationDisposition, + DWORD flagsAndAttributes) noexcept +{ + if (!Close()) { + return false; + } + + m_Handle = + ::CreateFileW(path.c_str(), desiredAccess, shareMode, (LPSECURITY_ATTRIBUTES)NULL, + creationDisposition, flagsAndAttributes, (HANDLE)NULL); + + return m_Handle != INVALID_HANDLE_VALUE; +} + +bool FileBase::GetFileInformation(std::filesystem::path const& path, + FileInfo* info) noexcept +{ + // Use FileBase to open/close the file: + FileBase file; + if (!file.Create(path, 0, FILE_SHARE_READ, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS)) + return false; + + BY_HANDLE_FILE_INFORMATION finfo; + if (!BOOLToBool(GetFileInformationByHandle(file.m_Handle, &finfo))) { + return false; + } + + *info = FileInfo(path, finfo); + return true; +} + +// FileIn + +bool FileIn::Open(std::filesystem::path const& filepath, DWORD shareMode, + DWORD creationDisposition, DWORD flagsAndAttributes) noexcept +{ + bool res = Create(filepath.c_str(), GENERIC_READ, shareMode, creationDisposition, + flagsAndAttributes); + return res; +} +bool FileIn::OpenShared(std::filesystem::path const& filepath, + bool shareForWrite) noexcept +{ + return Open(filepath, FILE_SHARE_READ | (shareForWrite ? FILE_SHARE_WRITE : 0), + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL); +} +bool FileIn::Open(std::filesystem::path const& filepath) noexcept +{ + return OpenShared(filepath, false); +} +bool FileIn::Read(void* data, UInt32 size, UInt32& processedSize) noexcept +{ + processedSize = 0; + do { + UInt32 processedLoc = 0; + bool res = ReadPart(data, size, processedLoc); + processedSize += processedLoc; + if (!res) + return false; + if (processedLoc == 0) + return true; + data = (void*)((unsigned char*)data + processedLoc); + size -= processedLoc; + } while (size > 0); + return true; +} +bool FileIn::Read1(void* data, UInt32 size, UInt32& processedSize) noexcept +{ + DWORD processedLoc = 0; + bool res = BOOLToBool(::ReadFile(m_Handle, data, size, &processedLoc, NULL)); + processedSize = (UInt32)processedLoc; + return res; +} +bool FileIn::ReadPart(void* data, UInt32 size, UInt32& processedSize) noexcept +{ + if (size > kChunkSizeMax) + size = kChunkSizeMax; + return Read1(data, size, processedSize); +} + +// FileOut + +bool FileOut::Open(std::filesystem::path const& fileName, DWORD shareMode, + DWORD creationDisposition, DWORD flagsAndAttributes) noexcept +{ + return Create(fileName, GENERIC_WRITE, shareMode, creationDisposition, + flagsAndAttributes); +} + +bool FileOut::Open(std::filesystem::path const& fileName) noexcept +{ + return Open(fileName, FILE_SHARE_READ, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL); +} + +bool FileOut::SetTime(const FILETIME* cTime, const FILETIME* aTime, + const FILETIME* mTime) noexcept +{ + return BOOLToBool(::SetFileTime(m_Handle, cTime, aTime, mTime)); +} +bool FileOut::SetMTime(const FILETIME* mTime) noexcept +{ + return SetTime(NULL, NULL, mTime); +} +bool FileOut::Write(const void* data, UInt32 size, UInt32& processedSize) noexcept +{ + processedSize = 0; + do { + UInt32 processedLoc = 0; + bool res = WritePart(data, size, processedLoc); + processedSize += processedLoc; + if (!res) + return false; + if (processedLoc == 0) + return true; + data = (const void*)((const unsigned char*)data + processedLoc); + size -= processedLoc; + } while (size > 0); + return true; +} + +bool FileOut::SetLength(UInt64 length) noexcept +{ + UInt64 newPosition; + if (!Seek(length, newPosition)) + return false; + if (newPosition != length) + return false; + return SetEndOfFile(); +} +bool FileOut::SetEndOfFile() noexcept +{ + return BOOLToBool(::SetEndOfFile(m_Handle)); +} + +bool FileOut::WritePart(const void* data, UInt32 size, UInt32& processedSize) noexcept +{ + if (size > kChunkSizeMax) + size = kChunkSizeMax; + DWORD processedLoc = 0; + bool res = BOOLToBool(::WriteFile(m_Handle, data, size, &processedLoc, NULL)); + processedSize = (UInt32)processedLoc; + return res; +} + +} // namespace IO + +#else // Linux + +#include +#include +#include +#include +#include +#include + +namespace IO +{ + +// FileBase + +bool FileBase::Close() noexcept +{ + if (m_Fd == -1) + return true; + if (::close(m_Fd) != 0) + return false; + m_Fd = -1; + return true; +} + +bool FileBase::GetPosition(UInt64& position) noexcept +{ + return Seek(0, SEEK_CUR, position); +} + +bool FileBase::GetLength(UInt64& length) const noexcept +{ + struct stat st; + if (fstat(m_Fd, &st) != 0) + return false; + length = (UInt64)st.st_size; + return true; +} + +bool FileBase::Seek(Int64 distanceToMove, int whence, UInt64& newPosition) noexcept +{ + off_t result = ::lseek(m_Fd, (off_t)distanceToMove, whence); + if (result == (off_t)-1) + return false; + newPosition = (UInt64)result; + return true; +} + +bool FileBase::Seek(UInt64 position, UInt64& newPosition) noexcept +{ + return Seek((Int64)position, SEEK_SET, newPosition); +} + +bool FileBase::SeekToBegin() noexcept +{ + UInt64 newPosition; + return Seek(0, newPosition); +} + +bool FileBase::SeekToEnd(UInt64& newPosition) noexcept +{ + return Seek(0, SEEK_END, newPosition); +} + +bool FileBase::Create(std::filesystem::path const& path, int flags, int mode) noexcept +{ + if (!Close()) { + return false; + } + + m_Fd = ::open(path.c_str(), flags, mode); + return m_Fd != -1; +} + +bool FileBase::GetFileInformation(std::filesystem::path const& path, + FileInfo* info) noexcept +{ + struct stat st; + if (::stat(path.c_str(), &st) != 0) { + return false; + } + + *info = FileInfo(path, st); + return true; +} + +// FileIn + +bool FileIn::Open(std::filesystem::path const& filepath) noexcept +{ + return Create(filepath, O_RDONLY); +} + +bool FileIn::Read(void* data, UInt32 size, UInt32& processedSize) noexcept +{ + processedSize = 0; + do { + UInt32 processedLoc = 0; + bool res = ReadPart(data, size, processedLoc); + processedSize += processedLoc; + if (!res) + return false; + if (processedLoc == 0) + return true; + data = (void*)((unsigned char*)data + processedLoc); + size -= processedLoc; + } while (size > 0); + return true; +} + +bool FileIn::Read1(void* data, UInt32 size, UInt32& processedSize) noexcept +{ + ssize_t result = ::read(m_Fd, data, size); + if (result < 0) { + processedSize = 0; + return false; + } + processedSize = (UInt32)result; + return true; +} + +bool FileIn::ReadPart(void* data, UInt32 size, UInt32& processedSize) noexcept +{ + if (size > kChunkSizeMax) + size = kChunkSizeMax; + return Read1(data, size, processedSize); +} + +// FileOut + +bool FileOut::Open(std::filesystem::path const& fileName) noexcept +{ + return Create(fileName, O_WRONLY | O_CREAT | O_TRUNC, 0644); +} + +bool FileOut::SetTime(const FILETIME* /*cTime*/, const FILETIME* /*aTime*/, + const FILETIME* mTime) noexcept +{ + return SetMTime(mTime); +} + +bool FileOut::SetMTime(const FILETIME* mTime) noexcept +{ + if (!mTime) return true; + + // Convert FILETIME to timespec + // FILETIME is 100ns intervals since 1601-01-01 + // Unix time is seconds since 1970-01-01 + constexpr UInt64 EPOCH_DIFF = 116444736000000000ULL; + UInt64 ticks = ((UInt64)mTime->dwHighDateTime << 32) | mTime->dwLowDateTime; + if (ticks < EPOCH_DIFF) return false; + ticks -= EPOCH_DIFF; + + struct timespec times[2]; + // atime - keep current + times[0].tv_sec = 0; + times[0].tv_nsec = UTIME_OMIT; + // mtime + times[1].tv_sec = (time_t)(ticks / 10000000ULL); + times[1].tv_nsec = (long)((ticks % 10000000ULL) * 100); + + return futimens(m_Fd, times) == 0; +} + +bool FileOut::Write(const void* data, UInt32 size, UInt32& processedSize) noexcept +{ + processedSize = 0; + do { + UInt32 processedLoc = 0; + bool res = WritePart(data, size, processedLoc); + processedSize += processedLoc; + if (!res) + return false; + if (processedLoc == 0) + return true; + data = (const void*)((const unsigned char*)data + processedLoc); + size -= processedLoc; + } while (size > 0); + return true; +} + +bool FileOut::SetLength(UInt64 length) noexcept +{ + UInt64 newPosition; + if (!Seek(length, newPosition)) + return false; + if (newPosition != length) + return false; + return SetEndOfFile(); +} + +bool FileOut::SetEndOfFile() noexcept +{ + UInt64 pos; + if (!GetPosition(pos)) + return false; + return ftruncate(m_Fd, (off_t)pos) == 0; +} + +bool FileOut::WritePart(const void* data, UInt32 size, UInt32& processedSize) noexcept +{ + if (size > kChunkSizeMax) + size = kChunkSizeMax; + ssize_t result = ::write(m_Fd, data, size); + if (result < 0) { + processedSize = 0; + return false; + } + processedSize = (UInt32)result; + return true; +} + +} // namespace IO + +#endif diff --git a/libs/archive/src/fileio.h b/libs/archive/src/fileio.h new file mode 100644 index 0000000..72b71c7 --- /dev/null +++ b/libs/archive/src/fileio.h @@ -0,0 +1,343 @@ +/* +Mod Organizer archive handling + +Copyright (C) 2020 MO2 Team. All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef ARCHIVE_FILEIO_H +#define ARCHIVE_FILEIO_H + +// This code is adapted from 7z client code. + +#ifdef _WIN32 +#include +#include "7zip//Archive/IArchive.h" +#else +#include +#include <7zip/Archive/IArchive.h> +#endif + +#include +#include + +#ifndef _WIN32 +#include +#endif + +namespace IO +{ + +#ifdef _WIN32 + +/** + * Small class that wraps windows BY_HANDLE_FILE_INFORMATION and returns + * type matching 7z types. + */ +class FileInfo +{ +public: + FileInfo() : m_Valid{false} {}; + FileInfo(std::filesystem::path const& path, BY_HANDLE_FILE_INFORMATION fileInfo) + : m_Valid{true}, m_Path(path), m_FileInfo{fileInfo} + {} + + bool isValid() const { return m_Valid; } + + const std::filesystem::path& path() const { return m_Path; } + + UInt32 fileAttributes() const { return m_FileInfo.dwFileAttributes; } + FILETIME creationTime() const { return m_FileInfo.ftCreationTime; } + FILETIME lastAccessTime() const { return m_FileInfo.ftLastAccessTime; } + FILETIME lastWriteTime() const { return m_FileInfo.ftLastWriteTime; } + UInt32 volumeSerialNumber() const { return m_FileInfo.dwVolumeSerialNumber; } + UInt64 fileSize() const + { + return ((UInt64)m_FileInfo.nFileSizeHigh) << 32 | m_FileInfo.nFileSizeLow; + } + UInt32 numberOfLinks() const { return m_FileInfo.nNumberOfLinks; } + UInt64 fileInfex() const + { + return ((UInt64)m_FileInfo.nFileIndexHigh) << 32 | m_FileInfo.nFileIndexLow; + } + + bool isArchived() const { return MatchesMask(FILE_ATTRIBUTE_ARCHIVE); } + bool isCompressed() const { return MatchesMask(FILE_ATTRIBUTE_COMPRESSED); } + bool isDir() const { return MatchesMask(FILE_ATTRIBUTE_DIRECTORY); } + bool isEncrypted() const { return MatchesMask(FILE_ATTRIBUTE_ENCRYPTED); } + bool isHidden() const { return MatchesMask(FILE_ATTRIBUTE_HIDDEN); } + bool isNormal() const { return MatchesMask(FILE_ATTRIBUTE_NORMAL); } + bool isOffline() const { return MatchesMask(FILE_ATTRIBUTE_OFFLINE); } + bool isReadOnly() const { return MatchesMask(FILE_ATTRIBUTE_READONLY); } + bool iasReparsePoint() const { return MatchesMask(FILE_ATTRIBUTE_REPARSE_POINT); } + bool isSparse() const { return MatchesMask(FILE_ATTRIBUTE_SPARSE_FILE); } + bool isSystem() const { return MatchesMask(FILE_ATTRIBUTE_SYSTEM); } + bool isTemporary() const { return MatchesMask(FILE_ATTRIBUTE_TEMPORARY); } + +private: + bool MatchesMask(UINT32 mask) const + { + return ((m_FileInfo.dwFileAttributes & mask) != 0); + } + + bool m_Valid; + std::filesystem::path m_Path; + BY_HANDLE_FILE_INFORMATION m_FileInfo; +}; + +#else // Linux + +/** + * FileInfo class for Linux - uses stat() to get file information. + * Returns 7zip-compatible types. + */ +class FileInfo +{ +public: + FileInfo() : m_Valid{false}, m_Stat{} {}; + FileInfo(std::filesystem::path const& path, struct stat const& st) + : m_Valid{true}, m_Path(path), m_Stat{st} + {} + + bool isValid() const { return m_Valid; } + + const std::filesystem::path& path() const { return m_Path; } + + UInt32 fileAttributes() const { + UInt32 attr = 0; + if (S_ISDIR(m_Stat.st_mode)) attr |= FILE_ATTRIBUTE_DIRECTORY; + if (!(m_Stat.st_mode & S_IWUSR)) attr |= FILE_ATTRIBUTE_READONLY; + if (attr == 0) attr = FILE_ATTRIBUTE_NORMAL; + return attr; + } + + // Convert timespec to FILETIME (100ns intervals since 1601-01-01) + static FILETIME timespecToFiletime(struct timespec const& ts) { + // Offset between 1601-01-01 and 1970-01-01 in 100ns intervals + constexpr UInt64 EPOCH_DIFF = 116444736000000000ULL; + UInt64 ticks = (UInt64)ts.tv_sec * 10000000ULL + (UInt64)ts.tv_nsec / 100ULL + EPOCH_DIFF; + FILETIME ft; + ft.dwLowDateTime = (DWORD)(ticks & 0xFFFFFFFF); + ft.dwHighDateTime = (DWORD)(ticks >> 32); + return ft; + } + + FILETIME creationTime() const { + // Linux doesn't have creation time in all filesystems, use ctime (status change) + return timespecToFiletime(m_Stat.st_ctim); + } + FILETIME lastAccessTime() const { + return timespecToFiletime(m_Stat.st_atim); + } + FILETIME lastWriteTime() const { + return timespecToFiletime(m_Stat.st_mtim); + } + UInt32 volumeSerialNumber() const { return (UInt32)m_Stat.st_dev; } + UInt64 fileSize() const { return (UInt64)m_Stat.st_size; } + UInt32 numberOfLinks() const { return (UInt32)m_Stat.st_nlink; } + UInt64 fileInfex() const { return (UInt64)m_Stat.st_ino; } + + bool isArchived() const { return false; } + bool isCompressed() const { return false; } + bool isDir() const { return S_ISDIR(m_Stat.st_mode); } + bool isEncrypted() const { return false; } + bool isHidden() const { return false; } + bool isNormal() const { return S_ISREG(m_Stat.st_mode); } + bool isOffline() const { return false; } + bool isReadOnly() const { return !(m_Stat.st_mode & S_IWUSR); } + bool iasReparsePoint() const { return S_ISLNK(m_Stat.st_mode); } + bool isSparse() const { return false; } + bool isSystem() const { return false; } + bool isTemporary() const { return false; } + +private: + bool m_Valid; + std::filesystem::path m_Path; + struct stat m_Stat; +}; + +#endif // _WIN32 + +class FileBase +{ +public: // Constructors, destructor, assignment. +#ifdef _WIN32 + FileBase() noexcept : m_Handle{INVALID_HANDLE_VALUE} {} + + FileBase(FileBase&& other) noexcept : m_Handle{other.m_Handle} + { + other.m_Handle = INVALID_HANDLE_VALUE; + } +#else + FileBase() noexcept : m_Fd{-1} {} + + FileBase(FileBase&& other) noexcept : m_Fd{other.m_Fd} + { + other.m_Fd = -1; + } +#endif + + ~FileBase() noexcept { Close(); } + + FileBase(FileBase const&) = delete; + FileBase& operator=(FileBase const&) = delete; + FileBase& operator=(FileBase&&) = delete; + +public: // Operations + bool Close() noexcept; + + bool GetPosition(UInt64& position) noexcept; + bool GetLength(UInt64& length) const noexcept; + +#ifdef _WIN32 + bool Seek(Int64 distanceToMove, DWORD moveMethod, UInt64& newPosition) noexcept; +#else + bool Seek(Int64 distanceToMove, int whence, UInt64& newPosition) noexcept; +#endif + bool Seek(UInt64 position, UInt64& newPosition) noexcept; + bool SeekToBegin() noexcept; + bool SeekToEnd(UInt64& newPosition) noexcept; + + // Note: Only the static version (unlike in 7z) because I want FileInfo to hold the + // path to the file, and the non-static version is never used (except by the static + // version). + static bool GetFileInformation(std::filesystem::path const& path, + FileInfo* info) noexcept; + +protected: +#ifdef _WIN32 + bool Create(std::filesystem::path const& path, DWORD desiredAccess, DWORD shareMode, + DWORD creationDisposition, DWORD flagsAndAttributes) noexcept; +#else + bool Create(std::filesystem::path const& path, int flags, int mode = 0644) noexcept; +#endif + +protected: + static constexpr UInt32 kChunkSizeMax = (1 << 22); + +#ifdef _WIN32 + HANDLE m_Handle; +#else + int m_Fd; +#endif +}; + +class FileIn : public FileBase +{ +public: + using FileBase::FileBase; + +public: // Operations +#ifdef _WIN32 + bool Open(std::filesystem::path const& filepath, DWORD shareMode, + DWORD creationDisposition, DWORD flagsAndAttributes) noexcept; + bool OpenShared(std::filesystem::path const& filepath, bool shareForWrite) noexcept; +#endif + bool Open(std::filesystem::path const& filepath) noexcept; + + bool Read(void* data, UInt32 size, UInt32& processedSize) noexcept; + +protected: + bool Read1(void* data, UInt32 size, UInt32& processedSize) noexcept; + bool ReadPart(void* data, UInt32 size, UInt32& processedSize) noexcept; +}; + +class FileOut : public FileBase +{ +public: + using FileBase::FileBase; + +public: // Operations: +#ifdef _WIN32 + bool Open(std::filesystem::path const& fileName, DWORD shareMode, + DWORD creationDisposition, DWORD flagsAndAttributes) noexcept; +#endif + bool Open(std::filesystem::path const& fileName) noexcept; + + bool SetTime(const FILETIME* cTime, const FILETIME* aTime, + const FILETIME* mTime) noexcept; + bool SetMTime(const FILETIME* mTime) noexcept; + bool Write(const void* data, UInt32 size, UInt32& processedSize) noexcept; + + bool SetLength(UInt64 length) noexcept; + bool SetEndOfFile() noexcept; + +protected: // Protected Operations: + bool WritePart(const void* data, UInt32 size, UInt32& processedSize) noexcept; +}; + +/** + * @brief Convert the given wide-string to a path object. + * + * On Windows: adds the long-path prefix if not present. + * On Linux: simply converts wstring to path (no long-path prefix needed). + * + * @param path The string containing the path. + * + * @return the created path. + */ +inline std::filesystem::path make_path(std::wstring const& pathstr) +{ + namespace fs = std::filesystem; + +#ifdef _WIN32 + constexpr const wchar_t* lprefix = L"\\\\?\\"; + constexpr const wchar_t* unc_prefix = L"\\\\"; + constexpr const wchar_t* unc_lprefix = L"\\\\?\\UNC\\"; + + // If path is already a long path, just return it: + if (pathstr.starts_with(lprefix)) { + return fs::path{pathstr}.make_preferred(); + } + + fs::path path{pathstr}; + + // Convert to an absolute path: + if (!path.is_absolute()) { + path = fs::absolute(path); + } + + // backslashes + path = path.make_preferred(); + + // Get rid of duplicate separators and relative moves + path = path.lexically_normal(); + + const std::wstring pathstr_fixed = path.native(); + + // If this is a UNC, the prefix is different + if (pathstr_fixed.starts_with(unc_prefix)) { + return fs::path{unc_lprefix + pathstr_fixed.substr(2)}; + } + + // Add the long-path prefix + return fs::path{lprefix + pathstr_fixed}; +#else + // On Linux, simply convert wstring to path (no long-path prefix needed) + fs::path path{pathstr}; + + if (!path.is_absolute()) { + path = fs::absolute(path); + } + + path = path.lexically_normal(); + return path; +#endif +} + +} // namespace IO + +#endif diff --git a/libs/archive/src/formatter.h b/libs/archive/src/formatter.h new file mode 100644 index 0000000..0776bee --- /dev/null +++ b/libs/archive/src/formatter.h @@ -0,0 +1,121 @@ +/* +Mod Organizer archive handling + +Copyright (C) 2020 MO2 Team. All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef ARCHIVE_FORMAT_H +#define ARCHIVE_FORMAT_H + +// This header specialize formatter() for some useful types. It should not be +// exposed outside of the library. It also contains some useful methods for +// string manipulation. + +#include + +#include +#include +#include +#include + +template <> +struct std::formatter : std::formatter +{ + template + auto format(std::string const& s, FormatContext& ctx) const + { + return std::formatter::format( + std::wstring(s.begin(), s.end()), ctx); + } +}; + +template <> +struct std::formatter : std::formatter +{ + template + auto format(std::exception const& ex, FormatContext& ctx) const + { + return std::formatter::format(ex.what(), ctx); + } +}; + +template <> +struct std::formatter : std::formatter +{ + template + auto format(std::error_code const& ec, FormatContext& ctx) const + { + return std::formatter::format(ec.message(), ctx); + } +}; + +template <> +struct std::formatter + : std::formatter +{ + template + auto format(std::filesystem::path const& path, FormatContext& ctx) const + { + return std::formatter::format(path.wstring(), ctx); + } +}; + +namespace ArchiveStrings +{ + +/** + * @brief Join the element of the given container using the given separator. + * + * @param c The container. Must be satisfy standard container requirements. + * @param sep The separator. + * + * @return a string containing the element joint, or an empty string if c + * is empty. + */ +template +std::wstring join(C const& c, std::wstring const& sep) +{ + auto begin = std::begin(c), end = std::end(c); + + if (begin == end) { + return {}; + } + std::wstring r = *begin++; + for (; begin != end; ++begin) { + r += *begin + sep; + } + + return r; +} + +/** + * @brief Conver the given string to lowercase. + * + * @param s The string to convert. + * + * @return the converted string. + */ +inline std::wstring towlower(std::wstring s) +{ + std::transform(std::begin(s), std::end(s), std::begin(s), [](wchar_t c) { + return static_cast(::towlower(c)); + }); + return s; +} +} // namespace ArchiveStrings + +#endif diff --git a/libs/archive/src/inputstream.cpp b/libs/archive/src/inputstream.cpp new file mode 100644 index 0000000..b44986a --- /dev/null +++ b/libs/archive/src/inputstream.cpp @@ -0,0 +1,70 @@ +/* +Mod Organizer archive handling + +Copyright (C) 2012 Sebastian Herbord, 2020 MO2 Team. All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "inputstream.h" +#include "compat.h" + +static inline HRESULT ConvertBoolToHRESULT(bool result) +{ + if (result) { + return S_OK; + } + DWORD lastError = ::GetLastError(); + if (lastError == 0) { + return E_FAIL; + } + return HRESULT_FROM_WIN32(lastError); +} + +InputStream::InputStream() {} + +InputStream::~InputStream() {} + +bool InputStream::Open(std::filesystem::path const& filename) +{ + return m_File.Open(filename); +} + +STDMETHODIMP InputStream::Read(void* data, UInt32 size, UInt32* processedSize) throw() +{ + UInt32 realProcessedSize; + bool result = m_File.Read(data, size, realProcessedSize); + + if (processedSize != nullptr) { + *processedSize = realProcessedSize; + } + + if (result) { + return S_OK; + } + + return HRESULT_FROM_WIN32(::GetLastError()); +} + +STDMETHODIMP InputStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64* newPosition) throw() +{ + UInt64 realNewPosition = offset; + bool result = m_File.Seek(offset, seekOrigin, realNewPosition); + + if (newPosition) { + *newPosition = realNewPosition; + } + return ConvertBoolToHRESULT(result); +} diff --git a/libs/archive/src/inputstream.h b/libs/archive/src/inputstream.h new file mode 100644 index 0000000..b305137 --- /dev/null +++ b/libs/archive/src/inputstream.h @@ -0,0 +1,54 @@ +/* +Mod Organizer archive handling + +Copyright (C) 2012 Sebastian Herbord, 2020 MO2 Team. All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef INPUTSTREAM_H +#define INPUTSTREAM_H + +#include <7zip/IStream.h> + +#include + +#include "fileio.h" +#include "unknown_impl.h" + +/** This class implements an input stream for opening archive files + * + * Note that the handling on errors could be better. + */ +class InputStream : public IInStream +{ + + UNKNOWN_1_INTERFACE(IInStream); + +public: + InputStream(); + + virtual ~InputStream(); + + bool Open(std::filesystem::path const& filename); + + STDMETHOD(Read)(void* data, UInt32 size, UInt32* processedSize) throw(); + STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64* newPosition) throw(); + +private: + IO::FileIn m_File; +}; + +#endif // INPUTSTREAM_H diff --git a/libs/archive/src/instrument.h b/libs/archive/src/instrument.h new file mode 100644 index 0000000..82dc3f7 --- /dev/null +++ b/libs/archive/src/instrument.h @@ -0,0 +1,111 @@ +/* +Mod Organizer archive handling + +Copyright (C) 2020 MO2 Team. All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef ARCHIVE_INSTRUMENT_H +#define ARCHIVE_INSTRUMENT_H + +#include +#include + +namespace ArchiveTimers +{ + +/** + * If INSTRUMENT_ARCHIVE is not defined, we define a Timer() class that is empty and + * does nothing, and thus should be optimized out by the compiler. + */ +#ifdef INSTRUMENT_ARCHIVE + +/** + * Small class that can be used to instrument portion of code using a guard. + * + */ +class Timer +{ +public: + using clock_t = std::chrono::system_clock; + + struct TimerGuard + { + + TimerGuard(TimerGuard const&) = delete; + TimerGuard(TimerGuard&&) = delete; + TimerGuard& operator=(TimerGuard const&) = delete; + TimerGuard& operator=(TimerGuard&&) = delete; + + ~TimerGuard() + { + m_Timer.ncalls++; + m_Timer.time += clock_t::now() - m_Start; + } + + private: + TimerGuard(Timer& timer) : m_Timer{timer}, m_Start{clock_t::now()} {} + + Timer& m_Timer; + clock_t::time_point m_Start; + + friend class Timer; + }; + + /** + * + */ + Timer() = default; + + /** + * @brief Instrument a portion of code. + * + * Instrumenting is done by calling `instrument()` and storing the result in a local + * variable. The scope of the local guard variable is the scope of the + * instrumentation. + * + * @return a guard to instrument the code. + */ + TimerGuard instrument() { return {*this}; } + + std::wstring toString(std::wstring const& name) const + { + auto ms = [](auto&& t) { + return std::chrono::duration(t); + }; + return std::format( + L"Instrument '{}': {} calls, total of {}ms, {:.3f}ms per call on average.", + name, ncalls, ms(time).count(), ms(time).count() / ncalls); + } + +private: + std::size_t ncalls{0}; + clock_t::duration time{0}; +}; + +#else + +struct Timer +{ + // This is the only method needed: + Timer& instrument() { return *this; } +}; + +#endif + +} // namespace ArchiveTimers + +#endif diff --git a/libs/archive/src/interfaceguids.cpp b/libs/archive/src/interfaceguids.cpp new file mode 100644 index 0000000..ae6659b --- /dev/null +++ b/libs/archive/src/interfaceguids.cpp @@ -0,0 +1,37 @@ +/* +Mod Organizer archive handling + +Copyright (C) 2012 Sebastian Herbord, 2020 MO2 Team. All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// This file instantiates the GUIDs needed for linking with the 7zip code +#ifdef _WIN32 +#include +#else +#define INITGUID +#include +#endif + +// extractcallback, opencallback +#include <7zip/IPassword.h> + +// archive, opencallback +// Note: In a sense, this is unnecessary as IArchive.h includes it +#include <7zip/IStream.h> + +// archive, opencallback +#include <7zip/Archive/IArchive.h> diff --git a/libs/archive/src/library.h b/libs/archive/src/library.h new file mode 100644 index 0000000..9fec56d --- /dev/null +++ b/libs/archive/src/library.h @@ -0,0 +1,164 @@ +/* +Mod Organizer archive handling + +Copyright (C) 2020 MO2 Team. All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef ARCHIVE_LIBRARY_H +#define ARCHIVE_LIBRARY_H + +#ifdef _WIN32 +#include +#else +#include +#include +#include +#include +#include +#include +#endif + +/** + * Very small wrapper around shared libraries (DLL on Windows, .so on Linux). + */ +class ALibrary +{ +public: +#ifdef _WIN32 + ALibrary(const char* path) : m_Module{nullptr}, m_LastError{ERROR_SUCCESS} + { + m_Module = LoadLibraryA(path); + if (m_Module == nullptr) { + updateLastError(); + } + } + + ~ALibrary() + { + if (m_Module) { + FreeLibrary(m_Module); + } + } + + template + T resolve(const char* procName) + { + if (!m_Module) { + return nullptr; + } + auto proc = GetProcAddress(m_Module, procName); + if (!proc) { + updateLastError(); + return nullptr; + } + return reinterpret_cast(proc); + } + + DWORD getLastError() const { return m_LastError; } + bool isOpen() const { return m_Module != nullptr; } + operator bool() const { return isOpen(); } + +private: + void updateLastError() { m_LastError = ::GetLastError(); } + + HMODULE m_Module; + DWORD m_LastError; + +#else // Linux + + ALibrary(const char* path) : m_Handle{nullptr}, m_LastError{0} + { + // Find the directory containing our own executable + std::string exeDir; + char selfPath[4096]; + ssize_t len = readlink("/proc/self/exe", selfPath, sizeof(selfPath) - 1); + if (len > 0) { + selfPath[len] = '\0'; + exeDir = std::string(selfPath); + auto slash = exeDir.rfind('/'); + if (slash != std::string::npos) + exeDir = exeDir.substr(0, slash); + } + + // AppImage: check MO2_DLLS_DIR env var first (writable dir next to AppImage) + std::string envDlls; + const char* envVal = std::getenv("MO2_DLLS_DIR"); + if (envVal && envVal[0] != '\0') { + envDlls = envVal; + } + + // Try bundled 7z.so locations first (env override, exe dir, dlls/ subdir) + std::vector tryPaths; + if (!envDlls.empty()) { + tryPaths.push_back(envDlls + "/7z.so"); + } + tryPaths.push_back(exeDir + "/7z.so"); + tryPaths.push_back(exeDir + "/dlls/7z.so"); + tryPaths.push_back("7z.so"); + tryPaths.push_back("dlls/7z.so"); + tryPaths.push_back("/usr/lib/p7zip/7z.so"); + tryPaths.push_back("/usr/lib64/p7zip/7z.so"); + tryPaths.push_back("/usr/libexec/p7zip/7z.so"); + + for (const auto& tryPath : tryPaths) { + m_Handle = dlopen(tryPath.c_str(), RTLD_LAZY); + if (m_Handle) break; + } + + if (!m_Handle) { + // Last resort: try the original path as-is + m_Handle = dlopen(path, RTLD_LAZY); + } + + if (!m_Handle) { + m_LastError = 1; + } + } + + ~ALibrary() + { + if (m_Handle) { + dlclose(m_Handle); + } + } + + template + T resolve(const char* procName) + { + if (!m_Handle) { + return nullptr; + } + void* sym = dlsym(m_Handle, procName); + if (!sym) { + m_LastError = 1; + return nullptr; + } + return reinterpret_cast(sym); + } + + DWORD getLastError() const { return m_LastError; } + bool isOpen() const { return m_Handle != nullptr; } + operator bool() const { return isOpen(); } + +private: + void* m_Handle; + DWORD m_LastError; + +#endif +}; + +#endif diff --git a/libs/archive/src/multioutputstream.cpp b/libs/archive/src/multioutputstream.cpp new file mode 100644 index 0000000..a2eca06 --- /dev/null +++ b/libs/archive/src/multioutputstream.cpp @@ -0,0 +1,142 @@ +/* +Mod Organizer archive handling + +Copyright (C) 2012 Sebastian Herbord, 2020 MO2 Team. All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "multioutputstream.h" +#include "compat.h" + +#ifdef _WIN32 +#include +#include +#endif + +static inline HRESULT ConvertBoolToHRESULT(bool result) +{ + if (result) { + return S_OK; + } + DWORD lastError = ::GetLastError(); + if (lastError == 0) { + return E_FAIL; + } + return HRESULT_FROM_WIN32(lastError); +} + +////////////////////////// +// MultiOutputStream + +MultiOutputStream::MultiOutputStream(WriteCallback callback) : m_WriteCallback(callback) +{} + +MultiOutputStream::~MultiOutputStream() {} + +HRESULT MultiOutputStream::Close() +{ + for (auto& file : m_Files) { + file.Close(); + } + return S_OK; +} + +bool MultiOutputStream::Open(std::vector const& filepaths) +{ + m_ProcessedSize = 0; + bool ok = true; + m_Files.clear(); + for (auto& path : filepaths) { + m_Files.emplace_back(); + if (!m_Files.back().Open(path)) { + ok = false; + } + } + return ok; +} + +STDMETHODIMP MultiOutputStream::Write(const void* data, UInt32 size, + UInt32* processedSize) throw() +{ + bool update_processed(true); + for (auto& file : m_Files) { + UInt32 realProcessedSize; + if (!file.Write(data, size, realProcessedSize)) { + return ConvertBoolToHRESULT(false); + } + if (update_processed) { + m_ProcessedSize += realProcessedSize; + if (m_WriteCallback) { + m_WriteCallback(realProcessedSize, m_ProcessedSize); + } + update_processed = false; + } + if (processedSize != nullptr) { + *processedSize = realProcessedSize; + } + } + return S_OK; +} + +STDMETHODIMP MultiOutputStream::Seek(Int64 offset, UInt32 seekOrigin, + UInt64* newPosition) throw() +{ + if (seekOrigin >= 3) + return STG_E_INVALIDFUNCTION; + + bool result = true; + for (auto& file : m_Files) { + UInt64 realNewPosition; + result = file.Seek(offset, seekOrigin, realNewPosition); + if (newPosition) + *newPosition = realNewPosition; + } + return ConvertBoolToHRESULT(result); +} + +STDMETHODIMP MultiOutputStream::SetSize(UInt64 newSize) throw() +{ + bool result = true; + for (auto& file : m_Files) { + UInt64 currentPos; +#ifdef _WIN32 + if (!file.Seek(0, FILE_CURRENT, currentPos)) +#else + if (!file.Seek(0, SEEK_CUR, currentPos)) +#endif + return E_FAIL; + bool cresult = file.SetLength(newSize); + UInt64 currentPos2; + result = result && cresult && file.Seek(currentPos, currentPos2); + } + return result ? S_OK : E_FAIL; +} + +HRESULT MultiOutputStream::GetSize(UInt64* size) +{ + if (m_Files.empty()) { + return ConvertBoolToHRESULT(false); + } + return ConvertBoolToHRESULT(m_Files[0].GetLength(*size)); +} + +bool MultiOutputStream::SetMTime(FILETIME const* mTime) +{ + for (auto& file : m_Files) { + file.SetMTime(mTime); + } + return true; +} diff --git a/libs/archive/src/multioutputstream.h b/libs/archive/src/multioutputstream.h new file mode 100644 index 0000000..624ab5b --- /dev/null +++ b/libs/archive/src/multioutputstream.h @@ -0,0 +1,106 @@ +/* +Mod Organizer archive handling + +Copyright (C) 2012 Sebastian Herbord, 2020 MO2 Team. All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef MULTIOUTPUTSTREAM_H +#define MULTIOUTPUTSTREAM_H + +#include +#include +#include +#include + +#include <7zip/IStream.h> + +#include "fileio.h" +#include "unknown_impl.h" + +/** This class allows you to open and output to multiple file handles at a time. + * It implements the ISequentalOutputStream interface and has some extra functions + * which are used by the CArchiveExtractCallback class to basically open and + * set the timestamp on all the files. + * + * Note that the handling on errors could be better. + */ +class MultiOutputStream : public IOutStream +{ + + UNKNOWN_1_INTERFACE(IOutStream); + +public: + // Callback for write. Args are: 1) number of bytes that have been + // written for this call, 2) number of bytes that have been written + // in total. + using WriteCallback = std::function; + + MultiOutputStream(WriteCallback callback = {}); + + virtual ~MultiOutputStream(); + + /** Opens the supplied files. + * + * @returns true if all went OK, false if any file failed to open + */ + bool Open(std::vector const& fileNames); + + /** Closes all the files opened by the last open + * + * Note if there are any errors, the code will merely report the last one. + */ + HRESULT Close(); + + /** Sets the modification time on the open files + * + * @returns true if all files had the time set succesfully, false otherwise + * note that this will give up as soon as it gets an error + */ + bool SetMTime(FILETIME const* mTime); + + // ISequentialOutStream interface + + /** Write data to all the streams + * + * The processedSize returned will be the same as size, unless + * there was an error, in which case it might or might not be different. + * @warn If an error happens, the code will not attempt any further writing, + * so some files might not get written to at all + */ + STDMETHOD(Write)(const void* data, UInt32 size, UInt32* processedSize) throw() override; + + STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64* newPosition) throw() override; + STDMETHOD(SetSize)(UInt64 newSize) throw() override; + HRESULT GetSize(UInt64* size); + +private: + WriteCallback m_WriteCallback; + + /** This is the amount of data written to *any one* file. + * + * If there are errors writing to one of the files, this might or might + * not match what was actually written to another of the files + */ + UInt64 m_ProcessedSize; + + /** All the files opened for this 'stream' + * + */ + std::vector m_Files; +}; + +#endif // MULTIOUTPUTSTREAM_H diff --git a/libs/archive/src/opencallback.cpp b/libs/archive/src/opencallback.cpp new file mode 100644 index 0000000..9dd0e24 --- /dev/null +++ b/libs/archive/src/opencallback.cpp @@ -0,0 +1,168 @@ +/* +Mod Organizer archive handling + +Copyright (C) 2012 Sebastian Herbord, 2020 MO2 Team. All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "opencallback.h" +#include "compat.h" + +#include "inputstream.h" +#include "propertyvariant.h" + +#include +#include +#include +#include +#include + +#include "fileio.h" + +#define UNUSED(x) + +CArchiveOpenCallback::CArchiveOpenCallback(Archive::PasswordCallback passwordCallback, + Archive::LogCallback logCallback, + std::filesystem::path const& filepath) + : m_PasswordCallback(passwordCallback), m_LogCallback(logCallback), + m_Path(filepath), m_SubArchiveMode(false) +{ + if (!exists(filepath)) { + throw std::runtime_error("invalid archive path"); + } + + if (!IO::FileBase::GetFileInformation(filepath, &m_FileInfo)) { + throw std::runtime_error("failed to retrieve file information"); + } +} + +/* -------------------- IArchiveOpenCallback -------------------- */ +STDMETHODIMP CArchiveOpenCallback::SetTotal(const UInt64* UNUSED(files), + const UInt64* UNUSED(bytes)) throw() +{ + return S_OK; +} + +STDMETHODIMP CArchiveOpenCallback::SetCompleted(const UInt64* UNUSED(files), + const UInt64* UNUSED(bytes)) throw() +{ + return S_OK; +} + +/* -------------------- ICryptoGetTextPassword -------------------- */ +/* This apparently implements ICryptoGetTextPassword but even with a passworded + * archive it doesn't seem to be called. There is also another API which isn't + * implemented. + */ +STDMETHODIMP CArchiveOpenCallback::CryptoGetTextPassword(BSTR* passwordOut) throw() +{ + if (!m_PasswordCallback) { + return E_ABORT; + } + m_Password = m_PasswordCallback(); + *passwordOut = ::SysAllocString(m_Password.c_str()); + return *passwordOut != 0 ? S_OK : E_OUTOFMEMORY; +} + +/* -------------------- IArchiveOpenSetSubArchiveName -------------------- */ +/* I don't know what this does or how you call it. */ +STDMETHODIMP CArchiveOpenCallback::SetSubArchiveName(const wchar_t* name) throw() +{ + m_SubArchiveMode = true; + m_SubArchiveName = name; + return S_OK; +} + +/* -------------------- IArchiveOpenVolumeCallback -------------------- */ + +STDMETHODIMP CArchiveOpenCallback::GetProperty(PROPID propID, + PROPVARIANT* value) throw() +{ + // A scan of the source code indicates that the only things that ever call the + // IArchiveOpenVolumeCallback interface ask for the file name and size. + PropertyVariant& prop = *static_cast(value); + + switch (propID) { + case kpidName: { + if (m_SubArchiveMode) { + prop = m_SubArchiveName; + } else { + // Note: Need to call .native(), otherwize we get a link error because we try to + // assign a fs::path to the variant. + prop = m_Path.filename().wstring(); + } + } break; + + case kpidIsDir: + prop = m_FileInfo.isDir(); + break; + case kpidSize: + prop = m_FileInfo.fileSize(); + break; + case kpidAttrib: + prop = m_FileInfo.fileAttributes(); + break; + case kpidCTime: + prop = m_FileInfo.creationTime(); + break; + case kpidATime: + prop = m_FileInfo.lastAccessTime(); + break; + case kpidMTime: + prop = m_FileInfo.lastWriteTime(); + break; + + default: + m_LogCallback(Archive::LogLevel::Warning, + std::format(L"Unexpected property {}.", propID)); + } + return S_OK; +} + +STDMETHODIMP CArchiveOpenCallback::GetStream(const wchar_t* name, + IInStream** inStream) throw() +{ + *inStream = nullptr; + + // this function will be called repeatedly for split archives, `name` will + // have increasing numbers in the extension and S_FALSE must be returned + // when a filename doesn't exist so the search stops + + if (!name) { + return S_FALSE; + } + + // `name` is just the filename, so build a path from the directory that + // contained the last file + const auto path = m_Path.parent_path() / name; + + if (!exists(m_FileInfo.path()) || m_FileInfo.isDir()) { + return S_FALSE; + } + + if (!IO::FileBase::GetFileInformation(path, &m_FileInfo)) { + return S_FALSE; + } + + CComPtr inFile(new InputStream); + + if (!inFile->Open(m_FileInfo.path())) { + return ::GetLastError(); + } + + *inStream = inFile.Detach(); + return S_OK; +} diff --git a/libs/archive/src/opencallback.h b/libs/archive/src/opencallback.h new file mode 100644 index 0000000..44367be --- /dev/null +++ b/libs/archive/src/opencallback.h @@ -0,0 +1,75 @@ +/* +Mod Organizer archive handling + +Copyright (C) 2012 Sebastian Herbord, 2020 MO2 Team. All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef OPENCALLBACK_H +#define OPENCALLBACK_H + +#include +#include + +#include <7zip/Archive/IArchive.h> +#include <7zip/IPassword.h> + +#include "archive.h" +#include "fileio.h" +#include "unknown_impl.h" + +class CArchiveOpenCallback : public IArchiveOpenCallback, + public IArchiveOpenVolumeCallback, + public ICryptoGetTextPassword, + public IArchiveOpenSetSubArchiveName +{ + + UNKNOWN_4_INTERFACE(IArchiveOpenCallback, IArchiveOpenVolumeCallback, + ICryptoGetTextPassword, IArchiveOpenSetSubArchiveName); + +public: + CArchiveOpenCallback(Archive::PasswordCallback passwordCallback, + Archive::LogCallback logCallback, + std::filesystem::path const& filepath); + + virtual ~CArchiveOpenCallback() {} + + const std::wstring& GetPassword() const { return m_Password; } + + Z7_IFACE_COM7_IMP(IArchiveOpenCallback) + Z7_IFACE_COM7_IMP(IArchiveOpenVolumeCallback) + + // ICryptoGetTextPassword interface + STDMETHOD(CryptoGetTextPassword)(BSTR* password) throw(); + // Not implemented STDMETHOD(CryptoGetTextPassword2)(Int32 *passwordIsDefined, BSTR + // *password); + + // IArchiveOpenSetSubArchiveName interface + STDMETHOD(SetSubArchiveName)(const wchar_t* name) throw(); + +private: + Archive::PasswordCallback m_PasswordCallback; + Archive::LogCallback m_LogCallback; + std::wstring m_Password; + + std::filesystem::path m_Path; + IO::FileInfo m_FileInfo; + + bool m_SubArchiveMode; + std::wstring m_SubArchiveName; +}; + +#endif // OPENCALLBACK_H diff --git a/libs/archive/src/propertyvariant.cpp b/libs/archive/src/propertyvariant.cpp new file mode 100644 index 0000000..fe882b2 --- /dev/null +++ b/libs/archive/src/propertyvariant.cpp @@ -0,0 +1,214 @@ +/* +Mod Organizer archive handling + +Copyright (C) 2012 Sebastian Herbord, 2020 MO2 Team. All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "propertyvariant.h" +#include "compat.h" + +#ifdef _WIN32 +#include +#endif + +#include +#include +#include + +PropertyVariant::PropertyVariant() +{ + PropVariantInit(this); +} + +PropertyVariant::~PropertyVariant() +{ + clear(); +} + +void PropertyVariant::clear() +{ + PropVariantClear(this); +} + +// Arguably the behviours for empty here are wrong. +template <> +PropertyVariant::operator bool() const +{ + switch (vt) { + case VT_EMPTY: + return false; + + case VT_BOOL: + return boolVal != VARIANT_FALSE; + + default: + throw std::runtime_error("Property is not a bool"); + } +} + +template <> +PropertyVariant::operator uint64_t() const +{ + switch (vt) { + case VT_EMPTY: + return 0; + + case VT_UI1: + return bVal; + + case VT_UI2: + return uiVal; + + case VT_UI4: + return ulVal; + + case VT_UI8: + return static_cast(uhVal.QuadPart); + + default: + throw std::runtime_error("Property is not an unsigned integer"); + } +} + +template <> +PropertyVariant::operator uint32_t() const +{ + switch (vt) { + case VT_EMPTY: + return 0; + + case VT_UI1: + return bVal; + + case VT_UI2: + return uiVal; + + case VT_UI4: + return ulVal; + + default: + throw std::runtime_error("Property is not an unsigned integer"); + } +} + +template <> +PropertyVariant::operator std::wstring() const +{ + switch (vt) { + case VT_EMPTY: + return L""; + + case VT_BSTR: + return std::wstring(bstrVal, ::SysStringLen(bstrVal)); + + default: + throw std::runtime_error("Property is not a string"); + } +} + +// This is what he does, though it looks rather a strange use of the property +template <> +PropertyVariant::operator std::string() const +{ + switch (vt) { + case VT_EMPTY: + return ""; + + case VT_BSTR: + // If he can do a memcpy, I can do a reinterpret case + return std::string(reinterpret_cast(bstrVal), + ::SysStringByteLen(bstrVal)); + + default: + throw std::runtime_error("Property is not a string"); + } +} + +// This is what he does, though it looks rather a strange use of the property +template <> +PropertyVariant::operator GUID() const +{ + switch (vt) { + case VT_BSTR: + // He did a cast too! + return *reinterpret_cast(bstrVal); + + default: + throw std::runtime_error("Property is not a GUID (string)"); + } +} + +template <> +PropertyVariant::operator FILETIME() const +{ + switch (vt) { + case VT_FILETIME: + return filetime; + + default: + throw std::runtime_error("Property is not a file time"); + } +} + +// Assignments +template <> +PropertyVariant& PropertyVariant::operator=(std::wstring const& str) +{ + clear(); + vt = VT_BSTR; + bstrVal = ::SysAllocString(str.c_str()); + if (bstrVal == NULL) { + throw std::bad_alloc(); + } + return *this; +} + +template <> +PropertyVariant& PropertyVariant::operator=(bool const& n) +{ + clear(); + vt = VT_BOOL; + boolVal = n ? VARIANT_TRUE : VARIANT_FALSE; + return *this; +} + +template <> +PropertyVariant& PropertyVariant::operator=(FILETIME const& n) +{ + clear(); + vt = VT_FILETIME; + filetime = n; + return *this; +} + +template <> +PropertyVariant& PropertyVariant::operator=(uint32_t const& n) +{ + clear(); + vt = VT_UI4; + ulVal = n; + return *this; +} + +template <> +PropertyVariant& PropertyVariant::operator=(uint64_t const& n) +{ + clear(); + vt = VT_UI8; + uhVal.QuadPart = n; + return *this; +} diff --git a/libs/archive/src/propertyvariant.h b/libs/archive/src/propertyvariant.h new file mode 100644 index 0000000..0748d94 --- /dev/null +++ b/libs/archive/src/propertyvariant.h @@ -0,0 +1,56 @@ +/* +Mod Organizer archive handling + +Copyright (C) 2012 Sebastian Herbord, 2020 MO2 Team. All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef PROPERTYVARIANT_H +#define PROPERTYVARIANT_H + +#ifdef _WIN32 +#include +#else +#include +#endif + +/** This class implements a wrapper round the PROPVARIANT structure which + * makes it a little friendler to use and a little more C++ish + * + * Sadly the inheritance needs to be public. Once you have a pointer to the + * base class you can do pretty much anything to it anyway. + */ +class PropertyVariant : public tagPROPVARIANT +{ +public: + PropertyVariant(); + ~PropertyVariant(); + + // clears the property should you wish to overwrite it with another one. + void clear(); + + bool is_empty() { return vt == VT_EMPTY; } + + // It's too much like hard work listing all the valid ones. If it doesn't + // link, then you need to implement it... + template + explicit operator T() const; + + template + PropertyVariant& operator=(T const&); +}; + +#endif // PROPVARIANT_H diff --git a/libs/archive/src/unknown_impl.h b/libs/archive/src/unknown_impl.h new file mode 100644 index 0000000..78e9f4a --- /dev/null +++ b/libs/archive/src/unknown_impl.h @@ -0,0 +1,191 @@ +/* +Mod Organizer archive handling + +Copyright (C) 2012 Sebastian Herbord, 2020 MO2 Team. All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef UNKNOWN_IMPL_H +#define UNKNOWN_IMPL_H + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#else +#include +#include +#endif + +/* This implements a common way of creating classes which implement one or more + * COM interfaces. + * + * Your implementaton should be something like this + * + * class MyImplementation : + * public interface1, + * public interface2 //etc to taste + * { + * UNKNOWN_1_INTERFACE(interface1); + * or UNKNOWN_2_INTERFACE(interface1, interface2); etc + * + * It would probably be possible to do something very magic with macros + * that allowed you to do + * class My_Implmentation : UNKNOWN_IMPL_n(interface1, ...) + * + * that did all the above for you, but I can't see how to maintain the braces + * in order to make the class declaration look nice. + * + * You might ask why I have e-implemented this from the 7-zip stuff (sort of). + * + * Well, + * + * Firstly, the 7zip macros are slightly buggy (they don't null the outpointer + * if the interface isn't found), and they aren't thread safe. + * + * Secondly, although 7-zip has a requirement to run on platforms other than + * windows, we don't. So I changed this to use the Com functionality supplied + * by windows, which (potentially) has better debugging facilities + * + * Thirdly, this removes a number of dependencies on 7-zip source which aren't + * really part of the API + */ + +#ifdef _WIN32 + +/* Do not use these macros, use the ones at the bottom */ +#define UNKNOWN__INTERFACE_BEGIN \ +public: \ + STDMETHOD_(ULONG, AddRef)() \ + { \ + return ::InterlockedIncrement(&m_RefCount__); \ + } \ + \ + STDMETHOD_(ULONG, Release)() \ + { \ + ULONG res = ::InterlockedDecrement(&m_RefCount__); \ + if (res == 0) { \ + delete this; \ + } \ + return res; \ + } \ + \ + STDMETHOD(QueryInterface)(REFGUID iid, void** outObject) \ + { \ + if (iid == IID_IUnknown) { + +#define UNKNOWN__INTERFACE_UNKNOWN(interface) \ + *outObject = static_cast(static_cast(this)); \ + } + +#define UNKNOWN__INTERFACE_NAME(interface) \ + else if (iid == IID_##interface) \ + { \ + *outObject = static_cast(this); \ + } + +#define UNKNOWN__INTERFACE_END \ + else \ + { \ + *outObject = nullptr; \ + return E_NOINTERFACE; \ + } \ + AddRef(); \ + return S_OK; \ + } \ + \ +private: \ + ULONG m_RefCount__ = 0 + +#else // Linux + +/* Do not use these macros, use the ones at the bottom */ +#define UNKNOWN__INTERFACE_BEGIN \ +public: \ + STDMETHOD_(ULONG, AddRef)() \ + { \ + return ++m_RefCount__; \ + } \ + \ + STDMETHOD_(ULONG, Release)() \ + { \ + ULONG res = --m_RefCount__; \ + if (res == 0) { \ + delete this; \ + } \ + return res; \ + } \ + \ + STDMETHOD(QueryInterface)(REFGUID iid, void** outObject) \ + { \ + if (iid == IID_IUnknown) { + +#define UNKNOWN__INTERFACE_UNKNOWN(interface) \ + *outObject = static_cast(static_cast(this)); \ + } + +#define UNKNOWN__INTERFACE_NAME(interface) \ + else if (iid == IID_##interface) \ + { \ + *outObject = static_cast(this); \ + } + +#define UNKNOWN__INTERFACE_END \ + else \ + { \ + *outObject = nullptr; \ + return E_NOINTERFACE; \ + } \ + AddRef(); \ + return S_OK; \ + } \ + \ +private: \ + std::atomic m_RefCount__{0} + +#endif // _WIN32 + +/* These are the macros you should be using */ +#define UNKNOWN_1_INTERFACE(interface) \ + UNKNOWN__INTERFACE_BEGIN \ + UNKNOWN__INTERFACE_UNKNOWN(interface) \ + UNKNOWN__INTERFACE_NAME(interface) \ + UNKNOWN__INTERFACE_END + +#define UNKNOWN_2_INTERFACE(interface1, interface2) \ + UNKNOWN__INTERFACE_BEGIN \ + UNKNOWN__INTERFACE_UNKNOWN(interface1) \ + UNKNOWN__INTERFACE_NAME(interface1) \ + UNKNOWN__INTERFACE_NAME(interface2) \ + UNKNOWN__INTERFACE_END + +#define UNKNOWN_3_INTERFACE(interface1, interface2, interface3) \ + UNKNOWN__INTERFACE_BEGIN \ + UNKNOWN__INTERFACE_UNKNOWN(interface1) \ + UNKNOWN__INTERFACE_NAME(interface1) \ + UNKNOWN__INTERFACE_NAME(interface2) \ + UNKNOWN__INTERFACE_NAME(interface3) \ + UNKNOWN__INTERFACE_END + +#define UNKNOWN_4_INTERFACE(interface1, interface2, interface3, interface4) \ + UNKNOWN__INTERFACE_BEGIN \ + UNKNOWN__INTERFACE_UNKNOWN(interface1) \ + UNKNOWN__INTERFACE_NAME(interface1) \ + UNKNOWN__INTERFACE_NAME(interface2) \ + UNKNOWN__INTERFACE_NAME(interface3) \ + UNKNOWN__INTERFACE_NAME(interface4) \ + UNKNOWN__INTERFACE_END + +#endif // UNKNOWN_IMPL_H diff --git a/libs/archive/src/version.rc b/libs/archive/src/version.rc new file mode 100644 index 0000000..0fb4cf0 --- /dev/null +++ b/libs/archive/src/version.rc @@ -0,0 +1,28 @@ +#include "Winver.h" + +#define VER_FILEVERSION 2,0,0 +#define VER_FILEVERSION_STR 2,0,0 + +VS_VERSION_INFO VERSIONINFO +FILEVERSION VER_FILEVERSION +PRODUCTVERSION VER_FILEVERSION +FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +FILEFLAGS (0) +FILEOS VOS__WINDOWS32 +FILETYPE VFT_DLL +FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "CompanyName", "Mod Organizer 2 Team" + VALUE "FileVersion", VER_FILEVERSION_STR + END +END + +BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 1200 +END +END diff --git a/libs/archive/thirdparty/C/7zTypes.h b/libs/archive/thirdparty/C/7zTypes.h new file mode 100644 index 0000000..5b77420 --- /dev/null +++ b/libs/archive/thirdparty/C/7zTypes.h @@ -0,0 +1,597 @@ +/* 7zTypes.h -- Basic types +2024-01-24 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_7Z_TYPES_H +#define ZIP7_7Z_TYPES_H + +#ifdef _WIN32 +/* #include */ +#else +#include +#endif + +#include + +#ifndef EXTERN_C_BEGIN +#ifdef __cplusplus +#define EXTERN_C_BEGIN extern "C" { +#define EXTERN_C_END } +#else +#define EXTERN_C_BEGIN +#define EXTERN_C_END +#endif +#endif + +EXTERN_C_BEGIN + +#define SZ_OK 0 + +#define SZ_ERROR_DATA 1 +#define SZ_ERROR_MEM 2 +#define SZ_ERROR_CRC 3 +#define SZ_ERROR_UNSUPPORTED 4 +#define SZ_ERROR_PARAM 5 +#define SZ_ERROR_INPUT_EOF 6 +#define SZ_ERROR_OUTPUT_EOF 7 +#define SZ_ERROR_READ 8 +#define SZ_ERROR_WRITE 9 +#define SZ_ERROR_PROGRESS 10 +#define SZ_ERROR_FAIL 11 +#define SZ_ERROR_THREAD 12 + +#define SZ_ERROR_ARCHIVE 16 +#define SZ_ERROR_NO_ARCHIVE 17 + +typedef int SRes; + + +#ifdef _MSC_VER + #if _MSC_VER > 1200 + #define MY_ALIGN(n) __declspec(align(n)) + #else + #define MY_ALIGN(n) + #endif +#else + /* + // C11/C++11: + #include + #define MY_ALIGN(n) alignas(n) + */ + #define MY_ALIGN(n) __attribute__ ((aligned(n))) +#endif + + +#ifdef _WIN32 + +/* typedef DWORD WRes; */ +typedef unsigned WRes; +#define MY_SRes_HRESULT_FROM_WRes(x) HRESULT_FROM_WIN32(x) + +// #define MY_HRES_ERROR_INTERNAL_ERROR MY_SRes_HRESULT_FROM_WRes(ERROR_INTERNAL_ERROR) + +#else // _WIN32 + +// #define ENV_HAVE_LSTAT +typedef int WRes; + +// (FACILITY_ERRNO = 0x800) is 7zip's FACILITY constant to represent (errno) errors in HRESULT +#define MY_FACILITY_ERRNO 0x800 +#define MY_FACILITY_WIN32 7 +#define MY_FACILITY_WRes MY_FACILITY_ERRNO + +#define MY_HRESULT_FROM_errno_CONST_ERROR(x) ((HRESULT)( \ + ( (HRESULT)(x) & 0x0000FFFF) \ + | (MY_FACILITY_WRes << 16) \ + | (HRESULT)0x80000000 )) + +#define MY_SRes_HRESULT_FROM_WRes(x) \ + ((HRESULT)(x) <= 0 ? ((HRESULT)(x)) : MY_HRESULT_FROM_errno_CONST_ERROR(x)) + +// we call macro HRESULT_FROM_WIN32 for system errors (WRes) that are (errno) +#define HRESULT_FROM_WIN32(x) MY_SRes_HRESULT_FROM_WRes(x) + +/* +#define ERROR_FILE_NOT_FOUND 2L +#define ERROR_ACCESS_DENIED 5L +#define ERROR_NO_MORE_FILES 18L +#define ERROR_LOCK_VIOLATION 33L +#define ERROR_FILE_EXISTS 80L +#define ERROR_DISK_FULL 112L +#define ERROR_NEGATIVE_SEEK 131L +#define ERROR_ALREADY_EXISTS 183L +#define ERROR_DIRECTORY 267L +#define ERROR_TOO_MANY_POSTS 298L + +#define ERROR_INTERNAL_ERROR 1359L +#define ERROR_INVALID_REPARSE_DATA 4392L +#define ERROR_REPARSE_TAG_INVALID 4393L +#define ERROR_REPARSE_TAG_MISMATCH 4394L +*/ + +// we use errno equivalents for some WIN32 errors: + +#define ERROR_INVALID_PARAMETER EINVAL +#define ERROR_INVALID_FUNCTION EINVAL +#define ERROR_ALREADY_EXISTS EEXIST +#define ERROR_FILE_EXISTS EEXIST +#define ERROR_PATH_NOT_FOUND ENOENT +#define ERROR_FILE_NOT_FOUND ENOENT +#define ERROR_DISK_FULL ENOSPC +// #define ERROR_INVALID_HANDLE EBADF + +// we use FACILITY_WIN32 for errors that has no errno equivalent +// Too many posts were made to a semaphore. +#define ERROR_TOO_MANY_POSTS ((HRESULT)0x8007012AL) +#define ERROR_INVALID_REPARSE_DATA ((HRESULT)0x80071128L) +#define ERROR_REPARSE_TAG_INVALID ((HRESULT)0x80071129L) + +// if (MY_FACILITY_WRes != FACILITY_WIN32), +// we use FACILITY_WIN32 for COM errors: +#define E_OUTOFMEMORY ((HRESULT)0x8007000EL) +#define E_INVALIDARG ((HRESULT)0x80070057L) +#define MY_E_ERROR_NEGATIVE_SEEK ((HRESULT)0x80070083L) + +/* +// we can use FACILITY_ERRNO for some COM errors, that have errno equivalents: +#define E_OUTOFMEMORY MY_HRESULT_FROM_errno_CONST_ERROR(ENOMEM) +#define E_INVALIDARG MY_HRESULT_FROM_errno_CONST_ERROR(EINVAL) +#define MY_E_ERROR_NEGATIVE_SEEK MY_HRESULT_FROM_errno_CONST_ERROR(EINVAL) +*/ + +#define TEXT(quote) quote + +#define FILE_ATTRIBUTE_READONLY 0x0001 +#define FILE_ATTRIBUTE_HIDDEN 0x0002 +#define FILE_ATTRIBUTE_SYSTEM 0x0004 +#define FILE_ATTRIBUTE_DIRECTORY 0x0010 +#define FILE_ATTRIBUTE_ARCHIVE 0x0020 +#define FILE_ATTRIBUTE_DEVICE 0x0040 +#define FILE_ATTRIBUTE_NORMAL 0x0080 +#define FILE_ATTRIBUTE_TEMPORARY 0x0100 +#define FILE_ATTRIBUTE_SPARSE_FILE 0x0200 +#define FILE_ATTRIBUTE_REPARSE_POINT 0x0400 +#define FILE_ATTRIBUTE_COMPRESSED 0x0800 +#define FILE_ATTRIBUTE_OFFLINE 0x1000 +#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x2000 +#define FILE_ATTRIBUTE_ENCRYPTED 0x4000 + +#define FILE_ATTRIBUTE_UNIX_EXTENSION 0x8000 /* trick for Unix */ + +#endif + + +#ifndef RINOK +#define RINOK(x) { const int _result_ = (x); if (_result_ != 0) return _result_; } +#endif + +#ifndef RINOK_WRes +#define RINOK_WRes(x) { const WRes _result_ = (x); if (_result_ != 0) return _result_; } +#endif + +typedef unsigned char Byte; +typedef short Int16; +typedef unsigned short UInt16; + +#ifdef Z7_DECL_Int32_AS_long +typedef long Int32; +typedef unsigned long UInt32; +#else +typedef int Int32; +typedef unsigned int UInt32; +#endif + + +#ifndef _WIN32 + +typedef int INT; +typedef Int32 INT32; +typedef unsigned int UINT; +typedef UInt32 UINT32; +typedef INT32 LONG; // LONG, ULONG and DWORD must be 32-bit for _WIN32 compatibility +typedef UINT32 ULONG; + +#undef DWORD +typedef UINT32 DWORD; + +#define VOID void + +#define HRESULT LONG + +typedef void *LPVOID; +// typedef void VOID; +// typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR; +// gcc / clang on Unix : sizeof(long==sizeof(void*) in 32 or 64 bits) +typedef long INT_PTR; +typedef unsigned long UINT_PTR; +typedef long LONG_PTR; +typedef unsigned long DWORD_PTR; + +typedef size_t SIZE_T; + +#endif // _WIN32 + + +#define MY_HRES_ERROR_INTERNAL_ERROR ((HRESULT)0x8007054FL) + + +#ifdef Z7_DECL_Int64_AS_long + +typedef long Int64; +typedef unsigned long UInt64; + +#else + +#if (defined(_MSC_VER) || defined(__BORLANDC__)) && !defined(__clang__) +typedef __int64 Int64; +typedef unsigned __int64 UInt64; +#else +#if defined(__clang__) || defined(__GNUC__) +#include +typedef int64_t Int64; +typedef uint64_t UInt64; +#else +typedef long long int Int64; +typedef unsigned long long int UInt64; +// #define UINT64_CONST(n) n ## ULL +#endif +#endif + +#endif + +#define UINT64_CONST(n) n + + +#ifdef Z7_DECL_SizeT_AS_unsigned_int +typedef unsigned int SizeT; +#else +typedef size_t SizeT; +#endif + +/* +#if (defined(_MSC_VER) && _MSC_VER <= 1200) +typedef size_t MY_uintptr_t; +#else +#include +typedef uintptr_t MY_uintptr_t; +#endif +*/ + +typedef int BoolInt; +/* typedef BoolInt Bool; */ +#define True 1 +#define False 0 + + +#ifdef _WIN32 +#define Z7_STDCALL __stdcall +#else +#define Z7_STDCALL +#endif + +#ifdef _MSC_VER + +#if _MSC_VER >= 1300 +#define Z7_NO_INLINE __declspec(noinline) +#else +#define Z7_NO_INLINE +#endif + +#define Z7_FORCE_INLINE __forceinline + +#define Z7_CDECL __cdecl +#define Z7_FASTCALL __fastcall + +#else // _MSC_VER + +#if (defined(__GNUC__) && (__GNUC__ >= 4)) \ + || (defined(__clang__) && (__clang_major__ >= 4)) \ + || defined(__INTEL_COMPILER) \ + || defined(__xlC__) +#define Z7_NO_INLINE __attribute__((noinline)) +#define Z7_FORCE_INLINE __attribute__((always_inline)) inline +#else +#define Z7_NO_INLINE +#define Z7_FORCE_INLINE +#endif + +#define Z7_CDECL + +#if defined(_M_IX86) \ + || defined(__i386__) +// #define Z7_FASTCALL __attribute__((fastcall)) +// #define Z7_FASTCALL __attribute__((cdecl)) +#define Z7_FASTCALL +#elif defined(MY_CPU_AMD64) +// #define Z7_FASTCALL __attribute__((ms_abi)) +#define Z7_FASTCALL +#else +#define Z7_FASTCALL +#endif + +#endif // _MSC_VER + + +/* The following interfaces use first parameter as pointer to structure */ + +// #define Z7_C_IFACE_CONST_QUAL +#define Z7_C_IFACE_CONST_QUAL const + +#define Z7_C_IFACE_DECL(a) \ + struct a ## _; \ + typedef Z7_C_IFACE_CONST_QUAL struct a ## _ * a ## Ptr; \ + typedef struct a ## _ a; \ + struct a ## _ + + +Z7_C_IFACE_DECL (IByteIn) +{ + Byte (*Read)(IByteInPtr p); /* reads one byte, returns 0 in case of EOF or error */ +}; +#define IByteIn_Read(p) (p)->Read(p) + + +Z7_C_IFACE_DECL (IByteOut) +{ + void (*Write)(IByteOutPtr p, Byte b); +}; +#define IByteOut_Write(p, b) (p)->Write(p, b) + + +Z7_C_IFACE_DECL (ISeqInStream) +{ + SRes (*Read)(ISeqInStreamPtr p, void *buf, size_t *size); + /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. + (output(*size) < input(*size)) is allowed */ +}; +#define ISeqInStream_Read(p, buf, size) (p)->Read(p, buf, size) + +/* try to read as much as avail in stream and limited by (*processedSize) */ +SRes SeqInStream_ReadMax(ISeqInStreamPtr stream, void *buf, size_t *processedSize); +/* it can return SZ_ERROR_INPUT_EOF */ +// SRes SeqInStream_Read(ISeqInStreamPtr stream, void *buf, size_t size); +// SRes SeqInStream_Read2(ISeqInStreamPtr stream, void *buf, size_t size, SRes errorType); +SRes SeqInStream_ReadByte(ISeqInStreamPtr stream, Byte *buf); + + +Z7_C_IFACE_DECL (ISeqOutStream) +{ + size_t (*Write)(ISeqOutStreamPtr p, const void *buf, size_t size); + /* Returns: result - the number of actually written bytes. + (result < size) means error */ +}; +#define ISeqOutStream_Write(p, buf, size) (p)->Write(p, buf, size) + +typedef enum +{ + SZ_SEEK_SET = 0, + SZ_SEEK_CUR = 1, + SZ_SEEK_END = 2 +} ESzSeek; + + +Z7_C_IFACE_DECL (ISeekInStream) +{ + SRes (*Read)(ISeekInStreamPtr p, void *buf, size_t *size); /* same as ISeqInStream::Read */ + SRes (*Seek)(ISeekInStreamPtr p, Int64 *pos, ESzSeek origin); +}; +#define ISeekInStream_Read(p, buf, size) (p)->Read(p, buf, size) +#define ISeekInStream_Seek(p, pos, origin) (p)->Seek(p, pos, origin) + + +Z7_C_IFACE_DECL (ILookInStream) +{ + SRes (*Look)(ILookInStreamPtr p, const void **buf, size_t *size); + /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. + (output(*size) > input(*size)) is not allowed + (output(*size) < input(*size)) is allowed */ + SRes (*Skip)(ILookInStreamPtr p, size_t offset); + /* offset must be <= output(*size) of Look */ + SRes (*Read)(ILookInStreamPtr p, void *buf, size_t *size); + /* reads directly (without buffer). It's same as ISeqInStream::Read */ + SRes (*Seek)(ILookInStreamPtr p, Int64 *pos, ESzSeek origin); +}; + +#define ILookInStream_Look(p, buf, size) (p)->Look(p, buf, size) +#define ILookInStream_Skip(p, offset) (p)->Skip(p, offset) +#define ILookInStream_Read(p, buf, size) (p)->Read(p, buf, size) +#define ILookInStream_Seek(p, pos, origin) (p)->Seek(p, pos, origin) + + +SRes LookInStream_LookRead(ILookInStreamPtr stream, void *buf, size_t *size); +SRes LookInStream_SeekTo(ILookInStreamPtr stream, UInt64 offset); + +/* reads via ILookInStream::Read */ +SRes LookInStream_Read2(ILookInStreamPtr stream, void *buf, size_t size, SRes errorType); +SRes LookInStream_Read(ILookInStreamPtr stream, void *buf, size_t size); + + +typedef struct +{ + ILookInStream vt; + ISeekInStreamPtr realStream; + + size_t pos; + size_t size; /* it's data size */ + + /* the following variables must be set outside */ + Byte *buf; + size_t bufSize; +} CLookToRead2; + +void LookToRead2_CreateVTable(CLookToRead2 *p, int lookahead); + +#define LookToRead2_INIT(p) { (p)->pos = (p)->size = 0; } + + +typedef struct +{ + ISeqInStream vt; + ILookInStreamPtr realStream; +} CSecToLook; + +void SecToLook_CreateVTable(CSecToLook *p); + + + +typedef struct +{ + ISeqInStream vt; + ILookInStreamPtr realStream; +} CSecToRead; + +void SecToRead_CreateVTable(CSecToRead *p); + + +Z7_C_IFACE_DECL (ICompressProgress) +{ + SRes (*Progress)(ICompressProgressPtr p, UInt64 inSize, UInt64 outSize); + /* Returns: result. (result != SZ_OK) means break. + Value (UInt64)(Int64)-1 for size means unknown value. */ +}; + +#define ICompressProgress_Progress(p, inSize, outSize) (p)->Progress(p, inSize, outSize) + + + +typedef struct ISzAlloc ISzAlloc; +typedef const ISzAlloc * ISzAllocPtr; + +struct ISzAlloc +{ + void *(*Alloc)(ISzAllocPtr p, size_t size); + void (*Free)(ISzAllocPtr p, void *address); /* address can be 0 */ +}; + +#define ISzAlloc_Alloc(p, size) (p)->Alloc(p, size) +#define ISzAlloc_Free(p, a) (p)->Free(p, a) + +/* deprecated */ +#define IAlloc_Alloc(p, size) ISzAlloc_Alloc(p, size) +#define IAlloc_Free(p, a) ISzAlloc_Free(p, a) + + + + + +#ifndef MY_offsetof + #ifdef offsetof + #define MY_offsetof(type, m) offsetof(type, m) + /* + #define MY_offsetof(type, m) FIELD_OFFSET(type, m) + */ + #else + #define MY_offsetof(type, m) ((size_t)&(((type *)0)->m)) + #endif +#endif + + + +#ifndef Z7_container_of + +/* +#define Z7_container_of(ptr, type, m) container_of(ptr, type, m) +#define Z7_container_of(ptr, type, m) CONTAINING_RECORD(ptr, type, m) +#define Z7_container_of(ptr, type, m) ((type *)((char *)(ptr) - offsetof(type, m))) +#define Z7_container_of(ptr, type, m) (&((type *)0)->m == (ptr), ((type *)(((char *)(ptr)) - MY_offsetof(type, m)))) +*/ + +/* + GCC shows warning: "perhaps the 'offsetof' macro was used incorrectly" + GCC 3.4.4 : classes with constructor + GCC 4.8.1 : classes with non-public variable members" +*/ + +#define Z7_container_of(ptr, type, m) \ + ((type *)(void *)((char *)(void *) \ + (1 ? (ptr) : &((type *)NULL)->m) - MY_offsetof(type, m))) + +#define Z7_container_of_CONST(ptr, type, m) \ + ((const type *)(const void *)((const char *)(const void *) \ + (1 ? (ptr) : &((type *)NULL)->m) - MY_offsetof(type, m))) + +/* +#define Z7_container_of_NON_CONST_FROM_CONST(ptr, type, m) \ + ((type *)(void *)(const void *)((const char *)(const void *) \ + (1 ? (ptr) : &((type *)NULL)->m) - MY_offsetof(type, m))) +*/ + +#endif + +#define Z7_CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m) ((type *)(void *)(ptr)) + +// #define Z7_CONTAINER_FROM_VTBL(ptr, type, m) Z7_CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m) +#define Z7_CONTAINER_FROM_VTBL(ptr, type, m) Z7_container_of(ptr, type, m) +// #define Z7_CONTAINER_FROM_VTBL(ptr, type, m) Z7_container_of_NON_CONST_FROM_CONST(ptr, type, m) + +#define Z7_CONTAINER_FROM_VTBL_CONST(ptr, type, m) Z7_container_of_CONST(ptr, type, m) + +#define Z7_CONTAINER_FROM_VTBL_CLS(ptr, type, m) Z7_CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m) +/* +#define Z7_CONTAINER_FROM_VTBL_CLS(ptr, type, m) Z7_CONTAINER_FROM_VTBL(ptr, type, m) +*/ +#if defined (__clang__) || defined(__GNUC__) +#define Z7_DIAGNOSTIC_IGNORE_BEGIN_CAST_QUAL \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") +#define Z7_DIAGNOSTIC_IGNORE_END_CAST_QUAL \ + _Pragma("GCC diagnostic pop") +#else +#define Z7_DIAGNOSTIC_IGNORE_BEGIN_CAST_QUAL +#define Z7_DIAGNOSTIC_IGNORE_END_CAST_QUAL +#endif + +#define Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR(ptr, type, m, p) \ + Z7_DIAGNOSTIC_IGNORE_BEGIN_CAST_QUAL \ + type *p = Z7_CONTAINER_FROM_VTBL(ptr, type, m); \ + Z7_DIAGNOSTIC_IGNORE_END_CAST_QUAL + +#define Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(type) \ + Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR(pp, type, vt, p) + + +// #define ZIP7_DECLARE_HANDLE(name) typedef void *name; +#define Z7_DECLARE_HANDLE(name) struct name##_dummy{int unused;}; typedef struct name##_dummy *name; + + +#define Z7_memset_0_ARRAY(a) memset((a), 0, sizeof(a)) + +#ifndef Z7_ARRAY_SIZE +#define Z7_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#endif + + +#ifdef _WIN32 + +#define CHAR_PATH_SEPARATOR '\\' +#define WCHAR_PATH_SEPARATOR L'\\' +#define STRING_PATH_SEPARATOR "\\" +#define WSTRING_PATH_SEPARATOR L"\\" + +#else + +#define CHAR_PATH_SEPARATOR '/' +#define WCHAR_PATH_SEPARATOR L'/' +#define STRING_PATH_SEPARATOR "/" +#define WSTRING_PATH_SEPARATOR L"/" + +#endif + +#define k_PropVar_TimePrec_0 0 +#define k_PropVar_TimePrec_Unix 1 +#define k_PropVar_TimePrec_DOS 2 +#define k_PropVar_TimePrec_HighPrec 3 +#define k_PropVar_TimePrec_Base 16 +#define k_PropVar_TimePrec_100ns (k_PropVar_TimePrec_Base + 7) +#define k_PropVar_TimePrec_1ns (k_PropVar_TimePrec_Base + 9) + +EXTERN_C_END + +#endif + +/* +#ifndef Z7_ST +#ifdef _7ZIP_ST +#define Z7_ST +#endif +#endif +*/ diff --git a/libs/archive/thirdparty/C/7zWindows.h b/libs/archive/thirdparty/C/7zWindows.h new file mode 100644 index 0000000..42c6db8 --- /dev/null +++ b/libs/archive/thirdparty/C/7zWindows.h @@ -0,0 +1,101 @@ +/* 7zWindows.h -- StdAfx +2023-04-02 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_7Z_WINDOWS_H +#define ZIP7_INC_7Z_WINDOWS_H + +#ifdef _WIN32 + +#if defined(__clang__) +# pragma clang diagnostic push +#endif + +#if defined(_MSC_VER) + +#pragma warning(push) +#pragma warning(disable : 4668) // '_WIN32_WINNT' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' + +#if _MSC_VER == 1900 +// for old kit10 versions +// #pragma warning(disable : 4255) // winuser.h(13979): warning C4255: 'GetThreadDpiAwarenessContext': +#endif +// win10 Windows Kit: +#endif // _MSC_VER + +#if defined(_MSC_VER) && _MSC_VER <= 1200 && !defined(_WIN64) +// for msvc6 without sdk2003 +#define RPC_NO_WINDOWS_H +#endif + +#if defined(__MINGW32__) || defined(__MINGW64__) +// #if defined(__GNUC__) && !defined(__clang__) +#include +#else +#include +#endif +// #include +// #include + +// but if precompiled with clang-cl then we need +// #include +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + +#if defined(__clang__) +# pragma clang diagnostic pop +#endif + +#if defined(_MSC_VER) && _MSC_VER <= 1200 && !defined(_WIN64) +#ifndef _W64 + +typedef long LONG_PTR, *PLONG_PTR; +typedef unsigned long ULONG_PTR, *PULONG_PTR; +typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR; + +#define Z7_OLD_WIN_SDK +#endif // _W64 +#endif // _MSC_VER == 1200 + +#ifdef Z7_OLD_WIN_SDK + +#ifndef INVALID_FILE_ATTRIBUTES +#define INVALID_FILE_ATTRIBUTES ((DWORD)-1) +#endif +#ifndef INVALID_SET_FILE_POINTER +#define INVALID_SET_FILE_POINTER ((DWORD)-1) +#endif +#ifndef FILE_SPECIAL_ACCESS +#define FILE_SPECIAL_ACCESS (FILE_ANY_ACCESS) +#endif + +// ShlObj.h: +// #define BIF_NEWDIALOGSTYLE 0x0040 + +#pragma warning(disable : 4201) +// #pragma warning(disable : 4115) + +#undef VARIANT_TRUE +#define VARIANT_TRUE ((VARIANT_BOOL)-1) +#endif + +#endif // Z7_OLD_WIN_SDK + +#ifdef UNDER_CE +#undef VARIANT_TRUE +#define VARIANT_TRUE ((VARIANT_BOOL)-1) +#endif + + +#if defined(_MSC_VER) +#if _MSC_VER >= 1400 && _MSC_VER <= 1600 + // BaseTsd.h(148) : 'HandleToULong' : unreferenced inline function has been removed + // string.h + // #pragma warning(disable : 4514) +#endif +#endif + + +/* #include "7zTypes.h" */ + +#endif diff --git a/libs/archive/thirdparty/C/Compiler.h b/libs/archive/thirdparty/C/Compiler.h new file mode 100644 index 0000000..2a9c2b7 --- /dev/null +++ b/libs/archive/thirdparty/C/Compiler.h @@ -0,0 +1,236 @@ +/* Compiler.h : Compiler specific defines and pragmas +2024-01-22 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_COMPILER_H +#define ZIP7_INC_COMPILER_H + +#if defined(__clang__) +# define Z7_CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) +#endif +#if defined(__clang__) && defined(__apple_build_version__) +# define Z7_APPLE_CLANG_VERSION Z7_CLANG_VERSION +#elif defined(__clang__) +# define Z7_LLVM_CLANG_VERSION Z7_CLANG_VERSION +#elif defined(__GNUC__) +# define Z7_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#endif + +#ifdef _MSC_VER +#if !defined(__clang__) && !defined(__GNUC__) +#define Z7_MSC_VER_ORIGINAL _MSC_VER +#endif +#endif + +#if defined(__MINGW32__) || defined(__MINGW64__) +#define Z7_MINGW +#endif + +#if defined(__LCC__) && (defined(__MCST__) || defined(__e2k__)) +#define Z7_MCST_LCC +#define Z7_MCST_LCC_VERSION (__LCC__ * 100 + __LCC_MINOR__) +#endif + +/* +#if defined(__AVX2__) \ + || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40900) \ + || defined(Z7_APPLE_CLANG_VERSION) && (Z7_APPLE_CLANG_VERSION >= 40600) \ + || defined(Z7_LLVM_CLANG_VERSION) && (Z7_LLVM_CLANG_VERSION >= 30100) \ + || defined(Z7_MSC_VER_ORIGINAL) && (Z7_MSC_VER_ORIGINAL >= 1800) \ + || defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1400) + #define Z7_COMPILER_AVX2_SUPPORTED + #endif +#endif +*/ + +// #pragma GCC diagnostic ignored "-Wunknown-pragmas" + +#ifdef __clang__ +// padding size of '' with 4 bytes to alignment boundary +#pragma GCC diagnostic ignored "-Wpadded" + +#if defined(Z7_LLVM_CLANG_VERSION) && (__clang_major__ == 13) \ + && defined(__FreeBSD__) +// freebsd: +#pragma GCC diagnostic ignored "-Wexcess-padding" +#endif + +#if __clang_major__ >= 16 +#pragma GCC diagnostic ignored "-Wunsafe-buffer-usage" +#endif + +#if __clang_major__ == 13 +#if defined(__SIZEOF_POINTER__) && (__SIZEOF_POINTER__ == 16) +// cheri +#pragma GCC diagnostic ignored "-Wcapability-to-integer-cast" +#endif +#endif + +#if __clang_major__ == 13 + // for + #pragma GCC diagnostic ignored "-Wreserved-identifier" +#endif + +#endif // __clang__ + +#if defined(_WIN32) && defined(__clang__) && __clang_major__ >= 16 +// #pragma GCC diagnostic ignored "-Wcast-function-type-strict" +#define Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION \ + _Pragma("GCC diagnostic ignored \"-Wcast-function-type-strict\"") +#else +#define Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION +#endif + +typedef void (*Z7_void_Function)(void); +#if defined(__clang__) || defined(__GNUC__) +#define Z7_CAST_FUNC_C (Z7_void_Function) +#elif defined(_MSC_VER) && _MSC_VER > 1920 +#define Z7_CAST_FUNC_C (void *) +// #pragma warning(disable : 4191) // 'type cast': unsafe conversion from 'FARPROC' to 'void (__cdecl *)()' +#else +#define Z7_CAST_FUNC_C +#endif +/* +#if (defined(__GNUC__) && (__GNUC__ >= 8)) || defined(__clang__) + // #pragma GCC diagnostic ignored "-Wcast-function-type" +#endif +*/ +#ifdef __GNUC__ +#if defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40000) && (Z7_GCC_VERSION < 70000) +#pragma GCC diagnostic ignored "-Wstrict-aliasing" +#endif +#endif + + +#ifdef _MSC_VER + + #ifdef UNDER_CE + #define RPC_NO_WINDOWS_H + /* #pragma warning(disable : 4115) // '_RPC_ASYNC_STATE' : named type definition in parentheses */ + #pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union + #pragma warning(disable : 4214) // nonstandard extension used : bit field types other than int + #endif + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif + +// == 1200 : -O1 : for __forceinline +// >= 1900 : -O1 : for printf +#pragma warning(disable : 4710) // function not inlined + +#if _MSC_VER < 1900 +// winnt.h: 'Int64ShllMod32' +#pragma warning(disable : 4514) // unreferenced inline function has been removed +#endif + +#if _MSC_VER < 1300 +// #pragma warning(disable : 4702) // unreachable code +// Bra.c : -O1: +#pragma warning(disable : 4714) // function marked as __forceinline not inlined +#endif + +/* +#if _MSC_VER > 1400 && _MSC_VER <= 1900 +// strcat: This function or variable may be unsafe +// sysinfoapi.h: kit10: GetVersion was declared deprecated +#pragma warning(disable : 4996) +#endif +*/ + +#if _MSC_VER > 1200 +// -Wall warnings + +#pragma warning(disable : 4711) // function selected for automatic inline expansion +#pragma warning(disable : 4820) // '2' bytes padding added after data member + +#if _MSC_VER >= 1400 && _MSC_VER < 1920 +// 1400: string.h: _DBG_MEMCPY_INLINE_ +// 1600 - 191x : smmintrin.h __cplusplus' +// is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' +#pragma warning(disable : 4668) + +// 1400 - 1600 : WinDef.h : 'FARPROC' : +// 1900 - 191x : immintrin.h: _readfsbase_u32 +// no function prototype given : converting '()' to '(void)' +#pragma warning(disable : 4255) +#endif + +#if _MSC_VER >= 1914 +// Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified +#pragma warning(disable : 5045) +#endif + +#endif // _MSC_VER > 1200 +#endif // _MSC_VER + + +#if defined(__clang__) && (__clang_major__ >= 4) + #define Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE \ + _Pragma("clang loop unroll(disable)") \ + _Pragma("clang loop vectorize(disable)") + #define Z7_ATTRIB_NO_VECTORIZE +#elif defined(__GNUC__) && (__GNUC__ >= 5) \ + && (!defined(Z7_MCST_LCC_VERSION) || (Z7_MCST_LCC_VERSION >= 12610)) + #define Z7_ATTRIB_NO_VECTORIZE __attribute__((optimize("no-tree-vectorize"))) + // __attribute__((optimize("no-unroll-loops"))); + #define Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE +#elif defined(_MSC_VER) && (_MSC_VER >= 1920) + #define Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE \ + _Pragma("loop( no_vector )") + #define Z7_ATTRIB_NO_VECTORIZE +#else + #define Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE + #define Z7_ATTRIB_NO_VECTORIZE +#endif + +#if defined(MY_CPU_X86_OR_AMD64) && ( \ + defined(__clang__) && (__clang_major__ >= 4) \ + || defined(__GNUC__) && (__GNUC__ >= 5)) + #define Z7_ATTRIB_NO_SSE __attribute__((__target__("no-sse"))) +#else + #define Z7_ATTRIB_NO_SSE +#endif + +#define Z7_ATTRIB_NO_VECTOR \ + Z7_ATTRIB_NO_VECTORIZE \ + Z7_ATTRIB_NO_SSE + + +#if defined(__clang__) && (__clang_major__ >= 8) \ + || defined(__GNUC__) && (__GNUC__ >= 1000) \ + /* || defined(_MSC_VER) && (_MSC_VER >= 1920) */ + // GCC is not good for __builtin_expect() + #define Z7_LIKELY(x) (__builtin_expect((x), 1)) + #define Z7_UNLIKELY(x) (__builtin_expect((x), 0)) + // #define Z7_unlikely [[unlikely]] + // #define Z7_likely [[likely]] +#else + #define Z7_LIKELY(x) (x) + #define Z7_UNLIKELY(x) (x) + // #define Z7_likely +#endif + + +#if (defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30600)) + +#if (Z7_CLANG_VERSION < 130000) +#define Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wreserved-id-macro\"") +#else +#define Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wreserved-macro-identifier\"") +#endif + +#define Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER \ + _Pragma("GCC diagnostic pop") +#else +#define Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER +#define Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER +#endif + +#define UNUSED_VAR(x) (void)x; +/* #define UNUSED_VAR(x) x=x; */ + +#endif diff --git a/libs/archive/thirdparty/C/Precomp.h b/libs/archive/thirdparty/C/Precomp.h new file mode 100644 index 0000000..7747fdd --- /dev/null +++ b/libs/archive/thirdparty/C/Precomp.h @@ -0,0 +1,127 @@ +/* Precomp.h -- precompilation file +2024-01-25 : Igor Pavlov : Public domain */ + +#ifndef ZIP7_INC_PRECOMP_H +#define ZIP7_INC_PRECOMP_H + +/* + this file must be included before another *.h files and before . + this file is included from the following files: + C\*.c + C\Util\*\Precomp.h <- C\Util\*\*.c + CPP\Common\Common.h <- *\StdAfx.h <- *\*.cpp + + this file can set the following macros: + Z7_LARGE_PAGES 1 + Z7_LONG_PATH 1 + Z7_WIN32_WINNT_MIN 0x0500 (or higher) : we require at least win2000+ for 7-Zip + _WIN32_WINNT 0x0500 (or higher) + WINVER _WIN32_WINNT + UNICODE 1 + _UNICODE 1 +*/ + +#include "Compiler.h" + +#ifdef _MSC_VER +// #pragma warning(disable : 4206) // nonstandard extension used : translation unit is empty +#if _MSC_VER >= 1912 +// #pragma warning(disable : 5039) // pointer or reference to potentially throwing function passed to 'extern "C"' function under - EHc.Undefined behavior may occur if this function throws an exception. +#endif +#endif + +/* +// for debug: +#define UNICODE 1 +#define _UNICODE 1 +#define _WIN32_WINNT 0x0500 // win2000 +#ifndef WINVER + #define WINVER _WIN32_WINNT +#endif +*/ + +#ifdef _WIN32 +/* + this "Precomp.h" file must be included before , + if we want to define _WIN32_WINNT before . +*/ + +#ifndef Z7_LARGE_PAGES +#ifndef Z7_NO_LARGE_PAGES +#define Z7_LARGE_PAGES 1 +#endif +#endif + +#ifndef Z7_LONG_PATH +#ifndef Z7_NO_LONG_PATH +#define Z7_LONG_PATH 1 +#endif +#endif + +#ifndef Z7_DEVICE_FILE +#ifndef Z7_NO_DEVICE_FILE +// #define Z7_DEVICE_FILE 1 +#endif +#endif + +// we don't change macros if included after +#ifndef _WINDOWS_ + +#ifndef Z7_WIN32_WINNT_MIN + #if defined(_M_ARM64) || defined(__aarch64__) + // #define Z7_WIN32_WINNT_MIN 0x0a00 // win10 + #define Z7_WIN32_WINNT_MIN 0x0600 // vista + #elif defined(_M_ARM) && defined(_M_ARMT) && defined(_M_ARM_NT) + // #define Z7_WIN32_WINNT_MIN 0x0602 // win8 + #define Z7_WIN32_WINNT_MIN 0x0600 // vista + #elif defined(_M_X64) || defined(_M_AMD64) || defined(__x86_64__) || defined(_M_IA64) + #define Z7_WIN32_WINNT_MIN 0x0503 // win2003 + // #elif defined(_M_IX86) || defined(__i386__) + // #define Z7_WIN32_WINNT_MIN 0x0500 // win2000 + #else // x86 and another(old) systems + #define Z7_WIN32_WINNT_MIN 0x0500 // win2000 + // #define Z7_WIN32_WINNT_MIN 0x0502 // win2003 // for debug + #endif +#endif // Z7_WIN32_WINNT_MIN + + +#ifndef Z7_DO_NOT_DEFINE_WIN32_WINNT +#ifdef _WIN32_WINNT + // #error Stop_Compiling_Bad_WIN32_WINNT +#else + #ifndef Z7_NO_DEFINE_WIN32_WINNT +Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER + #define _WIN32_WINNT Z7_WIN32_WINNT_MIN +Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER + #endif +#endif // _WIN32_WINNT + +#ifndef WINVER + #define WINVER _WIN32_WINNT +#endif +#endif // Z7_DO_NOT_DEFINE_WIN32_WINNT + + +#ifndef _MBCS +#ifndef Z7_NO_UNICODE +// UNICODE and _UNICODE are used by and by 7-zip code. + +#ifndef UNICODE +#define UNICODE 1 +#endif + +#ifndef _UNICODE +Z7_DIAGNOSTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER +#define _UNICODE 1 +Z7_DIAGNOSTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER +#endif + +#endif // Z7_NO_UNICODE +#endif // _MBCS +#endif // _WINDOWS_ + +// #include "7zWindows.h" + +#endif // _WIN32 + +#endif diff --git a/libs/archive/thirdparty/CPP/7zip/Archive/IArchive.h b/libs/archive/thirdparty/CPP/7zip/Archive/IArchive.h new file mode 100644 index 0000000..a817015 --- /dev/null +++ b/libs/archive/thirdparty/CPP/7zip/Archive/IArchive.h @@ -0,0 +1,754 @@ +// IArchive.h + +#ifndef ZIP7_INC_IARCHIVE_H +#define ZIP7_INC_IARCHIVE_H + +#include "../IProgress.h" +#include "../IStream.h" +#include "../PropID.h" + +Z7_PURE_INTERFACES_BEGIN + + +#define Z7_IFACE_CONSTR_ARCHIVE_SUB(i, base, n) \ + Z7_DECL_IFACE_7ZIP_SUB(i, base, 6, n) \ + { Z7_IFACE_COM7_PURE(i) }; + +#define Z7_IFACE_CONSTR_ARCHIVE(i, n) \ + Z7_IFACE_CONSTR_ARCHIVE_SUB(i, IUnknown, n) + +/* +How the function in 7-Zip returns object for output parameter via pointer + +1) The caller sets the value of variable before function call: + PROPVARIANT : vt = VT_EMPTY + BSTR : NULL + IUnknown* and derived interfaces : NULL + another scalar types : any non-initialized value is allowed + +2) The callee in current 7-Zip code now can free input object for output parameter: + PROPVARIANT : the callee calls VariantClear(propvaiant_ptr) for input + value stored in variable + another types : the callee ignores stored value. + +3) The callee writes new value to variable for output parameter and + returns execution to caller. + +4) The caller must free or release object returned by the callee: + PROPVARIANT : VariantClear(&propvaiant) + BSTR : SysFreeString(bstr) + IUnknown* and derived interfaces : if (ptr) ptr->Relase() +*/ + + +namespace NFileTimeType +{ + enum EEnum + { + kNotDefined = -1, + kWindows = 0, + kUnix, + kDOS, + k1ns + }; +} + +namespace NArcInfoFlags +{ + const UInt32 kKeepName = 1 << 0; // keep name of file in archive name + const UInt32 kAltStreams = 1 << 1; // the handler supports alt streams + const UInt32 kNtSecure = 1 << 2; // the handler supports NT security + const UInt32 kFindSignature = 1 << 3; // the handler can find start of archive + const UInt32 kMultiSignature = 1 << 4; // there are several signatures + const UInt32 kUseGlobalOffset = 1 << 5; // the seek position of stream must be set as global offset + const UInt32 kStartOpen = 1 << 6; // call handler for each start position + const UInt32 kPureStartOpen = 1 << 7; // call handler only for start of file + const UInt32 kBackwardOpen = 1 << 8; // archive can be open backward + const UInt32 kPreArc = 1 << 9; // such archive can be stored before real archive (like SFX stub) + const UInt32 kSymLinks = 1 << 10; // the handler supports symbolic links + const UInt32 kHardLinks = 1 << 11; // the handler supports hard links + const UInt32 kByExtOnlyOpen = 1 << 12; // call handler only if file extension matches + const UInt32 kHashHandler = 1 << 13; // the handler contains the hashes (checksums) + const UInt32 kCTime = 1 << 14; + const UInt32 kCTime_Default = 1 << 15; + const UInt32 kATime = 1 << 16; + const UInt32 kATime_Default = 1 << 17; + const UInt32 kMTime = 1 << 18; + const UInt32 kMTime_Default = 1 << 19; + // const UInt32 kTTime_Reserved = 1 << 20; + // const UInt32 kTTime_Reserved_Default = 1 << 21; +} + +namespace NArcInfoTimeFlags +{ + const unsigned kTime_Prec_Mask_bit_index = 0; + const unsigned kTime_Prec_Mask_num_bits = 26; + + const unsigned kTime_Prec_Default_bit_index = 27; + const unsigned kTime_Prec_Default_num_bits = 5; +} + +#define TIME_PREC_TO_ARC_FLAGS_MASK(v) \ + ((UInt32)1 << (NArcInfoTimeFlags::kTime_Prec_Mask_bit_index + (v))) + +#define TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT(v) \ + ((UInt32)(v) << NArcInfoTimeFlags::kTime_Prec_Default_bit_index) + +namespace NArchive +{ + namespace NHandlerPropID + { + enum + { + kName = 0, // VT_BSTR + kClassID, // binary GUID in VT_BSTR + kExtension, // VT_BSTR + kAddExtension, // VT_BSTR + kUpdate, // VT_BOOL + kKeepName, // VT_BOOL + kSignature, // binary in VT_BSTR + kMultiSignature, // binary in VT_BSTR + kSignatureOffset, // VT_UI4 + kAltStreams, // VT_BOOL + kNtSecure, // VT_BOOL + kFlags, // VT_UI4 + kTimeFlags // VT_UI4 + }; + } + + namespace NExtract + { + namespace NAskMode + { + enum + { + kExtract = 0, + kTest, + kSkip, + kReadExternal + }; + } + + namespace NOperationResult + { + enum + { + kOK = 0, + kUnsupportedMethod, + kDataError, + kCRCError, + kUnavailable, + kUnexpectedEnd, + kDataAfterEnd, + kIsNotArc, + kHeadersError, + kWrongPassword + // , kMemError + }; + } + } + + namespace NEventIndexType + { + enum + { + kNoIndex = 0, + kInArcIndex, + kBlockIndex, + kOutArcIndex + // kArcProp + }; + } + + namespace NUpdate + { + namespace NOperationResult + { + enum + { + kOK = 0 + // kError = 1, + // kError_FileChanged + }; + } + } +} + +#define Z7_IFACEM_IArchiveOpenCallback(x) \ + x(SetTotal(const UInt64 *files, const UInt64 *bytes)) \ + x(SetCompleted(const UInt64 *files, const UInt64 *bytes)) \ + +Z7_IFACE_CONSTR_ARCHIVE(IArchiveOpenCallback, 0x10) + +/* +IArchiveExtractCallback:: + +7-Zip doesn't call IArchiveExtractCallback functions + GetStream() + PrepareOperation() + SetOperationResult() +from different threads simultaneously. +But 7-Zip can call functions for IProgress or ICompressProgressInfo functions +from another threads simultaneously with calls for IArchiveExtractCallback interface. + +IArchiveExtractCallback::GetStream() + UInt32 index - index of item in Archive + Int32 askExtractMode (Extract::NAskMode) + if (askMode != NExtract::NAskMode::kExtract) + { + then the callee doesn't write data to stream: (*outStream == NULL) + } + + Out: + (*outStream == NULL) - for directories + (*outStream == NULL) - if link (hard link or symbolic link) was created + if (*outStream == NULL && askMode == NExtract::NAskMode::kExtract) + { + then the caller must skip extracting of that file. + } + + returns: + S_OK : OK + S_FALSE : data error (for decoders) + +if (IProgress::SetTotal() was called) +{ + IProgress::SetCompleted(completeValue) uses + packSize - for some stream formats (xz, gz, bz2, lzma, z, ppmd). + unpackSize - for another formats. +} +else +{ + IProgress::SetCompleted(completeValue) uses packSize. +} + +SetOperationResult() + 7-Zip calls SetOperationResult at the end of extracting, + so the callee can close the file, set attributes, timestamps and security information. + + Int32 opRes (NExtract::NOperationResult) +*/ + +// INTERFACE_IProgress(x) + +#define Z7_IFACEM_IArchiveExtractCallback(x) \ + x(GetStream(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode)) \ + x(PrepareOperation(Int32 askExtractMode)) \ + x(SetOperationResult(Int32 opRes)) \ + +Z7_IFACE_CONSTR_ARCHIVE_SUB(IArchiveExtractCallback, IProgress, 0x20) + + + +/* +v23: +IArchiveExtractCallbackMessage2 can be requested from IArchiveExtractCallback object + by Extract() or UpdateItems() functions to report about extracting errors +ReportExtractResult() + UInt32 indexType (NEventIndexType) + UInt32 index + Int32 opRes (NExtract::NOperationResult) +*/ +/* +before v23: +#define Z7_IFACEM_IArchiveExtractCallbackMessage(x) \ + x(ReportExtractResult(UInt32 indexType, UInt32 index, Int32 opRes)) +Z7_IFACE_CONSTR_ARCHIVE_SUB(IArchiveExtractCallbackMessage, IProgress, 0x21) +*/ +#define Z7_IFACEM_IArchiveExtractCallbackMessage2(x) \ + x(ReportExtractResult(UInt32 indexType, UInt32 index, Int32 opRes)) +Z7_IFACE_CONSTR_ARCHIVE(IArchiveExtractCallbackMessage2, 0x22) + +#define Z7_IFACEM_IArchiveOpenVolumeCallback(x) \ + x(GetProperty(PROPID propID, PROPVARIANT *value)) \ + x(GetStream(const wchar_t *name, IInStream **inStream)) +Z7_IFACE_CONSTR_ARCHIVE(IArchiveOpenVolumeCallback, 0x30) + + +#define Z7_IFACEM_IInArchiveGetStream(x) \ + x(GetStream(UInt32 index, ISequentialInStream **stream)) +Z7_IFACE_CONSTR_ARCHIVE(IInArchiveGetStream, 0x40) + +#define Z7_IFACEM_IArchiveOpenSetSubArchiveName(x) \ + x(SetSubArchiveName(const wchar_t *name)) +Z7_IFACE_CONSTR_ARCHIVE(IArchiveOpenSetSubArchiveName, 0x50) + + +/* +IInArchive::Open + stream + if (kUseGlobalOffset), stream current position can be non 0. + if (!kUseGlobalOffset), stream current position is 0. + if (maxCheckStartPosition == NULL), the handler can try to search archive start in stream + if (*maxCheckStartPosition == 0), the handler must check only current position as archive start + +IInArchive::Extract: + indices must be sorted + numItems = (UInt32)(Int32)-1 = 0xFFFFFFFF means "all files" + testMode != 0 means "test files without writing to outStream" + +IInArchive::GetArchiveProperty: + kpidOffset - start offset of archive. + VT_EMPTY : means offset = 0. + VT_UI4, VT_UI8, VT_I8 : result offset; negative values is allowed + kpidPhySize - size of archive. VT_EMPTY means unknown size. + kpidPhySize is allowed to be larger than file size. In that case it must show + supposed size. + + kpidIsDeleted: + kpidIsAltStream: + kpidIsAux: + kpidINode: + must return VARIANT_TRUE (VT_BOOL), if archive can support that property in GetProperty. + + +Notes: + Don't call IInArchive functions for same IInArchive object from different threads simultaneously. + Some IInArchive handlers will work incorrectly in that case. +*/ + +#if defined(_MSC_VER) && !defined(__clang__) + #define MY_NO_THROW_DECL_ONLY Z7_COM7F_E +#else + #define MY_NO_THROW_DECL_ONLY +#endif + +#define Z7_IFACEM_IInArchive(x) \ + x(Open(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback)) \ + x(Close()) \ + x(GetNumberOfItems(UInt32 *numItems)) \ + x(GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) \ + x(Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback)) \ + x(GetArchiveProperty(PROPID propID, PROPVARIANT *value)) \ + x(GetNumberOfProperties(UInt32 *numProps)) \ + x(GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \ + x(GetNumberOfArchiveProperties(UInt32 *numProps)) \ + x(GetArchivePropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \ + +Z7_IFACE_CONSTR_ARCHIVE(IInArchive, 0x60) + +namespace NParentType +{ + enum + { + kDir = 0, + kAltStream + }; +} + +namespace NPropDataType +{ + const UInt32 kMask_ZeroEnd = 1 << 4; + // const UInt32 kMask_BigEndian = 1 << 5; + const UInt32 kMask_Utf = 1 << 6; + const UInt32 kMask_Utf8 = kMask_Utf | 0; + const UInt32 kMask_Utf16 = kMask_Utf | 1; + // const UInt32 kMask_Utf32 = kMask_Utf | 2; + + const UInt32 kNotDefined = 0; + const UInt32 kRaw = 1; + + const UInt32 kUtf8z = kMask_Utf8 | kMask_ZeroEnd; + const UInt32 kUtf16z = kMask_Utf16 | kMask_ZeroEnd; +} + +// UTF string (pointer to wchar_t) with zero end and little-endian. +#define PROP_DATA_TYPE_wchar_t_PTR_Z_LE ((NPropDataType::kMask_Utf | NPropDataType::kMask_ZeroEnd) + (sizeof(wchar_t) >> 1)) + + +/* +GetRawProp: + Result: + S_OK - even if property is not set +*/ + +#define Z7_IFACEM_IArchiveGetRawProps(x) \ + x(GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType)) \ + x(GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)) \ + x(GetNumRawProps(UInt32 *numProps)) \ + x(GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID)) + +Z7_IFACE_CONSTR_ARCHIVE(IArchiveGetRawProps, 0x70) + +#define Z7_IFACEM_IArchiveGetRootProps(x) \ + x(GetRootProp(PROPID propID, PROPVARIANT *value)) \ + x(GetRootRawProp(PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)) \ + +Z7_IFACE_CONSTR_ARCHIVE(IArchiveGetRootProps, 0x71) + +#define Z7_IFACEM_IArchiveOpenSeq(x) \ + x(OpenSeq(ISequentialInStream *stream)) \ + +Z7_IFACE_CONSTR_ARCHIVE(IArchiveOpenSeq, 0x61) + +/* + OpenForSize + Result: + S_FALSE - is not archive + ? - DATA error +*/ + +/* +const UInt32 kOpenFlags_RealPhySize = 1 << 0; +const UInt32 kOpenFlags_NoSeek = 1 << 1; +// const UInt32 kOpenFlags_BeforeExtract = 1 << 2; +*/ + +/* +Flags: + 0 - opens archive with IInStream, if IInStream interface is supported + - if phySize is not available, it doesn't try to make full parse to get phySize + kOpenFlags_NoSeek - ArcOpen2 function doesn't use IInStream interface, even if it's available + kOpenFlags_RealPhySize - the handler will try to get PhySize, even if it requires full decompression for file + + if handler is not allowed to use IInStream and the flag kOpenFlags_RealPhySize is not specified, + the handler can return S_OK, but it doesn't check even Signature. + So next Extract can be called for that sequential stream. +*/ +/* +#define Z7_IFACEM_IArchiveOpen2(x) \ + x(ArcOpen2(ISequentialInStream *stream, UInt32 flags, IArchiveOpenCallback *openCallback)) +Z7_IFACE_CONSTR_ARCHIVE(IArchiveOpen2, 0x62) +*/ + +// ---------- UPDATE ---------- + +/* +GetUpdateItemInfo outs: +*newData *newProps + 0 0 - Copy data and properties from archive + 0 1 - Copy data from archive, request new properties + 1 0 - that combination is unused now + 1 1 - Request new data and new properties. It can be used even for folders + + indexInArchive = -1 if there is no item in archive, or if it doesn't matter. + + +GetStream out: + Result: + S_OK: + (*inStream == NULL) - only for directories + - the bug was fixed in 9.33: (*Stream == NULL) was in case of anti-file + (*inStream != NULL) - for any file, even for empty file or anti-file + S_FALSE - skip that file (don't add item to archive) - (client code can't open stream of that file by some reason) + (*inStream == NULL) + +The order of calling for hard links: + - GetStream() + - GetProperty(kpidHardLink) + +SetOperationResult() + Int32 opRes (NExtract::NOperationResult::kOK) +*/ + +// INTERFACE_IProgress(x) +#define Z7_IFACEM_IArchiveUpdateCallback(x) \ + x(GetUpdateItemInfo(UInt32 index, Int32 *newData, Int32 *newProps, UInt32 *indexInArchive)) \ + x(GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) \ + x(GetStream(UInt32 index, ISequentialInStream **inStream)) \ + x(SetOperationResult(Int32 operationResult)) \ + +Z7_IFACE_CONSTR_ARCHIVE_SUB(IArchiveUpdateCallback, IProgress, 0x80) + +// INTERFACE_IArchiveUpdateCallback(x) +#define Z7_IFACEM_IArchiveUpdateCallback2(x) \ + x(GetVolumeSize(UInt32 index, UInt64 *size)) \ + x(GetVolumeStream(UInt32 index, ISequentialOutStream **volumeStream)) \ + +Z7_IFACE_CONSTR_ARCHIVE_SUB(IArchiveUpdateCallback2, IArchiveUpdateCallback, 0x82) + +namespace NUpdateNotifyOp +{ + enum + { + kAdd = 0, + kUpdate, + kAnalyze, + kReplicate, + kRepack, + kSkip, + kDelete, + kHeader, + kHashRead, + kInFileChanged + // , kOpFinished + // , kNumDefined + }; +} + +/* +IArchiveUpdateCallbackFile::ReportOperation + UInt32 indexType (NEventIndexType) + UInt32 index + UInt32 notifyOp (NUpdateNotifyOp) +*/ + +#define Z7_IFACEM_IArchiveUpdateCallbackFile(x) \ + x(GetStream2(UInt32 index, ISequentialInStream **inStream, UInt32 notifyOp)) \ + x(ReportOperation(UInt32 indexType, UInt32 index, UInt32 notifyOp)) \ + +Z7_IFACE_CONSTR_ARCHIVE(IArchiveUpdateCallbackFile, 0x83) + + +#define Z7_IFACEM_IArchiveGetDiskProperty(x) \ + x(GetDiskProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) \ + +Z7_IFACE_CONSTR_ARCHIVE(IArchiveGetDiskProperty, 0x84) + +/* +#define Z7_IFACEM_IArchiveUpdateCallbackArcProp(x) \ + x(ReportProp(UInt32 indexType, UInt32 index, PROPID propID, const PROPVARIANT *value)) \ + x(ReportRawProp(UInt32 indexType, UInt32 index, PROPID propID, const void *data, UInt32 dataSize, UInt32 propType)) \ + x(ReportFinished(UInt32 indexType, UInt32 index, Int32 opRes)) \ + x(DoNeedArcProp(PROPID propID, Int32 *answer)) \ + +Z7_IFACE_CONSTR_ARCHIVE(IArchiveUpdateCallbackArcProp, 0x85) +*/ + +/* +UpdateItems() +------------- + + outStream: output stream. (the handler) MUST support the case when + Seek position in outStream is not ZERO. + but the caller calls with empty outStream and seek position is ZERO?? + + archives with stub: + + If archive is open and the handler and (Offset > 0), then the handler + knows about stub size. + UpdateItems(): + 1) the handler MUST copy that stub to outStream + 2) the caller MUST NOT copy the stub to outStream, if + "rsfx" property is set with SetProperties + + the handler must support the case where + ISequentialOutStream *outStream +*/ + + +#define Z7_IFACEM_IOutArchive(x) \ + x(UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, IArchiveUpdateCallback *updateCallback)) \ + x(GetFileTimeType(UInt32 *type)) + +Z7_IFACE_CONSTR_ARCHIVE(IOutArchive, 0xA0) + + +/* +ISetProperties::SetProperties() + PROPVARIANT values[i].vt: + VT_EMPTY + VT_BOOL + VT_UI4 - if 32-bit number + VT_UI8 - if 64-bit number + VT_BSTR +*/ + +#define Z7_IFACEM_ISetProperties(x) \ + x(SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)) + +Z7_IFACE_CONSTR_ARCHIVE(ISetProperties, 0x03) + +#define Z7_IFACEM_IArchiveKeepModeForNextOpen(x) \ + x(KeepModeForNextOpen()) \ + +Z7_IFACE_CONSTR_ARCHIVE(IArchiveKeepModeForNextOpen, 0x04) + +/* Exe handler: the handler for executable format (PE, ELF, Mach-O). + SFX archive: executable stub + some tail data. + before 9.31: exe handler didn't parse SFX archives as executable format. + for 9.31+: exe handler parses SFX archives as executable format, only if AllowTail(1) was called */ + +#define Z7_IFACEM_IArchiveAllowTail(x) \ + x(AllowTail(Int32 allowTail)) \ + +Z7_IFACE_CONSTR_ARCHIVE(IArchiveAllowTail, 0x05) + + +namespace NRequestMemoryUseFlags +{ + const UInt32 k_AllowedSize_WasForced = 1 << 0; // (*allowedSize) was forced by -mmemx or -smemx + const UInt32 k_DefaultLimit_Exceeded = 1 << 1; // default limit of archive format was exceeded + const UInt32 k_MLimit_Exceeded = 1 << 2; // -mmemx value was exceeded + const UInt32 k_SLimit_Exceeded = 1 << 3; // -smemx value was exceeded + + const UInt32 k_NoErrorMessage = 1 << 10; // do not show error message, and show only request + const UInt32 k_IsReport = 1 << 11; // only report is required, without user request + + const UInt32 k_SkipArc_IsExpected = 1 << 12; // NRequestMemoryAnswerFlags::k_SkipArc flag answer is expected + const UInt32 k_Report_SkipArc = 1 << 13; // report about SkipArc operation + + // const UInt32 k_SkipBigFile_IsExpected = 1 << 14; // NRequestMemoryAnswerFlags::k_SkipBigFiles flag answer is expected (unused) + // const UInt32 k_Report_SkipBigFile = 1 << 15; // report about SkipFile operation (unused) + + // const UInt32 k_SkipBigFiles_IsExpected = 1 << 16; // NRequestMemoryAnswerFlags::k_SkipBigFiles flag answer is expected (unused) + // const UInt32 k_Report_SkipBigFiles = 1 << 17; // report that all big files will be skipped (unused) +} + +namespace NRequestMemoryAnswerFlags +{ + const UInt32 k_Allow = 1 << 0; // allow further archive extraction + const UInt32 k_Stop = 1 << 1; // for exit (and return_code == E_ABORT is used) + const UInt32 k_SkipArc = 1 << 2; // skip current archive extraction + // const UInt32 k_SkipBigFile = 1 << 4; // skip extracting of files that exceed limit (unused) + // const UInt32 k_SkipBigFiles = 1 << 5; // skip extracting of files that exceed limit (unused) + const UInt32 k_Limit_Exceeded = 1 << 10; // limit was exceeded +} + +/* + *allowedSize is in/out: + in : default allowed memory usage size or forced size, if it was changed by switch -mmemx. + out : value specified by user or unchanged value. + + *answerFlags is in/out: + *answerFlags must be set by caller before calling for default action, + + indexType : must be set with NEventIndexType::* constant + (indexType == kNoIndex), if request for whole archive. + index : must be set for some (indexType) types (if + fileIndex , if (indexType == NEventIndexType::kInArcIndex) + 0, if if (indexType == kNoIndex) + path : NULL can be used for any indexType. +*/ +#define Z7_IFACEM_IArchiveRequestMemoryUseCallback(x) \ + x(RequestMemoryUse(UInt32 flags, UInt32 indexType, UInt32 index, const wchar_t *path, \ + UInt64 requiredSize, UInt64 *allowedSize, UInt32 *answerFlags)) +Z7_IFACE_CONSTR_ARCHIVE(IArchiveRequestMemoryUseCallback, 0x09) + + +struct CStatProp +{ + const char *Name; + UInt32 PropID; + VARTYPE vt; +}; + +namespace NWindows { +namespace NCOM { +// PropVariant.cpp +BSTR AllocBstrFromAscii(const char *s) throw(); +}} + + +#define IMP_IInArchive_GetProp_Base(fn, f, k) \ + Z7_COM7F_IMF(CHandler::fn(UInt32 *numProps)) \ + { *numProps = Z7_ARRAY_SIZE(k); return S_OK; } \ + Z7_COM7F_IMF(CHandler::f(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \ + { if (index >= Z7_ARRAY_SIZE(k)) return E_INVALIDARG; \ + +#define IMP_IInArchive_GetProp_NO_NAME(fn, f, k) \ + IMP_IInArchive_GetProp_Base(fn, f, k) \ + *propID = k[index]; \ + *varType = k7z_PROPID_To_VARTYPE[(unsigned)*propID]; \ + *name = NULL; return S_OK; } \ + +#define IMP_IInArchive_GetProp_WITH_NAME(fn, f, k) \ + IMP_IInArchive_GetProp_Base(fn, f, k) \ + const CStatProp &prop = k[index]; \ + *propID = (PROPID)prop.PropID; \ + *varType = prop.vt; \ + *name = NWindows::NCOM::AllocBstrFromAscii(prop.Name); return S_OK; } \ + + +#define IMP_IInArchive_Props \ + IMP_IInArchive_GetProp_NO_NAME(GetNumberOfProperties, GetPropertyInfo, kProps) + +#define IMP_IInArchive_Props_WITH_NAME \ + IMP_IInArchive_GetProp_WITH_NAME(GetNumberOfProperties, GetPropertyInfo, kProps) + +#define IMP_IInArchive_ArcProps \ + IMP_IInArchive_GetProp_NO_NAME(GetNumberOfArchiveProperties, GetArchivePropertyInfo, kArcProps) + +#define IMP_IInArchive_ArcProps_WITH_NAME \ + IMP_IInArchive_GetProp_WITH_NAME(GetNumberOfArchiveProperties, GetArchivePropertyInfo, kArcProps) + +#define IMP_IInArchive_ArcProps_NO_Table \ + Z7_COM7F_IMF(CHandler::GetNumberOfArchiveProperties(UInt32 *numProps)) \ + { *numProps = 0; return S_OK; } \ + Z7_COM7F_IMF(CHandler::GetArchivePropertyInfo(UInt32, BSTR *, PROPID *, VARTYPE *)) \ + { return E_NOTIMPL; } \ + +#define IMP_IInArchive_ArcProps_NO \ + IMP_IInArchive_ArcProps_NO_Table \ + Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID, PROPVARIANT *value)) \ + { value->vt = VT_EMPTY; return S_OK; } + + +#define Z7_class_CHandler_final \ + Z7_class_final(CHandler) + + +#define Z7_CLASS_IMP_CHandler_IInArchive_0 \ + Z7_CLASS_IMP_COM_1(CHandler, IInArchive) +#define Z7_CLASS_IMP_CHandler_IInArchive_1(i1) \ + Z7_CLASS_IMP_COM_2(CHandler, IInArchive, i1) +#define Z7_CLASS_IMP_CHandler_IInArchive_2(i1, i2) \ + Z7_CLASS_IMP_COM_3(CHandler, IInArchive, i1, i2) +#define Z7_CLASS_IMP_CHandler_IInArchive_3(i1, i2, i3) \ + Z7_CLASS_IMP_COM_4(CHandler, IInArchive, i1, i2, i3) +#define Z7_CLASS_IMP_CHandler_IInArchive_4(i1, i2, i3, i4) \ + Z7_CLASS_IMP_COM_5(CHandler, IInArchive, i1, i2, i3, i4) +#define Z7_CLASS_IMP_CHandler_IInArchive_5(i1, i2, i3, i4, i5) \ + Z7_CLASS_IMP_COM_6(CHandler, IInArchive, i1, i2, i3, i4, i5) + + + +#define k_IsArc_Res_NO 0 +#define k_IsArc_Res_YES 1 +#define k_IsArc_Res_NEED_MORE 2 +// #define k_IsArc_Res_YES_LOW_PROB 3 + +#define API_FUNC_IsArc EXTERN_C UInt32 WINAPI +#define API_FUNC_static_IsArc extern "C" { static UInt32 WINAPI + +extern "C" +{ + typedef HRESULT (WINAPI *Func_CreateObject)(const GUID *clsID, const GUID *iid, void **outObject); + + typedef UInt32 (WINAPI *Func_IsArc)(const Byte *p, size_t size); + typedef HRESULT (WINAPI *Func_GetIsArc)(UInt32 formatIndex, Func_IsArc *isArc); + + typedef HRESULT (WINAPI *Func_GetNumberOfFormats)(UInt32 *numFormats); + typedef HRESULT (WINAPI *Func_GetHandlerProperty)(PROPID propID, PROPVARIANT *value); + typedef HRESULT (WINAPI *Func_GetHandlerProperty2)(UInt32 index, PROPID propID, PROPVARIANT *value); + + typedef HRESULT (WINAPI *Func_SetCaseSensitive)(Int32 caseSensitive); + typedef HRESULT (WINAPI *Func_SetLargePageMode)(); + // typedef HRESULT (WINAPI *Func_SetClientVersion)(UInt32 version); + + typedef IOutArchive * (*Func_CreateOutArchive)(); + typedef IInArchive * (*Func_CreateInArchive)(); +} + + +/* + if there is no time in archive, external MTime of archive + will be used instead of _item.Time from archive. + For 7-zip before 22.00 we need to return some supported value. + But (kpidTimeType > kDOS) is not allowed in 7-Zip before 22.00. + So we return highest precision value supported by old 7-Zip. + new 7-Zip 22.00 doesn't use that value in usual cases. +*/ + + +#define DECLARE_AND_SET_CLIENT_VERSION_VAR +#define GET_FileTimeType_NotDefined_for_GetFileTimeType \ + NFileTimeType::kWindows + +/* +extern UInt32 g_ClientVersion; + +#define GET_CLIENT_VERSION(major, minor) \ + ((UInt32)(((UInt32)(major) << 16) | (UInt32)(minor))) + +#define DECLARE_AND_SET_CLIENT_VERSION_VAR \ + UInt32 g_ClientVersion = GET_CLIENT_VERSION(MY_VER_MAJOR, MY_VER_MINOR); + +#define GET_FileTimeType_NotDefined_for_GetFileTimeType \ + ((UInt32)(g_ClientVersion >= GET_CLIENT_VERSION(22, 0) ? \ + (UInt32)(Int32)NFileTimeType::kNotDefined : \ + NFileTimeType::kWindows)) +*/ + +Z7_PURE_INTERFACES_END +#endif diff --git a/libs/archive/thirdparty/CPP/7zip/ICoder.h b/libs/archive/thirdparty/CPP/7zip/ICoder.h new file mode 100644 index 0000000..aec2834 --- /dev/null +++ b/libs/archive/thirdparty/CPP/7zip/ICoder.h @@ -0,0 +1,477 @@ +// ICoder.h + +#ifndef ZIP7_INC_ICODER_H +#define ZIP7_INC_ICODER_H + +#include "IStream.h" + +Z7_PURE_INTERFACES_BEGIN + +#define Z7_IFACE_CONSTR_CODER(i, n) \ + Z7_DECL_IFACE_7ZIP(i, 4, n) \ + { Z7_IFACE_COM7_PURE(i) }; + +#define Z7_IFACEM_ICompressProgressInfo(x) \ + x(SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)) +Z7_IFACE_CONSTR_CODER(ICompressProgressInfo, 0x04) + /* + SetRatioInfo() + (inSize) can be NULL, if unknown + (outSize) can be NULL, if unknown + returns: + S_OK + E_ABORT : Break by user + another error codes + */ + +#define Z7_IFACEM_ICompressCoder(x) \ + x(Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, \ + const UInt64 *inSize, const UInt64 *outSize, \ + ICompressProgressInfo *progress)) +Z7_IFACE_CONSTR_CODER(ICompressCoder, 0x05) + +#define Z7_IFACEM_ICompressCoder2(x) \ + x(Code(ISequentialInStream * const *inStreams, const UInt64 *const *inSizes, UInt32 numInStreams, \ + ISequentialOutStream *const *outStreams, const UInt64 *const *outSizes, UInt32 numOutStreams, \ + ICompressProgressInfo *progress)) +Z7_IFACE_CONSTR_CODER(ICompressCoder2, 0x18) + +/* + ICompressCoder::Code + ICompressCoder2::Code + + returns: + S_OK : OK + S_FALSE : data error (for decoders) + E_OUTOFMEMORY : memory allocation error + E_NOTIMPL : unsupported encoding method (for decoders) + another error code : some error. For example, it can be error code received from inStream or outStream function. + + Parameters: + (inStream != NULL) + (outStream != NULL) + + if (inSize != NULL) + { + Encoders in 7-Zip ignore (inSize). + Decoder can use (*inSize) to check that stream was decoded correctly. + Some decoders in 7-Zip check it, if (full_decoding mode was set via ICompressSetFinishMode) + } + + If it's required to limit the reading from input stream (inStream), it can + be done with ISequentialInStream implementation. + + if (outSize != NULL) + { + Encoders in 7-Zip ignore (outSize). + Decoder unpacks no more than (*outSize) bytes. + } + + (progress == NULL) is allowed. + + + Decoding with Code() function + ----------------------------- + + You can request some interfaces before decoding + - ICompressSetDecoderProperties2 + - ICompressSetFinishMode + + If you need to decode full stream: + { + 1) try to set full_decoding mode with ICompressSetFinishMode::SetFinishMode(1); + 2) call the Code() function with specified (inSize) and (outSize), if these sizes are known. + } + + If you need to decode only part of stream: + { + 1) try to set partial_decoding mode with ICompressSetFinishMode::SetFinishMode(0); + 2) Call the Code() function with specified (inSize = NULL) and specified (outSize). + } + + Encoding with Code() function + ----------------------------- + + You can request some interfaces : + - ICompressSetCoderProperties - use it before encoding to set properties + - ICompressWriteCoderProperties - use it before or after encoding to request encoded properties. + + ICompressCoder2 is used when (numInStreams != 1 || numOutStreams != 1) + The rules are similar to ICompressCoder rules +*/ + + +namespace NCoderPropID +{ + enum EEnum + { + kDefaultProp = 0, + kDictionarySize, // VT_UI4 + kUsedMemorySize, // VT_UI4 + kOrder, // VT_UI4 + kBlockSize, // VT_UI4 or VT_UI8 + kPosStateBits, // VT_UI4 + kLitContextBits, // VT_UI4 + kLitPosBits, // VT_UI4 + kNumFastBytes, // VT_UI4 + kMatchFinder, // VT_BSTR + kMatchFinderCycles, // VT_UI4 + kNumPasses, // VT_UI4 + kAlgorithm, // VT_UI4 + kNumThreads, // VT_UI4 + kEndMarker, // VT_BOOL + kLevel, // VT_UI4 + kReduceSize, // VT_UI8 : it's estimated size of largest data stream that will be compressed + // encoder can use this value to reduce dictionary size and allocate data buffers + + kExpectedDataSize, // VT_UI8 : for ICompressSetCoderPropertiesOpt : + // it's estimated size of current data stream + // real data size can differ from that size + // encoder can use this value to optimize encoder initialization + + kBlockSize2, // VT_UI4 or VT_UI8 + kCheckSize, // VT_UI4 : size of digest in bytes + kFilter, // VT_BSTR + kMemUse, // VT_UI8 + kAffinity, // VT_UI8 + kBranchOffset, // VT_UI4 + kHashBits, // VT_UI4 + /* + // kHash3Bits, // VT_UI4 + // kHash2Bits, // VT_UI4 + // kChainBits, // VT_UI4 + kChainSize, // VT_UI4 + kNativeLevel, // VT_UI4 + kFast, // VT_UI4 + kMinMatch, // VT_UI4 The minimum slen is 3 and the maximum is 7. + kOverlapLog, // VT_UI4 The minimum ovlog is 0 and the maximum is 9. (default: 6) + kRowMatchFinder, // VT_BOOL + kLdmEnable, // VT_BOOL + // kLdmWindowSizeLog, // VT_UI4 + kLdmWindowSize, // VT_UI4 + kLdmHashLog, // VT_UI4 The minimum ldmhlog is 6 and the maximum is 26 (default: 20). + kLdmMinMatchLength, // VT_UI4 The minimum ldmslen is 4 and the maximum is 4096 (default: 64). + kLdmBucketSizeLog, // VT_UI4 The minimum ldmblog is 0 and the maximum is 8 (default: 3). + kLdmHashRateLog, // VT_UI4 The default value is wlog - ldmhlog. + kWriteUnpackSizeFlag, // VT_BOOL + kUsePledged, // VT_BOOL + kUseSizeHintPledgedForSmall, // VT_BOOL + kUseSizeHintForEach, // VT_BOOL + kUseSizeHintGlobal, // VT_BOOL + kParamSelectMode, // VT_UI4 + // kSearchLog, // VT_UI4 The minimum slog is 1 and the maximum is 26 + // kTargetLen, // VT_UI4 The minimum tlen is 0 and the maximum is 999. + */ + k_NUM_DEFINED + }; +} + +#define Z7_IFACEM_ICompressSetCoderPropertiesOpt(x) \ + x(SetCoderPropertiesOpt(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)) +Z7_IFACE_CONSTR_CODER(ICompressSetCoderPropertiesOpt, 0x1F) + + +#define Z7_IFACEM_ICompressSetCoderProperties(x) \ + x(SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)) +Z7_IFACE_CONSTR_CODER(ICompressSetCoderProperties, 0x20) + +/* +#define Z7_IFACEM_ICompressSetDecoderProperties(x) \ + x(SetDecoderProperties(ISequentialInStream *inStream)) +Z7_IFACE_CONSTR_CODER(ICompressSetDecoderProperties, 0x21) +*/ + +#define Z7_IFACEM_ICompressSetDecoderProperties2(x) \ + x(SetDecoderProperties2(const Byte *data, UInt32 size)) +Z7_IFACE_CONSTR_CODER(ICompressSetDecoderProperties2, 0x22) + /* returns: + S_OK + E_NOTIMP : unsupported properties + E_INVALIDARG : incorrect (or unsupported) properties + E_OUTOFMEMORY : memory allocation error + */ + + +#define Z7_IFACEM_ICompressWriteCoderProperties(x) \ + x(WriteCoderProperties(ISequentialOutStream *outStream)) +Z7_IFACE_CONSTR_CODER(ICompressWriteCoderProperties, 0x23) + +#define Z7_IFACEM_ICompressGetInStreamProcessedSize(x) \ + x(GetInStreamProcessedSize(UInt64 *value)) +Z7_IFACE_CONSTR_CODER(ICompressGetInStreamProcessedSize, 0x24) + +#define Z7_IFACEM_ICompressSetCoderMt(x) \ + x(SetNumberOfThreads(UInt32 numThreads)) +Z7_IFACE_CONSTR_CODER(ICompressSetCoderMt, 0x25) + +#define Z7_IFACEM_ICompressSetFinishMode(x) \ + x(SetFinishMode(UInt32 finishMode)) +Z7_IFACE_CONSTR_CODER(ICompressSetFinishMode, 0x26) + /* finishMode: + 0 : partial decoding is allowed. It's default mode for ICompressCoder::Code(), if (outSize) is defined. + 1 : full decoding. The stream must be finished at the end of decoding. */ + +#define Z7_IFACEM_ICompressGetInStreamProcessedSize2(x) \ + x(GetInStreamProcessedSize2(UInt32 streamIndex, UInt64 *value)) +Z7_IFACE_CONSTR_CODER(ICompressGetInStreamProcessedSize2, 0x27) + +#define Z7_IFACEM_ICompressSetMemLimit(x) \ + x(SetMemLimit(UInt64 memUsage)) +Z7_IFACE_CONSTR_CODER(ICompressSetMemLimit, 0x28) + + +/* + ICompressReadUnusedFromInBuf is supported by ICoder object + call ReadUnusedFromInBuf() after ICoder::Code(inStream, ...). + ICoder::Code(inStream, ...) decodes data, and the ICoder object is allowed + to read from inStream to internal buffers more data than minimal data required for decoding. + So we can call ReadUnusedFromInBuf() from same ICoder object to read unused input + data from the internal buffer. + in ReadUnusedFromInBuf(): the Coder is not allowed to use (ISequentialInStream *inStream) object, that was sent to ICoder::Code(). +*/ +#define Z7_IFACEM_ICompressReadUnusedFromInBuf(x) \ + x(ReadUnusedFromInBuf(void *data, UInt32 size, UInt32 *processedSize)) +Z7_IFACE_CONSTR_CODER(ICompressReadUnusedFromInBuf, 0x29) + + +#define Z7_IFACEM_ICompressGetSubStreamSize(x) \ + x(GetSubStreamSize(UInt64 subStream, UInt64 *value)) +Z7_IFACE_CONSTR_CODER(ICompressGetSubStreamSize, 0x30) + /* returns: + S_OK : (*value) contains the size or estimated size (can be incorrect size) + S_FALSE : size is undefined + E_NOTIMP : the feature is not implemented + Let's (read_size) is size of data that was already read by ISequentialInStream::Read(). + The caller should call GetSubStreamSize() after each Read() and check sizes: + if (start_of_subStream + *value < read_size) + { + // (*value) is correct, and it's allowed to call GetSubStreamSize() for next subStream: + start_of_subStream += *value; + subStream++; + } + */ + +#define Z7_IFACEM_ICompressSetInStream(x) \ + x(SetInStream(ISequentialInStream *inStream)) \ + x(ReleaseInStream()) +Z7_IFACE_CONSTR_CODER(ICompressSetInStream, 0x31) + +#define Z7_IFACEM_ICompressSetOutStream(x) \ + x(SetOutStream(ISequentialOutStream *outStream)) \ + x(ReleaseOutStream()) +Z7_IFACE_CONSTR_CODER(ICompressSetOutStream, 0x32) + +/* +#define Z7_IFACEM_ICompressSetInStreamSize(x) \ + x(SetInStreamSize(const UInt64 *inSize)) \ +Z7_IFACE_CONSTR_CODER(ICompressSetInStreamSize, 0x33) +*/ + +#define Z7_IFACEM_ICompressSetOutStreamSize(x) \ + x(SetOutStreamSize(const UInt64 *outSize)) +Z7_IFACE_CONSTR_CODER(ICompressSetOutStreamSize, 0x34) + /* That function initializes decoder structures. + Call this function only for stream version of decoder. + if (outSize == NULL), then output size is unknown + if (outSize != NULL), then the decoder must stop decoding after (*outSize) bytes. */ + +#define Z7_IFACEM_ICompressSetBufSize(x) \ + x(SetInBufSize(UInt32 streamIndex, UInt32 size)) \ + x(SetOutBufSize(UInt32 streamIndex, UInt32 size)) + +Z7_IFACE_CONSTR_CODER(ICompressSetBufSize, 0x35) + +#define Z7_IFACEM_ICompressInitEncoder(x) \ + x(InitEncoder()) +Z7_IFACE_CONSTR_CODER(ICompressInitEncoder, 0x36) + /* That function initializes encoder structures. + Call this function only for stream version of encoder. */ + +#define Z7_IFACEM_ICompressSetInStream2(x) \ + x(SetInStream2(UInt32 streamIndex, ISequentialInStream *inStream)) \ + x(ReleaseInStream2(UInt32 streamIndex)) +Z7_IFACE_CONSTR_CODER(ICompressSetInStream2, 0x37) + +/* +#define Z7_IFACEM_ICompressSetOutStream2(x) \ + x(SetOutStream2(UInt32 streamIndex, ISequentialOutStream *outStream)) + x(ReleaseOutStream2(UInt32 streamIndex)) +Z7_IFACE_CONSTR_CODER(ICompressSetOutStream2, 0x38) + +#define Z7_IFACEM_ICompressSetInStreamSize2(x) \ + x(SetInStreamSize2(UInt32 streamIndex, const UInt64 *inSize)) +Z7_IFACE_CONSTR_CODER(ICompressSetInStreamSize2, 0x39) +*/ + +/* +#define Z7_IFACEM_ICompressInSubStreams(x) \ + x(GetNextInSubStream(UInt64 *streamIndexRes, ISequentialInStream **stream)) +Z7_IFACE_CONSTR_CODER(ICompressInSubStreams, 0x3A) + +#define Z7_IFACEM_ICompressOutSubStreams(x) \ + x(GetNextOutSubStream(UInt64 *streamIndexRes, ISequentialOutStream **stream)) +Z7_IFACE_CONSTR_CODER(ICompressOutSubStreams, 0x3B) +*/ + +/* + ICompressFilter + Filter(Byte *data, UInt32 size) + (size) + converts as most as possible bytes required for fast processing. + Some filters have (smallest_fast_block). + For example, (smallest_fast_block == 16) for AES CBC/CTR filters. + If data stream is not finished, caller must call Filter() for larger block: + where (size >= smallest_fast_block). + if (size >= smallest_fast_block) + { + The filter can leave some bytes at the end of data without conversion: + if there are data alignment reasons or speed reasons. + The caller can read additional data from stream and call Filter() again. + } + If data stream was finished, caller can call Filter() for (size < smallest_fast_block) + + (data) parameter: + Some filters require alignment for any Filter() call: + 1) (stream_offset % alignment_size) == (data % alignment_size) + 2) (alignment_size == 2^N) + where (stream_offset) - is the number of bytes that were already filtered before. + The callers of Filter() are required to meet these requirements. + (alignment_size) can be different: + 16 : for AES filters + 4 or 2 : for some branch convert filters + 1 : for another filters + (alignment_size >= 16) is enough for all current filters of 7-Zip. + But the caller can use larger (alignment_size). + Recommended alignment for (data) of Filter() call is (alignment_size == 64). + Also it's recommended to use aligned value for (size): + (size % alignment_size == 0), + if it's not last call of Filter() for current stream. + + returns: (outSize): + if (outSize == 0) : Filter have not converted anything. + So the caller can stop processing, if data stream was finished. + if (outSize <= size) : Filter have converted outSize bytes + if (outSize > size) : Filter have not converted anything. + and it needs at least outSize bytes to convert one block + (it's for crypto block algorithms). +*/ + +#define Z7_IFACEM_ICompressFilter(x) \ + x(Init()) \ + x##2(UInt32, Filter(Byte *data, UInt32 size)) +Z7_IFACE_CONSTR_CODER(ICompressFilter, 0x40) + + +#define Z7_IFACEM_ICompressCodecsInfo(x) \ + x(GetNumMethods(UInt32 *numMethods)) \ + x(GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) \ + x(CreateDecoder(UInt32 index, const GUID *iid, void* *coder)) \ + x(CreateEncoder(UInt32 index, const GUID *iid, void* *coder)) +Z7_IFACE_CONSTR_CODER(ICompressCodecsInfo, 0x60) + +#define Z7_IFACEM_ISetCompressCodecsInfo(x) \ + x(SetCompressCodecsInfo(ICompressCodecsInfo *compressCodecsInfo)) +Z7_IFACE_CONSTR_CODER(ISetCompressCodecsInfo, 0x61) + +#define Z7_IFACEM_ICryptoProperties(x) \ + x(SetKey(const Byte *data, UInt32 size)) \ + x(SetInitVector(const Byte *data, UInt32 size)) +Z7_IFACE_CONSTR_CODER(ICryptoProperties, 0x80) + +/* + x(ResetSalt()) +Z7_IFACE_CONSTR_CODER(ICryptoResetSalt, 0x88) +*/ + +#define Z7_IFACEM_ICryptoResetInitVector(x) \ + x(ResetInitVector()) +Z7_IFACE_CONSTR_CODER(ICryptoResetInitVector, 0x8C) + /* Call ResetInitVector() only for encoding. + Call ResetInitVector() before encoding and before WriteCoderProperties(). + Crypto encoder can create random IV in that function. */ + +#define Z7_IFACEM_ICryptoSetPassword(x) \ + x(CryptoSetPassword(const Byte *data, UInt32 size)) +Z7_IFACE_CONSTR_CODER(ICryptoSetPassword, 0x90) + +#define Z7_IFACEM_ICryptoSetCRC(x) \ + x(CryptoSetCRC(UInt32 crc)) +Z7_IFACE_CONSTR_CODER(ICryptoSetCRC, 0xA0) + + +namespace NMethodPropID +{ + enum EEnum + { + kID, + kName, + kDecoder, + kEncoder, + kPackStreams, + kUnpackStreams, + kDescription, + kDecoderIsAssigned, + kEncoderIsAssigned, + kDigestSize, + kIsFilter + }; +} + +namespace NModuleInterfaceType +{ + /* + virtual destructor in IUnknown: + - no : 7-Zip (Windows) + - no : 7-Zip (Linux) (v23) in default mode + - yes : p7zip + - yes : 7-Zip (Linux) before v23 + - yes : 7-Zip (Linux) (v23), if Z7_USE_VIRTUAL_DESTRUCTOR_IN_IUNKNOWN is defined + */ + const UInt32 k_IUnknown_VirtDestructor_No = 0; + const UInt32 k_IUnknown_VirtDestructor_Yes = 1; + const UInt32 k_IUnknown_VirtDestructor_ThisModule = + #if !defined(_WIN32) && defined(Z7_USE_VIRTUAL_DESTRUCTOR_IN_IUNKNOWN) + k_IUnknown_VirtDestructor_Yes; + #else + k_IUnknown_VirtDestructor_No; + #endif +} + +namespace NModulePropID +{ + enum EEnum + { + kInterfaceType, // VT_UI4 + kVersion // VT_UI4 + }; +} + + +#define Z7_IFACEM_IHasher(x) \ + x##2(void, Init()) \ + x##2(void, Update(const void *data, UInt32 size)) \ + x##2(void, Final(Byte *digest)) \ + x##2(UInt32, GetDigestSize()) +Z7_IFACE_CONSTR_CODER(IHasher, 0xC0) + +#define Z7_IFACEM_IHashers(x) \ + x##2(UInt32, GetNumHashers()) \ + x(GetHasherProp(UInt32 index, PROPID propID, PROPVARIANT *value)) \ + x(CreateHasher(UInt32 index, IHasher **hasher)) +Z7_IFACE_CONSTR_CODER(IHashers, 0xC1) + +extern "C" +{ + typedef HRESULT (WINAPI *Func_GetNumberOfMethods)(UInt32 *numMethods); + typedef HRESULT (WINAPI *Func_GetMethodProperty)(UInt32 index, PROPID propID, PROPVARIANT *value); + typedef HRESULT (WINAPI *Func_CreateDecoder)(UInt32 index, const GUID *iid, void **outObject); + typedef HRESULT (WINAPI *Func_CreateEncoder)(UInt32 index, const GUID *iid, void **outObject); + + typedef HRESULT (WINAPI *Func_GetHashers)(IHashers **hashers); + + typedef HRESULT (WINAPI *Func_SetCodecs)(ICompressCodecsInfo *compressCodecsInfo); + typedef HRESULT (WINAPI *Func_GetModuleProp)(PROPID propID, PROPVARIANT *value); +} + +Z7_PURE_INTERFACES_END +#endif diff --git a/libs/archive/thirdparty/CPP/7zip/IDecl.h b/libs/archive/thirdparty/CPP/7zip/IDecl.h new file mode 100644 index 0000000..4dbf1eb --- /dev/null +++ b/libs/archive/thirdparty/CPP/7zip/IDecl.h @@ -0,0 +1,76 @@ +// IDecl.h + +#ifndef ZIP7_INC_IDECL_H +#define ZIP7_INC_IDECL_H + +#include "../Common/Common0.h" +#include "../Common/MyUnknown.h" + +#define k_7zip_GUID_Data1 0x23170F69 +#define k_7zip_GUID_Data2 0x40C1 + +#define k_7zip_GUID_Data3_Common 0x278A + +#define k_7zip_GUID_Data3_Decoder 0x2790 +#define k_7zip_GUID_Data3_Encoder 0x2791 +#define k_7zip_GUID_Data3_Hasher 0x2792 + +#define Z7_DECL_IFACE_7ZIP_SUB(i, _base, groupId, subId) \ + Z7_DEFINE_GUID(IID_ ## i, \ + k_7zip_GUID_Data1, \ + k_7zip_GUID_Data2, \ + k_7zip_GUID_Data3_Common, \ + 0, 0, 0, (groupId), 0, (subId), 0, 0); \ + struct Z7_DECLSPEC_NOVTABLE i: public _base + +#define Z7_DECL_IFACE_7ZIP(i, groupId, subId) \ + Z7_DECL_IFACE_7ZIP_SUB(i, IUnknown, groupId, subId) + + +#ifdef COM_DECLSPEC_NOTHROW +#define Z7_COMWF_B COM_DECLSPEC_NOTHROW STDMETHODIMP +#define Z7_COMWF_B_(t) COM_DECLSPEC_NOTHROW STDMETHODIMP_(t) +#else +#define Z7_COMWF_B STDMETHODIMP +#define Z7_COMWF_B_(t) STDMETHODIMP_(t) +#endif + +#if defined(_MSC_VER) && !defined(COM_DECLSPEC_NOTHROW) +#define Z7_COM7F_B __declspec(nothrow) STDMETHODIMP +#define Z7_COM7F_B_(t) __declspec(nothrow) STDMETHODIMP_(t) +#else +#define Z7_COM7F_B Z7_COMWF_B +#define Z7_COM7F_B_(t) Z7_COMWF_B_(t) +#endif + +// #define Z7_COM7F_E Z7_noexcept +#define Z7_COM7F_E throw() +#define Z7_COM7F_EO Z7_COM7F_E Z7_override +#define Z7_COM7F_EOF Z7_COM7F_EO Z7_final +#define Z7_COM7F_IMF(f) Z7_COM7F_B f Z7_COM7F_E +#define Z7_COM7F_IMF2(t, f) Z7_COM7F_B_(t) f Z7_COM7F_E + +#define Z7_COM7F_PURE(f) virtual Z7_COM7F_IMF(f) =0; +#define Z7_COM7F_PURE2(t, f) virtual Z7_COM7F_IMF2(t, f) =0; +#define Z7_COM7F_IMP(f) Z7_COM7F_IMF(f) Z7_override Z7_final; +#define Z7_COM7F_IMP2(t, f) Z7_COM7F_IMF2(t, f) Z7_override Z7_final; +#define Z7_COM7F_IMP_NONFINAL(f) Z7_COM7F_IMF(f) Z7_override; +#define Z7_COM7F_IMP_NONFINAL2(t, f) Z7_COM7F_IMF2(t, f) Z7_override; + +#define Z7_IFACE_PURE(name) Z7_IFACEN_ ## name(=0;) +#define Z7_IFACE_IMP(name) Z7_IFACEN_ ## name(Z7_override Z7_final;) + +#define Z7_IFACE_COM7_PURE(name) Z7_IFACEM_ ## name(Z7_COM7F_PURE) +#define Z7_IFACE_COM7_IMP(name) Z7_IFACEM_ ## name(Z7_COM7F_IMP) +#define Z7_IFACE_COM7_IMP_NONFINAL(name) Z7_IFACEM_ ## name(Z7_COM7F_IMP_NONFINAL) + + +#define Z7_IFACE_DECL_PURE(name) \ + DECLARE_INTERFACE(name) \ + { Z7_IFACE_PURE(name) }; + +#define Z7_IFACE_DECL_PURE_(name, baseiface) \ + DECLARE_INTERFACE_(name, baseiface) \ + { Z7_IFACE_PURE(name) }; + +#endif diff --git a/libs/archive/thirdparty/CPP/7zip/IPassword.h b/libs/archive/thirdparty/CPP/7zip/IPassword.h new file mode 100644 index 0000000..689f08c --- /dev/null +++ b/libs/archive/thirdparty/CPP/7zip/IPassword.h @@ -0,0 +1,54 @@ +// IPassword.h + +#ifndef ZIP7_INC_IPASSWORD_H +#define ZIP7_INC_IPASSWORD_H + +#include "../Common/MyTypes.h" + +#include "IDecl.h" + +Z7_PURE_INTERFACES_BEGIN + +#define Z7_IFACE_CONSTR_PASSWORD(i, n) \ + Z7_DECL_IFACE_7ZIP(i, 5, n) \ + { Z7_IFACE_COM7_PURE(i) }; + +/* +How to use output parameter (BSTR *password): + +in: The caller is required to set BSTR value as NULL (no string). + The callee (in 7-Zip code) ignores the input value stored in BSTR variable, + +out: The callee rewrites BSTR variable (*password) with new allocated string pointer. + The caller must free BSTR string with function SysFreeString(); +*/ + +#define Z7_IFACEM_ICryptoGetTextPassword(x) \ + x(CryptoGetTextPassword(BSTR *password)) +Z7_IFACE_CONSTR_PASSWORD(ICryptoGetTextPassword, 0x10) + + +/* +CryptoGetTextPassword2() +in: + The caller is required to set BSTR value as NULL (no string). + The caller is not required to set (*passwordIsDefined) value. + +out: + Return code: != S_OK : error code + Return code: S_OK : success + + if (*passwordIsDefined == 1), the variable (*password) contains password string + + if (*passwordIsDefined == 0), the password is not defined, + but the callee still could set (*password) to some allocated string, for example, as empty string. + + The caller must free BSTR string with function SysFreeString() +*/ + +#define Z7_IFACEM_ICryptoGetTextPassword2(x) \ + x(CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)) +Z7_IFACE_CONSTR_PASSWORD(ICryptoGetTextPassword2, 0x11) + +Z7_PURE_INTERFACES_END +#endif diff --git a/libs/archive/thirdparty/CPP/7zip/IProgress.h b/libs/archive/thirdparty/CPP/7zip/IProgress.h new file mode 100644 index 0000000..6714983 --- /dev/null +++ b/libs/archive/thirdparty/CPP/7zip/IProgress.h @@ -0,0 +1,20 @@ +// IProgress.h + +#ifndef ZIP7_INC_IPROGRESS_H +#define ZIP7_INC_IPROGRESS_H + +#include "../Common/MyTypes.h" + +#include "IDecl.h" + +Z7_PURE_INTERFACES_BEGIN + +#define Z7_IFACEM_IProgress(x) \ + x(SetTotal(UInt64 total)) \ + x(SetCompleted(const UInt64 *completeValue)) \ + +Z7_DECL_IFACE_7ZIP(IProgress, 0, 5) + { Z7_IFACE_COM7_PURE(IProgress) }; + +Z7_PURE_INTERFACES_END +#endif diff --git a/libs/archive/thirdparty/CPP/7zip/IStream.h b/libs/archive/thirdparty/CPP/7zip/IStream.h new file mode 100644 index 0000000..0c44a91 --- /dev/null +++ b/libs/archive/thirdparty/CPP/7zip/IStream.h @@ -0,0 +1,210 @@ +// IStream.h + +#ifndef ZIP7_INC_ISTREAM_H +#define ZIP7_INC_ISTREAM_H + +#include "../Common/Common0.h" +#include "../Common/MyTypes.h" +#include "../Common/MyWindows.h" + +#include "IDecl.h" + +Z7_PURE_INTERFACES_BEGIN + +#define Z7_IFACE_CONSTR_STREAM_SUB(i, base, n) \ + Z7_DECL_IFACE_7ZIP_SUB(i, base, 3, n) \ + { Z7_IFACE_COM7_PURE(i) }; + +#define Z7_IFACE_CONSTR_STREAM(i, n) \ + Z7_IFACE_CONSTR_STREAM_SUB(i, IUnknown, n) + + +/* +ISequentialInStream::Read() + The requirement for caller: (processedSize != NULL). + The callee can allow (processedSize == NULL) for compatibility reasons. + + if (size == 0), this function returns S_OK and (*processedSize) is set to 0. + + if (size != 0) + { + Partial read is allowed: (*processedSize <= avail_size && *processedSize <= size), + where (avail_size) is the size of remaining bytes in stream. + If (avail_size != 0), this function must read at least 1 byte: (*processedSize > 0). + You must call Read() in loop, if you need to read exact amount of data. + } + + If seek pointer before Read() call was changed to position past the end of stream: + if (seek_pointer >= stream_size), this function returns S_OK and (*processedSize) is set to 0. + + ERROR CASES: + If the function returns error code, then (*processedSize) is size of + data written to (data) buffer (it can be data before error or data with errors). + The recommended way for callee to work with reading errors: + 1) write part of data before error to (data) buffer and return S_OK. + 2) return error code for further calls of Read(). +*/ +#define Z7_IFACEM_ISequentialInStream(x) \ + x(Read(void *data, UInt32 size, UInt32 *processedSize)) +Z7_IFACE_CONSTR_STREAM(ISequentialInStream, 0x01) + + +/* +ISequentialOutStream::Write() + The requirement for caller: (processedSize != NULL). + The callee can allow (processedSize == NULL) for compatibility reasons. + + if (size != 0) + { + Partial write is allowed: (*processedSize <= size), + but this function must write at least 1 byte: (*processedSize > 0). + You must call Write() in loop, if you need to write exact amount of data. + } + + ERROR CASES: + If the function returns error code, then (*processedSize) is size of + data written from (data) buffer. +*/ +#define Z7_IFACEM_ISequentialOutStream(x) \ + x(Write(const void *data, UInt32 size, UInt32 *processedSize)) +Z7_IFACE_CONSTR_STREAM(ISequentialOutStream, 0x02) + + +#ifdef _WIN32 + +#ifdef __HRESULT_FROM_WIN32 +#define HRESULT_WIN32_ERROR_NEGATIVE_SEEK __HRESULT_FROM_WIN32(ERROR_NEGATIVE_SEEK) +#else +#define HRESULT_WIN32_ERROR_NEGATIVE_SEEK HRESULT_FROM_WIN32(ERROR_NEGATIVE_SEEK) +#endif + +#else + +#define HRESULT_WIN32_ERROR_NEGATIVE_SEEK MY_E_ERROR_NEGATIVE_SEEK + +#endif + + +/* +IInStream::Seek() / IOutStream::Seek() + If you seek to position before the beginning of the stream, + Seek() function returns error code: + Recommended error code is __HRESULT_FROM_WIN32(ERROR_NEGATIVE_SEEK). + or STG_E_INVALIDFUNCTION + It is allowed to seek past the end of the stream. + if Seek() returns error, then the value of *newPosition is undefined. +*/ + +#define Z7_IFACEM_IInStream(x) \ + x(Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) +Z7_IFACE_CONSTR_STREAM_SUB(IInStream, ISequentialInStream, 0x03) + +#define Z7_IFACEM_IOutStream(x) \ + x(Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) \ + x(SetSize(UInt64 newSize)) +Z7_IFACE_CONSTR_STREAM_SUB(IOutStream, ISequentialOutStream, 0x04) + +#define Z7_IFACEM_IStreamGetSize(x) \ + x(GetSize(UInt64 *size)) +Z7_IFACE_CONSTR_STREAM(IStreamGetSize, 0x06) + +#define Z7_IFACEM_IOutStreamFinish(x) \ + x(OutStreamFinish()) +Z7_IFACE_CONSTR_STREAM(IOutStreamFinish, 0x07) + +#define Z7_IFACEM_IStreamGetProps(x) \ + x(GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib)) +Z7_IFACE_CONSTR_STREAM(IStreamGetProps, 0x08) + + +struct CStreamFileProps +{ + UInt64 Size; + UInt64 VolID; + UInt64 FileID_Low; + UInt64 FileID_High; + UInt32 NumLinks; + UInt32 Attrib; + FILETIME CTime; + FILETIME ATime; + FILETIME MTime; +}; + + +#define Z7_IFACEM_IStreamGetProps2(x) \ + x(GetProps2(CStreamFileProps *props)) +Z7_IFACE_CONSTR_STREAM(IStreamGetProps2, 0x09) + +#define Z7_IFACEM_IStreamGetProp(x) \ + x(GetProperty(PROPID propID, PROPVARIANT *value)) \ + x(ReloadProps()) +Z7_IFACE_CONSTR_STREAM(IStreamGetProp, 0x0a) + + +/* +IStreamSetRestriction::SetRestriction(UInt64 begin, UInt64 end) + + It sets region of data in output stream that is restricted. + For restricted region it's expected (or allowed) + that the caller can write to same region with different calls of Write()/SetSize(). + Another regions of output stream will be supposed as non-restricted: + - The callee usually doesn't flush the data in restricted region. + - The callee usually can flush data from non-restricted region after writing. + +Actual restiction rules depend also from current stream position. +It's recommended to call SetRestriction() just before the Write() call. +So the callee can optimize writing and flushing, if that Write() +operation is not restricted. + +Note: Each new call of SetRestriction() sets new restictions, +so previous restrction calls has no effect anymore. + +inputs: + + (begin > end) is not allowed, and returns E_FAIL; + + if (begin == end) + { + No restriction. + The caller will call Write() in sequential order. + After SetRestriction(begin, begin), but before next call of SetRestriction() + { + Additional condition: + it's expected that current stream seek position is equal to stream size. + The callee can make final flushing for any data before current stream seek position. + For each Write(size) call: + The callee can make final flushing for that new written data. + } + The pair of values (begin == 0 && end == 0) is recommended to remove write restriction. + } + + if (begin < end) + { + it means that callee must NOT flush any data in region [begin, end). + The caller is allowed to Seek() to that region and rewrite the + data in that restriction region. + if (end == (UInt64)(Int64)-1) + { + there is no upper bound for restricted region. + So non-restricted region will be [0, begin) in that case + } + } + + returns: + - if (begin > end) it return ERROR code (E_FAIL) + - S_OK : if no errors. + - Also the call of SetRestriction() can initiate the flushing of already written data. + So it can return the result of that flushing. + + Note: IOutStream::SetSize() also can change the data. + So it's not expected the call + IOutStream::SetSize() to region that was written before as unrestricted. +*/ + +#define Z7_IFACEM_IStreamSetRestriction(x) \ + x(SetRestriction(UInt64 begin, UInt64 end)) \ + +Z7_IFACE_CONSTR_STREAM(IStreamSetRestriction, 0x10) + +Z7_PURE_INTERFACES_END +#endif diff --git a/libs/archive/thirdparty/CPP/7zip/MyVersion.h b/libs/archive/thirdparty/CPP/7zip/MyVersion.h new file mode 100644 index 0000000..8f52a12 --- /dev/null +++ b/libs/archive/thirdparty/CPP/7zip/MyVersion.h @@ -0,0 +1,2 @@ +#define USE_COPYRIGHT_CR +#include "../../C/7zVersion.h" diff --git a/libs/archive/thirdparty/CPP/7zip/PropID.h b/libs/archive/thirdparty/CPP/7zip/PropID.h new file mode 100644 index 0000000..e074794 --- /dev/null +++ b/libs/archive/thirdparty/CPP/7zip/PropID.h @@ -0,0 +1,178 @@ +// PropID.h + +#ifndef ZIP7_INC_7ZIP_PROP_ID_H +#define ZIP7_INC_7ZIP_PROP_ID_H + +#include "../Common/MyTypes.h" + +enum +{ + kpidNoProperty = 0, + kpidMainSubfile, + kpidHandlerItemIndex, + kpidPath, + kpidName, + kpidExtension, + kpidIsDir, + kpidSize, + kpidPackSize, + kpidAttrib, + kpidCTime, + kpidATime, + kpidMTime, + kpidSolid, + kpidCommented, + kpidEncrypted, + kpidSplitBefore, + kpidSplitAfter, + kpidDictionarySize, + kpidCRC, + kpidType, + kpidIsAnti, + kpidMethod, + kpidHostOS, + kpidFileSystem, + kpidUser, + kpidGroup, + kpidBlock, + kpidComment, + kpidPosition, + kpidPrefix, + kpidNumSubDirs, + kpidNumSubFiles, + kpidUnpackVer, + kpidVolume, + kpidIsVolume, + kpidOffset, + kpidLinks, + kpidNumBlocks, + kpidNumVolumes, + kpidTimeType, + kpidBit64, + kpidBigEndian, + kpidCpu, + kpidPhySize, + kpidHeadersSize, + kpidChecksum, + kpidCharacts, + kpidVa, + kpidId, + kpidShortName, + kpidCreatorApp, + kpidSectorSize, + kpidPosixAttrib, + kpidSymLink, + kpidError, + kpidTotalSize, + kpidFreeSpace, + kpidClusterSize, + kpidVolumeName, + kpidLocalName, + kpidProvider, + kpidNtSecure, + kpidIsAltStream, + kpidIsAux, + kpidIsDeleted, + kpidIsTree, + kpidSha1, + kpidSha256, + kpidErrorType, + kpidNumErrors, + kpidErrorFlags, + kpidWarningFlags, + kpidWarning, + kpidNumStreams, + kpidNumAltStreams, + kpidAltStreamsSize, + kpidVirtualSize, + kpidUnpackSize, + kpidTotalPhySize, + kpidVolumeIndex, + kpidSubType, + kpidShortComment, + kpidCodePage, + kpidIsNotArcType, + kpidPhySizeCantBeDetected, + kpidZerosTailIsAllowed, + kpidTailSize, + kpidEmbeddedStubSize, + kpidNtReparse, + kpidHardLink, + kpidINode, + kpidStreamId, + kpidReadOnly, + kpidOutName, + kpidCopyLink, + kpidArcFileName, + kpidIsHash, + kpidChangeTime, + kpidUserId, + kpidGroupId, + kpidDeviceMajor, + kpidDeviceMinor, + kpidDevMajor, + kpidDevMinor, + + kpid_NUM_DEFINED, + + kpidUserDefined = 0x10000 +}; + +extern const Byte k7z_PROPID_To_VARTYPE[kpid_NUM_DEFINED]; // VARTYPE + +const UInt32 kpv_ErrorFlags_IsNotArc = 1 << 0; +const UInt32 kpv_ErrorFlags_HeadersError = 1 << 1; +const UInt32 kpv_ErrorFlags_EncryptedHeadersError = 1 << 2; +const UInt32 kpv_ErrorFlags_UnavailableStart = 1 << 3; +const UInt32 kpv_ErrorFlags_UnconfirmedStart = 1 << 4; +const UInt32 kpv_ErrorFlags_UnexpectedEnd = 1 << 5; +const UInt32 kpv_ErrorFlags_DataAfterEnd = 1 << 6; +const UInt32 kpv_ErrorFlags_UnsupportedMethod = 1 << 7; +const UInt32 kpv_ErrorFlags_UnsupportedFeature = 1 << 8; +const UInt32 kpv_ErrorFlags_DataError = 1 << 9; +const UInt32 kpv_ErrorFlags_CrcError = 1 << 10; +// const UInt32 kpv_ErrorFlags_Unsupported = 1 << 11; + +/* +linux ctime : + file metadata was last changed. + changing the file modification time + counts as a metadata change, so will also have the side effect of updating the ctime. + +PROPVARIANT for timestamps in 7-Zip: +{ + vt = VT_FILETIME + wReserved1: set precision level + 0 : base value (backward compatibility value) + only filetime is used (7 digits precision). + wReserved2 and wReserved3 can contain random data + 1 : Unix (1 sec) + 2 : DOS (2 sec) + 3 : High Precision (1 ns) + 16 - 3 : (reserved) = 1 day + 16 - 2 : (reserved) = 1 hour + 16 - 1 : (reserved) = 1 minute + 16 + 0 : 1 sec (0 digits after point) + 16 + (1,2,3,4,5,6,7,8,9) : set subsecond precision level : + (number of decimal digits after point) + 16 + 9 : 1 ns (9 digits after point) + wReserved2 = ns % 100 : if (8 or 9 digits pecision) + = 0 : if not (8 or 9 digits pecision) + wReserved3 = 0; + filetime +} + +NOTE: TAR-PAX archives created by GNU TAR don't keep + whole information about original level of precision, + and timestamp are stored in reduced form, where tail zero + digits after point are removed. + So 7-Zip can return different precision levels for different items for such TAR archives. +*/ + +/* +TimePrec returned by IOutArchive::GetFileTimeType() +is used only for updating, when we compare MTime timestamp +from archive with timestamp from directory. +*/ + +#endif diff --git a/libs/archive/thirdparty/CPP/Common/Common.h b/libs/archive/thirdparty/CPP/Common/Common.h new file mode 100644 index 0000000..cde0c38 --- /dev/null +++ b/libs/archive/thirdparty/CPP/Common/Common.h @@ -0,0 +1,28 @@ +// Common.h + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif + +#ifndef ZIP7_INC_COMMON_H +#define ZIP7_INC_COMMON_H + +#include "../../C/Precomp.h" +#include "Common0.h" +#include "MyWindows.h" + +/* +This file is included to all cpp files in 7-Zip. +Each folder contains StdAfx.h file that includes "Common.h". +So 7-Zip includes "Common.h" in both modes: + with precompiled StdAfx.h +and + without precompiled StdAfx.h + +include "Common.h" before other h files of 7-zip, + if you need predefined macros. +do not include "Common.h", if you need only interfaces, + and you don't need predefined macros. +*/ + +#endif diff --git a/libs/archive/thirdparty/CPP/Common/Common0.h b/libs/archive/thirdparty/CPP/Common/Common0.h new file mode 100644 index 0000000..55606cd --- /dev/null +++ b/libs/archive/thirdparty/CPP/Common/Common0.h @@ -0,0 +1,330 @@ +// Common0.h + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +#pragma warning(disable : 4464) // relative include path contains '..' +#endif + +#ifndef ZIP7_INC_COMMON0_H +#define ZIP7_INC_COMMON0_H + +#include "../../C/Compiler.h" + +/* +This file contains compiler related things for cpp files. +This file is included to all cpp files in 7-Zip via "Common.h". +Also this file is included in "IDecl.h" (that is included in interface files). +So external modules can use 7-Zip interfaces without +predefined macros defined in "Common.h". +*/ + +#ifdef _MSC_VER + #pragma warning(disable : 4710) // function not inlined + // 'CUncopyable::CUncopyable': + #pragma warning(disable : 4514) // unreferenced inline function has been removed + #if _MSC_VER < 1300 + #pragma warning(disable : 4702) // unreachable code + #pragma warning(disable : 4714) // function marked as __forceinline not inlined + #pragma warning(disable : 4786) // identifier was truncated to '255' characters in the debug information + #endif + #if _MSC_VER < 1400 + #pragma warning(disable : 4511) // copy constructor could not be generated // #pragma warning(disable : 4512) // assignment operator could not be generated + #pragma warning(disable : 4512) // assignment operator could not be generated + #endif + #if _MSC_VER > 1400 && _MSC_VER <= 1900 + // #pragma warning(disable : 4996) + // strcat: This function or variable may be unsafe + // GetVersion was declared deprecated + #endif + +#if _MSC_VER > 1200 +// -Wall warnings + +#if _MSC_VER <= 1600 +#pragma warning(disable : 4917) // 'OLE_HANDLE' : a GUID can only be associated with a class, interface or namespace +#endif + +// #pragma warning(disable : 4061) // enumerator '' in switch of enum '' is not explicitly handled by a case label +// #pragma warning(disable : 4266) // no override available for virtual member function from base ''; function is hidden +#pragma warning(disable : 4625) // copy constructor was implicitly defined as deleted +#pragma warning(disable : 4626) // assignment operator was implicitly defined as deleted +#if _MSC_VER >= 1600 && _MSC_VER < 1920 +#pragma warning(disable : 4571) // Informational: catch(...) semantics changed since Visual C++ 7.1; structured exceptions (SEH) are no longer caught +#endif +#if _MSC_VER >= 1600 +#pragma warning(disable : 4365) // 'initializing' : conversion from 'int' to 'unsigned int', signed / unsigned mismatch +#endif +#if _MSC_VER < 1800 +// we disable the warning, if we don't use 'final' in class +#pragma warning(disable : 4265) // class has virtual functions, but destructor is not virtual +#endif + +#if _MSC_VER >= 1900 +#pragma warning(disable : 5026) // move constructor was implicitly defined as deleted +#pragma warning(disable : 5027) // move assignment operator was implicitly defined as deleted +#endif +#if _MSC_VER >= 1912 +#pragma warning(disable : 5039) // pointer or reference to potentially throwing function passed to 'extern "C"' function under - EHc.Undefined behavior may occur if this function throws an exception. +#endif +#if _MSC_VER >= 1925 +// #pragma warning(disable : 5204) // 'ISequentialInStream' : class has virtual functions, but its trivial destructor is not virtual; instances of objects derived from this class may not be destructed correctly +#endif +#if _MSC_VER >= 1934 +// #pragma warning(disable : 5264) // const variable is not used +#endif + +#endif // _MSC_VER > 1200 +#endif // _MSC_VER + + +#if defined(_MSC_VER) // && !defined(__clang__) +#define Z7_DECLSPEC_NOTHROW __declspec(nothrow) +#elif defined(__clang__) || defined(__GNUC__) +#define Z7_DECLSPEC_NOTHROW __attribute__((nothrow)) +#else +#define Z7_DECLSPEC_NOTHROW +#endif + +/* +#if defined (_MSC_VER) && _MSC_VER >= 1900 \ + || defined(__clang__) && __clang_major__ >= 6 \ + || defined(__GNUC__) && __GNUC__ >= 6 + #define Z7_noexcept noexcept +#else + #define Z7_noexcept throw() +#endif +*/ + + +#if defined(__clang__) + +#if /* defined(_WIN32) && */ __clang_major__ >= 16 +#pragma GCC diagnostic ignored "-Wc++98-compat-pedantic" +#endif + +#if __clang_major__ >= 4 && __clang_major__ < 12 && !defined(_WIN32) +/* +if compiled with new GCC libstdc++, GCC libstdc++ can use: +13.2.0/include/c++/ + : #define _NEW + : #define _GLIBCXX_STDLIB_H 1 +*/ +#pragma GCC diagnostic ignored "-Wreserved-id-macro" +#endif + +// noexcept, final, = delete +#pragma GCC diagnostic ignored "-Wc++98-compat" +#if __clang_major__ >= 4 +// throw() dynamic exception specifications are deprecated +#pragma GCC diagnostic ignored "-Wdeprecated-dynamic-exception-spec" +#endif + +#if __clang_major__ <= 6 // check it +#pragma GCC diagnostic ignored "-Wsign-conversion" +#endif + +#pragma GCC diagnostic ignored "-Wold-style-cast" +#pragma GCC diagnostic ignored "-Wglobal-constructors" +#pragma GCC diagnostic ignored "-Wexit-time-destructors" + +#if defined(Z7_LLVM_CLANG_VERSION) && __clang_major__ >= 18 // 18.1.0RC +#pragma GCC diagnostic ignored "-Wswitch-default" +#endif +// #pragma GCC diagnostic ignored "-Wunused-private-field" +// #pragma GCC diagnostic ignored "-Wnonportable-system-include-path" +// #pragma GCC diagnostic ignored "-Wsuggest-override" +// #pragma GCC diagnostic ignored "-Wsign-conversion" +// #pragma GCC diagnostic ignored "-Winconsistent-missing-override" +// #pragma GCC diagnostic ignored "-Wsuggest-destructor-override" +// #pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +// #pragma GCC diagnostic ignored "-Wdeprecated-copy-with-user-provided-dtor" +// #pragma GCC diagnostic ignored "-Wdeprecated-copy-dtor" +// #ifndef _WIN32 +// #pragma GCC diagnostic ignored "-Wweak-vtables" +// #endif +/* +#if defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40400) \ + || defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30000) +// enumeration values not explicitly handled in switch +#pragma GCC diagnostic ignored "-Wswitch-enum" +#endif +*/ +#endif // __clang__ + + +#ifdef __GNUC__ +// #pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor" +#endif + + +/* There is BUG in MSVC 6.0 compiler for operator new[]: + It doesn't check overflow, when it calculates size in bytes for allocated array. + So we can use Z7_ARRAY_NEW macro instead of new[] operator. */ + +#if defined(_MSC_VER) && (_MSC_VER == 1200) && !defined(_WIN64) + #define Z7_ARRAY_NEW(p, T, size) p = new T[((size) > 0xFFFFFFFFu / sizeof(T)) ? 0xFFFFFFFFu / sizeof(T) : (size)]; +#else + #define Z7_ARRAY_NEW(p, T, size) p = new T[size]; +#endif + +#if (defined(__GNUC__) && (__GNUC__ >= 8)) + #define Z7_ATTR_NORETURN __attribute__((noreturn)) +#elif (defined(__clang__) && (__clang_major__ >= 3)) + #if __has_feature(cxx_attributes) + #define Z7_ATTR_NORETURN [[noreturn]] + #else + #define Z7_ATTR_NORETURN __attribute__((noreturn)) + #endif +#elif (defined(_MSC_VER) && (_MSC_VER >= 1900)) + #define Z7_ATTR_NORETURN [[noreturn]] +#else + #define Z7_ATTR_NORETURN +#endif + + +// final in "GCC 4.7.0" +// In C++98 and C++03 code the alternative spelling __final can be used instead (this is a GCC extension.) + +#if defined (__cplusplus) && __cplusplus >= 201103L \ + || defined(_MSC_VER) && _MSC_VER >= 1800 \ + || defined(__clang__) && __clang_major__ >= 4 \ + /* || defined(__GNUC__) && __GNUC__ >= 9 */ + #define Z7_final final + #if defined(__clang__) && __cplusplus < 201103L + #pragma GCC diagnostic ignored "-Wc++11-extensions" + #endif +#elif defined (__cplusplus) && __cplusplus >= 199711L \ + && defined(__GNUC__) && __GNUC__ >= 4 && !defined(__clang__) + #define Z7_final __final +#else + #define Z7_final + #if defined(__clang__) && __clang_major__ >= 4 \ + || defined(__GNUC__) && __GNUC__ >= 4 + #pragma GCC diagnostic ignored "-Wnon-virtual-dtor" + #pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor" + #endif +#endif + +#define Z7_class_final(c) class c Z7_final + + +#if defined (__cplusplus) && __cplusplus >= 201103L \ + || (defined(_MSC_VER) && _MSC_VER >= 1800) + #define Z7_CPP_IS_SUPPORTED_default + #define Z7_eq_delete = delete + // #define Z7_DECL_DEFAULT_COPY_CONSTRUCTOR_IF_SUPPORTED(c) c(const c& k) = default; +#else + #define Z7_eq_delete + // #define Z7_DECL_DEFAULT_COPY_CONSTRUCTOR_IF_SUPPORTED(c) +#endif + + +#if defined(__cplusplus) && (__cplusplus >= 201103L) \ + || defined(_MSC_VER) && (_MSC_VER >= 1400) /* && (_MSC_VER != 1600) */ \ + || defined(__clang__) && __clang_major__ >= 4 + #if defined(_MSC_VER) && (_MSC_VER == 1600) /* && (_MSC_VER != 1600) */ + #pragma warning(disable : 4481) // nonstandard extension used: override specifier 'override' + #define Z7_DESTRUCTOR_override + #else + #define Z7_DESTRUCTOR_override override + #endif + #define Z7_override override +#else + #define Z7_override + #define Z7_DESTRUCTOR_override +#endif + + + +#define Z7_CLASS_NO_COPY(cls) \ + private: \ + cls(const cls &) Z7_eq_delete; \ + cls &operator=(const cls &) Z7_eq_delete; + +class CUncopyable +{ +protected: + CUncopyable() {} // allow constructor + // ~CUncopyable() {} + Z7_CLASS_NO_COPY(CUncopyable) +}; + +#define MY_UNCOPYABLE :private CUncopyable +// #define MY_UNCOPYABLE + + +// typedef void (*Z7_void_Function)(void); + +#if defined(__clang__) || defined(__GNUC__) +#define Z7_CAST_FUNC(t, e) reinterpret_cast(reinterpret_cast(e)) +#else +#define Z7_CAST_FUNC(t, e) reinterpret_cast(reinterpret_cast(e)) +// #define Z7_CAST_FUNC(t, e) reinterpret_cast(e) +#endif + +#define Z7_GET_PROC_ADDRESS(func_type, hmodule, func_name) \ + Z7_CAST_FUNC(func_type, GetProcAddress(hmodule, func_name)) + +// || defined(__clang__) +// || defined(__GNUC__) + +#if defined(_MSC_VER) && (_MSC_VER >= 1400) +#define Z7_DECLSPEC_NOVTABLE __declspec(novtable) +#else +#define Z7_DECLSPEC_NOVTABLE +#endif + +#ifdef __clang__ +#define Z7_PURE_INTERFACES_BEGIN \ +_Pragma("GCC diagnostic push") \ +_Pragma("GCC diagnostic ignored \"-Wnon-virtual-dtor\"") +_Pragma("GCC diagnostic ignored \"-Wweak-vtables\"") +#define Z7_PURE_INTERFACES_END \ +_Pragma("GCC diagnostic pop") +#else +#define Z7_PURE_INTERFACES_BEGIN +#define Z7_PURE_INTERFACES_END +#endif + +// NewHandler.h and NewHandler.cpp redefine operator new() to throw exceptions, if compiled with old MSVC compilers +#include "NewHandler.h" + +/* +// #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(a) Z7_ARRAY_SIZE(a) +#endif +*/ + +#endif // ZIP7_INC_COMMON0_H + + + +// #define Z7_REDEFINE_NULL + +#if defined(Z7_REDEFINE_NULL) /* && (!defined(__clang__) || defined(_MSC_VER)) */ + +// NULL is defined in +#include +#undef NULL + +#ifdef __cplusplus + #if defined (__cplusplus) && __cplusplus >= 201103L \ + || (defined(_MSC_VER) && _MSC_VER >= 1800) + #define NULL nullptr + #else + #define NULL 0 + #endif +#else + #define NULL ((void *)0) +#endif + +#else // Z7_REDEFINE_NULL + +#if defined(__clang__) && __clang_major__ >= 5 +#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" +#endif + +#endif // Z7_REDEFINE_NULL + +// for precompiler: +// #include "MyWindows.h" diff --git a/libs/archive/thirdparty/CPP/Common/MyGuidDef.h b/libs/archive/thirdparty/CPP/Common/MyGuidDef.h new file mode 100644 index 0000000..3aa5266 --- /dev/null +++ b/libs/archive/thirdparty/CPP/Common/MyGuidDef.h @@ -0,0 +1,63 @@ +// Common/MyGuidDef.h + +// #pragma message "Common/MyGuidDef.h" + +#ifndef GUID_DEFINED +#define GUID_DEFINED + +// #pragma message "GUID_DEFINED" + +#include "MyTypes.h" + +typedef struct { + UInt32 Data1; + UInt16 Data2; + UInt16 Data3; + Byte Data4[8]; +} GUID; + +#ifdef __cplusplus +#define REFGUID const GUID & +#else +#define REFGUID const GUID * +#endif + +// typedef GUID IID; +typedef GUID CLSID; + +#define REFCLSID REFGUID +#define REFIID REFGUID + +#ifdef __cplusplus +inline int operator==(REFGUID g1, REFGUID g2) +{ + for (unsigned i = 0; i < sizeof(g1); i++) + if (((const Byte *)&g1)[i] != ((const Byte *)&g2)[i]) + return 0; + return 1; +} +inline int operator!=(REFGUID g1, REFGUID g2) { return !(g1 == g2); } +#endif + +#endif // GUID_DEFINED + +#ifndef EXTERN_C +#ifdef __cplusplus + #define EXTERN_C extern "C" +#else + #define EXTERN_C extern +#endif +#endif + +#ifdef DEFINE_GUID +#undef DEFINE_GUID +#endif + +#ifdef INITGUID + #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + EXTERN_C const GUID name; \ + EXTERN_C const GUID name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } +#else + #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + EXTERN_C const GUID name +#endif diff --git a/libs/archive/thirdparty/CPP/Common/MyTypes.h b/libs/archive/thirdparty/CPP/Common/MyTypes.h new file mode 100644 index 0000000..eadc9a4 --- /dev/null +++ b/libs/archive/thirdparty/CPP/Common/MyTypes.h @@ -0,0 +1,38 @@ +// Common/MyTypes.h + +#ifndef ZIP7_INC_COMMON_MY_TYPES_H +#define ZIP7_INC_COMMON_MY_TYPES_H + +#include "Common0.h" +#include "../../C/7zTypes.h" + +// typedef int HRes; +// typedef HRESULT HRes; + +struct CBoolPair +{ + bool Val; + bool Def; + + CBoolPair(): Val(false), Def(false) {} + + void Init() + { + Val = false; + Def = false; + } + + void SetTrueTrue() + { + Val = true; + Def = true; + } + + void SetVal_as_Defined(bool val) + { + Val = val; + Def = true; + } +}; + +#endif diff --git a/libs/archive/thirdparty/CPP/Common/MyUnknown.h b/libs/archive/thirdparty/CPP/Common/MyUnknown.h new file mode 100644 index 0000000..75ee96f --- /dev/null +++ b/libs/archive/thirdparty/CPP/Common/MyUnknown.h @@ -0,0 +1,8 @@ +// MyUnknown.h + +#ifndef ZIP7_INC_MY_UNKNOWN_H +#define ZIP7_INC_MY_UNKNOWN_H + +#include "MyWindows.h" + +#endif diff --git a/libs/archive/thirdparty/CPP/Common/MyWindows.cpp b/libs/archive/thirdparty/CPP/Common/MyWindows.cpp new file mode 100644 index 0000000..a1dfbef --- /dev/null +++ b/libs/archive/thirdparty/CPP/Common/MyWindows.cpp @@ -0,0 +1,292 @@ +// MyWindows.cpp + +#include "StdAfx.h" + +#ifndef _WIN32 + +#include +#include +#ifdef __GNUC__ +#include +#endif + +#include "MyWindows.h" + +static inline void *AllocateForBSTR(size_t cb) { return ::malloc(cb); } +static inline void FreeForBSTR(void *pv) { ::free(pv);} + +/* Win32 uses DWORD (32-bit) type to store size of string before (OLECHAR *) string. + We must select CBstrSizeType for another systems (not Win32): + + if (CBstrSizeType is UINT32), + then we support only strings smaller than 4 GB. + Win32 version always has that limitation. + + if (CBstrSizeType is UINT), + (UINT can be 16/32/64-bit) + We can support strings larger than 4 GB (if UINT is 64-bit), + but sizeof(UINT) can be different in parts compiled by + different compilers/settings, + and we can't send such BSTR strings between such parts. +*/ + +typedef UINT32 CBstrSizeType; +// typedef UINT CBstrSizeType; + +#define k_BstrSize_Max 0xFFFFFFFF +// #define k_BstrSize_Max UINT_MAX +// #define k_BstrSize_Max ((UINT)(INT)-1) + +BSTR SysAllocStringByteLen(LPCSTR s, UINT len) +{ + /* Original SysAllocStringByteLen in Win32 maybe fills only unaligned null OLECHAR at the end. + We provide also aligned null OLECHAR at the end. */ + + if (len >= (k_BstrSize_Max - (UINT)sizeof(OLECHAR) - (UINT)sizeof(OLECHAR) - (UINT)sizeof(CBstrSizeType))) + return NULL; + + UINT size = (len + (UINT)sizeof(OLECHAR) + (UINT)sizeof(OLECHAR) - 1) & ~((UINT)sizeof(OLECHAR) - 1); + void *p = AllocateForBSTR(size + (UINT)sizeof(CBstrSizeType)); + if (!p) + return NULL; + *(CBstrSizeType *)p = (CBstrSizeType)len; + BSTR bstr = (BSTR)((CBstrSizeType *)p + 1); + if (s) + memcpy(bstr, s, len); + for (; len < size; len++) + ((Byte *)bstr)[len] = 0; + return bstr; +} + +BSTR SysAllocStringLen(const OLECHAR *s, UINT len) +{ + if (len >= (k_BstrSize_Max - (UINT)sizeof(OLECHAR) - (UINT)sizeof(CBstrSizeType)) / (UINT)sizeof(OLECHAR)) + return NULL; + + UINT size = len * (UINT)sizeof(OLECHAR); + void *p = AllocateForBSTR(size + (UINT)sizeof(CBstrSizeType) + (UINT)sizeof(OLECHAR)); + if (!p) + return NULL; + *(CBstrSizeType *)p = (CBstrSizeType)size; + BSTR bstr = (BSTR)((CBstrSizeType *)p + 1); + if (s) + memcpy(bstr, s, size); + bstr[len] = 0; + return bstr; +} + +BSTR SysAllocString(const OLECHAR *s) +{ + if (!s) + return NULL; + const OLECHAR *s2 = s; + while (*s2 != 0) + s2++; + return SysAllocStringLen(s, (UINT)(s2 - s)); +} + +void SysFreeString(BSTR bstr) +{ + if (bstr) + FreeForBSTR((CBstrSizeType *)(void *)bstr - 1); +} + +UINT SysStringByteLen(BSTR bstr) +{ + if (!bstr) + return 0; + return *((CBstrSizeType *)(void *)bstr - 1); +} + +UINT SysStringLen(BSTR bstr) +{ + if (!bstr) + return 0; + return *((CBstrSizeType *)(void *)bstr - 1) / (UINT)sizeof(OLECHAR); +} + + +HRESULT VariantClear(VARIANTARG *prop) +{ + if (prop->vt == VT_BSTR) + SysFreeString(prop->bstrVal); + prop->vt = VT_EMPTY; + return S_OK; +} + +HRESULT VariantCopy(VARIANTARG *dest, const VARIANTARG *src) +{ + HRESULT res = ::VariantClear(dest); + if (res != S_OK) + return res; + if (src->vt == VT_BSTR) + { + dest->bstrVal = SysAllocStringByteLen((LPCSTR)src->bstrVal, + SysStringByteLen(src->bstrVal)); + if (!dest->bstrVal) + return E_OUTOFMEMORY; + dest->vt = VT_BSTR; + } + else + *dest = *src; + return S_OK; +} + +LONG CompareFileTime(const FILETIME* ft1, const FILETIME* ft2) +{ + if (ft1->dwHighDateTime < ft2->dwHighDateTime) return -1; + if (ft1->dwHighDateTime > ft2->dwHighDateTime) return 1; + if (ft1->dwLowDateTime < ft2->dwLowDateTime) return -1; + if (ft1->dwLowDateTime > ft2->dwLowDateTime) return 1; + return 0; +} + +DWORD GetLastError() +{ + return (DWORD)errno; +} + +void SetLastError(DWORD dw) +{ + errno = (int)dw; +} + + +static LONG TIME_GetBias() +{ + time_t utc = time(NULL); + struct tm *ptm = localtime(&utc); + int localdaylight = ptm->tm_isdst; /* daylight for local timezone */ + ptm = gmtime(&utc); + ptm->tm_isdst = localdaylight; /* use local daylight, not that of Greenwich */ + LONG bias = (int)(mktime(ptm)-utc); + return bias; +} + +#define TICKS_PER_SEC 10000000 +/* +#define SECS_PER_DAY (24 * 60 * 60) +#define SECS_1601_TO_1970 ((369 * 365 + 89) * (UInt64)SECS_PER_DAY) +#define TICKS_1601_TO_1970 (SECS_1601_TO_1970 * TICKS_PER_SEC) +*/ + +#define GET_TIME_64(pft) ((pft)->dwLowDateTime | ((UInt64)(pft)->dwHighDateTime << 32)) + +#define SET_FILETIME(ft, v64) \ + (ft)->dwLowDateTime = (DWORD)v64; \ + (ft)->dwHighDateTime = (DWORD)(v64 >> 32); + + +BOOL WINAPI FileTimeToLocalFileTime(const FILETIME *fileTime, FILETIME *localFileTime) +{ + UInt64 v = GET_TIME_64(fileTime); + v = (UInt64)((Int64)v - (Int64)TIME_GetBias() * TICKS_PER_SEC); + SET_FILETIME(localFileTime, v) + return TRUE; +} + +BOOL WINAPI LocalFileTimeToFileTime(const FILETIME *localFileTime, FILETIME *fileTime) +{ + UInt64 v = GET_TIME_64(localFileTime); + v = (UInt64)((Int64)v + (Int64)TIME_GetBias() * TICKS_PER_SEC); + SET_FILETIME(fileTime, v) + return TRUE; +} + +/* +VOID WINAPI GetSystemTimeAsFileTime(FILETIME *ft) +{ + UInt64 t = 0; + timeval tv; + if (gettimeofday(&tv, NULL) == 0) + { + t = tv.tv_sec * (UInt64)TICKS_PER_SEC + TICKS_1601_TO_1970; + t += tv.tv_usec * 10; + } + SET_FILETIME(ft, t) +} +*/ + +DWORD WINAPI GetTickCount(VOID) +{ + #ifndef _WIN32 + // gettimeofday() doesn't work in some MINGWs by unknown reason + timeval tv; + if (gettimeofday(&tv, NULL) == 0) + { + // tv_sec and tv_usec are (long) + return (DWORD)((UInt64)(Int64)tv.tv_sec * (UInt64)1000 + (UInt64)(Int64)tv.tv_usec / 1000); + } + #endif + return (DWORD)time(NULL) * 1000; +} + + +#define PERIOD_4 (4 * 365 + 1) +#define PERIOD_100 (PERIOD_4 * 25 - 1) +#define PERIOD_400 (PERIOD_100 * 4 + 1) + +BOOL WINAPI FileTimeToSystemTime(const FILETIME *ft, SYSTEMTIME *st) +{ + UInt32 v; + UInt64 v64 = GET_TIME_64(ft); + v64 /= 10000; + st->wMilliseconds = (WORD)(v64 % 1000); v64 /= 1000; + st->wSecond = (WORD)(v64 % 60); v64 /= 60; + st->wMinute = (WORD)(v64 % 60); v64 /= 60; + v = (UInt32)v64; + st->wHour = (WORD)(v % 24); v /= 24; + + // 1601-01-01 was Monday + st->wDayOfWeek = (WORD)((v + 1) % 7); + + UInt32 leaps, year, day, mon; + leaps = (3 * ((4 * v + (365 - 31 - 28) * 4 + 3) / PERIOD_400) + 3) / 4; + v += 28188 + leaps; + // leaps - the number of exceptions from PERIOD_4 rules starting from 1600-03-01 + // (1959 / 64) - converts day from 03-01 to month + year = (20 * v - 2442) / (5 * PERIOD_4); + day = v - (year * PERIOD_4) / 4; + mon = (64 * day) / 1959; + st->wDay = (WORD)(day - (1959 * mon) / 64); + mon -= 1; + year += 1524; + if (mon > 12) + { + mon -= 12; + year++; + } + st->wMonth = (WORD)mon; + st->wYear = (WORD)year; + + /* + unsigned year, mon; + unsigned char ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + unsigned t; + + year = (WORD)(1601 + v / PERIOD_400 * 400); + v %= PERIOD_400; + + t = v / PERIOD_100; if (t == 4) t = 3; year += t * 100; v -= t * PERIOD_100; + t = v / PERIOD_4; if (t == 25) t = 24; year += t * 4; v -= t * PERIOD_4; + t = v / 365; if (t == 4) t = 3; year += t; v -= t * 365; + + st->wYear = (WORD)year; + + if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) + ms[1] = 29; + for (mon = 0;; mon++) + { + unsigned d = ms[mon]; + if (v < d) + break; + v -= d; + } + st->wDay = (WORD)(v + 1); + st->wMonth = (WORD)(mon + 1); + */ + + return TRUE; +} + +#endif diff --git a/libs/archive/thirdparty/CPP/Common/MyWindows.h b/libs/archive/thirdparty/CPP/Common/MyWindows.h new file mode 100644 index 0000000..da5370b --- /dev/null +++ b/libs/archive/thirdparty/CPP/Common/MyWindows.h @@ -0,0 +1,325 @@ +// MyWindows.h + +#ifdef Z7_DEFINE_GUID +#undef Z7_DEFINE_GUID +#endif + +#ifdef INITGUID + #define Z7_DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + EXTERN_C const GUID name; \ + EXTERN_C const GUID name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } +#else + #define Z7_DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ + EXTERN_C const GUID name +#endif + + +#ifndef ZIP7_INC_MY_WINDOWS_H +#define ZIP7_INC_MY_WINDOWS_H + +#ifdef _WIN32 + +#include "../../C/7zWindows.h" + +#else // _WIN32 + +#include // for wchar_t +#include +// #include // for uintptr_t + +#include "../../C/7zTypes.h" +#include "MyGuidDef.h" + +// WINAPI is __stdcall in Windows-MSVC in windef.h +#define WINAPI + +typedef char CHAR; +typedef unsigned char UCHAR; + +#undef BYTE +typedef unsigned char BYTE; + +typedef short SHORT; +typedef unsigned short USHORT; + +#undef WORD +typedef unsigned short WORD; +typedef short VARIANT_BOOL; + +#define LOWORD(l) ((WORD)((DWORD_PTR)(l) & 0xffff)) +#define HIWORD(l) ((WORD)((DWORD_PTR)(l) >> 16)) + +// MS uses long for BOOL, but long is 32-bit in MS. So we use int. +// typedef long BOOL; +typedef int BOOL; + +#ifndef FALSE + #define FALSE 0 + #define TRUE 1 +#endif + +// typedef size_t ULONG_PTR; +// typedef size_t DWORD_PTR; +// typedef uintptr_t UINT_PTR; +// typedef ptrdiff_t UINT_PTR; + +typedef Int64 LONGLONG; +typedef UInt64 ULONGLONG; + +typedef struct { LONGLONG QuadPart; } LARGE_INTEGER; +typedef struct { ULONGLONG QuadPart; } ULARGE_INTEGER; + +typedef const CHAR *LPCSTR; +typedef CHAR TCHAR; +typedef const TCHAR *LPCTSTR; +typedef wchar_t WCHAR; +typedef WCHAR OLECHAR; +typedef const WCHAR *LPCWSTR; +typedef OLECHAR *BSTR; +typedef const OLECHAR *LPCOLESTR; +typedef OLECHAR *LPOLESTR; + +typedef struct +{ + DWORD dwLowDateTime; + DWORD dwHighDateTime; +} FILETIME; + +#define SUCCEEDED(hr) ((HRESULT)(hr) >= 0) +#define FAILED(hr) ((HRESULT)(hr) < 0) +typedef ULONG PROPID; +typedef LONG SCODE; + + +#define S_OK ((HRESULT)0x00000000L) +#define S_FALSE ((HRESULT)0x00000001L) +#define E_NOTIMPL ((HRESULT)0x80004001L) +#define E_NOINTERFACE ((HRESULT)0x80004002L) +#define E_ABORT ((HRESULT)0x80004004L) +#define E_FAIL ((HRESULT)0x80004005L) +#define STG_E_INVALIDFUNCTION ((HRESULT)0x80030001L) +#define CLASS_E_CLASSNOTAVAILABLE ((HRESULT)0x80040111L) + + +#ifdef _MSC_VER +#define STDMETHODCALLTYPE __stdcall +#define STDAPICALLTYPE __stdcall +#else +// do we need __export here? +#define STDMETHODCALLTYPE +#define STDAPICALLTYPE +#endif + +#define STDAPI EXTERN_C HRESULT STDAPICALLTYPE + +#ifndef DECLSPEC_NOTHROW +#define DECLSPEC_NOTHROW Z7_DECLSPEC_NOTHROW +#endif + +#ifndef DECLSPEC_NOVTABLE +#define DECLSPEC_NOVTABLE Z7_DECLSPEC_NOVTABLE +#endif + +#ifndef COM_DECLSPEC_NOTHROW +#ifdef COM_STDMETHOD_CAN_THROW + #define COM_DECLSPEC_NOTHROW +#else + #define COM_DECLSPEC_NOTHROW DECLSPEC_NOTHROW +#endif +#endif + +#define DECLARE_INTERFACE(iface) struct DECLSPEC_NOVTABLE iface +#define DECLARE_INTERFACE_(iface, baseiface) struct DECLSPEC_NOVTABLE iface : public baseiface + +#define STDMETHOD_(t, f) virtual COM_DECLSPEC_NOTHROW t STDMETHODCALLTYPE f +#define STDMETHOD(f) STDMETHOD_(HRESULT, f) +#define STDMETHODIMP_(t) COM_DECLSPEC_NOTHROW t STDMETHODCALLTYPE +#define STDMETHODIMP STDMETHODIMP_(HRESULT) + + +#define PURE = 0 + +// #define MIDL_INTERFACE(x) struct + + +#ifdef __cplusplus + +/* + p7zip and 7-Zip before v23 used virtual destructor in IUnknown, + if _WIN32 is not defined. + It used virtual destructor, because some compilers don't like virtual + interfaces without virtual destructor. + IUnknown in Windows (_WIN32) doesn't use virtual destructor in IUnknown. + We still can define Z7_USE_VIRTUAL_DESTRUCTOR_IN_IUNKNOWN here, + if we want to be compatible with old plugin interface of p7zip and 7-Zip before v23. + +v23: + In new 7-Zip v23 we try to be more compatible with original IUnknown from _WIN32. + So we do not define Z7_USE_VIRTUAL_DESTRUCTOR_IN_IUNKNOWN here, +*/ +// #define Z7_USE_VIRTUAL_DESTRUCTOR_IN_IUNKNOWN + +#ifdef Z7_USE_VIRTUAL_DESTRUCTOR_IN_IUNKNOWN +#if defined(__clang__) +#pragma GCC diagnostic ignored "-Winconsistent-missing-destructor-override" +#endif +#endif + +Z7_PURE_INTERFACES_BEGIN + +DEFINE_GUID(IID_IUnknown, +0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46); +struct IUnknown +{ + STDMETHOD(QueryInterface) (REFIID iid, void **outObject) =0; + STDMETHOD_(ULONG, AddRef)() =0; + STDMETHOD_(ULONG, Release)() =0; + #ifdef Z7_USE_VIRTUAL_DESTRUCTOR_IN_IUNKNOWN + virtual ~IUnknown() {} + #endif +}; + +typedef IUnknown *LPUNKNOWN; + +Z7_PURE_INTERFACES_END + +#endif // __cplusplus + +#define VARIANT_TRUE ((VARIANT_BOOL)-1) +#define VARIANT_FALSE ((VARIANT_BOOL)0) + +enum VARENUM +{ + VT_EMPTY = 0, + VT_NULL = 1, + VT_I2 = 2, + VT_I4 = 3, + VT_R4 = 4, + VT_R8 = 5, + VT_CY = 6, + VT_DATE = 7, + VT_BSTR = 8, + VT_DISPATCH = 9, + VT_ERROR = 10, + VT_BOOL = 11, + VT_VARIANT = 12, + VT_UNKNOWN = 13, + VT_DECIMAL = 14, + + VT_I1 = 16, + VT_UI1 = 17, + VT_UI2 = 18, + VT_UI4 = 19, + VT_I8 = 20, + VT_UI8 = 21, + VT_INT = 22, + VT_UINT = 23, + VT_VOID = 24, + VT_HRESULT = 25, + VT_FILETIME = 64 +}; + +typedef unsigned short VARTYPE; +typedef WORD PROPVAR_PAD1; +typedef WORD PROPVAR_PAD2; +typedef WORD PROPVAR_PAD3; + +typedef struct tagPROPVARIANT +{ + VARTYPE vt; + PROPVAR_PAD1 wReserved1; + PROPVAR_PAD2 wReserved2; + PROPVAR_PAD3 wReserved3; + union + { + CHAR cVal; + UCHAR bVal; + SHORT iVal; + USHORT uiVal; + LONG lVal; + ULONG ulVal; + INT intVal; + UINT uintVal; + LARGE_INTEGER hVal; + ULARGE_INTEGER uhVal; + VARIANT_BOOL boolVal; + SCODE scode; + FILETIME filetime; + BSTR bstrVal; + }; +} PROPVARIANT; + +typedef PROPVARIANT tagVARIANT; +typedef tagVARIANT VARIANT; +typedef VARIANT VARIANTARG; + +EXTERN_C HRESULT VariantClear(VARIANTARG *prop); +EXTERN_C HRESULT VariantCopy(VARIANTARG *dest, const VARIANTARG *src); + +typedef struct tagSTATPROPSTG +{ + LPOLESTR lpwstrName; + PROPID propid; + VARTYPE vt; +} STATPROPSTG; + +EXTERN_C BSTR SysAllocStringByteLen(LPCSTR psz, UINT len); +EXTERN_C BSTR SysAllocStringLen(const OLECHAR *sz, UINT len); +EXTERN_C BSTR SysAllocString(const OLECHAR *sz); +EXTERN_C void SysFreeString(BSTR bstr); +EXTERN_C UINT SysStringByteLen(BSTR bstr); +EXTERN_C UINT SysStringLen(BSTR bstr); + +EXTERN_C DWORD GetLastError(); +EXTERN_C void SetLastError(DWORD dwCode); +EXTERN_C LONG CompareFileTime(const FILETIME* ft1, const FILETIME* ft2); + +EXTERN_C DWORD GetCurrentThreadId(); +EXTERN_C DWORD GetCurrentProcessId(); + +#define MAX_PATH 1024 + +#define CP_ACP 0 +#define CP_OEMCP 1 +#define CP_UTF8 65001 + +typedef enum tagSTREAM_SEEK +{ + STREAM_SEEK_SET = 0, + STREAM_SEEK_CUR = 1, + STREAM_SEEK_END = 2 +} STREAM_SEEK; + + + +typedef struct +{ + WORD wYear; + WORD wMonth; + WORD wDayOfWeek; + WORD wDay; + WORD wHour; + WORD wMinute; + WORD wSecond; + WORD wMilliseconds; +} SYSTEMTIME; + +BOOL WINAPI FileTimeToLocalFileTime(const FILETIME *fileTime, FILETIME *localFileTime); +BOOL WINAPI LocalFileTimeToFileTime(const FILETIME *localFileTime, FILETIME *fileTime); +BOOL WINAPI FileTimeToSystemTime(const FILETIME *fileTime, SYSTEMTIME *systemTime); +// VOID WINAPI GetSystemTimeAsFileTime(FILETIME *systemTimeAsFileTime); + +DWORD GetTickCount(); + + +/* +#define CREATE_NEW 1 +#define CREATE_ALWAYS 2 +#define OPEN_EXISTING 3 +#define OPEN_ALWAYS 4 +#define TRUNCATE_EXISTING 5 +*/ + +#endif // _WIN32 + +#endif diff --git a/libs/archive/thirdparty/CPP/Common/NewHandler.h b/libs/archive/thirdparty/CPP/Common/NewHandler.h new file mode 100644 index 0000000..5ba64b7 --- /dev/null +++ b/libs/archive/thirdparty/CPP/Common/NewHandler.h @@ -0,0 +1,121 @@ +// Common/NewHandler.h + +#ifndef ZIP7_INC_COMMON_NEW_HANDLER_H +#define ZIP7_INC_COMMON_NEW_HANDLER_H + +/* +NewHandler.h and NewHandler.cpp allows to solve problem with compilers that +don't throw exception in operator new(). + +This file must be included before any code that uses operators new() or delete() +and you must compile and link "NewHandler.cpp", if you use some old MSVC compiler. + +DOCs: + Since ISO C++98, operator new throws std::bad_alloc when memory allocation fails. + MSVC 6.0 returned a null pointer on an allocation failure. + Beginning in VS2002, operator new conforms to the standard and throws on failure. + + By default, the compiler also generates defensive null checks to prevent + these older-style allocators from causing an immediate crash on failure. + The /Zc:throwingNew option tells the compiler to leave out these null checks, + on the assumption that all linked memory allocators conform to the standard. + +The operator new() in some MSVC versions doesn't throw exception std::bad_alloc. +MSVC 6.0 (_MSC_VER == 1200) doesn't throw exception. +The code produced by some another MSVC compilers also can be linked +to library that doesn't throw exception. +We suppose that code compiled with VS2015+ (_MSC_VER >= 1900) throws exception std::bad_alloc. +For older _MSC_VER versions we redefine operator new() and operator delete(). +Our version of operator new() throws CNewException() exception on failure. + +It's still allowed to use redefined version of operator new() from "NewHandler.cpp" +with any compiler. 7-Zip's code can work with std::bad_alloc and CNewException() exceptions. +But if you use some additional code (outside of 7-Zip's code), you must check +that redefined version of operator new() is not problem for your code. +*/ + +#include + +#ifdef _WIN32 +// We can compile my_new and my_delete with _fastcall +/* +void * my_new(size_t size); +void my_delete(void *p) throw(); +// void * my_Realloc(void *p, size_t newSize, size_t oldSize); +*/ +#endif + + +#if defined(_MSC_VER) && (_MSC_VER < 1600) + // If you want to use default operator new(), you can disable the following line + #define Z7_REDEFINE_OPERATOR_NEW +#endif + + +#ifdef Z7_REDEFINE_OPERATOR_NEW + +// std::bad_alloc can require additional DLL dependency. +// So we don't define CNewException as std::bad_alloc here. + +class CNewException {}; + +void * +#ifdef _MSC_VER +__cdecl +#endif +operator new(size_t size); + +/* +#if 0 && defined(_MSC_VER) && _MSC_VER == 1600 + #define Z7_OPERATOR_DELETE_SPEC_THROW0 +#else + #define Z7_OPERATOR_DELETE_SPEC_THROW0 throw() +#endif +*/ +#if defined(_MSC_VER) && _MSC_VER == 1600 +#pragma warning(push) +#pragma warning(disable : 4986) // 'operator delete': exception specification does not match previous declaration +#endif + +void +#ifdef _MSC_VER +__cdecl +#endif +operator delete(void *p) throw(); + +void +#ifdef _MSC_VER +__cdecl +#endif +operator delete(void *p, size_t n) throw(); + +#if defined(_MSC_VER) && _MSC_VER == 1600 +#pragma warning(pop) +#endif + + +#else + +#include + +#define CNewException std::bad_alloc + +#endif + +/* +#ifdef _WIN32 +void * +#ifdef _MSC_VER +__cdecl +#endif +operator new[](size_t size); + +void +#ifdef _MSC_VER +__cdecl +#endif +operator delete[](void *p) throw(); +#endif +*/ + +#endif diff --git a/libs/archive/thirdparty/CPP/Common/StdAfx.h b/libs/archive/thirdparty/CPP/Common/StdAfx.h new file mode 100644 index 0000000..a5228b0 --- /dev/null +++ b/libs/archive/thirdparty/CPP/Common/StdAfx.h @@ -0,0 +1,8 @@ +// StdAfx.h + +#ifndef ZIP7_INC_STDAFX_H +#define ZIP7_INC_STDAFX_H + +#include "Common.h" + +#endif diff --git a/libs/archive/vcpkg.json b/libs/archive/vcpkg.json new file mode 100644 index 0000000..5367449 --- /dev/null +++ b/libs/archive/vcpkg.json @@ -0,0 +1,10 @@ +{ + "dependencies": ["7zip"], + "vcpkg-configuration": { + "default-registry": { + "kind": "git", + "repository": "https://github.com/Microsoft/vcpkg", + "baseline": "294f76666c3000630d828703e675814c05a4fd43" + } + } +} -- cgit v1.3.1