Witchcraft/src/int.sh

192 lines
4.0 KiB
Bash

#!/usr/bin/env bash
# int.sh - int conversion functions, and other numeric functions
# int2varint(int)
function int2varint() {
# very proud of my implementation; haven't seen anyone use a modulo for this ;p
local a
local b
local c
local out
out=$(printf '%02x' "$1")
if [[ $1 -lt 128 ]]; then
:
elif [[ $1 -lt 16384 ]]; then
a=$(($1%128))
b=$(($1/128))
out=$(printf "%02x" $((a+128)))$(printf "%02x" $b)
elif [[ $1 -lt $((128*128*128)) ]]; then
a=$(($1%128))
c=$((($1/128)%128))
b=$(($1/16384))
out=$(printf "%02x" $((a+128)))$(printf "%02x" $((c+128)))$(printf "%02x" $b)
fi
echo -n "$out"
}
# varint2int() <<< varint
function varint2int() {
local x
local uwu
local out
out=""
x=1
while true; do
uwu=$(dd count=1 bs=1 status=none | xxd -p)
out=$((out+((0x$uwu&127)*x)))
x=$((x*128))
if [[ $((0x$uwu>>7)) == 0 ]]; then
break
fi
done
echo -n "$out"
}
# decode_position(Position)
# https://wiki.vg/Protocol#Position
function decode_position() {
x=$((0x$1 >> 38))
y=$((0x$1 & 0xFFF))
z=$(((0x$1 >> 12) & 0x3FFFFFF))
[[ $x -gt 33554431 ]] && x=$((x-67108864))
[[ $y -gt 2047 ]] && y=$((y-4095))
[[ $z -gt 33554431 ]] && z=$((z-67108864))
}
# encode_position(x, y, z)
function encode_position() {
local x
local y
local z
x=$1
y=$2
z=$3
[[ $x -lt 33554433 ]] && x=$((x+67108864))
[[ $y -lt 2049 ]] && y=$((y+4095))
[[ $z -lt 33554433 ]] && z=$((z+67108864))
printf "%016x" $((((x & 0x3FFFFFF)<<38) | ((z & 0x3FFFFFF)<<12) | (y & 0xFFF)))
}
# packet_len(packet)
function packet_len() {
int2varint $((($(echo -n "$1" | wc -c)+1)))
}
# hexpacket_len(hexpacket)
function hexpacket_len() {
int2varint $((($(echo -n "$1" | unhex | wc -c)+1)))
}
# str_len(string)
function str_len() {
int2varint $(echo -n "$1" | wc -c)
}
# hexstrl_len(hexstring)
function hexstr_len() {
int2varint $(echo -n "$1" | unhex | wc -c)
}
# hex2bin(hexstring)
function hex2bin() {
# \o/
echo -n "$1" | sed -E 's/0/0000/g;s/1/0001/g;s/2/0010/g;s/3/0011/g;s/4/0100/g;s/5/0101/g;s/6/0110/g;s/7/0111/g;s/8/1000/g;s/9/1001/g;s/a/1010/g;s/b/1011/g;s/c/1100/g;s/d/1101/g;s/e/1110/g;s/f/1111/g'
}
# from_ieee754(hexstring)
# this works only on ints
function from_ieee754() {
local sign
local exponent
local asdf
local exponent_
local val
val=$(hex2bin "$1")
sign=$(cut -c 1 <<< $val)
exponent=$(cut -c 2-12 <<< $val)
asdf=$(cut -c 13- <<< $val | sed -E 's/./,&/g;s/,//' | tr -d '\n' | awk -F , \
'{
power_count=-1
x=0;
for(i=1; i<=NF; i++) {
x=(x + ($i * (2 ** power_count)))
power_count=power_count-1;
}
print(x+1)
}')
exponent_=$((2#$exponent))
if [[ $sign == 0 ]]; then
echo "$asdf $exponent_" | awk '{print (int($1 * (2 ** ($2 - 1023))))}'
else
echo "$asdf $exponent_" | awk '{print -(int($1 * (2 ** ($2 - 1023))))}'
fi
}
# to_ieee754(number)
# this works only on ints
function to_ieee754() {
local n
local m
local i
local sign
local mantissa
n=$1
m=2
i=0
sign=0
if [[ $n -lt 0 ]]; then
n=$((n-2*n))
sign=1
fi
while true; do
if [[ $n -lt $((m*2)) ]]; then
break
fi
i=$((i+1))
m=$((m*2))
done
# we need to lie and tell Bash that this string is decimal, even though it's binary
# otherwise, it will interpret this as octal
# shh, nobody tell Bash
mantissa=$(printf "1%010d" $((10#$(hex2bin $(printf "%x" $i)))))
# leading zeroes kept screwing me over, I'm hardcoding 1 and -1.. and 0
if [[ $n == -1 ]]; then
printf "bff0000000000000"
elif [[ $n == 1 ]]; then
printf "3ff0000000000000"
elif [[ $n == 0 ]]; then
printf "0000000000000000"
else
res=$sign$mantissa$(printf "%0$((i+1))d" $(hex2bin $(printf "%x" $((n-m))) | sed -E 's/^0*//'))
printf "%x" $((2#$res$(repeat $((64-$(echo -n $res | wc -c))) 0)))
fi
}
# to_short(number)
function to_short() {
if [[ $1 -lt 0 && $1 -gt -32769 ]]; then
printf "%04x" $(($1+65536))
elif [[ $1 -lt 32768 && $1 -gt -1 ]]; then
printf "%04x" $1
elif [[ $1 -lt -32768 ]]; then
printf "8000"
elif [[ $1 -gt 32767 ]]; then
printf "7FFF"
fi
}