a2cloud/setup/acmd
T. Joseph Carter 55c53b9c10 Clarify license on script files
As noted, Ivan has agreed to allow these scripts to be relicensed under
CC0.  We have one file under LGPL (a unit file we lifted wholesake from
systemd) and the ADTPro wrapper which I'm pretty sure Ivan wrote, but if
he didn't we need to fix its license to be the same as ADTPro.

Either way, to the best of my knowledge, this resolves the question of
how things are licensed explicitly.  (Closes #21)
2018-06-24 21:48:42 -07:00

422 lines
18 KiB
Bash
Executable File

#! /bin/bash
# vim: set tabstop=4 shiftwidth=4 noexpandtab filetype=sh:
# acmd - a2cloud command-line wrapper for Apple II file utilities
#
# To the extent possible under law, T. Joseph Carter and Ivan Drucker have
# waived all copyright and related or neighboring rights to the a2cloud
# scripts themselves. Software used or installed by these scripts is subject
# to other licenses. This work is published from the United States.
# set default AppleCommander location if ADTPro is not installed
defaultAcPath=$(echo -n /usr/local/bin/AppleCommander-*-ac.jar)
echoerr() {
echo "$@" 1>&2;
}
helpExit () {
if [[ -s $acmdStdErr ]]; then
if [[ $(grep CommandLineHelp $acmdStdErr) ]]; then
grep -v ^-[pge][[:space:]] $acmdStdErr | grep -v '^ or' | grep -v 0x2000 1>&2
echoerr "-g <imagename> <filename> [<outputFilename>] copy filename out of any"
echoerr " disk image. Using - for outputFilename will copy to stdout."
echoerr "-e <imagename> <filename> [<outputFilename>] like -g, with conversion"
echoerr " to modern file format if possible."
echoerr "-p <imagename> <filename> [[$|0x]<type>] [[$|0x]<auxtype>] copy filename"
echoerr " into ProDOS disk image. <type> is either three-letter or numeric"
echoerr " ProDOS file type (BIN if omitted). Will read from stdin if supplied."
echoerr " ProDOS subdirectories in <filename> will be created if needed."
echoerr " If an AppleDouble file or Nulib2 extended filename is detected,"
echoerr " <type> and <auxtype> are automatically set, and resource forks are kept."
if hash cppo &> /dev/null; then
echoerr " (To extract these from a ProDOS image file, use cppo -ad or cppo -e.)"
fi
echoerr "-c <filename> <imagename> [[$|0x]<type>] [[$|0x]<auxtype>] synonym for -p"
echoerr " with filename and imagename reversed."
else
cat $acmdStdErr
fi
if [[ $arg1 == "-h" ]]; then
exitVal=0
else
exitVal=1
fi
else
if [[ $vsd1_md5 && ( "$vsd1_md5" != "$(md5sum /usr/local/adtpro/disks/Virtual.po)" || "$vsd2_md5" != "$(md5sum /usr/local/adtpro/disks/Virtual2.po)" ) ]]; then
if [[ "$vsd1_md5" != "$(md5sum /usr/local/adtpro/disks/Virtual.po)" || "$vsd2_md5" != "$(md5sum /usr/local/adtpro/disks/Virtual2.po)" ]]; then
echoerr "One of the virtual drive image files has changed while ADTPro server is active."
echoerr " If using VSDRIVE, type 'vsdsync' now to see changes and prevent corruption."
fi
fi
exitval=0
fi
rm $acmdStdErr &> /dev/null
exit $exitVal
}
decToBin () {
dec="$(( 10#$1 ))"
bits=""
for i in 7 6 5 4 3 2 1 0; do
bits+=$(( (dec & (2**i)) >> i ))
done
echo -n "$(( 10#$bits ))"
}
arg1=$1
acmdStdErr="/tmp/acmd_$RANDOM$RANDOM"
[[ -f /usr/libexec/java_home ]] && osx=1 || osx=
if [[ $osx ]]; then
if ! /usr/libexec/java_home &> /dev/null; then
echo -n "AppleCommander requires the Java JDK. Do you want to install it now? "
read
if [[ ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then
# install Oracle Java for OS X
echo "Downloading Java JDK..."
mkdir -p /tmp/jdk
curl -L --cookie oraclelicense=accept-securebackup-cookie $(curl -L "http://www.oracle.com/"$(curl -L "http://www.oracle.com/technetwork/java/javase/downloads/" 2> /dev/null | grep -o -m 1 '/technetwork/java/javase/downloads/jdk.-downloads-[0-9]*\.html') 2> /dev/null | grep -o 'http://.*macosx-x64.dmg' | sort | tail -1) 2> /dev/null > /tmp/jdk/jdk.dmg
echo "Installing Java JDK..."
hdiutil attach /tmp/jdk/jdk.dmg &> /dev/null
sudo installer -pkg /Volumes/JDK*/JDK*.pkg -target /
diskutil unmountDisk /Volumes/JDK*
rm -r /tmp/jdk 2> /dev/null
if ! /usr/libexec/java_home &> /dev/null; then
echo "The Java JDK could not be installed."
echo "Type \"java\" and then click \"More Info...\" to download and install it manually."
exit 1
fi
else
exit 1
fi
fi
else # not OS X, so presumably Linux
if ! hash java &> /dev/null; then
echo -n "AppleCommander requires the Java JDK. "
if hash apt-get; then
echo -n "Do you want to install it now? "
read
if [[ ${REPLY:0:1} == "Y" || ${REPLY:0:1} == "y" ]]; then
# from http://www.webupd8.org/2012/06/how-to-install-oracle-java-7-in-debian.html
if { ! grep -q webupd8team /etc/apt/sources.list; }; then
{
echo;
echo "# Oracle Java JDK";
echo "deb http://ppa.launchpad.net/webupd8team/java/ubuntu precise main";
echo "deb-src http://ppa.launchpad.net/webupd8team/java/ubuntu precise main";
} | sudo tee -a /etc/apt/sources.list > /dev/null
fi
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys EEA14886
sudo apt-get -y update
echo debconf shared/accepted-oracle-license-v1-1 select true | sudo debconf-set-selections
sudo apt-get -y install oracle-java8-installer
sudo apt-get -y clean
else
exit 1
fi
fi
fi
if ! hash java &> /dev/null; then
echo
echo "Get it from http://www.oracle.com/technetwork/java/javase/downloads/"
exit 1
fi
fi
setAcPath () {
acPath=$defaultAcPath
adtPath=
if [[ ! -f $acPath ]]; then
if [[ -f /usr/local/adtpro/adtpro.sh ]]; then
adtPath="/usr/local/adtpro"
elif [[ $osx ]]; then
adtPath=$(echo -n /Applications/ADTPro* | tr ' ' '\n' | sort | head -1);
fi
if [[ -d "$adtPath" ]]; then
acPath="$adtPath"/lib/AppleCommander/AppleCommander-ac.jar
[[ ! -f $acPath ]] && acPath=$(echo -n "$adtPath"/lib/AppleCommander/AppleCommander-*-ac.jar)
fi
fi
acPath=$(echo -n $acPath)
}
setAcPath
if [[ ! -f $acPath ]]; then
echo "Installing AppleCommander..."
sudo mkdir -p /usr/local/bin
acUrl="http://sourceforge.net/projects/applecommander/files/AppleCommander%20-%20Interim/testcase/AppleCommander-1.3.5.13id-ac.jar/download"
if [[ $osx ]]; then
curl -L "$acUrl" 2> /dev/null | sudo tee /usr/local/bin/AppleCommander-1.3.5.13id-ac.jar > /dev/null
else
sudo wget -qO /usr/local/bin/AppleCommander-1.3.5.13id-ac.jar "$acUrl"
fi
setAcPath
if [[ ! -f "$acPath" ]]; then
echo "AppleCommander couldn't be installed. Download it from"
echo "http://applecommander.sourceforge.net and put it in /usr/local/bin."
exit 1
fi
fi
ac="java -Xmx128m -jar $acPath"
if [[ ! $2 || $arg1 == "-h" ]]; then
java -jar "$acPath" 2> $acmdStdErr
[[ $? -eq 127 ]] && exit 127 || helpExit $arg1
fi
if [[ $arg1 != "-i" && $arg1 != "-ls" && $arg1 != "-l" && $arg1 != "-ll" && $arg1 != "-x" && $arg1 != "-g" && $arg1 != "-e" && $(ps aux | grep [A]DTPro) ]]; then
vsd1_md5="$(md5sum /usr/local/adtpro/disks/Virtual.po)"
vsd2_md5="$(md5sum /usr/local/adtpro/disks/Virtual2.po)"
fi
if [[ ( $arg1 == "-p" || $arg1 == "-c" || $arg1 == "-g" || $arg1 == "-e" ) && $2 && $3 ]]; then
AD=
EX=
prodosArg=
prodosArgParent=
rFile=
getArg=
if [[ $arg1 == "-c" || $arg1 == "-p" ]]; then
if [[ $arg1 == "-c" ]]; then
prodosArg="$2"
imageArg="$3"
elif [[ $arg1 == "-p" ]]; then
prodosArg="$3"
imageArg="$2"
fi
[[ $prodosArg == *"/"* ]] && prodosArgParent="${prodosArg%/*}/"
rFile="${prodosArgParent}.AppleDouble/${prodosArg##*/}"
if [[ -f "$prodosArg" && -f "$rFile" ]]; then # AppleDouble
AD=1
elif [ -f "${prodosArg%#*}"#?????? ]; then # Nulib2 ext filename
EX=1
prodosArg=$(echo -n "${prodosArg%#*}"#??????)
rFile="${prodosArg}"r
fi
if [[ $AD || $EX ]]; then
# if target is not a ProDOS disk, ignore metadata
if ! $ac -i "$imageArg" | grep -q '^Disk Format: ProDOS'; then
AD=
EX=
fi
fi
elif [[ $arg1 == "-g" || $arg1 == "-e" ]]; then
fileArg="$3"
imageArg="$2"
getArg="$arg1"
else
exit 2;
fi
shift
if [[ $getArg ]]; then # get file
outFile=
[[ $3 && $3 != "-" ]] && outFile="$3"
[[ ! $3 ]] && outFile="${2##*/}"
$ac $getArg "$imageArg" "$fileArg" $outFile 2> $acmdStdErr
else # put file
# test ProDOS name validity
prodosPath=$(tr [:lower:] [:upper:] <<< "${prodosArg%#*}" )
IFS_orig="$IFS"; IFS="/";
prodosPathParts="$prodosPath"
for thisProdosPathPart in $prodosPathParts; do
if [[ ${#thisProdosPathPart} -gt 15 || ! $(grep ^[A-Z][0-9A-Z\.]*$ <<< $thisProdosPathPart) ]]; then
echoerr "Invalid ProDOS name: $prodosPath"; exit 1;
fi
done
IFS="$IFS_orig"
# filetype to name table
P_00=UNK; P_01=BAD; P_02=PCD; P_03=PTX; P_04=TXT; P_05=PDA; P_06=BIN; P_07=FNT; P_08=FOT; P_09=BA3; P_0a=DA3; P_0b=WPF; P_0c=SOS; P_0f=DIR; P_10=RPD; P_11=RPI; P_12=AFD; P_13=AFM; P_14=AFR; P_15=SCL; P_16=PFS; P_19=ADB; P_1a=AWP; P_1b=ASP; P_20=TDM; P_21=IPS; P_22=UPV; P_29=3SD; P_2a=8SC; P_2b=8OB; P_2c=8IC; P_2d=8LD; P_2e=P8C; P_41=OCR; P_42=FTD; P_50=GWP; P_51=GSS; P_52=GDB; P_53=DRW; P_54=GDP; P_55=HMD; P_56=EDU; P_57=STN; P_58=HLP; P_59=COM; P_5a=CFG; P_5b=ANM; P_5c=MUM; P_5d=ENT; P_5e=DVU; P_60=PRE; P_6b=BIO; P_6d=DVR; P_6e=PRE; P_6f=HDV; P_80=GEZ; P_81=GE1; P_82=GEO; P_83=GE3; P_84=GE4; P_85=GE5; P_86=GE6; P_87=GE7; P_88=GE8; P_89=GE9; P_8a=GEA; P_8b=GEB; P_8c=GEC; P_8d=GED; P_8e=GEE; P_8f=GEF; P_a0=WP_; P_ab=GSB; P_ac=TDF; P_ad=BDF; P_b0=SRC; P_b1=OBJ; P_b2=LIB; P_b3=S16; P_b4=RTL; P_b5=EXE; P_b6=STR; P_b7=TSF; P_b8=NDA; P_b9=CDA; P_ba=TOL; P_bb=DRV; P_bc=LDF; P_bd=FST; P_bf=DOC; P_c0=PNT; P_c1=PIC; P_c2=ANI; P_c3=PAL; P_c5=OOG; P_c6=SCR; P_c7=CDV; P_c8=FON; P_c9=FND; P_ca=ICN; P_d5=MUS; P_d6=INS; P_d7=MDI; P_d8=SND; P_db=DBM; P_e0=SHK; P_e2=DTS; P_ee=R16; P_ef=PAS; P_f0=CMD; P_f9=P16; P_fa=INT; P_fb=IVR; P_fc=BAS; P_fd=VAR; P_fe=REL; P_ff=SYS;
# process filetype
if [[ ! $AD && ! $EX ]]; then # no resource fork or metadata
[[ ${3:0:2} == "0x" ]] && ftArg="\$${3:2}" || ftArg="$3"
auxType="$4"
# assume BIN/$2000 if filetype omitted
if [[ ! $ftArg ]]; then
ft="BIN"
auxType="\$2000"
# accept hex or decimal number for file type
elif [[ ( ${ftArg:0:1} == '$' && ${#ftArg} -eq 3 ) || $(grep [0-9] <<< ${ftArg:0:1}) ]]; then
if [[ ${ftArg:0:1} == '$' ]]; then
fc=$(tr [:upper:] [:lower:] <<< ${ftArg:1:2})
else
fc=$(printf %02X "$ftArg" | tr [:upper:] [:lower:])
fi
ftVar="P_$fc";
[[ ${!ftVar} ]] && ft=${!ftVar} || ft="\$$fc";
else
ft="$ftArg"
fi
# set auxtype to $0801 for Applesoft programs if not specified
[[ $ft == "BAS" && ! $auxType ]] && auxType="\$0801"
# test for absence of stdin [[ -t 0 ]] and if absent use ProDOS name
if [[ -t 0 ]]; then
[[ ! -f $prodosArg ]] && { echoerr "$prodosArg not found."; exit 1; }
$ac -d "$imageArg" $prodosPath &> /dev/null
$ac -p "$imageArg" $prodosPath $ft $auxType < $prodosArg 2> $acmdStdErr
else
$ac -d "$imageArg" $prodosPath &> /dev/null
$ac -p "$imageArg" $prodosPath $ft $auxType 2> $acmdStdErr
fi
else # AppleDouble or nulib extended, get resource fork and file metadata from header file
[[ ! -f $prodosArg ]] && { echoerr "$prodosArg not found."; exit 1; }
[[ $AD && ! -f $rFile ]] && { echoerr "Not an AppleDouble file: $rFile"; exit 1; }
if [[ $AD ]]; then
# get metadata from AppleDouble header
[[ $(dd if="$rFile" bs=1 count=1 skip=741 2> /dev/null | wc -c) -gt 0 ]] && isExtFile=1 || isExtFile=
fileData=$(dd if="$rFile" bs=1 count=24 skip=637 2> /dev/null | xxd -p | tr -d '\n')
ftVar="P_${fileData:34:2}";
auxType="\$"${fileData:36:4}
cDateTime=$(printf %d 0x${fileData:0:8})
mDateTime=$(printf %d 0x${fileData:8:8})
[[ $(printf %d 0x"${fileData:0:2}") -gt 127 ]] && (( cDateTime-=4294967296 )) # handle negative hex number
[[ $(printf %d 0x"${fileData:8:2}") -gt 127 ]] && (( mDateTime-=4294967296 )) # handle negative hex number
(( cDateTime+=946684800 )) # convert AD timestamp to Unix timestamp
(( mDateTime+=946684800 )) # convert AD timestamp to Unix timestamp
else # EX
# get metadata from file info
[[ -f "$rFile" ]] && isExtFile=1 || isExtFile=
ftVar="P_${prodosArg: -6:2}"
auxType="\$"${prodosArg: -4}
if [[ $osx ]]; then
mDateTime=$(stat -f "%m" "$prodosArg")
else
mDateTime=$(stat -c %Y "$prodosArg")
fi
cDateTime=$mDateTime
fi
[[ ${!ftVar} ]] && ft=${!ftVar} || ft="\$$fc"; # set file type
# convert unix timestamp to ProDOS bitfield yyyyyyymmmmddddd 000hhhhh00mmmmmm
cDateFields=($(date -d @$cDateTime +"%y %m %d %H %M" 2> /dev/null))
[[ ! $cDateFields ]] && cDateFields=($(date -r $cDateTime +"%y %m %d %H %M")) # OS X/BSD
mDateFields=($(date -d @$mDateTime +"%y %m %d %H %M" 2> /dev/null))
[[ ! $mDateFields ]] && mDateFields=($(date -r $mDateTime +"%y %m %d %H %M")) # OS X/BSD
cDateTimeHex=$(printf %08X $(( 2#$(printf %07d $(decToBin ${cDateFields[0]}))$(printf %04d $(decToBin ${cDateFields[1]}))$(printf %05d $(decToBin ${cDateFields[2]}))$(printf %08d $(decToBin ${cDateFields[3]}))$(printf %08d $(decToBin ${cDateFields[4]})) )))
cDateTimeHex=${cDateTimeHex:2:2}${cDateTimeHex:0:2}${cDateTimeHex:6:2}${cDateTimeHex:4:2}
mDateTimeHex=$(printf %08X $(( 2#$(printf %07d $(decToBin ${mDateFields[0]}))$(printf %04d $(decToBin ${mDateFields[1]}))$(printf %05d $(decToBin ${mDateFields[2]}))$(printf %08d $(decToBin ${mDateFields[3]}))$(printf %08d $(decToBin ${mDateFields[4]})) )))
mDateTimeHex=${mDateTimeHex:2:2}${mDateTimeHex:0:2}${mDateTimeHex:6:2}${mDateTimeHex:4:2}
# create forks and file entry
### RIGHT HERE PROBLEMS IF #000000 specified and maybe if not
fileName="${prodosPath##*/}"
if [[ $isExtFile ]]; then
dfName=X$(printf %04X $RANDOM $RANDOM $RANDOM)
while [[ ! $rfName || $rfName == $dfName ]]; do
rfName=X$(printf %04X $RANDOM $RANDOM $RANDOM)
done
while [[ $fileName == "${prodosPath##*/}" || $rfName == $fileName || $dfName == $fileName ]]; do
fileName=X$(printf %04X $RANDOM $RANDOM $RANDOM)
done
$ac -d "$imageArg" "${prodosArgParent}$dfName" 2> /dev/null
dd if="$prodosArg" 2> /dev/null | $ac -p "$imageArg" "${prodosArgParent}$dfName" $00 2> $acmdStdErr
$ac -d "$imageArg" "${prodosArgParent}$rfName" 2> /dev/null
dd if="$rFile" bs=1 skip=$(( 0$AD ? 741 : 0 )) 2> /dev/null | $ac -p "$imageArg" "${prodosArgParent}$rfName" $00 2> $acmdStdErr
fi
# create file entry, then find it
$ac -d "$imageArg" "${prodosArgParent}$fileName" 2> /dev/null
[[ $isExtFile ]] && ddsrc="if=/dev/zero bs=512 count=1" || ddsrc="if=$prodosArg"
dd $ddsrc 2> /dev/null | $ac -p "$imageArg" "${prodosArgParent}$fileName" "$ft" "$auxType" 2> $acmdStdErr
# thx to http://unix.stackexchange.com/a/122945/99697 for perl alternative to broken --byte-offset in grep 2.5.1 (e.g. in OS X)
fileEntryOffset=$(perl -n0777e "print pos()-length('.$fileName') while /.$fileName/g" < "$imageArg")
fileEntry=$(dd if="$imageArg" bs=1 count=39 skip=$fileEntryOffset 2> /dev/null | xxd -p | tr -d '\n')
if [[ $isExtFile ]]; then
extKeyBlockOffset=$(( ( ( $(printf %d 0x"${fileEntry:36:2}") * 256 ) + $(printf %d 0x"${fileEntry:34:2}") * 512 ) ))
# find data fork, copy storage type, key block, block size, length to extended key block mini-entry
# then mark as available/deleted
dfOffset=$(perl -n0777e "print pos()-length('.$dfName') while /.$dfName/g" < "$imageArg")
dfEntry=$(dd if="$imageArg" bs=1 count=39 skip=$dfOffset 2> /dev/null | xxd -p | tr -d '\n')
dfStorageType=$(printf %02X $(( $(printf %d 0x${dfEntry:0:2}) >> 4 )) )
dfBlocksUsed=$(( ( $(printf %d 0x${dfEntry:40:2}) * 256 ) + $(printf %d 0x${dfEntry:38:2}) ))
dfInfo=${dfEntry:34:14}
echo -n -e \\x"$dfStorageType"$(sed 's/../\\x&/g' <<< $dfInfo) \
| dd of="$imageArg" conv=notrunc bs=1 seek=$(( extKeyBlockOffset+0 )) 2> /dev/null
# mark as deleted
echo -n -e \\x0${dfEntry:1:1} \
| dd of="$imageArg" conv=notrunc bs=1 seek=$(( dfOffset+0 )) 2> /dev/null
# find resource fork, copy storage type, key block, block size, length to extended key block mini-entry
# then mark as available/deleted
rfOffset=$(perl -n0777e "print pos()-length('.$rfName') while /.$rfName/g" < "$imageArg")
rfEntry=$(dd if="$imageArg" bs=1 count=39 skip=$rfOffset 2> /dev/null | xxd -p | tr -d '\n')
rfStorageType=$(printf %02X $(( $(printf %d 0x${rfEntry:0:2}) >> 4 )) )
rfBlocksUsed=$(( ( $(printf %d 0x${rfEntry:40:2}) * 256 ) + $(printf %d 0x${rfEntry:38:2}) ))
rfInfo=${rfEntry:34:14}
echo -n -e \\x"$rfStorageType"$(sed 's/../\\x&/g' <<< $rfInfo) \
| dd of="$imageArg" conv=notrunc bs=1 seek=$(( extKeyBlockOffset+256 )) 2> /dev/null
# mark as deleted
echo -n -e \\x0${rfEntry:1:1} \
| dd of="$imageArg" conv=notrunc bs=1 seek=$(( rfOffset+0 )) 2> /dev/null
# reduce active file count in directory by two
parentDirKeyBlockOffset=$(( ( ( $(printf %d 0x"${fileEntry:76:2}") * 256 ) + $(printf %d 0x"${fileEntry:74:2}") * 512 ) ))
fileCountHex=$(dd if="$imageArg" bs=1 count=2 skip=$((parentDirKeyBlockOffset+4+33)) 2> /dev/null | xxd -p)
fileCount=$(( ( $(printf %d 0x${fileCountHex:2:2}) * 256 ) + $(printf %d 0x${fileCountHex:0:2}) ))
fileCountHex=$(printf %04X $((fileCount - 2)))
echo -n -e \\x${fileCountHex:2:2}\\x${fileCountHex:0:2} \
| dd of="$imageArg" conv=notrunc bs=1 seek=$((parentDirKeyBlockOffset+4+33)) 2> /dev/null
# update extended file metadata
# storage type (5), name length, name
name="${prodosPath##*/}"
nameLen=${#name}
nameHeader=$(printf %02X $((nameLen + 80)) )
nameField=$(echo -n $name | xxd -p | tr -d '\n' | sed -e :a -e 's/^.\{1,29\}$/&00/;ta')
# blocks used
blocksUsed=$(( dfBlocksUsed + rfBlocksUsed + 1 ))
# store updated metadata
fileEntry=${nameHeader}${nameField}${fileEntry:32}
fi
# put creation and modified date in file entry
fileEntry=${fileEntry:0:48}${cDateTimeHex}${fileEntry:56:10}${mDateTimeHex}${fileEntry:74:4}
# put casemask for mixed case filename in file entry
[[ $EX ]] && prodosArg="${prodosArg%#*}"
if [[ "${prodosPath##*/}" != "${prodosArg##*/}" ]]; then # mixed case
caseMaskDec=32768
mixedName="${prodosArg##*/}"
[[ $EX ]] && mixedName="${mixedName%#*}"
for (( i=0; i<${#mixedName}; i++ )); do
[[ "${mixedName:$i:1}" == $(tr [:lower:] [:upper:] <<< "${mixedName:$i:1}") ]] # $? == 0 means uppercase
(( caseMaskDec+=$(( $? * (2**(14-i)) )) ))
done
caseMaskHex=$(printf %04X $caseMaskDec)
fileEntry=${fileEntry:0:56}${caseMaskHex:2:2}${caseMaskHex:0:2}${fileEntry:60}
fi
# write updated metadata to file entry
echo -n -e $(sed 's/../\\x&/g' <<< $fileEntry) | dd of="$imageArg" bs=1 conv=notrunc seek=$fileEntryOffset 2> /dev/null
fi
fi
else
imageArg="$2"
$ac "$@" 2> $acmdStdErr
fi
helpExit