Skip to content

Instantly share code, notes, and snippets.

@anosatsuk124
Created February 11, 2026 00:43
Show Gist options
  • Select an option

  • Save anosatsuk124/dbedfaacdd8a20ff52fff89eb55c3f0b to your computer and use it in GitHub Desktop.

Select an option

Save anosatsuk124/dbedfaacdd8a20ff52fff89eb55c3f0b to your computer and use it in GitHub Desktop.
Key/Zip Automation (for CFC)

Key/Zip Automation

Scripts to generate name.key from keys.h (matching name.zip -> //name) and add/update both name.key and dl-1425.bin in each target zip.

  • Bash script: make_keys_and_update_zips.sh
  • PowerShell script: make_keys_and_update_zips.ps1

Required Files

Place these in the same folder:

  • keys.h
  • dl-1425.bin
  • target *.zip files

What It Does

For each zip:

  1. Get name from name.zip
  2. Find the line in keys.h ending with //name
  3. Parse { 0x.., 0x.., ... } and write binary name.key
  4. Add/update name.key and dl-1425.bin inside the zip

If no matching //name line exists in keys.h, that zip is skipped with a warning.

PowerShell Version (Windows built-in only)

make_keys_and_update_zips.ps1 uses only PowerShell + .NET. No external commands are required (grep, rg, python, zip are not needed).

Examples

Process all zips:

.\make_keys_and_update_zips.ps1

Process selected zips:

.\make_keys_and_update_zips.ps1 hsf2.zip vsavj.zip

Output

  • target count (対象 zip: N 件)
  • progress ([i/N] Processing: xxx.zip)
  • success/warning lines
  • final summary (Done: total=... updated=... skipped=... failed=...)

Bash Version

make_keys_and_update_zips.sh requires grep, python3, and zip.

Examples

./make_keys_and_update_zips.sh
./make_keys_and_update_zips.sh hsf2.zip vsavj.zip

Common Errors

  • keys file not found: keys.h is missing
  • dl bin not found: dl-1425.bin is missing
  • keys.hに //name が見つからない: no key line for that zip in keys.h

Notes

  • Existing entries with the same name are replaced.
  • name.key is generated next to each zip file.

日本語

keys.h//name コメント (name.zip -> name) に対応するキーを name.key として生成し、dl-1425.bin と一緒に zip へ追加/更新するスクリプトです。

  • Bash 版: make_keys_and_update_zips.sh
  • PowerShell 版: make_keys_and_update_zips.ps1

前提ファイル

同じフォルダに以下を置いてください。

  • keys.h
  • dl-1425.bin
  • 対象の *.zip

処理内容

各 zip ごとに以下を実行します。

  1. name.zip から name を取得
  2. keys.h から //name で終わる行を検索
  3. 行内の { 0x.., 0x.., ... } をバイナリ化して name.key を作成
  4. name.keydl-1425.bin を zip に追加/更新

keys.h に対応行がない zip は警告を出してスキップします。

PowerShell 版 (Windows標準のみ)

make_keys_and_update_zips.ps1 は PowerShell + .NET のみで動作します。 外部コマンド (grep / rg / python / zip) は不要です。

実行例:

.\make_keys_and_update_zips.ps1
.\make_keys_and_update_zips.ps1 hsf2.zip vsavj.zip

出力:

  • 対象件数 (対象 zip: N 件)
  • 進捗 ([i/N] Processing: xxx.zip)
  • 成功/警告
  • 最終集計 (Done: total=... updated=... skipped=... failed=...)

Bash 版

make_keys_and_update_zips.shgrep, python3, zip が必要です。

実行例:

./make_keys_and_update_zips.sh
./make_keys_and_update_zips.sh hsf2.zip vsavj.zip

よくあるエラー

  • keys file not found: keys.h がない
  • dl bin not found: dl-1425.bin がない
  • keys.hに //name が見つからない: その zip のキー行が未定義

補足

  • zip 内に同名エントリがある場合は置き換えます。
  • name.key は zip の隣に生成されます。
param(
[Parameter(ValueFromRemainingArguments = $true)]
[string[]]$ZipFiles,
[string]$KeysFile = "keys.h",
[string]$DlBin = "dl-1425.bin"
)
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
# Ensure array semantics even when no args were provided.
$ZipFiles = @($ZipFiles)
$ZipFiles = @($ZipFiles | Where-Object { -not [string]::IsNullOrWhiteSpace($_) })
$BaseDir = if ([string]::IsNullOrWhiteSpace($PSScriptRoot)) { (Get-Location).Path } else { $PSScriptRoot }
function Resolve-AgainstBaseDir {
param([Parameter(Mandatory = $true)][string]$PathValue)
if ([System.IO.Path]::IsPathRooted($PathValue)) {
return [System.IO.Path]::GetFullPath($PathValue)
}
return [System.IO.Path]::GetFullPath((Join-Path -Path $BaseDir -ChildPath $PathValue))
}
function Show-Usage {
@"
Usage:
.\make_keys_and_update_zips.ps1
.\make_keys_and_update_zips.ps1 hsf2.zip vsavj.zip
事前準備(以下を同一階層のフォルダに用意):
1) keys.h を用意 (GitHub等から入手可能)( https://github.com/ArcadeHacker/ArcadeHacker_CPS2 の ArcadeHacker_CPS2.ino などをリネームして利用可能)
2) dl-1425.bin を用意 (自分で用意)
3) 処理対象の zip ファイルを用意
処理内容:
1) zip名(name.zip -> name)と一致する //name を keys.h から grep相当で検索
2) その行の { 0x.. } をバイナリ化して name.key を保存
3) name.key と dl-1425.bin を name.zip に追加/更新
"@
}
function Get-KeyLine {
param(
[Parameter(Mandatory = $true)][string]$Name,
[Parameter(Mandatory = $true)][string]$Path
)
$pattern = "//" + [Regex]::Escape($Name) + "\s*$"
$match = Select-String -Path $Path -Pattern $pattern | Select-Object -First 1
if ($null -eq $match) {
return $null
}
return $match.Line
}
function Convert-LineToBytes {
param([Parameter(Mandatory = $true)][string]$Line)
$m = [Regex]::Match($Line, "\{([^}]*)\}")
if (-not $m.Success) {
throw "key bytes parse failed: $Line"
}
$hexMatches = [Regex]::Matches($m.Groups[1].Value, "0x([0-9A-Fa-f]{1,2})")
if ($hexMatches.Count -eq 0) {
throw "hex tokens not found: $Line"
}
[byte[]]$bytes = @()
foreach ($hm in $hexMatches) {
$bytes += [Convert]::ToByte($hm.Groups[1].Value, 16)
}
return $bytes
}
function Update-ZipEntryFromFile {
param(
[Parameter(Mandatory = $true)][string]$ZipPath,
[Parameter(Mandatory = $true)][string]$SourcePath,
[Parameter(Mandatory = $true)][string]$EntryName
)
$zip = [System.IO.Compression.ZipFile]::Open($ZipPath, [System.IO.Compression.ZipArchiveMode]::Update)
try {
$existing = $zip.GetEntry($EntryName)
if ($null -ne $existing) {
$existing.Delete()
}
$entry = $zip.CreateEntry($EntryName, [System.IO.Compression.CompressionLevel]::Optimal)
$entryStream = $entry.Open()
try {
$src = [System.IO.File]::OpenRead($SourcePath)
try {
$src.CopyTo($entryStream)
}
finally {
$src.Dispose()
}
}
finally {
$entryStream.Dispose()
}
}
finally {
$zip.Dispose()
}
}
if ($ZipFiles.Count -eq 1 -and ($ZipFiles[0] -eq "-h" -or $ZipFiles[0] -eq "--help")) {
Show-Usage
exit 0
}
$KeysFile = Resolve-AgainstBaseDir -PathValue $KeysFile
$DlBin = Resolve-AgainstBaseDir -PathValue $DlBin
if (-not (Test-Path -LiteralPath $KeysFile -PathType Leaf)) {
throw "keys file not found: $KeysFile"
}
if (-not (Test-Path -LiteralPath $DlBin -PathType Leaf)) {
throw "dl bin not found: $DlBin"
}
Add-Type -AssemblyName System.IO.Compression
Add-Type -AssemblyName System.IO.Compression.FileSystem
if ($ZipFiles.Count -eq 0) {
$ZipFiles = Get-ChildItem -LiteralPath $BaseDir -Filter "*.zip" -File | ForEach-Object { $_.FullName }
$ZipFiles = @($ZipFiles)
if ($ZipFiles.Count -eq 0) {
throw "*.zip が見つかりません"
}
}
else {
$ZipFiles = @($ZipFiles | ForEach-Object { Resolve-AgainstBaseDir -PathValue $_ })
}
[int]$total = 0
[int]$updated = 0
[int]$skipped = 0
[int]$failed = 0
Write-Host "対象 zip: $($ZipFiles.Count) 件"
foreach ($zipFile in $ZipFiles) {
$total++
$zipPath = $zipFile
$zipLeaf = [System.IO.Path]::GetFileName($zipPath)
Write-Host "[$total/$($ZipFiles.Count)] Processing: $zipLeaf"
if (-not (Test-Path -LiteralPath $zipFile -PathType Leaf)) {
Write-Warning "zip not found, skipped: $zipFile"
$skipped++
continue
}
$name = [System.IO.Path]::GetFileNameWithoutExtension($zipPath)
$zipDir = [System.IO.Path]::GetDirectoryName($zipPath)
$keyFile = Join-Path -Path $zipDir -ChildPath ("$name.key")
try {
$line = Get-KeyLine -Name $name -Path $KeysFile
if ([string]::IsNullOrWhiteSpace($line)) {
Write-Warning "keys.hに //$name が見つからないためスキップ: $zipFile"
$skipped++
continue
}
$bytes = Convert-LineToBytes -Line $line
[System.IO.File]::WriteAllBytes($keyFile, $bytes)
Update-ZipEntryFromFile -ZipPath $zipPath -SourcePath $keyFile -EntryName ([System.IO.Path]::GetFileName($keyFile)
)
Update-ZipEntryFromFile -ZipPath $zipPath -SourcePath $DlBin -EntryName ([System.IO.Path]::GetFileName($DlBin)
)
Write-Host "OK: $zipLeaf <= $([System.IO.Path]::GetFileName($keyFile)), $([System.IO.Path]::GetFileName($DlBin))"
$updated++
}
catch {
Write-Warning "failed: $zipFile : $($_.Exception.Message)"
$failed++
}
}
Write-Host "Done: total=$total updated=$updated skipped=$skipped failed=$failed"
if ($failed -gt 0) {
exit 1
}
#!/usr/bin/env bash
set -euo pipefail
KEYS_FILE="keys.h"
DL_BIN="dl-1425.bin"
usage() {
cat <<'EOF'
Usage:
./make_keys_and_update_zips.sh # current directoryの*.zipを全処理
./make_keys_and_update_zips.sh a.zip b.zip # 指定zipのみ処理
事前準備(以下を同一階層のフォルダに用意):
1) keys.h を用意 (GitHub等から入手可能)( https://github.com/ArcadeHacker/ArcadeHacker_CPS2 の ArcadeHacker_CPS2.ino などをリネームして利用可能)
2) dl-1425.bin を用意 (自分で用意)
3) 処理対象の zip ファイルを用意
処理内容:
1) zip名(name.zip -> name)と一致する //name を keys.h から grep で検索
2) その行の { 0x.. } をバイナリ化して name.key を保存
3) name.key と dl-1425.bin を name.zip に追加/更新
EOF
}
need_cmd() {
if ! command -v "$1" >/dev/null 2>&1; then
echo "ERROR: required command not found: $1" >&2
exit 1
fi
}
process_zip() {
local zip_file="$1"
local base name key_file line
if [[ ! -f "$zip_file" ]]; then
echo "WARN: zip not found, skipped: $zip_file" >&2
return 0
fi
base="${zip_file##*/}"
name="${base%.zip}"
key_file="${name}.key"
line="$(grep -m1 -E "//${name}[[:space:]]*$" "$KEYS_FILE" || true)"
if [[ -z "$line" ]]; then
echo "WARN: keys.hに //${name} が見つからないためスキップ: ${zip_file}" >&2
return 0
fi
python3 - "$line" "$key_file" <<'PY'
import pathlib
import re
import sys
line = sys.argv[1]
out_path = pathlib.Path(sys.argv[2])
m = re.search(r"\{([^}]*)\}", line)
if not m:
print(f"ERROR: could not parse key bytes from line: {line}", file=sys.stderr)
sys.exit(2)
tokens = re.findall(r"0x([0-9A-Fa-f]{1,2})", m.group(1))
if not tokens:
print(f"ERROR: no hex tokens found in line: {line}", file=sys.stderr)
sys.exit(2)
out_path.write_bytes(bytes(int(t, 16) for t in tokens))
PY
zip -q -j -u "$zip_file" "$key_file" "$DL_BIN"
echo "OK: ${zip_file} <= ${key_file}, ${DL_BIN}"
}
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
usage
exit 0
fi
need_cmd grep
need_cmd python3
need_cmd zip
if [[ ! -f "$KEYS_FILE" ]]; then
echo "ERROR: ${KEYS_FILE} not found" >&2
exit 1
fi
if [[ ! -f "$DL_BIN" ]]; then
echo "ERROR: ${DL_BIN} not found" >&2
exit 1
fi
if [[ "$#" -gt 0 ]]; then
for zip_file in "$@"; do
process_zip "$zip_file"
done
else
shopt -s nullglob
zips=(*.zip)
if [[ "${#zips[@]}" -eq 0 ]]; then
echo "ERROR: *.zip が見つかりません" >&2
exit 1
fi
for zip_file in "${zips[@]}"; do
process_zip "$zip_file"
done
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment