Skip to content

Instantly share code, notes, and snippets.

@Europia79
Created October 18, 2023 08:45
Show Gist options
  • Save Europia79/e06c296301e0a0424bceca9e4054df3b to your computer and use it in GitHub Desktop.
Save Europia79/e06c296301e0a0424bceca9e4054df3b to your computer and use it in GitHub Desktop.
Automatically fixes headers for VGM Player v3.30
#!/bin/bash
# _FIX_HEADER.sh by Europia79
##########################################
# README #
##########################################
# (1) This script requires Linux, Mac, or Git-for-Windows:
# https://gitforwindows.org/
# https://git-scm.com/download/win
# (2) Requires a ROM set:
# https://r-roms.github.io/
# (3) Requires Megadrive VGM Player v3.30:
# http://www.mjsstuf.x10host.com/pages/vgmPlay/vgmPlay.htm
# https://github.com/TheDeadFish/vgmPlay-vgmConv
# https://github.com/Europia79/vgmPlay-vgmConv
# (4) Requires 7-zip:
# https://www.7-zip.org/download.html
# (5) Add the 7-zip directory to your PATH environment variable:
# https://gist.github.com/nex3/c395b2f8fd4b02068be37c961301caa7
# (6) Alternatively, if you cannot change your PATH environment, then
# you can instead, copy 7-zip to your ~/Git/usr/bin/ folder.
# (7) Edit CONFIG below for Roms Folder & Headers Directory:
# (8) Edit FILENAME FORMAT section for nomenclature (naming convention):
# GoodSets, IUPAG, no-intro, other (custom format).
##########################################
# CONFIG #
##########################################
ROMS="_roms"
HEADERS="_no-intro.headers"
BAD_HEADERS="${HEADERS}/_BAD_HEADERS"
temp="temp_abc123xyz789"
OUTPUT_DIR="_vgm.roms"
##########################################
# FILENAME GLOBALS #
##########################################
declare FILENAME=""
declare TITLE=""
declare SEP="~"
declare SUBTITLE=""
declare -i TRACKS=0
declare AUTHOR=""
declare VERSION=""
declare REVISION=""
declare TAGS=""
declare SUFFIX="[OST] [!]"
declare EXT="bin"
##########################################
# FILENAME FORMAT #
##########################################
# SF II ~ VGM Player v3.30; 36 Tracks (@Dark Pulse)(v2005-11-20)(rev1.00)[OST] [!].bin
declare -a TEMPLATE_FILENAME=('${TITLE}' '${SEP}' '${SUBTITLE}' '${TAGS}' '${SUFFIX}' '${EXT}')
declare FORMAT_FILENAME='%s %s %s %s%s.%s'
declare -a TEMPLATE_TAGS=('${AUTHOR}' '${VERSION}' '${REVISION}')
declare FORMAT_TAGS='%s%s%s'
declare FORMAT_SUBTITLE='VGM Player v3.30; %02d Tracks'
declare FORMAT_AUTHOR='(@%s)'
declare FORMAT_VERSION='(v%s)'
declare FORMAT_REVISION='(rev%s)'
##########################################
# CONSTANTS & GLOBALS #
##########################################
# add line numbers in debug mode (bash set -x ./_fix_header.sh):
PS4='+ \e[0;33m${LINENO}\e[0m::'
# 7z??'.="37 7A BC AF 27 1C"
CMAGIC_7Z="377ABCAF271C"
# PK..="50 4B 03 04"
CMAGIC_ZIP="504B0304"
global_args=("$@")
declare -i arg_count_nes_cli=0
declare -a CLEANUP_FILES=()
declare -a ADDED_FILES=()
declare -a FAILED_FILES=()
declare -a UNSUPPORTED=()
# grep -n "^function " _fix_header.sh | sed 's/^/# /g' | sed 's/:function /::/g' | sed 's/() {/()::/g'
##########################################
# FUNCTION MENU: (Ctl+G) #
##########################################
# 134::pause()::
# 139::close()::
# 148::close_now()::
# 154::close_delay()::
# 159::pipeout()::
# 164::die()::
# 168::die_now()::
# 173::die_delay()::
# 178::cleanupValidation()::
# 193::cleanup()::
# 200::onExit()::
# 211::get_crc32()::
# 214::calculate_crc32()::
# 217::get_bytesize()::
# 221::getFileBirth()::
# 224::getFileSize()::
# 228::get_magic_num()::
# 231::is_archive()::
# 234::has_archive_magic()::
# 237::has_7z_magic()::
# 240::has_zip_magic()::
# 243::is_archive_file()::
# 246::is_7z()::
# 249::is_zip()::
# 252::is_gen()::
# 255::is_32x()::
# 258::is_smd()::
# 262::has_gen_ext()::
# 275::parseInput()::
# 288::parseFullpath()::
# 313::getFile()::
# 320::getDirectory()::
# 327::getBase()::
# 334::getExtention()::
# 343::isFileType()::
# 358::getFileType()::
# 366::get_baserom()::
# 381::create_baserom()::
# 411::create_romhack()::
# 440::fix_year_dot_month()::
# 448::fix_tracks()::
# 460::fix_intl_datecode()::
# 470::get_bytesum()::
# 481::get_checksum()::
# 493::fix_checksum()::
# 501::fix_eof_line()::
# 509::fix_author()::
# 553::fix_filename()::
# 561::getFileType_ReturnValues_Comment()::
# 616::FILETYPE_CONSTANTS()::
# 687::windows_fix()::
# 711::require_args()::
# 714::onStartupClientsideValidation()::
##########################################
# CONTROL FUNCTIONS #
##########################################
# PAUSE
function pause() {
read -rsn1 -p "Press any key to continue..."
echo ""
}
# CLOSE
function close() {
if [ $# -eq 0 ]
then
close_now $?
else
close_now $1
fi
}
# CLOSE_NOW
function close_now() {
local status=0
if [ -n "$1" ] && (( $1 + 0 > 0 )); then status=$1; fi
exit $status
}
# CLOSE_DELAY
function close_delay() {
pause
close $1
}
# PIPEOUT
function pipeout() {
printf "%s" $*
close 0
}
# DIE
function die() {
die_now "$1"
}
# DIE_NOW
function die_now() {
printf "Aborted: %s\n" "$"; echo ""
close 1
}
# DIE_DELAY
function die_delay() {
printf "Aborted: %s\n" "$1"; echo ""
pause
close 1
}
function cleanupValidation() {
printf "\e[1;36m"
for failedfile in "${FAILED_FILES[@]}"
do
echo "FAILED: ${failedfile}"
done
for ufile in "${UNSUPPORTED[@]}"
do
echo "UNSUPPORTED: ${ufile}"
done
echo "TOTAL HEADERS: "$(find "./${HEADERS}" -maxdepth 1 -type f | wc -l)
pwd
printf "\e[0m"
}
# Remove specific files before dying onError/onExit.
function cleanup() {
rm -rf -- "${temp}"
for cfile in "$@"
do
rm -vf -- "${cfile}"
done
}
function onExit() {
printf "\e[1;33m%s\e[1;31m\n" "onExit() cleanup..." >&2
cleanup "${CLEANUP_FILES[@]}"
printf "\e[1;33m%s\e[0m\n" "...done." >&2
cleanupValidation
pause
} >&2
trap onExit EXIT
##########################################
# FILE METHODS #
##########################################
function get_crc32() {
cat "$1" | gzip -1 -c | tail -c8 | xxd -ps -l 4
}
function calculate_crc32() {
printf "$1" | gzip -1 -c | tail -c8 | xxd -ps -l 4
}
function get_bytesize() {
wc -c < "$1"
}
# find . -type f -name "*.vgz" -printf "%BF\n" | head -1
function getFileBirth() {
stat --printf='%w' "$1" | head -c 10
}
function getFileSize() {
stat --printf='%s' "$1"
}
# return_val=$(get_magic_num "${file1}")
function get_magic_num() {
xxd -p -l 4 "$1" | tr '[:lower:]' '[:upper:]'
}
function is_archive() {
$(is_archive_file "$1") || $(has_archive_magic "$1")
}
function has_archive_magic() {
$(has_zip_magic "$1") || $(has_7z_magic "$1")
}
function has_7z_magic() {
[[ ${CMAGIC_7Z} = $(get_magic_num "$1") ]]
}
function has_zip_magic() {
[[ ${CMAGIC_ZIP} = $(get_magic_num "$1") ]]
}
function is_archive_file() {
$(is_7z "$1") || $(is_zip "$1")
}
function is_7z() {
isFileType "$1" "7z"
}
function is_zip() {
isFileType "$1" "zip"
}
function is_gen() {
isFileType "$1" "gen"
}
function is_32x() {
isFileType "$1" "32x"
}
function is_smd() {
isFileType "$1" "smd"
}
# 32x 68k bin gen md smd
function has_gen_ext() {
ext=$(getExtention "$1")
case "${ext}" in
32x) true; return;;
68k) true; return;;
bin) true; return;;
gen) true; return;;
md) true; return;;
smd) true; return;;
*) false; return;;
esac
}
# Null Check for function arguments: $* $1 $2 etc.
function parseInput() {
local PARSED_INPUT=""
if [ -n "$1" ]
then
PARSED_INPUT="$1"
else
die "$(basename $0): function argument cannot be NULL"
fi
echo "${PARSED_INPUT}"
}
# $(parseFullpath _RETURN_VAR "${__INPUT_VAL}")
# _RETURN_VAR: $1 = A named reference to the array used to store the return values.
# __INPUT_VAL: $2 = the input string.
function parseFullpath() {
local -n returnvar=$1
local input_path=$(parseInput "$2")
# Convert backslashes on \Windows\ to foward slashes: /Windows/
local FULLPATH="${input_path//\\//}"
# [0] Strip longest match of */ from start
local file="${FULLPATH##*/}"
# [1] Substring from 0 thru pos of filename
local dir="${FULLPATH:0:${#FULLPATH} - ${#file}}"
[ -z "${dir}" ] && dir="."
# [2] Strip shortest match of . plus at least one non-dot char from end
local base="${file%.[^.]*}"
# [3] If we have an extension and no base, it's really the base
local ext="${file:${#base} + 1}"
if [ -z "${base}" ] && [ -n "${ext}" ]
then
base=".${ext}"
ext=""
fi
returnvar[0]="${file}"
returnvar[1]="${dir}"
returnvar[2]="${base}"
returnvar[3]="${ext}"
}
# gets the entire Filename including extention.
function getFile() {
local -a path_array=()
local file_input=$(parseInput "$1")
parseFullpath path_array "${file_input}"
echo "${path_array[0]}"
}
# gets the Directory, or, "." if none.
function getDirectory() {
local -a path_array=()
local dir_input=$(parseInput "$1")
parseFullpath path_array "${dir_input}"
echo "${path_array[1]}"
}
# get only the base Filename without the extention.
function getBase() {
local -a path_array=()
local base_input=$(parseInput "$1")
parseFullpath path_array "${base_input}"
echo "${path_array[2]}"
}
# gets the Extention without the period.
function getExtention() {
local -a path_array=()
local ext_input=$(parseInput "$1")
parseFullpath path_array "${ext_input}"
echo "${path_array[3]}"
}
# Remember, type 'nes' specifically refers to an NES ROM with a header !!!
# $(isFileType "$1" bps) && echo "BPS=true" || echo "BPS=false"
# $(isFileType "$2" nes) && echo "NES=true" || echo "NES=false"
function isFileType() {
local T1=$(getFileType "$1")
local T2="${qFILE_TYPE[$2]}"
[[ ${T1} = ${T2}* ]] && return
if [[ ${T2} = "declare -a"* ]]
then
eval "${T2}"
for element in "${array[@]}"
do
[[ ${T1} = ${element}* ]] && return
done
fi
false
}
# Fully qualified FileType with extraneous information:
function getFileType() {
if [ ! -f "$1" ]; then die "getFileTypeOf() requires a File argument: Not: $1"; fi
file -b "$1"
}
##########################################
# FIX HEADER FUNCTIONS #
##########################################
# find . -maxdepth 1 -type f -name "Shining Force*" | awk '{ print length(), $0 | "sort -n" }' | tr '\n' '\0'
function get_baserom() {
local vgm_input_dir=$(getBase "$1")
local input="${vgm_input_dir%% \(*\)}"
local -a results=()
readarray -d '' results < <(find "${HEADERS}" -maxdepth 1 -type f -name "${input}*" | awk '{ print length(), $0 | "sort -n" }' | tr '\n' '\0')
local baserom=""
if [ ${#results[@]} -eq 0 ]
then
baserom=$(create_baserom "${input}")
else
baserom="${results[0]}"
baserom="${baserom#[[:digit:]]* }"
fi
echo -n "${baserom}"
}
function create_baserom() {
local rom_name="$1"
mkdir -p "${temp}"
# POEM
xxd -ps -l 0x100 "vgmPlay.dat" | xxd -r -ps > "${temp}/baserom.bin"
# SEGA CONSOLE, (C)AUTH DATE
xxd -ps -s 0x100 -l 0x20 "vgmPlay.dat" | xxd -r -ps >> "${temp}/baserom.bin"
# ORIGINAL DOMESTIC NAME:
printf '%-48.48s' "${rom_name}" >> "${temp}/baserom.bin"
# INTERNATIONAL NAME:
# VGM Player v3.30; 36 Tracks (v2023-10-11)[OST]__
xxd -ps -s 0x150 -l 0x30 "vgmPlay.dat" | xxd -r -ps >> "${temp}/baserom.bin"
# SERIAL NUMBER + CHECKSUM:
printf 'GM ' >> "${temp}/baserom.bin"
local hashcode=$(calculate_crc32 "${rom_name}")
printf '%08.8s' "${hashcode}" >> "${temp}/baserom.bin"
printf -- '-00XX' >> "${temp}/baserom.bin"
# CONTROLLER SUPPORT FLAG(S):
xxd -ps -s 0x190 -l 0x10 "vgmPlay.dat" | xxd -r -ps >> "${temp}/baserom.bin"
# EOF_LINE:
printf '%032X' 0 | xxd -r -ps >> "${temp}/baserom.bin"
# Comment Lines + REGION CODES:
# 0x1B0: " "
# 0x1C0: " Hack by "
# 0x1D0: "(@Author) "
# 0x1E0: " "
# 0x1F0: "JUE "
xxd -ps -s 0x1B0 -l 0x50 "vgmPlay.dat" | xxd -r -ps >> "${temp}/baserom.bin"
echo -n "${temp}/baserom.bin"
}
function create_romhack() {
BASEROM="$1"
CLEANUP_FILES+=("vgmPlay.bin")
CLEANUP_FILES+=("romhack.bin")
CLEANUP_FILES+=("fixed.bin")
CLEANUP_FILES+=("temp.bin")
# POEM
xxd -ps -l 0x100 "vgmPlay.dat" | xxd -r -ps > "romhack.bin"
# SEGA CONSOLE, (C)AUTH DATE, & ORIGINAL DOMESTIC NAME.
xxd -ps -s 0x100 -l 0x50 "${BASEROM}" | xxd -r -ps >> "romhack.bin"
# INTERNATIONAL NAME:
# VGM Player v3.30; 36 Tracks (v2023-10-11)[OST]__
xxd -ps -s 0x150 -l 0x30 "vgmPlay.dat" | xxd -r -ps >> "romhack.bin"
# SERIAL NUMBER + CHECKSUM:
xxd -ps -s 0x180 -l 0x10 "${BASEROM}" | xxd -r -ps >> "romhack.bin"
# CONTROLLER SUPPORT FLAG(S):
xxd -ps -s 0x190 -l 0x10 "vgmPlay.dat" | xxd -r -ps >> "romhack.bin"
# EOF_LINE:
xxd -ps -s 0x1A0 -l 0x10 "${BASEROM}" | xxd -r -ps >> "romhack.bin"
# Comment Lines + REGION CODES:
# 0x1B0: " "
# 0x1C0: " Hack by "
# 0x1D0: "(@Author) "
# 0x1E0: " "
# 0x1F0: "JUE "
xxd -ps -s 0x1B0 -l 0x50 "vgmPlay.dat" | xxd -r -ps >> "romhack.bin"
# TRACKS DATA:
xxd -ps -s 0x200 "vgmPlay.bin" | xxd -r -ps >> "romhack.bin"
}
function fix_year_dot_month() {
xxd -ps -l 0x118 'romhack.bin' | xxd -r -ps > "temp.bin"
printf -- '%4.4s' $(date "+%Y") | tr ' ' X >> "temp.bin"
printf -- '%1.1s' "." >> "temp.bin"
printf -- '%3.3s' $(date "+%b" | tr '[:lower:]' '[:upper:]') | tr ' ' X >> "temp.bin"
cat <(xxd -ps -l 0x120 "temp.bin") <(xxd -ps -s 0x120 "romhack.bin") | xxd -r -ps > "fixed.bin"
rm -f "temp.bin"
}
function fix_tracks() {
# REQUIRES VGM FOLDER:
VGM_FOLDER="$1"
xxd -ps -l 0x162 'fixed.bin' | xxd -r -ps > "temp.bin"
local -i total=$(find "${VGM_FOLDER}" -type f -name "*.vgz" | wc -l)
printf "%02d" ${total} >> "temp.bin"
printf ' Tracks ' >> "temp.bin"
cat <(xxd -ps -l 0x16C "temp.bin") <(xxd -ps -s 0x16C "romhack.bin") | xxd -r -ps > "fixed.bin"
rm -f "temp.bin"
TRACKS=${total}
SUBTITLE=$(printf "${FORMAT_SUBTITLE}" ${TRACKS})
}
function fix_intl_datecode() {
xxd -ps -l 0x16C 'fixed.bin' | xxd -r -ps > "temp.bin"
local datecode=$(find "$1" -type f -name "*.vgz" -printf "%BF\n" | head -1)
printf -- "(v" >> "temp.bin"
printf -- "%s" ${datecode} >> "temp.bin"
printf -- ')[OST] ' >> "temp.bin"
cat <(xxd -ps -l 0x180 "temp.bin") <(xxd -ps -s 0x180 "romhack.bin") | xxd -r -ps > "fixed.bin"
rm -f "temp.bin"
VERSION=$(printf "${FORMAT_VERSION}" ${datecode})
}
function get_bytesum() {
set -x
csum=0
xxd -p -c 1 -s 0x200 -l 0x20 "$1" | while read byte
do
csum=$(($csum + "0x${byte}"))
done
csum=$(( csum & 0xFFFF ))
printf '%04.4s' "${csum}"
set +x
}
function get_checksum() {
set -x
readarray -t bytes < <(xxd -p -c 1 -s 0x200 -l 0x20 "$1")
# bytes=( $(xxd -p -c 1 -s 0x200 -l 0x20 "$1" | tr '\n' ' ') )
total=0;
for(( i=0; i<${#bytes[@]}; i++));
do
total=$((total + 0x${bytes[i]}))
done
printf '%04X' $(( total & 0xFFFF ))
set +x
}
function fix_checksum() {
xxd -ps -l 0x18E 'fixed.bin' | xxd -r -ps > "temp.bin"
# local -i total=0x$(get_bytesum "romhack.bin")
# printf -- '%04X' $(( total & 0xFFFF )) >> "temp.bin"
printf -- '%02.2s' "XX" >> "temp.bin"
cat <(xxd -ps -l 0x190 "temp.bin") <(xxd -ps -s 0x190 "romhack.bin") | xxd -r -ps > "fixed.bin"
rm -f "temp.bin"
}
function fix_eof_line() {
xxd -ps -l 0x1A0 'fixed.bin' | xxd -r -ps > "temp.bin"
local -i eof=$(( $(wc -c < 'romhack.bin') - 1 ))
printf '%016X' ${eof} | xxd -r -ps >> "temp.bin"
printf '%016X' 0 | xxd -r -ps >> "temp.bin"
cat <(xxd -ps -l 0x1B0 "temp.bin") <(xxd -ps -s 0x1B0 "romhack.bin") | xxd -r -ps > "fixed.bin"
rm -f "temp.bin"
}
function fix_author() {
xxd -ps -l 0x1D0 'fixed.bin' | xxd -r -ps > "temp.bin"
local auth=""
local revv=""
local base_dir=$(getBase "$1")
declare -a filearray=()
readarray -d '' filearray < <(find "${base_dir}" -maxdepth 1 -type f -name "*.txt" -print0)
for file in "${filearray[@]}"
do
local package_by=""
package_by=$(grep -Po "(?<=^Package created by: ).*" "./${file}" | xargs)
if [ -n "$package_by" ] && [ -z "$auth" ]
then
TITLE=$(getBase "${file}")
if [ ${#package_by} -gt 29 ]
then
auth="${package_by:0:29}"
else
auth="${package_by}"
fi
fi
local package_ver=""
package_ver=$(grep -Po "(?<=^Package version: ).*" "./${file}" | xargs)
if [ -n "${package_ver}" ] && [ -z "${revv}" ]
then
if [ ${#package_ver} -gt 15 ]
then
revv="${package_ver:0:15}"
else
revv="${package_ver}"
fi
fi
done
if [ -z "$auth" ]; then auth="Unknown"; fi
if [ -z "$revv" ]; then rev="1.00"; fi
AUTHOR=$(printf "${FORMAT_AUTHOR}" "${auth}")
REVISION=$(printf "${FORMAT_REVISION}" "${revv}")
printf '%-32.32s' "${AUTHOR}" >> "temp.bin"
cat <(xxd -ps -l 0x1F0 "temp.bin") <(xxd -ps -s 0x1F0 "romhack.bin") | xxd -r -ps > "fixed.bin"
rm -f "temp.bin"
}
# SF II ~ VGM Player v3.30; 36 Tracks (@Dark Pulse)(v2005-11-20)(rev1.00)[OST] [!].bin
# TEMPLATE_FILENAME='${TITLE} ${SEP} ${SUBTITLE} ${TAGS}${SUFFIX}.${EXT}'
# TEMPLATE_TAGS='${AUTHOR}${VERSION}${REVISION}'
function fix_filename() {
TAGS=$(eval printf -- "${FORMAT_TAGS}" "${TEMPLATE_TAGS[@]}")
FILENAME=$(printf -- "${FORMAT_FILENAME}" "${TITLE}" "${SEP}" "${SUBTITLE}" "${TAGS}" "${SUFFIX}" "${EXT}")
# FILENAME=$(eval printf -- "${FORMAT_FILENAME}" "${TEMPLATE_FILENAME[@]}")
mkdir -p "${OUTPUT_DIR}"
mv -f -- 'fixed.bin' "${OUTPUT_DIR}/${FILENAME}"
}
# Comment: do-nothing.
function getFileType_ReturnValues_Comment() {
true
}
##########################################
# getFileType() return values #
##########################################
#-----------------------------------------
# input: Output
#-----------COMPRESSED-FILES--------------
# .7z 7-zip archive data, version 0.4
# .zip Zip archive data, at least v2.0 to extract, compression method=deflate
#-----------PATCH-FILES-------------------
# .aps
# .bps BPS patch file
# .ebp IPS patch file
# .ips IPS patch file
# .ppf Playstation Patch File version 3.0, PPF 3.0 patch, Imagetype BIN (any), Blockcheck disabled, Undo data not available, description: FFT: WotL - Valeria 2.2 (PSP USA)
# .rup data
# .ups UPS patch file
# .xdelta VCDIFF binary diff
#-----------ROM-FILES---------------------
# .pce data
# .nes NES ROM image (iNES): 8x16k PRG, 0x8k CHR [H-mirror] [SRAM]
# .fds Famicom Disk System disk image: FMC-ARM, mfr FFFFFFA4 (Rev.00) (2 sides)
# .unh data
# .unf NES ROM image (UNIF v7 format)
# .bs data
# .st Sufami Turbo ROM image: "\276\260\327\2", ID 010003, series index 1 [FastROM]
# .sfc data
# .n64 Nintendo 64 ROM image (32-bit byteswapped)
# .v64 Nintendo 64 ROM image (V64)
# .z64 Nintendo 64 ROM image: "SUPER MARIO 64 " (NSME, Rev.00)
# .iso Nintendo GameCube disc image: "The Legend of Zelda Twilight Princess" (GZ2E01, Rev.00)
# .iso Nintendo Wii disc image: "SPORTS PACK for REVOLUTION" (RSPE01, Rev.01)
# .wbfs Nintendo Wii disc image (WBFS format): "SPORTS PACK for REVOLUTION" (RSPE01, Rev.01)
# .gb Game Boy ROM image: "ZELDA" (Rev.02) [MBC1+RAM+BATT], ROM: 4Mbit, RAM: 64Kbit
# .gbc Game Boy ROM image: "PM_CRYSTAL" (Rev.01) [CGB ONLY] [MBC3+TIMER+RAM+BATT], ROM: 16Mbit, RAM: 256Kbit
# .gba Game Boy Advance ROM image: "POKEMON RUBY" (AXVE01, Rev.02)
# .nds Nintendo DS ROM image: "CASTLEVANIA1" (ACVPA4, Rev.00) (decrypted)
# .gg Sega Game Gear ROM image: 2408 (Rev.01) (256 KB)
# .sms Sega Master System ROM image: 7076 (Rev.00) (256 KB)
# .32x Sega 32X ROM image: "DOOM " (GM MK-84506-00, (C)SEGA 1994.OCT)
# .68k Sega Mega Drive / Genesis ROM image: "\377\377\377\377" (\377\377\377\3, \377\377\377\377)
# .bin Sega Mega Drive / Genesis ROM image: "SONIC THE " (GM 00001051-02, (C)SEGA 1992.SEP)
# .gen Sega Mega Drive / Genesis ROM image: "NHL HOCKEY " (GM T-50236 -00, (C)T-50 1991.MAY)
# .md Sega Mega Drive / Genesis ROM image: "EA HOCKEY " (GM T-50236 -50, (C)T-50 1991.JUN)
# .smd Sega Mega Drive / Genesis ROM image (SMD format): 64x16k blocks, last in series or standalone
# .img Sega Mega CD disc image: "SOULSTAR " (GM T-115035-00, (C)T-1151994.NOV), 2352-byte sectors
# .iso Sega Mega CD disc image: "SOULSTAR " (GM T-115035-00, (C)T-1151994.NOV), 2048-byte sectors
# .bin Sega Saturn disc image: "AREA 51 " (T-9705H , V1.000) (2352-byte sectors)
# .bin Sega Dreamcast disc image: "CRAZY TAXI " (MK-51035 , V1.004) (2352-byte sectors)
# .iso UDF filesystem data (version 1.5) 'FINAL_FANTASY_X'
##########################################
# CONSTANTS2 #
##########################################
function FILETYPE_CONSTANTS() {
true
}
declare -A qFILE_TYPE
declare -A qFILE_TYPE_COM
declare -A qFILE_TYPE_DIF
declare -A qFILE_TYPE_ROM
qFILE_TYPE_COM["7z"]="7-zip archive"
qFILE_TYPE_COM[zip]="Zip archive"
qFILE_TYPE_DIF[aps]="UNKNOWN: NOT SUPPORTED"
qFILE_TYPE_DIF[bps]="BPS patch file"
qFILE_TYPE_DIF[ebp]="IPS patch file"
qFILE_TYPE_DIF[ips]="IPS patch file"
qFILE_TYPE_DIF[ppf]="Playstation Patch File"
qFILE_TYPE_DIF[rup]="data"
qFILE_TYPE_DIF[ups]="UPS patch file"
qFILE_TYPE_DIF[xdelta]="VCDIFF binary diff"
qFILE_TYPE_ROM[pce]="data"
qFILE_TYPE_ROM[nes]="NES ROM image (iNES)"
qFILE_TYPE_ROM[fds]="Famicom Disk System disk image:"
qFILE_TYPE_ROM[unh]="data"
qFILE_TYPE_ROM[unf]="NES ROM image (UNIF"
qFILE_TYPE_ROM[bs]="data"
qFILE_TYPE_ROM[st]="Sufami Turbo ROM image:"
qFILE_TYPE_ROM[sfc]="data"
qFILE_TYPE_ROM[n64]="Nintendo 64 ROM image (32-bit byteswapped)"
qFILE_TYPE_ROM[v64]="Nintendo 64 ROM image (V64)"
qFILE_TYPE_ROM[z64]="Nintendo 64 ROM image:"
qFILE_TYPE_ROM[wbfs]="Nintendo Wii disc image (WBFS format):"
qFILE_TYPE_ROM[gb]="Game Boy ROM image:"
qFILE_TYPE_ROM[gbc]="Game Boy ROM image:"
qFILE_TYPE_ROM[gba]="Game Boy Advance ROM image:"
qFILE_TYPE_ROM[nds]="Nintendo DS ROM image:"
qFILE_TYPE_ROM[gg]="Sega Game Gear ROM image:"
qFILE_TYPE_ROM[sms]="Sega Master System ROM image:"
qFILE_TYPE_ROM["32x"]="Sega 32X ROM image:"
qFILE_TYPE_ROM["68k"]="Sega Mega Drive / Genesis ROM image:"
qFILE_TYPE_ROM[gen]="Sega Mega Drive / Genesis ROM image:"
qFILE_TYPE_ROM[md]="Sega Mega Drive / Genesis ROM image:"
qFILE_TYPE_ROM[smd]="Sega Mega Drive / Genesis ROM image (SMD format):"
qFILE_TYPE_ROM[img]="Sega Mega CD disc image:"
declare -a array=("Sega Mega Drive / Genesis ROM image:" "Sega Saturn disc image:" "Sega Dreamcast disc image:")
qFILE_TYPE_ROM[bin]=$(declare -p array)
declare -a array=("Nintendo GameCube disc image:" "Nintendo Wii disc image:" "Sega Mega CD disc image:" "UDF filesystem data")
qFILE_TYPE_ROM[iso]=$(declare -p array)
array=()
# re-populate array Object:
# if [ "declare -a" = "${qFILE_TYPE[$key]::10}" ]; then eval "${qFILE_TYPE[$key]}"; fi
# or
# if [[ $value = "declare -a"* ]]; then eval "$value"; ...; fi
for key in "${!qFILE_TYPE_COM[@]}"
do
qFILE_TYPE[$key]="${qFILE_TYPE_COM[$key]}"
done
for key in "${!qFILE_TYPE_DIF[@]}"
do
qFILE_TYPE[$key]="${qFILE_TYPE_DIF[$key]}"
done
for key in "${!qFILE_TYPE_ROM[@]}"
do
qFILE_TYPE[$key]="${qFILE_TYPE_ROM[$key]}"
done
##########################################
# WINDOWS BUG FIX #
##########################################
# Fixes a BUG on Windows:
# Where Drag N Drop changes the working directory to
# C:\Windows\system32
# /c/Windows/system32
# This functions attempts to change it back based on the input of DragNdrop:
# changes=$(windows_fix)
function windows_fix() {
echo "windows_fix()"
local THIS_DIR=$(pwd)
for arg in "${global_args[@]}"
do
if [ "/c/Windows/system32" = "${THIS_DIR}" ]
then
local temp=$(getDirectory "${arg}")
if [ -n "${arg}" ] && [ -n "${temp}" ] && [ -d "${temp}" ]
then
echo "CHANGING DIRECTORY TO..."
echo "${temp}"
THIS_DIR="${temp}"
cd "${THIS_DIR}"
pwd
return 1
fi
fi
done
return 0
}
##########################################
# CLIENT-SIDE METHODS #
##########################################
function require_args() {
if [ $arg_count_nes_cli -le $(( $1 - 1 )) ]; then die "Not enough command line arguments (${arg_count_nes_cli}): ${operation}() requires $1"; fi
}
function onStartupClientsideValidation() {
# command -v xxd
true
}
##########################################
# START #
##########################################
onStartupClientsideValidation
windows_fix
# set -x
vgm_dir=$(getBase "$1")
base_header=$(get_baserom "${vgm_dir}")
echo "BASE HEADER:"
echo "${base_header}"
create_romhack "${base_header}"
# OPERATIONS ORDERED BY ADDRESS:
# 0x118
fix_year_dot_month
# 0x162
fix_tracks "${vgm_dir}"
# 0x16C
fix_intl_datecode "${vgm_dir}"
# 0x18E
fix_checksum
# 0x1A0
fix_eof_line
# 0x1D0
fix_author "${vgm_dir}"
# fixed.bin:
# SF II ~ VGM Player v3.30; 36 Tracks (@Dark Pulse)(v2005-11-20)(rev1.00)[OST] [!].bin
fix_filename "${vgm_dir}"
pause
close
@Europia79
Copy link
Author

Drag'N'Drop the VGM folder onto _FIX_HEADER.sh: Will fix the header & filename (in IUPAG format).
get_checksum() & get_bytesum() currently not working.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment