@echo off
setlocal EnableExtensions
set "BP_DIST_ROOT=%~dp0"
set "BP_MANIFEST=%BP_DIST_ROOT%release_manifest.txt"
set "BP_VERSION_FILE=%BP_DIST_ROOT%VERSION"
set "BP_WRAPPER_VERSION=0.34.0"

set "BP_INPUT="
set "BP_MODE=pack"

:parse_args
if "%~1"=="" goto parsed_args
if /I "%~1"=="--help" goto usage
if /I "%~1"=="-h" goto usage
if /I "%~1"=="--version" (
    set "BP_MODE=version"
    shift
    goto parse_args
)
if /I "%~1"=="--stub" (
    echo ERROR: --stub is managed by BinaryProtector_pack.bat and cannot be overridden.
    exit /b 1
)
if /I "%~1"=="--verify-release" (
    set "BP_MODE=verify-release"
    shift
    goto parse_args
)
if /I "%~1"=="--verify-packed" (
    if "%~2"=="" (
        echo ERROR: Missing value for --verify-packed.
        exit /b 1
    )
    set "BP_MODE=verify"
    set "BP_INPUT=%~2"
    shift
    shift
    goto parse_args
)
if /I "%~1"=="--dump-info" (
    set "BP_MODE=info"
    shift
    goto parse_args
)
if /I "%~1"=="--explain-unsupported" (
    set "BP_MODE=compat"
    shift
    goto parse_args
)
if /I "%~1"=="--compat-report" (
    if "%~2"=="" (
        echo ERROR: Missing value for --compat-report.
        exit /b 1
    )
    set "BP_MODE=compat"
    shift
    shift
    goto parse_args
)
if /I "%~1"=="--i" (
    if "%~2"=="" (
        echo ERROR: Missing value for --i.
        exit /b 1
    )
    set "BP_INPUT=%~2"
    shift
    shift
    goto parse_args
)
shift
goto parse_args

:parsed_args
if /I "%BP_MODE%"=="version" goto version_mode
if /I "%BP_MODE%"=="verify-release" goto verify_release_mode
if not defined BP_INPUT (
    echo ERROR: Specify an input executable with --i or --verify-packed.
    goto usage_error
)
if not exist "%BP_INPUT%" (
    echo ERROR: Input executable was not found: "%BP_INPUT%"
    exit /b 1
)

set "BP_DETECT_INPUT=%BP_INPUT%"
set "BP_INPUT_ARCH="
for /f "usebackq delims=" %%A in (`powershell -NoProfile -Command "$b=[IO.File]::ReadAllBytes($env:BP_DETECT_INPUT); if ($b.Length -lt 64 -or $b[0] -ne 0x4D -or $b[1] -ne 0x5A) { 'invalid'; exit }; $o=[BitConverter]::ToInt32($b,0x3C); if ($o -lt 0 -or $o + 6 -gt $b.Length -or [BitConverter]::ToUInt32($b,$o) -ne 0x4550) { 'invalid'; exit }; switch ([BitConverter]::ToUInt16($b,$o + 4)) { 0x014C { 'x86' } 0x8664 { 'x64' } 0xAA64 { 'arm64' } default { 'unsupported' } }"`) do set "BP_INPUT_ARCH=%%A"

if /I "%BP_INPUT_ARCH%"=="invalid" (
    echo ERROR: Input is not a valid PE executable: "%BP_INPUT%"
    exit /b 1
)
if /I "%BP_INPUT_ARCH%"=="unsupported" (
    echo ERROR: Input PE architecture is not supported: "%BP_INPUT%"
    exit /b 1
)
if not defined BP_INPUT_ARCH (
    echo ERROR: Failed to detect input PE architecture: "%BP_INPUT%"
    exit /b 1
)

set "BP_BUILDER=%BP_DIST_ROOT%%BP_INPUT_ARCH%\BinaryProtector_builder.exe"
set "BP_STUB=%BP_DIST_ROOT%%BP_INPUT_ARCH%\BinaryProtector_stub.exe"
if not exist "%BP_BUILDER%" (
    echo ERROR: Distribution builder for %BP_INPUT_ARCH% is missing: "%BP_BUILDER%"
    exit /b 1
)

echo Selected %BP_INPUT_ARCH% release tools for "%BP_INPUT%".
if /I "%BP_MODE%"=="verify" goto verify_packed_mode
if /I "%BP_MODE%"=="info" goto info_mode
if /I "%BP_MODE%"=="compat" goto compat_mode

if not exist "%BP_STUB%" (
    echo ERROR: Distribution runtime stub for %BP_INPUT_ARCH% is missing: "%BP_STUB%"
    exit /b 1
)
powershell -NoProfile -ExecutionPolicy Bypass -Command "$root=$env:BP_DIST_ROOT; $manifest=$env:BP_MANIFEST; $headers=@('manifest_version=1',('release_version=' + $env:BP_WRAPPER_VERSION),'tail_format_version=5','ulam_metadata_version=4'); if(-not (Test-Path -LiteralPath $env:BP_VERSION_FILE -PathType Leaf) -or (Get-Content -LiteralPath $env:BP_VERSION_FILE -Raw).Trim() -ne $env:BP_WRAPPER_VERSION) { Write-Output 'ERROR: Release VERSION does not match wrapper version.'; exit 1 }; if(-not (Test-Path -LiteralPath $manifest -PathType Leaf)) { Write-Output ('ERROR: Release manifest is missing: ' + $manifest); exit 1 }; $lines=Get-Content -LiteralPath $manifest; foreach($header in $headers) { if($lines -notcontains $header) { Write-Output 'ERROR: Release manifest format or product version is incompatible.'; exit 1 } }; foreach($relative in @('BinaryProtector_pack.bat','VERSION',($env:BP_INPUT_ARCH + '/BinaryProtector_builder.exe'),($env:BP_INPUT_ARCH + '/BinaryProtector_stub.exe'))) { $entry=$lines | Where-Object { $_ -match ('^SHA256 ([A-F0-9]{64}) ' + [regex]::Escape($relative) + '$') } | Select-Object -First 1; if(-not $entry) { Write-Output ('ERROR: Release manifest entry is missing for ' + $relative + '.'); exit 1 }; [void]($entry -match '^SHA256 ([A-F0-9]{64}) '); $path=Join-Path $root $relative.Replace('/','\'); if(-not (Test-Path -LiteralPath $path -PathType Leaf)) { Write-Output ('ERROR: Release artifact is missing: ' + $relative + '.'); exit 1 }; if((Get-FileHash -LiteralPath $path -Algorithm SHA256).Hash -ne $Matches[1]) { Write-Output ('ERROR: Release SHA-256 mismatch for ' + $relative + '.'); exit 1 } }"
if errorlevel 1 exit /b 1
"%BP_BUILDER%" %* --stub "%BP_STUB%"
exit /b %ERRORLEVEL%

:version_mode
powershell -NoProfile -ExecutionPolicy Bypass -Command "$manifest=$env:BP_MANIFEST; if(-not (Test-Path -LiteralPath $env:BP_VERSION_FILE -PathType Leaf) -or (Get-Content -LiteralPath $env:BP_VERSION_FILE -Raw).Trim() -ne $env:BP_WRAPPER_VERSION) { Write-Output 'ERROR: Release VERSION does not match wrapper version.'; exit 1 }; if(-not (Test-Path -LiteralPath $manifest -PathType Leaf) -or (Get-Content -LiteralPath $manifest) -notcontains ('release_version=' + $env:BP_WRAPPER_VERSION)) { Write-Output 'ERROR: Release manifest product version is incompatible.'; exit 1 }; Write-Output ('BinaryProtector_pack ' + $env:BP_WRAPPER_VERSION + ' (tail=5, ulam=4)')"
exit /b %ERRORLEVEL%

:verify_release_mode
powershell -NoProfile -ExecutionPolicy Bypass -Command "$root=$env:BP_DIST_ROOT; $manifest=$env:BP_MANIFEST; $headers=@('manifest_version=1',('release_version=' + $env:BP_WRAPPER_VERSION),'tail_format_version=5','ulam_metadata_version=4'); $artifacts=@('BinaryProtector_pack.bat','README.md','COMPATIBILITY.md','COMPATIBILITY_TEST_CORPUS.md','DLL_PAYLOAD_SUPPORT_PLAN.md','VERSION','RELEASE_NOTES.md','RELEASE_AUTHENTICITY.md','x86/BinaryProtector_builder.exe','x86/BinaryProtector_stub.exe','x86/BinaryProtector_selftest.exe','x64/BinaryProtector_builder.exe','x64/BinaryProtector_stub.exe','x64/BinaryProtector_selftest.exe','arm64/BinaryProtector_builder.exe','arm64/BinaryProtector_stub.exe','arm64/BinaryProtector_selftest.exe'); if(-not (Test-Path -LiteralPath $env:BP_VERSION_FILE -PathType Leaf) -or (Get-Content -LiteralPath $env:BP_VERSION_FILE -Raw).Trim() -ne $env:BP_WRAPPER_VERSION) { Write-Output 'ERROR: Release VERSION does not match wrapper version.'; exit 1 }; if(-not (Test-Path -LiteralPath $manifest -PathType Leaf)) { Write-Output ('ERROR: Release manifest is missing: ' + $manifest); exit 1 }; $lines=Get-Content -LiteralPath $manifest; foreach($header in $headers) { if($lines -notcontains $header) { Write-Output 'ERROR: Unsupported or missing release manifest/product version.'; exit 1 } }; if(@($lines | Where-Object { $_ -like 'build_utc=*' }).Count -ne 1) { Write-Output 'ERROR: Release manifest build timestamp is missing or duplicated.'; exit 1 }; if(@($lines | Where-Object { $_ -like 'SHA256 *' }).Count -ne $artifacts.Count) { Write-Output 'ERROR: Release manifest has unexpected artifact count.'; exit 1 }; foreach($relative in $artifacts) { $entry=$lines | Where-Object { $_ -match ('^SHA256 ([A-F0-9]{64}) ' + [regex]::Escape($relative) + '$') } | Select-Object -First 1; if(-not $entry) { Write-Output ('ERROR: Release manifest entry is missing for ' + $relative + '.'); exit 1 }; [void]($entry -match '^SHA256 ([A-F0-9]{64}) '); $path=Join-Path $root $relative.Replace('/','\'); if(-not (Test-Path -LiteralPath $path -PathType Leaf)) { Write-Output ('ERROR: Release artifact is missing: ' + $relative + '.'); exit 1 }; if((Get-FileHash -LiteralPath $path -Algorithm SHA256).Hash -ne $Matches[1]) { Write-Output ('ERROR: Release SHA-256 mismatch for ' + $relative + '.'); exit 1 } }; Write-Output ('VERIFY OK: release ' + $env:BP_WRAPPER_VERSION + ' manifest versions and SHA-256 artifact hashes are valid.')"
exit /b %ERRORLEVEL%

:verify_packed_mode
powershell -NoProfile -ExecutionPolicy Bypass -Command "$root=$env:BP_DIST_ROOT; $manifest=$env:BP_MANIFEST; $headers=@('manifest_version=1',('release_version=' + $env:BP_WRAPPER_VERSION),'tail_format_version=5','ulam_metadata_version=4'); if(-not (Test-Path -LiteralPath $env:BP_VERSION_FILE -PathType Leaf) -or (Get-Content -LiteralPath $env:BP_VERSION_FILE -Raw).Trim() -ne $env:BP_WRAPPER_VERSION) { Write-Output 'ERROR: Release VERSION does not match wrapper version.'; exit 1 }; if(-not (Test-Path -LiteralPath $manifest -PathType Leaf)) { Write-Output ('ERROR: Release manifest is missing: ' + $manifest); exit 1 }; $lines=Get-Content -LiteralPath $manifest; foreach($header in $headers) { if($lines -notcontains $header) { Write-Output 'ERROR: Release manifest format or product version is incompatible.'; exit 1 } }; foreach($relative in @('BinaryProtector_pack.bat','VERSION',($env:BP_INPUT_ARCH + '/BinaryProtector_builder.exe'))) { $entry=$lines | Where-Object { $_ -match ('^SHA256 ([A-F0-9]{64}) ' + [regex]::Escape($relative) + '$') } | Select-Object -First 1; if(-not $entry) { Write-Output ('ERROR: Release manifest entry is missing for ' + $relative + '.'); exit 1 }; [void]($entry -match '^SHA256 ([A-F0-9]{64}) '); $path=Join-Path $root $relative.Replace('/','\'); if(-not (Test-Path -LiteralPath $path -PathType Leaf)) { Write-Output ('ERROR: Release artifact is missing: ' + $relative + '.'); exit 1 }; if((Get-FileHash -LiteralPath $path -Algorithm SHA256).Hash -ne $Matches[1]) { Write-Output ('ERROR: Release SHA-256 mismatch for ' + $relative + '.'); exit 1 } }"
if errorlevel 1 exit /b 1
"%BP_BUILDER%" %*
exit /b %ERRORLEVEL%

:info_mode
powershell -NoProfile -ExecutionPolicy Bypass -Command "$root=$env:BP_DIST_ROOT; $manifest=$env:BP_MANIFEST; $headers=@('manifest_version=1',('release_version=' + $env:BP_WRAPPER_VERSION),'tail_format_version=5','ulam_metadata_version=4'); if(-not (Test-Path -LiteralPath $env:BP_VERSION_FILE -PathType Leaf) -or (Get-Content -LiteralPath $env:BP_VERSION_FILE -Raw).Trim() -ne $env:BP_WRAPPER_VERSION) { Write-Output 'ERROR: Release VERSION does not match wrapper version.'; exit 1 }; if(-not (Test-Path -LiteralPath $manifest -PathType Leaf)) { Write-Output ('ERROR: Release manifest is missing: ' + $manifest); exit 1 }; $lines=Get-Content -LiteralPath $manifest; foreach($header in $headers) { if($lines -notcontains $header) { Write-Output 'ERROR: Release manifest format or product version is incompatible.'; exit 1 } }; foreach($relative in @('BinaryProtector_pack.bat','VERSION',($env:BP_INPUT_ARCH + '/BinaryProtector_builder.exe'))) { $entry=$lines | Where-Object { $_ -match ('^SHA256 ([A-F0-9]{64}) ' + [regex]::Escape($relative) + '$') } | Select-Object -First 1; if(-not $entry) { Write-Output ('ERROR: Release manifest entry is missing for ' + $relative + '.'); exit 1 }; [void]($entry -match '^SHA256 ([A-F0-9]{64}) '); $path=Join-Path $root $relative.Replace('/','\'); if(-not (Test-Path -LiteralPath $path -PathType Leaf)) { Write-Output ('ERROR: Release artifact is missing: ' + $relative + '.'); exit 1 }; if((Get-FileHash -LiteralPath $path -Algorithm SHA256).Hash -ne $Matches[1]) { Write-Output ('ERROR: Release SHA-256 mismatch for ' + $relative + '.'); exit 1 } }"
if errorlevel 1 exit /b 1
"%BP_BUILDER%" %*
exit /b %ERRORLEVEL%

:compat_mode
powershell -NoProfile -ExecutionPolicy Bypass -Command "$root=$env:BP_DIST_ROOT; $manifest=$env:BP_MANIFEST; $headers=@('manifest_version=1',('release_version=' + $env:BP_WRAPPER_VERSION),'tail_format_version=5','ulam_metadata_version=4'); if(-not (Test-Path -LiteralPath $env:BP_VERSION_FILE -PathType Leaf) -or (Get-Content -LiteralPath $env:BP_VERSION_FILE -Raw).Trim() -ne $env:BP_WRAPPER_VERSION) { Write-Output 'ERROR: Release VERSION does not match wrapper version.'; exit 1 }; if(-not (Test-Path -LiteralPath $manifest -PathType Leaf)) { Write-Output ('ERROR: Release manifest is missing: ' + $manifest); exit 1 }; $lines=Get-Content -LiteralPath $manifest; foreach($header in $headers) { if($lines -notcontains $header) { Write-Output 'ERROR: Release manifest format or product version is incompatible.'; exit 1 } }; foreach($relative in @('BinaryProtector_pack.bat','VERSION',($env:BP_INPUT_ARCH + '/BinaryProtector_builder.exe'))) { $entry=$lines | Where-Object { $_ -match ('^SHA256 ([A-F0-9]{64}) ' + [regex]::Escape($relative) + '$') } | Select-Object -First 1; if(-not $entry) { Write-Output ('ERROR: Release manifest entry is missing for ' + $relative + '.'); exit 1 }; [void]($entry -match '^SHA256 ([A-F0-9]{64}) '); $path=Join-Path $root $relative.Replace('/','\'); if(-not (Test-Path -LiteralPath $path -PathType Leaf)) { Write-Output ('ERROR: Release artifact is missing: ' + $relative + '.'); exit 1 }; if((Get-FileHash -LiteralPath $path -Algorithm SHA256).Hash -ne $Matches[1]) { Write-Output ('ERROR: Release SHA-256 mismatch for ' + $relative + '.'); exit 1 } }"
if errorlevel 1 exit /b 1
"%BP_BUILDER%" %*
exit /b %ERRORLEVEL%

:usage
echo BinaryProtector distribution wrapper
echo Usage: BinaryProtector_pack.bat --i ^<input.exe^> [--o ^<output.exe^>] [--vm] [--c] [--ulam-layout] [--dump-ulam-map ^<file.txt^>] [--report ^<report.json^>]
echo        BinaryProtector_pack.bat --dump-info --i ^<input.exe^>
echo        BinaryProtector_pack.bat --explain-unsupported --i ^<input.exe^>
echo        BinaryProtector_pack.bat --compat-report ^<report.json^> --i ^<input.exe^>
echo        BinaryProtector_pack.bat --verify-packed ^<packed.exe^> [--json ^<verify-report.json^>]
echo        BinaryProtector_pack.bat --verify-release
echo        BinaryProtector_pack.bat --version
echo.
echo The wrapper detects x86, x64, or ARM64 input architecture and validates selected release tools against release_manifest.txt.
echo --explain-unsupported and --compat-report include a verdict, reason, category, and suggested action.
echo DLL boundary: load-only DLL payloads and explicit local no-argument export dispatch are supported; wrapper-DLL output and PEB/LDR loader-list registration are unsupported.
exit /b 0

:usage_error
echo Run BinaryProtector_pack.bat --help for usage.
exit /b 1
