2023-05-29 14:47:19 +02:00
|
|
|
if [ "$1" = "-v" ]; then
|
|
|
|
VERBOSE=true
|
|
|
|
shift
|
|
|
|
else
|
|
|
|
VERBOSE=false
|
|
|
|
fi
|
|
|
|
|
2024-03-24 18:55:52 +01:00
|
|
|
if [ "$1" = "-n" ]; then
|
|
|
|
DECOMPRESS=false
|
|
|
|
shift
|
|
|
|
else
|
|
|
|
DECOMPRESS=true
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
2023-05-29 14:47:19 +02:00
|
|
|
if [ ! -f "$1" ]; then
|
2024-03-24 18:55:52 +01:00
|
|
|
echo "Usage: $0 [-v] [-n] FILE"
|
2023-05-29 14:47:19 +02:00
|
|
|
echo " -v display raw content and NBT dump"
|
2024-03-24 18:55:52 +01:00
|
|
|
echo " -n don't decompress"
|
2023-05-29 14:47:19 +02:00
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
# pointer data
|
|
|
|
OFFSET_HEX="0x$(dd bs=1 if="$1" count=3 2>/dev/null | hexdump -e '3/1 "%02x" "\n"')"
|
|
|
|
OFFSET="$(baseconvert -d $OFFSET_HEX)"
|
|
|
|
echo " offset: $OFFSET ($OFFSET_HEX)"
|
|
|
|
LENGTH_HEX="0x$(dd bs=1 if="$1" count=1 skip=3 2>/dev/null | hexdump -e '1/1 "%02x" "\n"')"
|
|
|
|
LENGTH="$(baseconvert -d $LENGTH_HEX)"
|
|
|
|
echo " length: $LENGTH ($LENGTH_HEX)"
|
|
|
|
|
|
|
|
#TODO: last modified
|
|
|
|
|
|
|
|
# chunk
|
|
|
|
DATA="$(dd if="$1" bs=4096 count=$LENGTH skip=$OFFSET 2>/dev/null | hexdump -v -e '16/1 "%02x" "\n"' | tr -d '
|
|
|
|
')"
|
|
|
|
|
|
|
|
# blob header
|
|
|
|
# bs=2 because each byte is two digits hex
|
|
|
|
COMPRESSED_LENGTH_HEX="0x$(dd bs=2 count=4 2> /dev/null <<< $DATA)"
|
|
|
|
COMPRESSED_LENGTH="$(baseconvert -d $COMPRESSED_LENGTH_HEX)"
|
|
|
|
echo " compressed length in bytes: $COMPRESSED_LENGTH ($COMPRESSED_LENGTH_HEX)"
|
|
|
|
FORMAT_HEX="0x$(dd bs=2 skip=4 count=1 2> /dev/null <<< $DATA)"
|
|
|
|
case $FORMAT_HEX in
|
|
|
|
"0x01")
|
|
|
|
FORMAT="gzip"
|
|
|
|
function UNCOMPRESS {
|
|
|
|
gzip -dc
|
|
|
|
}
|
|
|
|
;;
|
|
|
|
"0x02")
|
|
|
|
FORMAT="zlib"
|
|
|
|
function UNCOMPRESS {
|
|
|
|
cat > /tmp/chunk_zlib_decompress
|
|
|
|
python3 <<< "
|
|
|
|
import zlib,sys
|
|
|
|
a = open('/tmp/chunk_zlib_decompress', 'rb')
|
|
|
|
data = a.read()
|
|
|
|
a.close()
|
|
|
|
sys.stdout.buffer.write(zlib.decompress(data))
|
|
|
|
sys.stdout.buffer.flush()
|
|
|
|
"
|
|
|
|
rm /tmp/chunk_zlib_decompress
|
|
|
|
}
|
|
|
|
;;
|
|
|
|
*)
|
|
|
|
FORMAT="unknown"
|
|
|
|
function UNCOMPRESS {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
echo " format: $FORMAT ($FORMAT_HEX)"
|
|
|
|
|
2024-03-24 18:55:52 +01:00
|
|
|
|
|
|
|
if $DECOMPRESS; then
|
|
|
|
dd if="$1" bs=4096 count=$LENGTH skip=$OFFSET 2>/dev/null | dd bs=1 skip=5 count=$(($COMPRESSED_LENGTH-1)) 2>/dev/null | UNCOMPRESS > /tmp/chunk_uncompressed_nbt
|
|
|
|
else
|
|
|
|
dd if="$1" bs=4096 count=$LENGTH skip=$OFFSET 2>/dev/null | dd bs=1 skip=5 count=$(($COMPRESSED_LENGTH-1)) 2>/dev/null > /tmp/chunk_compressed_nbt
|
|
|
|
fi
|
|
|
|
|
2023-05-29 14:47:19 +02:00
|
|
|
if $VERBOSE; then
|
|
|
|
echo "Raw chunk data:"
|
|
|
|
echo "$DATA"
|
|
|
|
echo "NBT dump:"
|
|
|
|
|
|
|
|
#TODO: use pipes instead of a file
|
2024-03-24 18:55:52 +01:00
|
|
|
#TODO: fix this up to work with both compressed and uncompressed NBT
|
2023-05-29 14:47:19 +02:00
|
|
|
dumpnbt /tmp/chunk_uncompressed_nbt
|
|
|
|
rm /tmp/chunk_uncompressed_nbt
|
|
|
|
fi
|