diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..54ed8cd
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "versions/7-zip-zstd"]
+ path = versions/7-zip-zstd
+ url = https://github.com/mcmilk/7-Zip-zstd.git
diff --git a/build.cmd b/build.cmd
new file mode 100644
index 0000000..eeb6fc7
--- /dev/null
+++ b/build.cmd
@@ -0,0 +1,7 @@
+@echo off
+:: Generic wrapper for build_plugin.py
+:: Usage: build.cmd [--7zip-version 19.00|25.01|26.00|zstd] [--toolset 2022|2026|auto] [...]
+:: Default: --7zip-version 26.00 --toolset auto
+setlocal
+python "%~dp0build_plugin.py" %*
+exit /b %errorlevel%
diff --git a/build_1900.cmd b/build_1900.cmd
new file mode 100644
index 0000000..cc7c1f3
--- /dev/null
+++ b/build_1900.cmd
@@ -0,0 +1,6 @@
+@echo off
+:: Build ns7zip using 7-Zip 19.00 sources
+:: Usage: build_1900.cmd [--toolset 2022|2026|auto] [...]
+setlocal
+python "%~dp0build_plugin.py" --7zip-version 19.00 %*
+exit /b %errorlevel%
diff --git a/build_2501.cmd b/build_2501.cmd
new file mode 100644
index 0000000..4f8e629
--- /dev/null
+++ b/build_2501.cmd
@@ -0,0 +1,6 @@
+@echo off
+:: Build ns7zip using 7-Zip 25.01 sources
+:: Usage: build_2501.cmd [--toolset 2022|2026|auto] [...]
+setlocal
+python "%~dp0build_plugin.py" --7zip-version 25.01 %*
+exit /b %errorlevel%
diff --git a/build_2600.cmd b/build_2600.cmd
new file mode 100644
index 0000000..876d60c
--- /dev/null
+++ b/build_2600.cmd
@@ -0,0 +1,6 @@
+@echo off
+:: Build ns7zip using 7-Zip 26.00 sources (default)
+:: Usage: build_2600.cmd [--toolset 2022|2026|auto] [...]
+setlocal
+python "%~dp0build_plugin.py" --7zip-version 26.00 %*
+exit /b %errorlevel%
diff --git a/build_plugin.py b/build_plugin.py
index a41e47f..ab44676 100644
--- a/build_plugin.py
+++ b/build_plugin.py
@@ -23,14 +23,17 @@ SCRIPTS = {
"2026": "tools/legacy/build_plugin_2501_vs2026.py"},
"26.00": {"2022": None,
"2026": "tools/legacy/build_plugin_2600_vs2026.py"},
+ "zstd": {"2022": None,
+ "2026": "tools/legacy/build_plugin_zstd_vs2026.py"},
}
def main() -> int:
parser = argparse.ArgumentParser(description="Build nsis7z NSIS plugin")
parser.add_argument("--7zip-version", dest="zip_version",
- choices=["19.00", "25.01", "26.00"], default="26.00",
- help="7-Zip version to build (default: 26.00)")
+ choices=["19.00", "25.01", "26.00", "zstd"], default="26.00",
+ help="7-Zip version to build (default: 26.00); "
+ "'zstd' uses mcmilk/7-Zip-zstd submodule")
parser.add_argument("--toolset", choices=["2022", "2026", "auto"], default="auto",
help="Visual Studio toolset version (default: auto)")
parser.add_argument("--version", action="store_true",
@@ -42,8 +45,9 @@ def main() -> int:
return 0
ver = (ROOT / "VERSION").read_text(encoding="utf-8-sig").strip()
+ zip_label = "7z-ZS" if known.zip_version == "zstd" else f"7z {known.zip_version}"
print(f"{Colors.BOLD}{Colors.BRIGHT_CYAN}=== Building ns7zip v{ver} "
- f"(7z {known.zip_version}) ==={Colors.RESET}")
+ f"({zip_label}) ==={Colors.RESET}")
toolset = known.toolset
if toolset == "auto":
diff --git a/build_zstd.cmd b/build_zstd.cmd
new file mode 100644
index 0000000..32d7b2a
--- /dev/null
+++ b/build_zstd.cmd
@@ -0,0 +1,6 @@
+@echo off
+:: Build ns7zip using 7-Zip-zstd sources (mcmilk fork)
+:: Usage: build_zstd.cmd [--toolset 2022|2026|auto] [...]
+setlocal
+python "%~dp0build_plugin.py" --7zip-version zstd %*
+exit /b %errorlevel%
diff --git a/plugins/amd64-unicode/nsis7z.dll b/plugins/amd64-unicode/nsis7z.dll
new file mode 100644
index 0000000..202f5b2
Binary files /dev/null and b/plugins/amd64-unicode/nsis7z.dll differ
diff --git a/plugins/x86-ansi/nsis7z.dll b/plugins/x86-ansi/nsis7z.dll
new file mode 100644
index 0000000..ec6d5f0
Binary files /dev/null and b/plugins/x86-ansi/nsis7z.dll differ
diff --git a/plugins/x86-unicode/nsis7z.dll b/plugins/x86-unicode/nsis7z.dll
new file mode 100644
index 0000000..9515502
Binary files /dev/null and b/plugins/x86-unicode/nsis7z.dll differ
diff --git a/tools/fix_vcxproj.py b/tools/fix_vcxproj.py
new file mode 100644
index 0000000..82057e9
--- /dev/null
+++ b/tools/fix_vcxproj.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python3
+"""Add missing source files to Nsis7z_vs2026.vcxproj"""
+from pathlib import Path
+
+ROOT = Path(__file__).resolve().parent.parent
+vcxproj = ROOT / 'versions/zstd/CPP/7zip/Bundles/Nsis7z/Nsis7z_vs2026.vcxproj'
+
+# Relative paths from vcxproj dir (versions/zstd/CPP/7zip/Bundles/Nsis7z/)
+# 5 levels up = versions/
+MISSING = [
+ r'..\..\..\..\..\7-zip-zstd\CPP\Common\MyWindows.cpp',
+ r'..\..\..\..\..\7-zip-zstd\C\hashes\xxhash.c',
+ r'..\..\..\..\..\7-zip-zstd\C\fast-lzma2\dict_buffer.c',
+ r'..\..\..\..\..\7-zip-zstd\C\fast-lzma2\fl2_common.c',
+ r'..\..\..\..\..\7-zip-zstd\C\fast-lzma2\fl2_compress.c',
+ r'..\..\..\..\..\7-zip-zstd\C\fast-lzma2\fl2_pool.c',
+ r'..\..\..\..\..\7-zip-zstd\C\fast-lzma2\fl2_threading.c',
+ r'..\..\..\..\..\7-zip-zstd\C\fast-lzma2\lzma2_enc.c',
+ r'..\..\..\..\..\7-zip-zstd\C\fast-lzma2\radix_bitpack.c',
+ r'..\..\..\..\..\7-zip-zstd\C\fast-lzma2\radix_mf.c',
+ r'..\..\..\..\..\7-zip-zstd\C\fast-lzma2\radix_struct.c',
+ r'..\..\..\..\..\7-zip-zstd\C\fast-lzma2\range_enc.c',
+ r'..\..\..\..\..\7-zip-zstd\C\fast-lzma2\util.c',
+]
+
+content = vcxproj.read_text(encoding='utf-8')
+
+ANCHOR = ' '
+if ANCHOR not in content:
+ print('ERROR: anchor not found in vcxproj')
+ exit(1)
+
+lines = [f' ' for p in MISSING]
+block = '\n'.join(lines) + '\n '
+content = content.replace(ANCHOR, block + ANCHOR.lstrip())
+vcxproj.write_text(content, encoding='utf-8')
+print(f'Added {len(MISSING)} source files to vcxproj')
diff --git a/tools/legacy/build_plugin_2501_vs2026.py b/tools/legacy/build_plugin_2501_vs2026.py
index 99295db..7ada1d1 100644
--- a/tools/legacy/build_plugin_2501_vs2026.py
+++ b/tools/legacy/build_plugin_2501_vs2026.py
@@ -84,6 +84,7 @@ def _find_msbuild_via_vswhere(vs_version: str) -> 'Optional[Tuple[Path, str, str
result = subprocess.run(
[
str(_VSWHERE_PATH),
+ '-products', '*',
'-version', _VS_VERSION_RANGE[ver],
'-latest',
'-requires', 'Microsoft.Component.MSBuild',
@@ -102,6 +103,13 @@ def _find_msbuild_via_vswhere(vs_version: str) -> 'Optional[Tuple[Path, str, str
return None
+# Numeric version folder used by VS2026 installer (version 18.x)
+_VS_NUMERIC_FOLDER = {
+ '2026': '18',
+ '2022': '2022',
+}
+
+
def find_msbuild(vs_version: str = 'auto') -> 'Optional[Tuple[Path, str, str]]':
"""Find MSBuild.exe via vswhere, then well-known fallback paths.
@@ -114,11 +122,16 @@ def find_msbuild(vs_version: str = 'auto') -> 'Optional[Tuple[Path, str, str]]':
vs_editions = ['Community', 'Professional', 'Enterprise', 'BuildTools']
versions_to_try = ['2026', '2022'] if vs_version == 'auto' else [vs_version]
for version in versions_to_try:
- base_path = Path(rf'C:\Program Files\Microsoft Visual Studio\{version}')
- for edition in vs_editions:
- msbuild_path = base_path / edition / 'MSBuild' / 'Current' / 'Bin' / 'MSBuild.exe'
- if msbuild_path.exists():
- return msbuild_path, _VS_TOOLSET[version], version
+ numeric = _VS_NUMERIC_FOLDER.get(version, version)
+ base_paths = [
+ Path(rf'C:\Program Files (x86)\Microsoft Visual Studio\{numeric}'),
+ Path(rf'C:\Program Files\Microsoft Visual Studio\{version}'),
+ ]
+ for base_path in base_paths:
+ for edition in vs_editions:
+ msbuild_path = base_path / edition / 'MSBuild' / 'Current' / 'Bin' / 'MSBuild.exe'
+ if msbuild_path.exists():
+ return msbuild_path, _VS_TOOLSET[version], version
return None
def get_project_paths() -> Tuple[Path, Path, Path]:
diff --git a/tools/legacy/build_plugin_2600_vs2026.py b/tools/legacy/build_plugin_2600_vs2026.py
index 4641d35..3641fc4 100644
--- a/tools/legacy/build_plugin_2600_vs2026.py
+++ b/tools/legacy/build_plugin_2600_vs2026.py
@@ -84,6 +84,7 @@ def _find_msbuild_via_vswhere(vs_version: str) -> 'Optional[Tuple[Path, str, str
result = subprocess.run(
[
str(_VSWHERE_PATH),
+ '-products', '*',
'-version', _VS_VERSION_RANGE[ver],
'-latest',
'-requires', 'Microsoft.Component.MSBuild',
@@ -102,6 +103,13 @@ def _find_msbuild_via_vswhere(vs_version: str) -> 'Optional[Tuple[Path, str, str
return None
+# Numeric version folder used by VS2026 installer (version 18.x)
+_VS_NUMERIC_FOLDER = {
+ '2026': '18',
+ '2022': '2022',
+}
+
+
def find_msbuild(vs_version: str = 'auto') -> 'Optional[Tuple[Path, str, str]]':
"""Find MSBuild.exe via vswhere, then well-known fallback paths.
@@ -114,11 +122,16 @@ def find_msbuild(vs_version: str = 'auto') -> 'Optional[Tuple[Path, str, str]]':
vs_editions = ['Community', 'Professional', 'Enterprise', 'BuildTools']
versions_to_try = ['2026', '2022'] if vs_version == 'auto' else [vs_version]
for version in versions_to_try:
- base_path = Path(rf'C:\Program Files\Microsoft Visual Studio\{version}')
- for edition in vs_editions:
- msbuild_path = base_path / edition / 'MSBuild' / 'Current' / 'Bin' / 'MSBuild.exe'
- if msbuild_path.exists():
- return msbuild_path, _VS_TOOLSET[version], version
+ numeric = _VS_NUMERIC_FOLDER.get(version, version)
+ base_paths = [
+ Path(rf'C:\Program Files (x86)\Microsoft Visual Studio\{numeric}'),
+ Path(rf'C:\Program Files\Microsoft Visual Studio\{version}'),
+ ]
+ for base_path in base_paths:
+ for edition in vs_editions:
+ msbuild_path = base_path / edition / 'MSBuild' / 'Current' / 'Bin' / 'MSBuild.exe'
+ if msbuild_path.exists():
+ return msbuild_path, _VS_TOOLSET[version], version
return None
def get_project_paths(toolset: str = 'v145') -> Tuple[Path, Path, Path]:
diff --git a/tools/legacy/build_plugin_vs2026.py b/tools/legacy/build_plugin_vs2026.py
index c041c19..b9ed587 100644
--- a/tools/legacy/build_plugin_vs2026.py
+++ b/tools/legacy/build_plugin_vs2026.py
@@ -84,6 +84,7 @@ def _find_msbuild_via_vswhere(vs_version: str) -> 'Optional[Tuple[Path, str, str
result = subprocess.run(
[
str(_VSWHERE_PATH),
+ '-products', '*',
'-version', _VS_VERSION_RANGE[ver],
'-latest',
'-requires', 'Microsoft.Component.MSBuild',
@@ -102,6 +103,13 @@ def _find_msbuild_via_vswhere(vs_version: str) -> 'Optional[Tuple[Path, str, str
return None
+# Numeric version folder used by VS2026 installer (version 18.x)
+_VS_NUMERIC_FOLDER = {
+ '2026': '18',
+ '2022': '2022',
+}
+
+
def find_msbuild(vs_version: str = 'auto') -> 'Optional[Tuple[Path, str, str]]':
"""Find MSBuild.exe via vswhere, then well-known fallback paths.
@@ -114,11 +122,16 @@ def find_msbuild(vs_version: str = 'auto') -> 'Optional[Tuple[Path, str, str]]':
vs_editions = ['Community', 'Professional', 'Enterprise', 'BuildTools']
versions_to_try = ['2026', '2022'] if vs_version == 'auto' else [vs_version]
for version in versions_to_try:
- base_path = Path(rf'C:\Program Files\Microsoft Visual Studio\{version}')
- for edition in vs_editions:
- msbuild_path = base_path / edition / 'MSBuild' / 'Current' / 'Bin' / 'MSBuild.exe'
- if msbuild_path.exists():
- return msbuild_path, _VS_TOOLSET[version], version
+ numeric = _VS_NUMERIC_FOLDER.get(version, version)
+ base_paths = [
+ Path(rf'C:\Program Files (x86)\Microsoft Visual Studio\{numeric}'),
+ Path(rf'C:\Program Files\Microsoft Visual Studio\{version}'),
+ ]
+ for base_path in base_paths:
+ for edition in vs_editions:
+ msbuild_path = base_path / edition / 'MSBuild' / 'Current' / 'Bin' / 'MSBuild.exe'
+ if msbuild_path.exists():
+ return msbuild_path, _VS_TOOLSET[version], version
return None
def get_project_paths() -> Tuple[Path, Path, Path]:
diff --git a/tools/legacy/build_plugin_zstd_vs2026.py b/tools/legacy/build_plugin_zstd_vs2026.py
new file mode 100644
index 0000000..5913559
--- /dev/null
+++ b/tools/legacy/build_plugin_zstd_vs2026.py
@@ -0,0 +1,700 @@
+#!/usr/bin/env python3
+"""
+Build script for nsis7z plugin (7-Zip ZS / mcmilk/7-Zip-zstd) - Visual Studio 2026
+Supports multiple build configurations with flexible parameters.
+Uses PlatformToolset v145 (Visual Studio 2026 Build Tools).
+
+The 7-Zip ZS source is pulled from the git submodule at versions/7-zip-zstd/.
+The NSIS plugin wrapper (nsis7z.cpp, vcxproj, …) lives in versions/zstd/.
+
+NOTE: VS2026 Build Tools use v145 toolset (version 18.x)
+"""
+
+import argparse
+import os
+import sys
+import subprocess
+import shutil
+import time
+import multiprocessing
+import threading
+from concurrent.futures import ThreadPoolExecutor, as_completed
+from pathlib import Path
+from typing import List, Tuple, Optional
+import xml.etree.ElementTree as ET
+
+
+class BuildConfig:
+ """Configuration for a single build target"""
+ def __init__(self, name: str, config: str, platform: str, dest_dir: str):
+ self.name = name
+ self.config = config
+ self.platform = platform
+ self.dest_dir = dest_dir
+
+
+# Predefined build configurations
+CONFIGS = {
+ 'x86-unicode': BuildConfig(
+ name='x86-unicode',
+ config='Release Unicode',
+ platform='Win32',
+ dest_dir='x86-unicode'
+ ),
+ 'x64-unicode': BuildConfig(
+ name='x64-unicode',
+ config='Release Unicode',
+ platform='x64',
+ dest_dir='amd64-unicode'
+ ),
+ 'x86-ansi': BuildConfig(
+ name='x86-ansi',
+ config='Release',
+ platform='Win32',
+ dest_dir='x86-ansi'
+ ),
+}
+
+
+# Standard vswhere.exe location (installed with any VS 2017+ setup)
+_VSWHERE_PATH = Path(r'C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe')
+
+# vswhere version range per VS year
+_VS_VERSION_RANGE = {
+ '2026': '[18.0,19.0)',
+ '2022': '[17.0,18.0)',
+}
+
+# MSBuild toolset per VS year
+_VS_TOOLSET = {
+ '2026': 'v145', # VS 2026 uses v145 toolset
+ '2022': 'v143', # VS 2022 uses v143 toolset
+}
+
+
+def _find_msbuild_via_vswhere(vs_version: str) -> 'Optional[Tuple[Path, str, str]]':
+ """Locate MSBuild via vswhere.exe."""
+ if not _VSWHERE_PATH.exists():
+ return None
+ versions_to_try = ['2026', '2022'] if vs_version == 'auto' else [vs_version]
+ for ver in versions_to_try:
+ if ver not in _VS_VERSION_RANGE:
+ continue
+ try:
+ result = subprocess.run(
+ [
+ str(_VSWHERE_PATH),
+ '-products', '*',
+ '-version', _VS_VERSION_RANGE[ver],
+ '-latest',
+ '-requires', 'Microsoft.Component.MSBuild',
+ '-find', r'MSBuild\**\Bin\MSBuild.exe',
+ ],
+ capture_output=True, text=True, timeout=15,
+ )
+ if result.returncode == 0:
+ lines = [ln.strip() for ln in result.stdout.splitlines() if ln.strip()]
+ if lines:
+ msbuild_path = Path(lines[0])
+ if msbuild_path.exists():
+ return msbuild_path, _VS_TOOLSET[ver], ver
+ except Exception:
+ pass
+ return None
+
+
+# Numeric version folder used by VS2026 installer (version 18.x)
+_VS_NUMERIC_FOLDER = {
+ '2026': '18',
+ '2022': '2022',
+}
+
+
+def find_msbuild(vs_version: str = 'auto') -> 'Optional[Tuple[Path, str, str]]':
+ """Find MSBuild.exe via vswhere, then well-known fallback paths.
+
+ Returns (msbuild_path, toolset_version, vs_year) or None.
+ """
+ result = _find_msbuild_via_vswhere(vs_version)
+ if result is not None:
+ return result
+
+ vs_editions = ['Community', 'Professional', 'Enterprise', 'BuildTools']
+ versions_to_try = ['2026', '2022'] if vs_version == 'auto' else [vs_version]
+ for version in versions_to_try:
+ numeric = _VS_NUMERIC_FOLDER.get(version, version)
+ base_paths = [
+ Path(rf'C:\Program Files (x86)\Microsoft Visual Studio\{numeric}'),
+ Path(rf'C:\Program Files\Microsoft Visual Studio\{version}'),
+ ]
+ for base_path in base_paths:
+ for edition in vs_editions:
+ msbuild_path = base_path / edition / 'MSBuild' / 'Current' / 'Bin' / 'MSBuild.exe'
+ if msbuild_path.exists():
+ return msbuild_path, _VS_TOOLSET[version], version
+ return None
+
+
+def get_project_paths(toolset: str = 'v145') -> Tuple[Path, Path, Path]:
+ """Get project directory, project file, and plugins directory"""
+ script_dir = Path(__file__).parent.absolute()
+ project_dir = script_dir.parent.parent / 'versions' / 'zstd'
+ vcxproj = 'Nsis7z_vs2026.vcxproj'
+ project_file = project_dir / 'CPP' / '7zip' / 'Bundles' / 'Nsis7z' / vcxproj
+ plugins_dir = script_dir.parent.parent / 'plugins'
+
+ return project_dir, project_file, plugins_dir
+
+
+def get_cpu_info() -> dict:
+ """Get CPU information for parallel build optimization"""
+ try:
+ import psutil
+ logical_cores = psutil.cpu_count(logical=True)
+ physical_cores = psutil.cpu_count(logical=False)
+
+ return {
+ 'logical_cores': logical_cores,
+ 'physical_cores': physical_cores,
+ 'has_hyperthreading': logical_cores > physical_cores,
+ 'has_psutil': True
+ }
+ except ImportError:
+ cpu_count = multiprocessing.cpu_count()
+ return {
+ 'logical_cores': cpu_count,
+ 'physical_cores': cpu_count,
+ 'has_hyperthreading': False,
+ 'has_psutil': False
+ }
+
+
+def get_optimal_thread_count() -> int:
+ """Get optimal thread count for compilation"""
+ cpu_info = get_cpu_info()
+ if cpu_info['has_hyperthreading'] and cpu_info['physical_cores'] > 1:
+ return cpu_info['physical_cores']
+ return cpu_info['logical_cores']
+
+
+def get_build_optimizations() -> List[str]:
+ """Get additional build optimization flags"""
+ return [
+ '/p:BuildInParallel=true',
+ '/p:MultiProcessorCompilation=true',
+ '/p:PreferredToolArchitecture=x64',
+ '/p:UseSharedCompilation=true',
+ '/p:TrackFileAccess=false',
+ '/nodeReuse:true',
+ '/p:GenerateResourceUsePreserializedResources=true'
+ ]
+
+
+def get_memory_optimizations() -> List[str]:
+ """Get memory optimization flags for faster builds"""
+ try:
+ import psutil
+ memory_gb = psutil.virtual_memory().total / (1024 ** 3)
+ if memory_gb >= 16:
+ return [
+ '/p:DisableFastUpToDateCheck=false',
+ '/p:BuildProjectReferences=true',
+ '/p:UseCommonOutputDirectory=false'
+ ]
+ elif memory_gb >= 8:
+ return ['/p:DisableFastUpToDateCheck=false']
+ else:
+ return []
+ except ImportError:
+ return ['/p:DisableFastUpToDateCheck=false']
+
+
+def print_cpu_info(use_parallel: bool, use_optimizations: bool = True) -> None:
+ """Print CPU information for build optimization"""
+ if not use_parallel:
+ print("Build mode: Single-threaded")
+ if use_optimizations:
+ print("Optimizations: ENABLED (memory, caching)")
+ return
+
+ cpu_info = get_cpu_info()
+ optimal_threads = get_optimal_thread_count()
+
+ print("Build mode: Parallel")
+ print(f"Logical cores: {cpu_info['logical_cores']}")
+ print(f"Physical cores: {cpu_info['physical_cores']}")
+
+ if cpu_info['has_hyperthreading']:
+ print("Hyperthreading: ENABLED")
+ print(f"Optimal threads: {optimal_threads} (using physical cores)")
+ else:
+ print("Hyperthreading: NOT AVAILABLE")
+ print(f"Optimal threads: {optimal_threads}")
+
+ print(f"MSBuild threads: {optimal_threads}")
+
+ if use_optimizations:
+ print("Optimizations: ENABLED (parallel, memory, caching)")
+ try:
+ import psutil
+ memory_gb = psutil.virtual_memory().total / (1024 ** 3)
+ print(f"Available memory: {memory_gb:.1f} GB")
+ except ImportError:
+ print("Available memory: Unknown (install psutil for details)")
+ else:
+ print("Optimizations: DISABLED")
+
+ if not cpu_info['has_psutil']:
+ print("Note: Install 'psutil' for detailed CPU/memory info (pip install psutil)")
+
+ print()
+
+
+def build_configuration(
+ msbuild_path: Path,
+ project_file: Path,
+ config: BuildConfig,
+ rebuild: bool = True,
+ verbosity: str = 'quiet',
+ parallel: bool = True,
+ optimizations: bool = True,
+ counter: str = "",
+ capture_output: bool = False,
+ toolset: str = 'v145',
+) -> Tuple[bool, float, str]:
+ """Build a single configuration.
+
+ Returns (success, elapsed_time, captured_output).
+ """
+ cmd = [
+ str(msbuild_path),
+ str(project_file),
+ f'/t:{"Rebuild" if rebuild else "Build"}',
+ f'/p:Configuration={config.config}',
+ f'/p:Platform={config.platform}',
+ f'/p:OutDir=Build\\{config.name}\\',
+ f'/p:IntDir=Build\\{config.name}\\obj\\',
+ '/p:WindowsTargetPlatformVersion=10.0',
+ f'/p:PlatformToolset={toolset}',
+ f'/v:{verbosity}',
+ ]
+
+ if parallel:
+ optimal_threads = get_optimal_thread_count()
+ cmd.extend([
+ f'/maxcpucount:{optimal_threads}',
+ '/p:UseMultiToolTask=true',
+ f'/p:CL_MPCount={optimal_threads}'
+ ])
+
+ if optimizations:
+ cmd.extend(get_build_optimizations())
+ cmd.extend(get_memory_optimizations())
+ cache_dir = setup_build_cache()
+ if cache_dir:
+ cmd.append('/p:MSBuildCacheEnabled=true')
+
+ if not capture_output:
+ print(f"\n{'=' * 50}")
+ if counter:
+ print(f"Building {config.name} [{counter}]")
+ else:
+ print(f"Building {config.name}...")
+ print('=' * 50)
+
+ start_time = time.time()
+ try:
+ if capture_output:
+ result = subprocess.run(cmd, check=False, capture_output=True, text=True)
+ elapsed = time.time() - start_time
+ return result.returncode == 0, elapsed, result.stdout + result.stderr
+ else:
+ result = subprocess.run(cmd, check=False)
+ elapsed = time.time() - start_time
+ return result.returncode == 0, elapsed, ""
+ except Exception as e:
+ elapsed = time.time() - start_time
+ msg = f"ERROR: Build failed with exception: {e}"
+ if capture_output:
+ return False, elapsed, msg
+ print(msg)
+ return False, elapsed, ""
+
+
+def copy_output(
+ project_dir: Path,
+ plugins_dir: Path,
+ config: BuildConfig
+) -> Tuple[bool, int, Optional[Path]]:
+ """Copy built DLL to destination directory.
+
+ Returns (success, file_size, dest_path).
+ """
+ output_file = (
+ project_dir / 'CPP' / '7zip' / 'Bundles' / 'Nsis7z'
+ / 'Build' / config.name / 'nsis7z.dll'
+ )
+ dest_dir = plugins_dir / config.dest_dir
+
+ if not output_file.exists():
+ print(f"ERROR: {config.name} DLL not found at {output_file}")
+ return False, 0, None
+
+ dest_dir.mkdir(parents=True, exist_ok=True)
+
+ try:
+ dest_path = dest_dir / 'nsis7z.dll'
+ shutil.copy2(output_file, dest_path)
+ file_size = output_file.stat().st_size
+ print(f"SUCCESS: {config.name} - {file_size:,} bytes - Copied to {dest_dir}")
+ return True, file_size, dest_path
+ except Exception as e:
+ print(f"ERROR: Failed to copy {config.name}: {e}")
+ return False, 0, None
+
+
+def clean_build_artifacts(project_dir: Path, configs: List[BuildConfig]) -> None:
+ """Clean up build artifacts"""
+ print("\nCleaning build artifacts...")
+
+ build_base_dir = (
+ project_dir / 'CPP' / '7zip' / 'Bundles' / 'Nsis7z' / 'Build'
+ )
+
+ dirs_to_clean = {build_base_dir / config.name for config in configs}
+
+ for dir_path in dirs_to_clean:
+ if dir_path.exists():
+ try:
+ shutil.rmtree(dir_path)
+ print(f" - Cleaned: {dir_path.name}")
+ except Exception as e:
+ print(f" - Failed to clean {dir_path.name}: {e}")
+
+ print("Build artifacts cleaned successfully.")
+
+
+def format_time(seconds: float) -> str:
+ """Format seconds to human-readable string"""
+ if seconds < 60:
+ return f"{seconds:.2f}s"
+ elif seconds < 3600:
+ minutes = int(seconds // 60)
+ secs = seconds % 60
+ return f"{minutes}m {secs:.1f}s"
+ else:
+ hours = int(seconds // 3600)
+ minutes = int((seconds % 3600) // 60)
+ secs = seconds % 60
+ return f"{hours}h {minutes}m {secs:.0f}s"
+
+
+def setup_build_cache() -> Optional[str]:
+ """Setup build cache directory for faster incremental builds"""
+ try:
+ cache_dir = Path.home() / '.msbuild_cache' / 'nsis7z-zstd-vs2026'
+ cache_dir.mkdir(parents=True, exist_ok=True)
+ return str(cache_dir)
+ except Exception:
+ return None
+
+
+def get_available_configurations(project_file: Path) -> List[Tuple[str, str]]:
+ """Parse .vcxproj file to get available configurations"""
+ try:
+ tree = ET.parse(project_file)
+ root = tree.getroot()
+ ns = {'ms': 'http://schemas.microsoft.com/developer/msbuild/2003'}
+ configs = []
+ for item_group in root.findall('.//ms:ItemGroup', ns):
+ for proj_config in item_group.findall('ms:ProjectConfiguration', ns):
+ include = proj_config.get('Include')
+ if include:
+ parts = include.split('|')
+ if len(parts) == 2:
+ configs.append((parts[0], parts[1]))
+ return configs
+ except Exception as e:
+ print(f"Warning: Could not parse project file: {e}")
+ return []
+
+
+def print_available_configurations(project_file: Path) -> None:
+ """Print all configurations available in the project"""
+ configs = get_available_configurations(project_file)
+ if not configs:
+ print("No configurations found or could not read project file.")
+ return
+
+ print("Available configurations in project:")
+ print("-" * 60)
+ from collections import defaultdict
+ grouped = defaultdict(list)
+ for config, platform in configs:
+ grouped[config].append(platform)
+ for config_name in sorted(grouped.keys()):
+ platforms = ', '.join(sorted(grouped[config_name]))
+ print(f" {config_name:25s} - {platforms}")
+ print(f"\nTotal: {len(configs)} configuration(s)")
+ print()
+ print("Configurations mapped in this build script:")
+ print("-" * 60)
+ for name, config in CONFIGS.items():
+ print(f" {name:15s} -> {config.config} / {config.platform}")
+ print()
+
+
+_print_lock = threading.Lock()
+
+
+def _build_configs_parallel(
+ msbuild_path: Path,
+ project_file: Path,
+ configs: 'List[BuildConfig]',
+ *,
+ rebuild: bool,
+ verbosity: str,
+ parallel: bool,
+ optimizations: bool,
+ project_dir: Path,
+ plugins_dir: Path,
+ toolset: str = 'v145',
+) -> list:
+ """Build all configurations simultaneously, printing output atomically."""
+ n = len(configs)
+ print(f"\nParallel-configs: launching {n} builds simultaneously...")
+ print("=" * 50)
+
+ total_start = time.time()
+ results_by_idx: dict = {}
+ idx_lock = threading.Lock()
+
+ def _build_one(idx: int, config: 'BuildConfig'):
+ success, build_time, captured = build_configuration(
+ msbuild_path, project_file, config,
+ rebuild=rebuild, verbosity=verbosity,
+ parallel=parallel, optimizations=optimizations,
+ capture_output=True, toolset=toolset,
+ )
+ import io, contextlib
+ copy_buf = io.StringIO()
+ if success:
+ with contextlib.redirect_stdout(copy_buf):
+ copy_ok, file_size, dest_path = copy_output(project_dir, plugins_dir, config)
+ else:
+ copy_ok, file_size, dest_path = False, 0, None
+
+ with _print_lock:
+ all_ok = success and copy_ok
+ tag = "OK" if all_ok else "FAILED"
+ size_str = f"{file_size:,} bytes" if file_size > 0 else "N/A"
+ print(f"[{tag}] {config.name} ({format_time(build_time)}) {size_str}")
+ if dest_path:
+ print(f" -> {dest_path}")
+ if not all_ok:
+ copy_out = copy_buf.getvalue()
+ if copy_out.strip():
+ print(copy_out.rstrip())
+ if captured.strip():
+ print("--- Build output ---")
+ print(captured.rstrip())
+
+ with idx_lock:
+ results_by_idx[idx] = (config, success and copy_ok, build_time, file_size, dest_path)
+
+ with ThreadPoolExecutor(max_workers=n) as executor:
+ futures = {executor.submit(_build_one, i, cfg): i for i, cfg in enumerate(configs)}
+ for fut in as_completed(futures):
+ exc = fut.exception()
+ if exc:
+ idx = futures[fut]
+ with _print_lock:
+ print(f"ERROR: worker for config index {idx} raised: {exc}")
+ with idx_lock:
+ results_by_idx[idx] = (configs[idx], False, 0.0, 0, None)
+
+ wall_time = time.time() - total_start
+ print(f"\nAll {n} configs finished in {format_time(wall_time)} (wall clock)")
+ return [results_by_idx[i] for i in range(n)]
+
+
+def main():
+ """Main build function"""
+ parser = argparse.ArgumentParser(
+ description='Build nsis7z plugin (7-Zip ZS / mcmilk/7-Zip-zstd, Visual Studio 2026)',
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ epilog="""
+Examples:
+ %(prog)s # Build all configurations
+ %(prog)s --list # List script configurations
+ %(prog)s --list-project # List all project configurations
+ %(prog)s --configs x86-unicode # Build only x86-unicode
+ %(prog)s --configs x86-unicode x64-unicode
+ %(prog)s --no-rebuild # Incremental build
+ %(prog)s --no-parallel # Single-threaded build
+ %(prog)s --no-clean # Skip cleanup
+ %(prog)s --verbosity minimal # Show more build output
+ """
+ )
+
+ parser.add_argument(
+ '--configs', nargs='+',
+ choices=list(CONFIGS.keys()) + ['all'],
+ default=['all'],
+ help='Configurations to build (default: all)'
+ )
+ parser.add_argument('--rebuild', action='store_true', default=True)
+ parser.add_argument('--no-rebuild', action='store_false', dest='rebuild',
+ help='Incremental build (only changed files)')
+ parser.add_argument('--parallel', action='store_true', default=True)
+ parser.add_argument('--no-parallel', action='store_false', dest='parallel')
+ parser.add_argument('--verbosity',
+ choices=['quiet', 'minimal', 'normal', 'detailed', 'diagnostic'],
+ default='quiet')
+ parser.add_argument('--clean', action='store_true', default=True)
+ parser.add_argument('--no-clean', action='store_false', dest='clean')
+ parser.add_argument('--list', action='store_true',
+ help='List script configurations and exit')
+ parser.add_argument('--list-project', action='store_true',
+ help='List all configurations in the .vcxproj and exit')
+ parser.add_argument('--pause', action='store_true',
+ help='Wait for key press at the end')
+ parser.add_argument('--no-optimizations', action='store_true',
+ help='Disable additional build optimizations')
+ parser.add_argument('--vs-version', choices=['auto', '2026', '2022'], default='auto',
+ help='Visual Studio version to use (default: auto)')
+
+ args = parser.parse_args()
+
+ # Find MSBuild
+ msbuild_result = find_msbuild(args.vs_version)
+ if not msbuild_result:
+ print("ERROR: MSBuild not found!")
+ return 1
+ msbuild_path, platform_toolset, vs_version_name = msbuild_result
+
+ # Get project paths
+ project_dir, project_file, plugins_dir = get_project_paths(platform_toolset)
+
+ if args.list_project:
+ if not project_file.exists():
+ print(f"ERROR: Project file not found: {project_file}")
+ return 1
+ print_available_configurations(project_file)
+ return 0
+
+ if args.list:
+ print("Build script configurations (7-Zip ZS / mcmilk, VS2026):")
+ print("-" * 60)
+ for name, config in CONFIGS.items():
+ print(f" {name:15s} -> {config.config} / {config.platform}")
+ print(f"\nTotal: {len(CONFIGS)} configuration(s)")
+ return 0
+
+ if not project_file.exists():
+ print(f"ERROR: Project file not found: {project_file}")
+ print()
+ print("Make sure the submodule is initialised:")
+ print(" git submodule update --init versions/7-zip-zstd")
+ return 1
+
+ # Determine configurations to build
+ if 'all' in args.configs:
+ configs_to_build = list(CONFIGS.values())
+ else:
+ configs_to_build = [CONFIGS[name] for name in args.configs]
+
+ # Print header
+ print("=" * 60)
+ print(
+ f"Building nsis7z plugin (7-Zip ZS, VS2026)"
+ f" - {len(configs_to_build)} configuration(s)"
+ )
+ print("=" * 60)
+ print(f"Visual Studio: {vs_version_name} (toolset {platform_toolset})")
+ print(f"MSBuild: {msbuild_path}")
+ print(f"Project: {project_file}")
+ print(f"Plugins: {plugins_dir}")
+ print(f"Rebuild: {args.rebuild}")
+ print(f"Verbosity: {args.verbosity}")
+ print()
+
+ use_optimizations = not args.no_optimizations
+ print_cpu_info(args.parallel, use_optimizations)
+
+ # Build
+ build_results = []
+ total_start_time = time.time()
+
+ if args.parallel and len(configs_to_build) > 1:
+ build_results = _build_configs_parallel(
+ msbuild_path, project_file, configs_to_build,
+ rebuild=args.rebuild, verbosity=args.verbosity,
+ parallel=args.parallel, optimizations=use_optimizations,
+ project_dir=project_dir, plugins_dir=plugins_dir,
+ toolset=platform_toolset,
+ )
+ else:
+ for i, config in enumerate(configs_to_build, 1):
+ success, build_time, _ = build_configuration(
+ msbuild_path, project_file, config,
+ rebuild=args.rebuild, verbosity=args.verbosity,
+ parallel=args.parallel, optimizations=use_optimizations,
+ counter=f"{i}/{len(configs_to_build)}",
+ toolset=platform_toolset,
+ )
+
+ if not success:
+ print(f"ERROR: {config.name} build failed! (Time: {format_time(build_time)})")
+ build_results.append((config, False, build_time, 0, None))
+ continue
+
+ success, file_size, dest_path = copy_output(project_dir, plugins_dir, config)
+ print(f"Build time: {format_time(build_time)}")
+ build_results.append((config, success, build_time, file_size, dest_path))
+
+ total_time = time.time() - total_start_time
+
+ # Summary
+ print("\n" + "=" * 50)
+ all_success = all(success for _, success, _, _, _ in build_results)
+
+ if all_success:
+ print("ALL BUILDS SUCCESSFUL!")
+ print("=" * 50)
+ print("\nPlugins copied to:")
+ for config, _, build_time, file_size, dest_path in build_results:
+ dest = dest_path or plugins_dir / config.dest_dir / 'nsis7z.dll'
+ print(f" - {dest}")
+ if args.clean:
+ print()
+ clean_build_artifacts(project_dir, configs_to_build)
+ else:
+ print("SOME BUILDS FAILED!")
+ print("=" * 50)
+ print("\nFailed configurations:")
+ for config, success, build_time, file_size, dest_path in build_results:
+ if not success:
+ print(f" - {config.name}")
+
+ print("\n" + "-" * 50)
+ print("Build Summary:")
+ for config, success, build_time, file_size, dest_path in build_results:
+ status = "OK" if success else "FAIL"
+ size_str = f"{file_size:,} bytes" if file_size > 0 else "N/A"
+ print(f" {status} {config.name:15s} - {format_time(build_time):8s} - {size_str}")
+ print("-" * 50)
+ print(f"Total time: {format_time(total_time)}")
+ print()
+
+ if args.pause:
+ try:
+ input("Press Enter to continue...")
+ except EOFError:
+ pass
+
+ return 0 if all_success else 1
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/versions/7-zip-zstd b/versions/7-zip-zstd
new file mode 160000
index 0000000..6146959
--- /dev/null
+++ b/versions/7-zip-zstd
@@ -0,0 +1 @@
+Subproject commit 6146959af008acfb7e92c7d38ef9e43bf9f6afbb
diff --git a/versions/zstd/CPP/7zip/Bundles/Nsis7z/Nsis7z_vs2026.vcxproj b/versions/zstd/CPP/7zip/Bundles/Nsis7z/Nsis7z_vs2026.vcxproj
new file mode 100644
index 0000000..a994824
--- /dev/null
+++ b/versions/zstd/CPP/7zip/Bundles/Nsis7z/Nsis7z_vs2026.vcxproj
@@ -0,0 +1,1023 @@
+
+
+
+
+
+ Debug Unicode
+ Win32
+
+
+ Debug Unicode
+ x64
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release Unicode
+ Win32
+
+
+ Release Unicode
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+
+
+ {B3A7F2E1-9DC8-4B51-A36F-C4D33E86A6FD}
+ 10.0.26100.0
+
+
+
+ DynamicLibrary
+ v145
+ false
+ MultiByte
+
+
+ DynamicLibrary
+ v145
+ false
+ MultiByte
+
+
+ DynamicLibrary
+ v145
+ false
+ Unicode
+
+
+ DynamicLibrary
+ v145
+ false
+ Unicode
+
+
+ DynamicLibrary
+ v145
+ false
+ Unicode
+
+
+ DynamicLibrary
+ v145
+ false
+ Unicode
+
+
+ DynamicLibrary
+ v145
+ false
+ MultiByte
+
+
+ DynamicLibrary
+ v145
+ false
+ MultiByte
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+ false
+ nsis7z
+ $(Configuration)\
+ $(Configuration)\
+
+
+ false
+ false
+ nsis7z
+
+
+ true
+ false
+
+
+ true
+ false
+ nsis7z
+
+
+ false
+ false
+ nsis7z
+ $(Configuration)\
+ $(Configuration)\
+
+
+ false
+ false
+ nsis7z
+ $(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+
+
+ true
+ false
+
+
+ true
+ false
+ nsis7z
+
+
+
+
+ MultiThreaded
+ Default
+ true
+ true
+ MinSpace
+ true
+ false
+ true
+ Level3
+ ..\..\..\..\..\7-zip-zstd\CPP\;..\..\..\..\..\7-zip-zstd\;..\..\..\;%(AdditionalIncludeDirectories)
+ NDEBUG;WIN32;%(PreprocessorDefinitions)
+ AssemblyAndMachineCode
+ FastCall
+ None
+ 4100
+
+
+ .\Release\Alone.tlb
+
+
+ 0x0419
+ NDEBUG;%(PreprocessorDefinitions)
+
+
+ true
+ .\Release\Alone.bsc
+
+
+ true
+
+
+ No
+ UseLinkTimeCodeGeneration
+ true
+ true
+
+
+
+
+
+ MultiThreaded
+ Default
+ true
+ true
+ MinSpace
+ true
+ false
+ true
+ Level3
+ ..\..\..\..\..\7-zip-zstd\CPP\;..\..\..\..\..\7-zip-zstd\;..\..\..\;%(AdditionalIncludeDirectories)
+ NDEBUG;WIN32;%(PreprocessorDefinitions)
+ AssemblyAndMachineCode
+ FastCall
+
+
+ .\Release\Alone.tlb
+
+
+ 0x0419
+ NDEBUG;%(PreprocessorDefinitions)
+
+
+ true
+ .\Release\Alone.bsc
+
+
+ true
+
+
+ UseLinkTimeCodeGeneration
+ true
+ true
+
+
+
+
+
+ MultiThreadedDebugDLL
+ Default
+ false
+ Disabled
+ true
+ Level4
+ true
+ EditAndContinue
+ ..\..\..\..\..\7-zip-zstd\CPP\;..\..\..\..\..\7-zip-zstd\;..\..\..\;%(AdditionalIncludeDirectories)
+ _DEBUG;UNICODE;WIN32;_CONSOLE;%(PreprocessorDefinitions)
+ NotUsing
+ FastCall
+ EnableFastChecks
+
+
+ .\DebugU\Alone.tlb
+
+
+ 0x0419
+ _DEBUG;%(PreprocessorDefinitions)
+
+
+ true
+ .\DebugU\Alone.bsc
+
+
+ true
+ true
+ odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+ MultiThreadedDebugDLL
+ Default
+ false
+ Disabled
+ true
+ Level4
+ ProgramDatabase
+ ..\..\..\..\..\7-zip-zstd\CPP\;..\..\..\..\..\7-zip-zstd\;..\..\..\;%(AdditionalIncludeDirectories)
+ _DEBUG;UNICODE;WIN32;_CONSOLE;%(PreprocessorDefinitions)
+ NotUsing
+ FastCall
+ EnableFastChecks
+
+
+ .\DebugU\Alone.tlb
+
+
+ 0x0419
+ _DEBUG;%(PreprocessorDefinitions)
+
+
+ true
+ .\DebugU\Alone.bsc
+
+
+ true
+ true
+ odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+ MultiThreaded
+ Default
+ true
+ true
+ MinSpace
+ true
+ false
+ true
+ Level4
+ ..\..\..\..\..\7-zip-zstd\CPP\;..\..\..\..\..\7-zip-zstd\;..\..\..\;%(AdditionalIncludeDirectories)
+ NDEBUG;UNICODE;WIN32;%(PreprocessorDefinitions)
+ NotUsing
+ FastCall
+ None
+ 4100
+
+
+ .\ReleaseU\Alone.tlb
+
+
+ 0x0419
+ NDEBUG;%(PreprocessorDefinitions)
+
+
+ true
+ .\ReleaseU\Alone.bsc
+
+
+ true
+
+
+ No
+ UseLinkTimeCodeGeneration
+ true
+ true
+
+
+
+
+
+ MultiThreaded
+ Default
+ true
+ true
+ MinSpace
+ true
+ false
+ true
+ Level4
+ ..\..\..\..\..\7-zip-zstd\CPP\;..\..\..\..\..\7-zip-zstd\;..\..\..\;%(AdditionalIncludeDirectories)
+ NDEBUG;UNICODE;WIN32;%(PreprocessorDefinitions)
+ NotUsing
+ FastCall
+ None
+ 4100
+
+
+ .\ReleaseU\Alone.tlb
+
+
+ 0x0419
+ NDEBUG;%(PreprocessorDefinitions)
+
+
+ true
+ .\ReleaseU\Alone.bsc
+
+
+ true
+
+
+ No
+ UseLinkTimeCodeGeneration
+ true
+ true
+
+
+
+
+
+ MultiThreadedDebugDLL
+ Default
+ Disabled
+ true
+ Level3
+ true
+ EditAndContinue
+ ..\..\..\..\..\7-zip-zstd\CPP\;..\..\..\..\..\7-zip-zstd\;..\..\..\;%(AdditionalIncludeDirectories)
+ _DEBUG;WIN32;_CONSOLE;%(PreprocessorDefinitions)
+ FastCall
+ EnableFastChecks
+
+
+ .\Debug\Alone.tlb
+
+
+ 0x0419
+ _DEBUG;%(PreprocessorDefinitions)
+
+
+ true
+ .\Debug\Alone.bsc
+
+
+ true
+ true
+ odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+ MultiThreadedDebugDLL
+ Default
+ false
+ Disabled
+ true
+ Level3
+ ProgramDatabase
+ ..\..\..\..\..\7-zip-zstd\CPP\;..\..\..\..\..\7-zip-zstd\;..\..\..\;%(AdditionalIncludeDirectories)
+ _DEBUG;WIN32;_CONSOLE;%(PreprocessorDefinitions)
+ FastCall
+ EnableFastChecks
+
+
+ .\Debug\Alone.tlb
+
+
+ 0x0419
+ _DEBUG;%(PreprocessorDefinitions)
+
+
+ true
+ .\Debug\Alone.bsc
+
+
+ true
+ true
+ odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Create
+ Create
+ StdAfx.h
+ StdAfx.h
+ Create
+ Create
+ StdAfx.h
+ StdAfx.h
+ Create
+ Create
+ StdAfx.h
+ StdAfx.h
+ Create
+ Create
+ StdAfx.h
+ StdAfx.h
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/versions/zstd/CPP/7zip/Bundles/Nsis7z/StdAfx.h b/versions/zstd/CPP/7zip/Bundles/Nsis7z/StdAfx.h
new file mode 100644
index 0000000..26f54c6
--- /dev/null
+++ b/versions/zstd/CPP/7zip/Bundles/Nsis7z/StdAfx.h
@@ -0,0 +1,13 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "Common/Common.h"
+#include
+#include
+#include "Common/MyWindows.h"
+#include "Common/NewHandler.h"
+#include "pluginapi.h"
+
+#endif
diff --git a/versions/zstd/CPP/7zip/Bundles/Nsis7z/StdAfx2.cpp b/versions/zstd/CPP/7zip/Bundles/Nsis7z/StdAfx2.cpp
new file mode 100644
index 0000000..d0feea8
--- /dev/null
+++ b/versions/zstd/CPP/7zip/Bundles/Nsis7z/StdAfx2.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/versions/zstd/CPP/7zip/Bundles/Nsis7z/afxres.h b/versions/zstd/CPP/7zip/Bundles/Nsis7z/afxres.h
new file mode 100644
index 0000000..c2fadd4
--- /dev/null
+++ b/versions/zstd/CPP/7zip/Bundles/Nsis7z/afxres.h
@@ -0,0 +1 @@
+#include
diff --git a/versions/zstd/CPP/7zip/Bundles/Nsis7z/api.h b/versions/zstd/CPP/7zip/Bundles/Nsis7z/api.h
new file mode 100644
index 0000000..85d41c4
--- /dev/null
+++ b/versions/zstd/CPP/7zip/Bundles/Nsis7z/api.h
@@ -0,0 +1,83 @@
+/*
+ * apih
+ *
+ * This file is a part of NSIS.
+ *
+ * Copyright (C) 1999-2013 Nullsoft and Contributors
+ *
+ * Licensed under the zlib/libpng license (the "License");
+ * you may not use this file except in compliance with the License.
+ *
+ * Licence details can be found in the file COPYING.
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.
+ */
+
+#ifndef _NSIS_EXEHEAD_API_H_
+#define _NSIS_EXEHEAD_API_H_
+
+// Starting with NSIS 2.42, you can check the version of the plugin API in exec_flags->plugin_api_version
+// The format is 0xXXXXYYYY where X is the major version and Y is the minor version (MAKELONG(y,x))
+// When doing version checks, always remember to use >=, ex: if (pX->exec_flags->plugin_api_version >= NSISPIAPIVER_1_0) {}
+
+#define NSISPIAPIVER_1_0 0x00010000
+#define NSISPIAPIVER_CURR NSISPIAPIVER_1_0
+
+// NSIS Plug-In Callback Messages
+enum NSPIM
+{
+ NSPIM_UNLOAD, // This is the last message a plugin gets, do final cleanup
+ NSPIM_GUIUNLOAD, // Called after .onGUIEnd
+};
+
+// Prototype for callbacks registered with extra_parameters->RegisterPluginCallback()
+// Return NULL for unknown messages
+// Should always be __cdecl for future expansion possibilities
+typedef UINT_PTR (*NSISPLUGINCALLBACK)(enum NSPIM);
+
+// extra_parameters data structures containing other interesting stuff
+// but the stack, variables and HWND passed on to plug-ins.
+typedef struct
+{
+ int autoclose;
+ int all_user_var;
+ int exec_error;
+ int abort;
+ int exec_reboot; // NSIS_SUPPORT_REBOOT
+ int reboot_called; // NSIS_SUPPORT_REBOOT
+ int XXX_cur_insttype; // depreacted
+ int plugin_api_version; // see NSISPIAPIVER_CURR
+ // used to be XXX_insttype_changed
+ int silent; // NSIS_CONFIG_SILENT_SUPPORT
+ int instdir_error;
+ int rtl;
+ int errlvl;
+ int alter_reg_view;
+ int status_update;
+} exec_flags_t;
+
+#ifndef NSISCALL
+# define NSISCALL __stdcall
+#endif
+
+typedef struct {
+ exec_flags_t *exec_flags;
+ int (NSISCALL *ExecuteCodeSegment)(int, HWND);
+ void (NSISCALL *validate_filename)(TCHAR *);
+ int (NSISCALL *RegisterPluginCallback)(HMODULE, NSISPLUGINCALLBACK); // returns 0 on success, 1 if already registered and < 0 on errors
+} extra_parameters;
+
+// Definitions for page showing plug-ins
+// See Ui.c to understand better how they're used
+
+// sent to the outer window to tell it to go to the next inner window
+#define WM_NOTIFY_OUTER_NEXT (WM_USER+0x8)
+
+// custom pages should send this message to let NSIS know they're ready
+#define WM_NOTIFY_CUSTOM_READY (WM_USER+0xd)
+
+// sent as wParam with WM_NOTIFY_OUTER_NEXT when user cancels - heed its warning
+#define NOTIFY_BYE_BYE 'x'
+
+#endif /* _PLUGIN_H_ */
diff --git a/versions/zstd/CPP/7zip/Bundles/Nsis7z/nsis7z.cpp b/versions/zstd/CPP/7zip/Bundles/Nsis7z/nsis7z.cpp
new file mode 100644
index 0000000..8f8daaa
--- /dev/null
+++ b/versions/zstd/CPP/7zip/Bundles/Nsis7z/nsis7z.cpp
@@ -0,0 +1,190 @@
+#include "StdAfx.h"
+
+#include "../../UI/NSIS/ExtractCallbackConsole.h"
+#include "Common/StringConvert.h"
+
+#pragma warning(disable: 4100)
+
+#define IDC_PROGRESS 1004
+#define IDC_INTROTEXT 1006
+
+#define EXTRACTFUNC(funcname) extern "C" { \
+void __declspec(dllexport) __cdecl funcname(HWND hwndParent, int string_size, \
+ TCHAR *variables, stack_t **stacktop, \
+ extra_parameters *extra) \
+{ \
+ EXDLL_INIT();\
+ g_lastVal = -1; \
+ g_hwndParent=hwndParent; \
+ HWND hwndDlg = FindWindowEx(g_hwndParent, NULL, TEXT("#32770"), NULL); \
+ g_hwndProgress = GetDlgItem(hwndDlg, IDC_PROGRESS); \
+ g_hwndText = GetDlgItem(hwndDlg, IDC_INTROTEXT); \
+ TCHAR sArchive[1024], *outDir = getuservariable(INST_OUTDIR); \
+ popstring(sArchive); \
+ g_pluginExtra = extra; \
+
+#define EXTRACTFUNCEND } }
+
+HINSTANCE g_hInstance2;
+HWND g_hwndParent;
+HWND g_hwndProgress;
+HWND g_hwndText;
+extra_parameters *g_pluginExtra;
+
+void DoInitialize();
+int DoExtract(LPTSTR archive, LPTSTR dir, bool overwrite, bool expath, ExtractProgressHandler epc, const UStringVector& skipPatterns);
+int DoExtractWithFile(LPTSTR archive, LPTSTR dir, bool overwrite, bool expath, ExtractProgressWithFileHandler epc, const UStringVector& skipPatterns);
+
+int g_progressCallback = -1;
+int g_lastVal = -1;
+TCHAR* g_sDetails;
+
+static void PopSkipPatterns(UStringVector& skipPatterns)
+{
+ TCHAR *buf = new TCHAR[g_stringsize];
+ while (popstring(buf) == 0 && lstrlen(buf) > 0)
+ {
+#ifdef UNICODE
+ skipPatterns.Add(UString(buf));
+#else
+ skipPatterns.Add(MultiByteToUnicodeString(AString(buf)));
+#endif
+ }
+ delete[] buf;
+}
+
+int GetPercentComplete(UInt64 completedSize, UInt64 totalSize)
+{
+ if (totalSize == 0) return 0;
+ const int nsisProgressMax = 30000;
+ int val = (int)((completedSize*nsisProgressMax)/totalSize);
+ if (val < 0) return 0;
+ if (val > nsisProgressMax) return nsisProgressMax;
+ return val;
+}
+
+void SimpleProgressHandler(UInt64 completedSize, UInt64 totalSize)
+{
+ int val = GetPercentComplete(completedSize, totalSize);
+ if (g_lastVal != val)
+ SendMessage(g_hwndProgress, PBM_SETPOS, g_lastVal = val, 0);
+}
+
+void CallbackProgressHandler(UInt64 completedSize, UInt64 totalSize)
+{
+ int val = 0;
+
+ if (totalSize > 0)
+ {
+ val = GetPercentComplete(completedSize, totalSize);
+
+ static TCHAR buf[32];
+ wsprintf(buf, TEXT("%lu"), totalSize);
+ pushstring(buf);
+ wsprintf(buf, TEXT("%lu"), completedSize);
+ pushstring(buf);
+ g_pluginExtra->ExecuteCodeSegment(g_progressCallback-1, 0);
+ }
+
+ if (g_lastVal != val)
+ SendMessage(g_hwndProgress, PBM_SETPOS, g_lastVal = val, 0);
+}
+
+void CallbackFileProgressHandler(UInt64 completedSize, UInt64 totalSize, const wchar_t *fileName)
+{
+ int val = 0;
+
+ if (totalSize > 0)
+ val = GetPercentComplete(completedSize, totalSize);
+
+ // Notify NSIS only when a new file starts (filename changes)
+ if (fileName && fileName[0])
+ {
+ static TCHAR fileNameBuf[MAX_PATH];
+ static TCHAR prevFileNameBuf[MAX_PATH];
+ static TCHAR buf[32];
+
+ lstrcpyn(fileNameBuf, (const TCHAR*)fileName, MAX_PATH);
+ if (lstrcmp(fileNameBuf, prevFileNameBuf) != 0)
+ {
+ lstrcpy(prevFileNameBuf, fileNameBuf);
+ pushstring(fileNameBuf);
+ wsprintf(buf, TEXT("%lu"), (DWORD)totalSize);
+ pushstring(buf);
+ wsprintf(buf, TEXT("%lu"), (DWORD)completedSize);
+ pushstring(buf);
+ g_pluginExtra->ExecuteCodeSegment(g_progressCallback-1, 0);
+ }
+ }
+
+ if (g_lastVal != val)
+ SendMessage(g_hwndProgress, PBM_SETPOS, g_lastVal = val, 0);
+}
+
+void DetailsProgressHandler(UInt64 completedSize, UInt64 totalSize)
+{
+ int val = 0;
+
+ if (totalSize > 0)
+ {
+ val = GetPercentComplete(completedSize, totalSize);
+
+ TCHAR* buf = new TCHAR[g_stringsize];
+ TCHAR* buf2 = new TCHAR[g_stringsize];
+ wsprintf(buf, TEXT("%d%% (%d / %d MB)"), (int)(val?val/300:0), (int)(completedSize?completedSize/(1024*1024):0), (int)(totalSize/(1024*1024)));
+ wsprintf(buf2, g_sDetails, buf);
+ SetWindowText(g_hwndText, buf2);
+ delete[] buf;
+ delete[] buf2;
+ }
+
+ if (g_lastVal != val)
+ SendMessage(g_hwndProgress, PBM_SETPOS, g_lastVal = val, 0);
+}
+
+EXTRACTFUNC(Extract)
+{
+ UStringVector skipPatterns;
+ PopSkipPatterns(skipPatterns);
+ DoExtract(sArchive, outDir, true, true, (ExtractProgressHandler)SimpleProgressHandler, skipPatterns);
+}
+EXTRACTFUNCEND
+
+EXTRACTFUNC(ExtractWithDetails)
+{
+ g_sDetails = new TCHAR[string_size];
+ popstring(g_sDetails);
+ UStringVector skipPatterns;
+ PopSkipPatterns(skipPatterns);
+ DoExtract(sArchive, outDir, true, true, (ExtractProgressHandler)DetailsProgressHandler, skipPatterns);
+ delete[] g_sDetails;
+}
+EXTRACTFUNCEND
+
+EXTRACTFUNC(ExtractWithCallback)
+{
+ g_progressCallback = popint();
+ UStringVector skipPatterns;
+ PopSkipPatterns(skipPatterns);
+ DoExtract(sArchive, outDir, true, true, (ExtractProgressHandler)CallbackProgressHandler, skipPatterns);
+}
+EXTRACTFUNCEND
+
+EXTRACTFUNC(ExtractWithFileCallback)
+{
+ g_progressCallback = popint();
+ UStringVector skipPatterns;
+ PopSkipPatterns(skipPatterns);
+ DoExtractWithFile(sArchive, outDir, true, true, CallbackFileProgressHandler, skipPatterns);
+}
+EXTRACTFUNCEND
+
+extern "C" BOOL WINAPI DllMain(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
+{
+ g_hInstance2=(HINSTANCE)hInst;
+ if (ul_reason_for_call == DLL_PROCESS_ATTACH)
+ {
+ DoInitialize();
+ }
+ return TRUE;
+}
diff --git a/versions/zstd/CPP/7zip/Bundles/Nsis7z/nsis_tchar.h b/versions/zstd/CPP/7zip/Bundles/Nsis7z/nsis_tchar.h
new file mode 100644
index 0000000..210bab1
--- /dev/null
+++ b/versions/zstd/CPP/7zip/Bundles/Nsis7z/nsis_tchar.h
@@ -0,0 +1,229 @@
+/*
+ * nsis_tchar.h
+ *
+ * This file is a part of NSIS.
+ *
+ * Copyright (C) 1999-2013 Nullsoft and Contributors
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.
+ *
+ * For Unicode support by Jim Park -- 08/30/2007
+ */
+
+// Jim Park: Only those we use are listed here.
+
+#pragma once
+
+#ifdef _UNICODE
+
+#ifndef _T
+#define __T(x) L ## x
+#define _T(x) __T(x)
+#define _TEXT(x) __T(x)
+#endif
+
+#ifndef _TCHAR_DEFINED
+#define _TCHAR_DEFINED
+#if !defined(_NATIVE_WCHAR_T_DEFINED) && !defined(_WCHAR_T_DEFINED)
+typedef unsigned short TCHAR;
+#else
+typedef wchar_t TCHAR;
+#endif
+#endif
+
+
+// program
+#define _tenviron _wenviron
+#define __targv __wargv
+
+// printfs
+#define _ftprintf fwprintf
+#define _sntprintf _snwprintf
+#if (defined(_MSC_VER) && (_MSC_VER<=1310)) || defined(__MINGW32__)
+# define _stprintf swprintf
+#else
+# define _stprintf _swprintf
+#endif
+#define _tprintf wprintf
+#define _vftprintf vfwprintf
+#define _vsntprintf _vsnwprintf
+#if defined(_MSC_VER) && (_MSC_VER<=1310)
+# define _vstprintf vswprintf
+#else
+# define _vstprintf _vswprintf
+#endif
+
+// scanfs
+#define _tscanf wscanf
+#define _stscanf swscanf
+
+// string manipulations
+#define _tcscat wcscat
+#define _tcschr wcschr
+#define _tcsclen wcslen
+#define _tcscpy wcscpy
+#define _tcsdup _wcsdup
+#define _tcslen wcslen
+#define _tcsnccpy wcsncpy
+#define _tcsncpy wcsncpy
+#define _tcsrchr wcsrchr
+#define _tcsstr wcsstr
+#define _tcstok wcstok
+
+// string comparisons
+#define _tcscmp wcscmp
+#define _tcsicmp _wcsicmp
+#define _tcsncicmp _wcsnicmp
+#define _tcsncmp wcsncmp
+#define _tcsnicmp _wcsnicmp
+
+// upper / lower
+#define _tcslwr _wcslwr
+#define _tcsupr _wcsupr
+#define _totlower towlower
+#define _totupper towupper
+
+// conversions to numbers
+#define _tcstoi64 _wcstoi64
+#define _tcstol wcstol
+#define _tcstoul wcstoul
+#define _tstof _wtof
+#define _tstoi _wtoi
+#define _tstoi64 _wtoi64
+#define _ttoi _wtoi
+#define _ttoi64 _wtoi64
+#define _ttol _wtol
+
+// conversion from numbers to strings
+#define _itot _itow
+#define _ltot _ltow
+#define _i64tot _i64tow
+#define _ui64tot _ui64tow
+
+// file manipulations
+#define _tfopen _wfopen
+#define _topen _wopen
+#define _tremove _wremove
+#define _tunlink _wunlink
+
+// reading and writing to i/o
+#define _fgettc fgetwc
+#define _fgetts fgetws
+#define _fputts fputws
+#define _gettchar getwchar
+
+// directory
+#define _tchdir _wchdir
+
+// environment
+#define _tgetenv _wgetenv
+#define _tsystem _wsystem
+
+// time
+#define _tcsftime wcsftime
+
+#else // ANSI
+
+#ifndef _T
+#define _T(x) x
+#define _TEXT(x) x
+#endif
+
+#ifndef _TCHAR_DEFINED
+#define _TCHAR_DEFINED
+typedef char TCHAR;
+#endif
+
+// program
+#define _tenviron environ
+#define __targv __argv
+
+// printfs
+#define _ftprintf fprintf
+#define _sntprintf _snprintf
+#define _stprintf sprintf
+#define _tprintf printf
+#define _vftprintf vfprintf
+#define _vsntprintf _vsnprintf
+#define _vstprintf vsprintf
+
+// scanfs
+#define _tscanf scanf
+#define _stscanf sscanf
+
+// string manipulations
+#define _tcscat strcat
+#define _tcschr strchr
+#define _tcsclen strlen
+#define _tcscnlen strnlen
+#define _tcscpy strcpy
+#define _tcsdup _strdup
+#define _tcslen strlen
+#define _tcsnccpy strncpy
+#define _tcsrchr strrchr
+#define _tcsstr strstr
+#define _tcstok strtok
+
+// string comparisons
+#define _tcscmp strcmp
+#define _tcsicmp _stricmp
+#define _tcsncmp strncmp
+#define _tcsncicmp _strnicmp
+#define _tcsnicmp _strnicmp
+
+// upper / lower
+#define _tcslwr _strlwr
+#define _tcsupr _strupr
+
+#define _totupper toupper
+#define _totlower tolower
+
+// conversions to numbers
+#define _tcstol strtol
+#define _tcstoul strtoul
+#define _tstof atof
+#define _tstoi atoi
+#define _tstoi64 _atoi64
+#define _tstoi64 _atoi64
+#define _ttoi atoi
+#define _ttoi64 _atoi64
+#define _ttol atol
+
+// conversion from numbers to strings
+#define _i64tot _i64toa
+#define _itot _itoa
+#define _ltot _ltoa
+#define _ui64tot _ui64toa
+
+// file manipulations
+#define _tfopen fopen
+#define _topen _open
+#define _tremove remove
+#define _tunlink _unlink
+
+// reading and writing to i/o
+#define _fgettc fgetc
+#define _fgetts fgets
+#define _fputts fputs
+#define _gettchar getchar
+
+// directory
+#define _tchdir _chdir
+
+// environment
+#define _tgetenv getenv
+#define _tsystem system
+
+// time
+#define _tcsftime strftime
+
+#endif
+
+// is functions (the same in Unicode / ANSI)
+#define _istgraph isgraph
+#define _istascii __isascii
+
+#define __TFILE__ _T(__FILE__)
+#define __TDATE__ _T(__DATE__)
+#define __TTIME__ _T(__TIME__)
diff --git a/versions/zstd/CPP/7zip/Bundles/Nsis7z/pluginapi.cpp b/versions/zstd/CPP/7zip/Bundles/Nsis7z/pluginapi.cpp
new file mode 100644
index 0000000..69406a8
--- /dev/null
+++ b/versions/zstd/CPP/7zip/Bundles/Nsis7z/pluginapi.cpp
@@ -0,0 +1,292 @@
+#include "StdAfx.h"
+
+#ifdef _countof
+#define COUNTOF _countof
+#else
+#define COUNTOF(a) (sizeof(a)/sizeof(a[0]))
+#endif
+
+unsigned int g_stringsize;
+stack_t **g_stacktop;
+TCHAR *g_variables;
+
+// utility functions (not required but often useful)
+
+int NSISCALL popstring(TCHAR *str)
+{
+ stack_t *th;
+ if (!g_stacktop || !*g_stacktop) return 1;
+ th=(*g_stacktop);
+ if (str) lstrcpy(str,th->text);
+ *g_stacktop = th->next;
+ GlobalFree((HGLOBAL)th);
+ return 0;
+}
+
+int NSISCALL popstringn(TCHAR *str, int maxlen)
+{
+ stack_t *th;
+ if (!g_stacktop || !*g_stacktop) return 1;
+ th=(*g_stacktop);
+ if (str) lstrcpyn(str,th->text,maxlen?maxlen:g_stringsize);
+ *g_stacktop = th->next;
+ GlobalFree((HGLOBAL)th);
+ return 0;
+}
+
+void NSISCALL pushstring(const TCHAR *str)
+{
+ stack_t *th;
+ if (!g_stacktop) return;
+ th=(stack_t*)GlobalAlloc(GPTR,(sizeof(stack_t)+(g_stringsize)*sizeof(TCHAR)));
+ lstrcpyn(th->text,str,g_stringsize);
+ th->next=*g_stacktop;
+ *g_stacktop=th;
+}
+
+TCHAR* NSISCALL getuservariable(const int varnum)
+{
+ if (varnum < 0 || varnum >= __INST_LAST) return NULL;
+ return g_variables+varnum*g_stringsize;
+}
+
+void NSISCALL setuservariable(const int varnum, const TCHAR *var)
+{
+ if (var != NULL && varnum >= 0 && varnum < __INST_LAST)
+ lstrcpy(g_variables + varnum*g_stringsize, var);
+}
+
+#ifdef _UNICODE
+int NSISCALL PopStringA(char* ansiStr)
+{
+ wchar_t* wideStr = (wchar_t*) GlobalAlloc(GPTR, g_stringsize*sizeof(wchar_t));
+ int rval = popstring(wideStr);
+ WideCharToMultiByte(CP_ACP, 0, wideStr, -1, ansiStr, g_stringsize, NULL, NULL);
+ GlobalFree((HGLOBAL)wideStr);
+ return rval;
+}
+
+int NSISCALL PopStringNA(char* ansiStr, int maxlen)
+{
+ int realLen = maxlen ? maxlen : g_stringsize;
+ wchar_t* wideStr = (wchar_t*) GlobalAlloc(GPTR, realLen*sizeof(wchar_t));
+ int rval = popstringn(wideStr, realLen);
+ WideCharToMultiByte(CP_ACP, 0, wideStr, -1, ansiStr, realLen, NULL, NULL);
+ GlobalFree((HGLOBAL)wideStr);
+ return rval;
+}
+
+void NSISCALL PushStringA(const char* ansiStr)
+{
+ wchar_t* wideStr = (wchar_t*) GlobalAlloc(GPTR, g_stringsize*sizeof(wchar_t));
+ MultiByteToWideChar(CP_ACP, 0, ansiStr, -1, wideStr, g_stringsize);
+ pushstring(wideStr);
+ GlobalFree((HGLOBAL)wideStr);
+ return;
+}
+
+void NSISCALL GetUserVariableW(const int varnum, wchar_t* wideStr)
+{
+ lstrcpyW(wideStr, getuservariable(varnum));
+}
+
+void NSISCALL GetUserVariableA(const int varnum, char* ansiStr)
+{
+ wchar_t* wideStr = getuservariable(varnum);
+ WideCharToMultiByte(CP_ACP, 0, wideStr, -1, ansiStr, g_stringsize, NULL, NULL);
+}
+
+void NSISCALL SetUserVariableA(const int varnum, const char* ansiStr)
+{
+ if (ansiStr != NULL && varnum >= 0 && varnum < __INST_LAST)
+ {
+ wchar_t* wideStr = g_variables + varnum * g_stringsize;
+ MultiByteToWideChar(CP_ACP, 0, ansiStr, -1, wideStr, g_stringsize);
+ }
+}
+
+#else
+// ANSI defs
+int NSISCALL PopStringW(wchar_t* wideStr)
+{
+ char* ansiStr = (char*) GlobalAlloc(GPTR, g_stringsize);
+ int rval = popstring(ansiStr);
+ MultiByteToWideChar(CP_ACP, 0, ansiStr, -1, wideStr, g_stringsize);
+ GlobalFree((HGLOBAL)ansiStr);
+ return rval;
+}
+
+int NSISCALL PopStringNW(wchar_t* wideStr, int maxlen)
+{
+ int realLen = maxlen ? maxlen : g_stringsize;
+ char* ansiStr = (char*) GlobalAlloc(GPTR, realLen);
+ int rval = popstringn(ansiStr, realLen);
+ MultiByteToWideChar(CP_ACP, 0, ansiStr, -1, wideStr, realLen);
+ GlobalFree((HGLOBAL)ansiStr);
+ return rval;
+}
+
+void NSISCALL PushStringW(wchar_t* wideStr)
+{
+ char* ansiStr = (char*) GlobalAlloc(GPTR, g_stringsize);
+ WideCharToMultiByte(CP_ACP, 0, wideStr, -1, ansiStr, g_stringsize, NULL, NULL);
+ pushstring(ansiStr);
+ GlobalFree((HGLOBAL)ansiStr);
+}
+
+void NSISCALL GetUserVariableW(const int varnum, wchar_t* wideStr)
+{
+ char* ansiStr = getuservariable(varnum);
+ MultiByteToWideChar(CP_ACP, 0, ansiStr, -1, wideStr, g_stringsize);
+}
+
+void NSISCALL GetUserVariableA(const int varnum, char* ansiStr)
+{
+ lstrcpyA(ansiStr, getuservariable(varnum));
+}
+
+void NSISCALL SetUserVariableW(const int varnum, const wchar_t* wideStr)
+{
+ if (wideStr != NULL && varnum >= 0 && varnum < __INST_LAST)
+ {
+ char* ansiStr = g_variables + varnum * g_stringsize;
+ WideCharToMultiByte(CP_ACP, 0, wideStr, -1, ansiStr, g_stringsize, NULL, NULL);
+ }
+}
+#endif
+
+// playing with integers
+
+INT_PTR NSISCALL nsishelper_str_to_ptr(const TCHAR *s)
+{
+ INT_PTR v=0;
+ if (*s == _T('0') && (s[1] == _T('x') || s[1] == _T('X')))
+ {
+ s++;
+ for (;;)
+ {
+ int c=*(++s);
+ if (c >= _T('0') && c <= _T('9')) c-=_T('0');
+ else if (c >= _T('a') && c <= _T('f')) c-=_T('a')-10;
+ else if (c >= _T('A') && c <= _T('F')) c-=_T('A')-10;
+ else break;
+ v<<=4;
+ v+=c;
+ }
+ }
+ else if (*s == _T('0') && s[1] <= _T('7') && s[1] >= _T('0'))
+ {
+ for (;;)
+ {
+ int c=*(++s);
+ if (c >= _T('0') && c <= _T('7')) c-=_T('0');
+ else break;
+ v<<=3;
+ v+=c;
+ }
+ }
+ else
+ {
+ int sign=0;
+ if (*s == _T('-')) sign++; else s--;
+ for (;;)
+ {
+ int c=*(++s) - _T('0');
+ if (c < 0 || c > 9) break;
+ v*=10;
+ v+=c;
+ }
+ if (sign) v = -v;
+ }
+
+ return v;
+}
+
+unsigned int NSISCALL myatou(const TCHAR *s)
+{
+ unsigned int v=0;
+
+ for (;;)
+ {
+ unsigned int c=*s++;
+ if (c >= _T('0') && c <= _T('9')) c-=_T('0');
+ else break;
+ v*=10;
+ v+=c;
+ }
+ return v;
+}
+
+int NSISCALL myatoi_or(const TCHAR *s)
+{
+ int v=0;
+ if (*s == _T('0') && (s[1] == _T('x') || s[1] == _T('X')))
+ {
+ s++;
+ for (;;)
+ {
+ int c=*(++s);
+ if (c >= _T('0') && c <= _T('9')) c-=_T('0');
+ else if (c >= _T('a') && c <= _T('f')) c-=_T('a')-10;
+ else if (c >= _T('A') && c <= _T('F')) c-=_T('A')-10;
+ else break;
+ v<<=4;
+ v+=c;
+ }
+ }
+ else if (*s == _T('0') && s[1] <= _T('7') && s[1] >= _T('0'))
+ {
+ for (;;)
+ {
+ int c=*(++s);
+ if (c >= _T('0') && c <= _T('7')) c-=_T('0');
+ else break;
+ v<<=3;
+ v+=c;
+ }
+ }
+ else
+ {
+ int sign=0;
+ if (*s == _T('-')) sign++; else s--;
+ for (;;)
+ {
+ int c=*(++s) - _T('0');
+ if (c < 0 || c > 9) break;
+ v*=10;
+ v+=c;
+ }
+ if (sign) v = -v;
+ }
+
+ // Support for simple ORed expressions
+ if (*s == _T('|'))
+ {
+ v |= myatoi_or(s+1);
+ }
+
+ return v;
+}
+
+INT_PTR NSISCALL popintptr()
+{
+ TCHAR buf[128];
+ if (popstringn(buf,COUNTOF(buf)))
+ return 0;
+ return nsishelper_str_to_ptr(buf);
+}
+
+int NSISCALL popint_or()
+{
+ TCHAR buf[128];
+ if (popstringn(buf,COUNTOF(buf)))
+ return 0;
+ return myatoi_or(buf);
+}
+
+void NSISCALL pushintptr(INT_PTR value)
+{
+ TCHAR buffer[30];
+ wsprintf(buffer, sizeof(void*) > 4 ? _T("%Id") : _T("%d"), value);
+ pushstring(buffer);
+}
diff --git a/versions/zstd/CPP/7zip/Bundles/Nsis7z/pluginapi.h b/versions/zstd/CPP/7zip/Bundles/Nsis7z/pluginapi.h
new file mode 100644
index 0000000..f607b11
--- /dev/null
+++ b/versions/zstd/CPP/7zip/Bundles/Nsis7z/pluginapi.h
@@ -0,0 +1,115 @@
+#ifndef ___NSIS_PLUGIN__H___
+#define ___NSIS_PLUGIN__H___
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "api.h"
+#ifdef _UNICODE
+#ifndef _T
+#define __T(x) L ## x
+#define _T(x) __T(x)
+#define _TEXT(x) __T(x)
+#endif
+#else
+#ifndef _T
+#define _T(x) x
+#define _TEXT(x) x
+#endif
+#endif
+
+#ifndef NSISCALL
+# define NSISCALL __stdcall
+#endif
+
+#define EXDLL_INIT() { \
+ g_stringsize=string_size; \
+ g_stacktop=stacktop; \
+ g_variables=variables; }
+
+typedef struct _stack_t {
+ struct _stack_t *next;
+ TCHAR text[1]; // this should be the length of string_size
+} stack_t;
+
+enum
+{
+INST_0, // $0
+INST_1, // $1
+INST_2, // $2
+INST_3, // $3
+INST_4, // $4
+INST_5, // $5
+INST_6, // $6
+INST_7, // $7
+INST_8, // $8
+INST_9, // $9
+INST_R0, // $R0
+INST_R1, // $R1
+INST_R2, // $R2
+INST_R3, // $R3
+INST_R4, // $R4
+INST_R5, // $R5
+INST_R6, // $R6
+INST_R7, // $R7
+INST_R8, // $R8
+INST_R9, // $R9
+INST_CMDLINE, // $CMDLINE
+INST_INSTDIR, // $INSTDIR
+INST_OUTDIR, // $OUTDIR
+INST_EXEDIR, // $EXEDIR
+INST_LANG, // $LANGUAGE
+__INST_LAST
+};
+
+extern unsigned int g_stringsize;
+extern stack_t **g_stacktop;
+extern TCHAR *g_variables;
+
+void NSISCALL pushstring(const TCHAR *str);
+void NSISCALL pushintptr(INT_PTR value);
+#define pushint(v) pushintptr((INT_PTR)(v))
+int NSISCALL popstring(TCHAR *str); // 0 on success, 1 on empty stack
+int NSISCALL popstringn(TCHAR *str, int maxlen); // with length limit, pass 0 for g_stringsize
+INT_PTR NSISCALL popintptr();
+#define popint() ( (int) popintptr() )
+int NSISCALL popint_or(); // with support for or'ing (2|4|8)
+INT_PTR NSISCALL nsishelper_str_to_ptr(const TCHAR *s);
+#define myatoi(s) ( (int) nsishelper_str_to_ptr(s) ) // converts a string to an integer
+unsigned int NSISCALL myatou(const TCHAR *s); // converts a string to an unsigned integer, decimal only
+int NSISCALL myatoi_or(const TCHAR *s); // with support for or'ing (2|4|8)
+TCHAR* NSISCALL getuservariable(const int varnum);
+void NSISCALL setuservariable(const int varnum, const TCHAR *var);
+
+#ifdef _UNICODE
+#define PopStringW(x) popstring(x)
+#define PushStringW(x) pushstring(x)
+#define SetUserVariableW(x,y) setuservariable(x,y)
+
+int NSISCALL PopStringA(char* ansiStr);
+void NSISCALL PushStringA(const char* ansiStr);
+void NSISCALL GetUserVariableW(const int varnum, wchar_t* wideStr);
+void NSISCALL GetUserVariableA(const int varnum, char* ansiStr);
+void NSISCALL SetUserVariableA(const int varnum, const char* ansiStr);
+
+#else
+// ANSI defs
+
+#define PopStringA(x) popstring(x)
+#define PushStringA(x) pushstring(x)
+#define SetUserVariableA(x,y) setuservariable(x,y)
+
+int NSISCALL PopStringW(wchar_t* wideStr);
+void NSISCALL PushStringW(wchar_t* wideStr);
+void NSISCALL GetUserVariableW(const int varnum, wchar_t* wideStr);
+void NSISCALL GetUserVariableA(const int varnum, char* ansiStr);
+void NSISCALL SetUserVariableW(const int varnum, const wchar_t* wideStr);
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif//!___NSIS_PLUGIN__H___
diff --git a/versions/zstd/CPP/7zip/Bundles/Nsis7z/resource.h b/versions/zstd/CPP/7zip/Bundles/Nsis7z/resource.h
new file mode 100644
index 0000000..08340b3
--- /dev/null
+++ b/versions/zstd/CPP/7zip/Bundles/Nsis7z/resource.h
@@ -0,0 +1,19 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by resource.rc
+//
+#define MY_VER_BUILD 0
+#define DBG_FL 0
+#define MY_VER_MAJOR 9
+#define MY_VER_MINOR 20
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1000
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/versions/zstd/CPP/7zip/Bundles/Nsis7z/resource.rc b/versions/zstd/CPP/7zip/Bundles/Nsis7z/resource.rc
new file mode 100644
index 0000000..18da943
--- /dev/null
+++ b/versions/zstd/CPP/7zip/Bundles/Nsis7z/resource.rc
@@ -0,0 +1,99 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (United States) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 25,01,0,0
+ PRODUCTVERSION 25,01,0,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "Igor Pavlov"
+ VALUE "FileDescription", "7-Zip NSIS Plug-in"
+ VALUE "FileVersion", "25.01.0.0"
+ VALUE "InternalName", "nsis7z"
+ VALUE "LegalCopyright", "Copyright (c) 1999-2025 Igor Pavlov, Nik Medved, Marek Mizanin, Stuart Welch"
+ VALUE "OriginalFilename", "nsis7z.dll"
+ VALUE "ProductName", "7-Zip"
+ VALUE "ProductVersion", "25.01.0.0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+#endif // English (United States) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/versions/zstd/CPP/7zip/UI/NSIS/ExtractCallbackConsole.cpp b/versions/zstd/CPP/7zip/UI/NSIS/ExtractCallbackConsole.cpp
new file mode 100644
index 0000000..f0cb06a
--- /dev/null
+++ b/versions/zstd/CPP/7zip/UI/NSIS/ExtractCallbackConsole.cpp
@@ -0,0 +1,163 @@
+// ExtractCallbackConsole.h
+
+#include "StdAfx.h"
+
+#include "Common/Common.h"
+#include "ExtractCallbackConsole.h"
+#include "UserInputUtils2.h"
+#include "NSISBreak.h"
+
+#include "Common/Wildcard.h"
+
+#include "Windows/FileDir.h"
+#include "Windows/FileFind.h"
+#include "Windows/TimeUtils.h"
+#include "Windows/Defs.h"
+#include "Windows/PropVariant.h"
+#include "Windows/ErrorMsg.h"
+#include "Windows/PropVariantConv.h"
+
+#include "7zip/Common/FilePathAutoRename.h"
+
+#include "7zip/UI/Common/ExtractingFilePath.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NDir;
+
+extern HWND g_hwndProgress;
+
+void CExtractCallbackConsole::UpdateProgress()
+{
+ // Prima controlla se c'è il callback con filename (nuova funzione)
+ if (ProgressWithFileHandler != NULL)
+ {
+ if (completedSize != -1 || totalSize > 0)
+ ProgressWithFileHandler(completedSize, totalSize, CurrentFileName.Ptr());
+ else
+ ProgressWithFileHandler(0, 0, CurrentFileName.Ptr());
+ }
+ // Altrimenti usa il callback originale (per compatibilità)
+ else if (ProgressHandler != NULL)
+ {
+ if (completedSize != -1 || totalSize > 0)
+ ProgressHandler(completedSize, totalSize);
+ else
+ ProgressHandler(0, 0);
+ }
+}
+
+STDMETHODIMP CExtractCallbackConsole::SetTotal(UInt64 val)
+{
+ totalSize = val;
+ UpdateProgress();
+ if (NNSISBreak::TestBreakSignal())
+ return E_ABORT;
+ return S_OK;
+}
+
+STDMETHODIMP CExtractCallbackConsole::SetCompleted(const UInt64 *val)
+{
+ completedSize = *val;
+ UpdateProgress();
+ if (NNSISBreak::TestBreakSignal())
+ return E_ABORT;
+ return S_OK;
+}
+
+STDMETHODIMP CExtractCallbackConsole::AskOverwrite(
+ const wchar_t *existName, const FILETIME *, const UInt64 *,
+ const wchar_t *newName, const FILETIME *, const UInt64 *,
+ Int32 *answer)
+{
+ *answer = NOverwriteAnswer::kYesToAll;
+ return S_OK;
+}
+
+STDMETHODIMP CExtractCallbackConsole::PrepareOperation(const wchar_t *name, Int32 isFolder, Int32 askExtractMode, const UInt64 *position)
+{
+ // Memorizza il nome del file corrente per passarlo al callback
+ CurrentFileName = name;
+ return S_OK;
+}
+
+STDMETHODIMP CExtractCallbackConsole::MessageError(const wchar_t *message)
+{
+ NumFileErrorsInCurrentArchive++;
+ NumFileErrors++;
+ return S_OK;
+}
+
+STDMETHODIMP CExtractCallbackConsole::SetOperationResult(Int32 opRes, Int32 encrypted)
+{
+ switch(opRes)
+ {
+ case NArchive::NExtract::NOperationResult::kOK:
+ break;
+ default:
+ {
+ NumFileErrorsInCurrentArchive++;
+ NumFileErrors++;
+
+ }
+ }
+ return S_OK;
+}
+
+#ifndef Z7_NO_CRYPTO
+
+HRESULT CExtractCallbackConsole::SetPassword(const UString &password)
+{
+ PasswordIsDefined = true;
+ Password = password;
+ return S_OK;
+}
+
+STDMETHODIMP CExtractCallbackConsole::CryptoGetTextPassword(BSTR *password)
+{
+ if (!PasswordIsDefined)
+ {
+ Password = GetPassword(OutStream);
+ PasswordIsDefined = true;
+ }
+ return StringToBstr(Password, password);
+}
+
+#endif
+
+HRESULT CExtractCallbackConsole::BeforeOpen(const wchar_t *name, bool testMode)
+{
+ NumArchives++;
+ NumFileErrorsInCurrentArchive = 0;
+ return S_OK;
+}
+
+HRESULT CExtractCallbackConsole::OpenResult(const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result)
+{
+ if (result != S_OK)
+ {
+ NumArchiveErrors++;
+ }
+ return S_OK;
+}
+
+HRESULT CExtractCallbackConsole::ThereAreNoFiles()
+{
+ return S_OK;
+}
+
+HRESULT CExtractCallbackConsole::ExtractResult(HRESULT result)
+{
+ if (result == S_OK)
+ {
+ if (NumFileErrorsInCurrentArchive != 0)
+ {
+ NumArchiveErrors++;
+ }
+ return result;
+ }
+ NumArchiveErrors++;
+ if (result == E_ABORT || result == ERROR_DISK_FULL)
+ return result;
+ return S_OK;
+}
diff --git a/versions/zstd/CPP/7zip/UI/NSIS/ExtractCallbackConsole.h b/versions/zstd/CPP/7zip/UI/NSIS/ExtractCallbackConsole.h
new file mode 100644
index 0000000..cb4c236
--- /dev/null
+++ b/versions/zstd/CPP/7zip/UI/NSIS/ExtractCallbackConsole.h
@@ -0,0 +1,98 @@
+// ExtractCallbackConsole.h
+// NSIS version adapted for 7-Zip 25.01 API
+
+#ifndef __EXTRACTCALLBACKCONSOLE_H
+#define __EXTRACTCALLBACKCONSOLE_H
+
+#include "Common/MyCom.h"
+#include "Common/MyString.h"
+#include "Common/StdOutStream.h"
+#include "7zip/Common/FileStreams.h"
+#include "7zip/IPassword.h"
+#include "7zip/Archive/IArchive.h"
+#include "7zip/UI/Common/ArchiveExtractCallback.h"
+#include "7zip/UI/Console/OpenCallbackConsole.h"
+
+typedef void (*ExtractProgressHandler)(UInt64 completedSize, UInt64 totalSize);
+typedef void (*ExtractProgressWithFileHandler)(UInt64 completedSize, UInt64 totalSize, const wchar_t *fileName);
+
+class CExtractCallbackConsole Z7_final:
+ public IFolderArchiveExtractCallback,
+ public IExtractCallbackUI,
+#ifndef Z7_NO_CRYPTO
+ public ICryptoGetTextPassword,
+#endif
+ public COpenCallbackConsole,
+ public CMyUnknownImp
+{
+ Z7_COM_QI_BEGIN2(IFolderArchiveExtractCallback)
+#ifndef Z7_NO_CRYPTO
+ Z7_COM_QI_ENTRY(ICryptoGetTextPassword)
+#endif
+ Z7_COM_QI_END
+ Z7_COM_ADDREF_RELEASE
+
+ // IProgress
+ Z7_IFACE_COM7_IMP(IProgress)
+
+ // IFolderArchiveExtractCallback
+ Z7_IFACE_COM7_IMP(IFolderArchiveExtractCallback)
+
+ // IExtractCallbackUI (non-COM interface)
+ Z7_IFACE_IMP(IExtractCallbackUI)
+
+#ifndef Z7_NO_CRYPTO
+ Z7_IFACE_COM7_IMP(ICryptoGetTextPassword)
+#endif
+
+public:
+#ifndef Z7_NO_CRYPTO
+ bool PasswordIsDefined;
+ UString Password;
+#endif
+
+ UInt64 NumArchives;
+ UInt64 NumArchiveErrors;
+ UInt64 NumFileErrors;
+ UInt64 NumFileErrorsInCurrentArchive;
+
+ CStdOutStream *OutStream;
+
+ UInt64 totalSize, completedSize, lastVal;
+
+ ExtractProgressHandler ProgressHandler;
+ ExtractProgressWithFileHandler ProgressWithFileHandler;
+ UString CurrentFileName;
+
+ CExtractCallbackConsole():
+ PasswordIsDefined(false),
+ NumArchives(0),
+ NumArchiveErrors(0),
+ NumFileErrors(0),
+ NumFileErrorsInCurrentArchive(0),
+ OutStream(NULL),
+ totalSize((UInt64)(Int64)-1),
+ completedSize(0),
+ lastVal(0),
+ ProgressHandler(NULL),
+ ProgressWithFileHandler(NULL)
+ {}
+
+ void Init()
+ {
+ NumArchives = 0;
+ NumArchiveErrors = 0;
+ NumFileErrors = 0;
+ NumFileErrorsInCurrentArchive = 0;
+
+ totalSize = (UInt64)(Int64)-1;
+ completedSize = 0;
+ lastVal = 0;
+ ProgressHandler = NULL;
+ ProgressWithFileHandler = NULL;
+ }
+
+ void UpdateProgress();
+};
+
+#endif
diff --git a/versions/zstd/CPP/7zip/UI/NSIS/Main.cpp b/versions/zstd/CPP/7zip/UI/NSIS/Main.cpp
new file mode 100644
index 0000000..bcc392b
--- /dev/null
+++ b/versions/zstd/CPP/7zip/UI/NSIS/Main.cpp
@@ -0,0 +1,313 @@
+// Main.cpp
+
+#include "StdAfx.h"
+
+#include "Common/Common.h"
+#include "Common/MyInitGuid.h"
+
+#include "Common/CommandLineParser.h"
+#include "Common/MyException.h"
+#include "Common/IntToString.h"
+#include "Common/StdOutStream.h"
+#include "Common/StringConvert.h"
+#include "Common/StringToInt.h"
+
+#include "Windows/FileDir.h"
+#include "Windows/FileName.h"
+#include "Windows/Defs.h"
+#include "Windows/ErrorMsg.h"
+#ifdef _WIN32
+#include "Windows/MemoryLock.h"
+#endif
+
+#include "7zip/IPassword.h"
+#include "7zip/ICoder.h"
+#include "7zip/UI/Common/UpdateAction.h"
+#include "7zip/UI/Common/Update.h"
+#include "7zip/UI/Common/Extract.h"
+#include "7zip/UI/Common/ArchiveCommandLine.h"
+#include "7zip/UI/Common/ExitCode.h"
+#ifdef EXTERNAL_CODECS
+#include "7zip/UI/Common/LoadCodecs.h"
+#endif
+
+//#include "../../Compress/LZMA_Alone/LzmaBenchCon.h"
+
+#include "7zip/UI/Console/OpenCallbackConsole.h"
+#include "ExtractCallbackConsole.h"
+
+#include "7zip/MyVersion.h"
+
+#if defined( _WIN32) && defined( _7ZIP_LARGE_PAGES)
+extern "C"
+{
+#include "C/Alloc.h"
+}
+#endif
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NCommandLineParser;
+
+HINSTANCE g_hInstance = 0;
+
+// ---------------------------
+// exception messages
+
+#ifndef _WIN32
+static void GetArguments(int numArguments, const char *arguments[], UStringVector &parts)
+{
+ parts.Clear();
+ for(int i = 0; i < numArguments; i++)
+ {
+ UString s = MultiByteToUnicodeString(arguments[i]);
+ parts.Add(s);
+ }
+}
+#endif
+
+#ifdef EXTERNAL_CODECS
+static void PrintString(CStdOutStream &stdStream, const AString &s, int size)
+{
+ int len = s.Length();
+ stdStream << s;
+ for (int i = len; i < size; i++)
+ stdStream << ' ';
+}
+#endif
+
+static inline char GetHex(Byte value)
+{
+ return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
+}
+
+#ifdef _WIN32
+void SwitchFileAPIEncoding(BOOL ansi)
+{
+ if (ansi)
+ {
+ SetFileApisToOEM();
+ }
+ else
+ {
+ SetFileApisToANSI();
+ }
+}
+#endif
+
+int DoExtractArchive(UString archive, UString targetDir, bool overwrite, bool extractPaths, ExtractProgressHandler epc, const UStringVector& skipPatterns)
+{
+ CCodecs *codecs = new CCodecs;
+ CMyComPtr compressCodecsInfo = codecs;
+ HRESULT result = codecs->Load();
+
+ if (result != S_OK)
+ throw CSystemException(result);
+
+ if (codecs->Formats.Size() == 0) throw -1;
+
+ CIntVector formatIndices;
+
+ if (!codecs->FindFormatForArchiveType(L"7z", formatIndices))
+ {
+ throw -1;
+ }
+
+ BOOL bApisAreAnsi = AreFileApisANSI();
+
+#ifdef _WIN32
+ if (bApisAreAnsi)
+ SwitchFileAPIEncoding(bApisAreAnsi);
+#endif
+
+ CExtractCallbackConsole *ecs = new CExtractCallbackConsole();
+ CMyComPtr extractCallback = ecs;
+ ecs->Init();
+ ecs->ProgressHandler = epc; // Imposta DOPO Init()
+
+ COpenCallbackConsole openCallback;
+
+ CExtractOptions eo;
+ eo.StdOutMode = false;
+ eo.PathMode = extractPaths?NExtract::NPathMode::kCurPaths:NExtract::NPathMode::kNoPaths;
+ eo.TestMode = false;
+ eo.OverwriteMode = overwrite?NExtract::NOverwriteMode::kOverwrite:NExtract::NOverwriteMode::kSkip;
+ eo.OutputDir = targetDir;
+ eo.YesToAll = true;
+#ifdef COMPRESS_MT
+ CObjectVector prp;
+ eo.Properties = prp;
+#endif
+ UString errorMessage;
+ CDecompressStat stat;
+ NWildcard::CCensor wildcardCensor;
+ NWildcard::CCensorPathProps props;
+ props.Recursive = true;
+ props.WildcardMatching = true;
+ wildcardCensor.AddItem(NWildcard::ECensorPathMode::k_FullPath, true, L"*", props);
+ for (unsigned i = 0; i < skipPatterns.Size(); i++)
+ {
+ const UString &p = skipPatterns[i];
+ if (p.IsEmpty()) continue;
+ // Keep only single-name patterns: multi-segment ones land in a separate Pair
+ // and would be silently ignored by Pairs.Front().Head below.
+ if (p.Find(L'\\') >= 0 || p.Find(L'/') >= 0) continue;
+ wildcardCensor.AddItem(NWildcard::ECensorPathMode::k_FullPath, false, p, props);
+ }
+ UStringVector ArchivePathsSorted;
+ UStringVector ArchivePathsFullSorted;
+ ArchivePathsSorted.Add(archive);
+ UString fullPath;
+ NFile::NDir::MyGetFullPathName(archive, fullPath);
+ ArchivePathsFullSorted.Add(fullPath);
+
+ UStringVector v1, v2;
+ v1.Add(fs2us(archive));
+ v2.Add(fs2us(archive));
+ const NWildcard::CCensorNode &wildcardCensorHead =
+ wildcardCensor.Pairs.Front().Head;
+
+ result = Extract(
+ codecs, CObjectVector(), CIntVector(),
+ v1, v2,
+ wildcardCensorHead,
+ eo, ecs, ecs, ecs,
+#ifndef Z7_SFX
+ NULL, // hash
+#endif
+ errorMessage, stat);
+
+#ifdef _WIN32
+ if (bApisAreAnsi)
+ SwitchFileAPIEncoding(!bApisAreAnsi);
+#endif
+
+
+ if (!errorMessage.IsEmpty())
+ {
+ if (result == S_OK)
+ result = E_FAIL;
+ }
+
+ if (ecs->NumArchiveErrors != 0 || ecs->NumFileErrors != 0)
+ {
+ if (result != S_OK)
+ throw CSystemException(result);
+
+ return NExitCode::kFatalError;
+ }
+
+ if (result != S_OK)
+ throw CSystemException(result);
+
+ return 0;
+}
+
+int DoExtractArchiveWithFile(UString archive, UString targetDir, bool overwrite, bool extractPaths, ExtractProgressWithFileHandler epc, const UStringVector& skipPatterns)
+{
+ CCodecs *codecs = new CCodecs;
+ CMyComPtr compressCodecsInfo = codecs;
+ HRESULT result = codecs->Load();
+
+ if (result != S_OK)
+ throw CSystemException(result);
+
+ if (codecs->Formats.Size() == 0) throw -1;
+
+ CIntVector formatIndices;
+
+ if (!codecs->FindFormatForArchiveType(L"7z", formatIndices))
+ {
+ throw -1;
+ }
+
+ BOOL bApisAreAnsi = AreFileApisANSI();
+
+#ifdef _WIN32
+ if (bApisAreAnsi)
+ SwitchFileAPIEncoding(bApisAreAnsi);
+#endif
+
+ CExtractCallbackConsole *ecs = new CExtractCallbackConsole();
+ CMyComPtr extractCallback = ecs;
+ ecs->Init();
+ ecs->ProgressWithFileHandler = epc; // Imposta DOPO Init() per evitare che venga resettato
+
+ COpenCallbackConsole openCallback;
+
+ CExtractOptions eo;
+ eo.StdOutMode = false;
+ eo.PathMode = extractPaths?NExtract::NPathMode::kCurPaths:NExtract::NPathMode::kNoPaths;
+ eo.TestMode = false;
+ eo.OverwriteMode = overwrite?NExtract::NOverwriteMode::kOverwrite:NExtract::NOverwriteMode::kSkip;
+ eo.OutputDir = targetDir;
+ eo.YesToAll = true;
+#ifdef COMPRESS_MT
+ CObjectVector prp;
+ eo.Properties = prp;
+#endif
+ UString errorMessage;
+ CDecompressStat stat;
+ NWildcard::CCensor wildcardCensor;
+ NWildcard::CCensorPathProps props;
+ props.Recursive = true;
+ props.WildcardMatching = true;
+ wildcardCensor.AddItem(NWildcard::ECensorPathMode::k_FullPath, true, L"*", props);
+ for (unsigned i = 0; i < skipPatterns.Size(); i++)
+ {
+ const UString &p = skipPatterns[i];
+ if (p.IsEmpty()) continue;
+ // Keep only single-name patterns: multi-segment ones land in a separate Pair
+ // and would be silently ignored by Pairs.Front().Head below.
+ if (p.Find(L'\\') >= 0 || p.Find(L'/') >= 0) continue;
+ wildcardCensor.AddItem(NWildcard::ECensorPathMode::k_FullPath, false, p, props);
+ }
+ UStringVector ArchivePathsSorted;
+ UStringVector ArchivePathsFullSorted;
+ ArchivePathsSorted.Add(archive);
+ UString fullPath;
+ NFile::NDir::MyGetFullPathName(archive, fullPath);
+ ArchivePathsFullSorted.Add(fullPath);
+
+ UStringVector v1, v2;
+ v1.Add(fs2us(archive));
+ v2.Add(fs2us(archive));
+ const NWildcard::CCensorNode &wildcardCensorHead =
+ wildcardCensor.Pairs.Front().Head;
+
+ result = Extract(
+ codecs, CObjectVector(), CIntVector(),
+ v1, v2,
+ wildcardCensorHead,
+ eo, ecs, ecs, ecs,
+#ifndef Z7_SFX
+ NULL, // hash
+#endif
+ errorMessage, stat);
+
+#ifdef _WIN32
+ if (bApisAreAnsi)
+ SwitchFileAPIEncoding(!bApisAreAnsi);
+#endif
+
+
+ if (!errorMessage.IsEmpty())
+ {
+ if (result == S_OK)
+ result = E_FAIL;
+ }
+
+ if (ecs->NumArchiveErrors != 0 || ecs->NumFileErrors != 0)
+ {
+ if (result != S_OK)
+ throw CSystemException(result);
+
+ return NExitCode::kFatalError;
+ }
+
+ if (result != S_OK)
+ throw CSystemException(result);
+
+ return 0;
+}
+
diff --git a/versions/zstd/CPP/7zip/UI/NSIS/MainAr.cpp b/versions/zstd/CPP/7zip/UI/NSIS/MainAr.cpp
new file mode 100644
index 0000000..425c767
--- /dev/null
+++ b/versions/zstd/CPP/7zip/UI/NSIS/MainAr.cpp
@@ -0,0 +1,109 @@
+// MainAr.cpp
+
+#include "StdAfx.h"
+
+// #include
+
+#include "Common/Common.h"
+
+#include "Windows/ErrorMsg.h"
+
+#include "Common/StdOutStream.h"
+#include "Common/NewHandler.h"
+#include "Common/MyException.h"
+#include "Common/StringConvert.h"
+
+#include "7zip/UI/Common/ExitCode.h"
+#include "7zip/UI/Common/ArchiveCommandLine.h"
+#include "ExtractCallbackConsole.h"
+#include "NSISBreak.h"
+
+using namespace NWindows;
+
+#ifdef _WIN32
+
+#pragma warning(disable : 4996)
+
+#ifndef _UNICODE
+bool g_IsNT = false;
+#endif
+#if !defined(_UNICODE) || !defined(_WIN64)
+static inline bool IsItWindowsNT()
+{
+ OSVERSIONINFO versionInfo;
+ versionInfo.dwOSVersionInfoSize = sizeof(versionInfo);
+ if (!::GetVersionEx(&versionInfo))
+ return false;
+ return (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT);
+}
+#endif
+#endif
+
+void DoInitialize()
+{
+ #ifdef _WIN32
+
+ #ifdef _UNICODE
+ #ifndef _WIN64
+ if (!IsItWindowsNT())
+ {
+ //(*g_StdStream) << "This program requires Windows NT/2000/2003/2008/XP/Vista";
+ // return NExitCode::kFatalError;
+ return;
+ }
+ #endif
+ #else
+ g_IsNT = IsItWindowsNT();
+ #endif
+
+ #endif
+}
+
+
+extern int DoExtractArchive(UString archive, UString targetDir, bool overwrite, bool extractPathes, ExtractProgressHandler epc, const UStringVector& skipPatterns);
+extern int DoExtractArchiveWithFile(UString archive, UString targetDir, bool overwrite, bool extractPathes, ExtractProgressWithFileHandler epc, const UStringVector& skipPatterns);
+
+int DoExtract(LPTSTR archive, LPTSTR dir, bool overwrite, bool expath, ExtractProgressHandler epc, const UStringVector& skipPatterns)
+{
+ if (!archive || !dir) return -1;
+ int res = 0;
+ try
+ {
+#ifdef UNICODE
+ UString uarchive(archive);
+ UString udir(dir);
+#else
+ UString uarchive = MultiByteToUnicodeString(AString(archive));
+ UString udir = MultiByteToUnicodeString(AString(dir));
+#endif
+ res = DoExtractArchive(uarchive, udir, overwrite, expath, epc, skipPatterns);
+ }
+ catch(...)
+ {
+ return -1;
+ }
+ return res;
+}
+
+int DoExtractWithFile(LPTSTR archive, LPTSTR dir, bool overwrite, bool expath, ExtractProgressWithFileHandler epc, const UStringVector& skipPatterns)
+{
+ if (!archive || !dir) return -1;
+ int res = 0;
+ try
+ {
+#ifdef UNICODE
+ UString uarchive(archive);
+ UString udir(dir);
+#else
+ UString uarchive = MultiByteToUnicodeString(AString(archive));
+ UString udir = MultiByteToUnicodeString(AString(dir));
+#endif
+ res = DoExtractArchiveWithFile(uarchive, udir, overwrite, expath, epc, skipPatterns);
+ }
+ catch(...)
+ {
+ return -1;
+ }
+ return res;
+}
+
diff --git a/versions/zstd/CPP/7zip/UI/NSIS/NSISBreak.cpp b/versions/zstd/CPP/7zip/UI/NSIS/NSISBreak.cpp
new file mode 100644
index 0000000..93ac0d5
--- /dev/null
+++ b/versions/zstd/CPP/7zip/UI/NSIS/NSISBreak.cpp
@@ -0,0 +1,31 @@
+// ConsoleClose.cpp
+
+#include "StdAfx.h"
+
+#include "NSISBreak.h"
+
+static int g_BreakCounter = 0;
+
+namespace NNSISBreak {
+
+void SendBreakSignal()
+{
+ g_BreakCounter++;
+}
+
+bool TestBreakSignal()
+{
+ /*
+ if (g_BreakCounter > 0)
+ return true;
+ */
+ return (g_BreakCounter > 0);
+}
+
+void CheckCtrlBreak()
+{
+ if (TestBreakSignal())
+ throw CCtrlBreakException();
+}
+
+}
diff --git a/versions/zstd/CPP/7zip/UI/NSIS/NSISBreak.h b/versions/zstd/CPP/7zip/UI/NSIS/NSISBreak.h
new file mode 100644
index 0000000..ca43f20
--- /dev/null
+++ b/versions/zstd/CPP/7zip/UI/NSIS/NSISBreak.h
@@ -0,0 +1,16 @@
+#ifndef __NSISBREAKUTILS_H
+#define __NSISBREAKUTILS_H
+
+namespace NNSISBreak {
+
+bool TestBreakSignal();
+void SendBreakSignal();
+
+class CCtrlBreakException
+{};
+
+void CheckCtrlBreak();
+
+}
+
+#endif
diff --git a/versions/zstd/CPP/7zip/UI/NSIS/StdAfx.h b/versions/zstd/CPP/7zip/UI/NSIS/StdAfx.h
new file mode 100644
index 0000000..c8c5279
--- /dev/null
+++ b/versions/zstd/CPP/7zip/UI/NSIS/StdAfx.h
@@ -0,0 +1,9 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include
+#include "7zip/Bundles/Nsis7z/pluginapi.h"
+
+#endif
diff --git a/versions/zstd/CPP/7zip/UI/NSIS/UserInputUtils2.cpp b/versions/zstd/CPP/7zip/UI/NSIS/UserInputUtils2.cpp
new file mode 100644
index 0000000..85d6d4f
--- /dev/null
+++ b/versions/zstd/CPP/7zip/UI/NSIS/UserInputUtils2.cpp
@@ -0,0 +1,60 @@
+// UserInputUtils.cpp
+
+#include "StdAfx.h"
+
+#include "Common/StdInStream.h"
+#include "Common/StringConvert.h"
+
+#include "UserInputUtils2.h"
+
+static const char kYes = 'Y';
+static const char kNo = 'N';
+static const char kYesAll = 'A';
+static const char kNoAll = 'S';
+static const char kAutoRename = 'U';
+static const char kQuit = 'Q';
+
+static const char *kFirstQuestionMessage = "?\n";
+static const char *kHelpQuestionMessage =
+ "(Y)es / (N)o / (A)lways / (S)kip all / A(u)to rename / (Q)uit? ";
+
+// return true if pressed Quite;
+// in: anAll
+// out: anAll, anYes;
+
+NUserAnswerMode::EEnum ScanUserYesNoAllQuit2(CStdOutStream *outStream)
+{
+ (*outStream) << kFirstQuestionMessage;
+ for(;;)
+ {
+ (*outStream) << kHelpQuestionMessage;
+ AString scannedString;
+ g_StdIn.ScanAStringUntilNewLine(scannedString);
+ scannedString.Trim();
+ if(!scannedString.IsEmpty())
+ switch(::MyCharUpper(scannedString[0]))
+ {
+ case kYes:
+ return NUserAnswerMode::kYes;
+ case kNo:
+ return NUserAnswerMode::kNo;
+ case kYesAll:
+ return NUserAnswerMode::kYesAll;
+ case kNoAll:
+ return NUserAnswerMode::kNoAll;
+ case kAutoRename:
+ return NUserAnswerMode::kAutoRename;
+ case kQuit:
+ return NUserAnswerMode::kQuit;
+ }
+ }
+}
+
+UString GetPassword(CStdOutStream *outStream)
+{
+ (*outStream) << "\nEnter password:";
+ outStream->Flush();
+ AString oemPassword;
+ g_StdIn.ScanAStringUntilNewLine(oemPassword);
+ return MultiByteToUnicodeString(oemPassword, CP_OEMCP);
+}
diff --git a/versions/zstd/CPP/7zip/UI/NSIS/UserInputUtils2.h b/versions/zstd/CPP/7zip/UI/NSIS/UserInputUtils2.h
new file mode 100644
index 0000000..d8c3de0
--- /dev/null
+++ b/versions/zstd/CPP/7zip/UI/NSIS/UserInputUtils2.h
@@ -0,0 +1,24 @@
+// UserInputUtils.h
+
+#ifndef __USERINPUTUTILS_H
+#define __USERINPUTUTILS_H
+
+#include "Common/StdOutStream.h"
+
+namespace NUserAnswerMode {
+
+enum EEnum
+{
+ kYes,
+ kNo,
+ kYesAll,
+ kNoAll,
+ kAutoRename,
+ kQuit
+};
+}
+
+NUserAnswerMode::EEnum ScanUserYesNoAllQuit2(CStdOutStream *outStream);
+UString GetPassword(CStdOutStream *outStream);
+
+#endif