Skip to content

Instantly share code, notes, and snippets.

@yvesf
Created May 2, 2015 20:35
Show Gist options
  • Save yvesf/d8cf8d647c88513a5e5e to your computer and use it in GitHub Desktop.
Save yvesf/d8cf8d647c88513a5e5e to your computer and use it in GitHub Desktop.
Parse google-chrome .pak files in shell
#!/bin/bash
# Parse google-chrome .pak resourcefiles
parse_int() {
( echo "ibase=16; "; cat; echo -e "\n") | bc
}
endian_conversion() {
if [[ "$1" == "little" ]]; then
tac
else
cat
fi
}
read_bytes() {
local length=$1
local endian=$2
local i=0
while [ $i -lt $length ]; do
read -r -d ' ' byte
[ "$byte" == "" ] && read -r -d ' ' byte
echo $byte
let i+=1
done \
| endian_conversion "$endian" \
| tr -d '\n'
}
parse() {
local format=$1
local endian=big
local i=0
while [[ $i -lt ${#format} ]]; do
case "${format:$i:1}" in
"<") endian="little";;
">") endian="big";;
"I") read_bytes "4" "$endian" | parse_int; let offset+=4;;
"H") read_bytes "2" "$endian" | parse_int; let offset+=2;;
"B") read_bytes "1" "$endian" | parse_int; let offset+=1;;
*)
echo "Invalid format: ${format:$i:1}" >&2;;
esac
let i+=1
done | tr '\n' ' '
}
read_file() {
local file=$1
local offset=$2
local format=$3
dd if=$file bs=1 skip=$offset count=$(format_len "$format") 2>/dev/null \
| od --output-duplicates --format=x1 --address-radix=n \
| tr 'a-z' 'A-Z' | tr -d '\n'
}
parse_file() {
read_file "$1" "$2" "$3" | parse "$3"
}
format_len() {
local format=$1
local len=0
local i=0
while [[ $i -lt ${#format} ]]; do
case "${format:$i:1}" in
"I") let len+=4 ;;
"H") let len+=2 ;;
"B") let len+=1 ;;
"<"|">") ;;
*) echo "Invalid format: ${format:$i:1}" >&2;;
esac
let i+=1
done
echo "$len"
}
##################
header_size=$(format_len "<IIB")
entry_size=$(format_len "<HI")
read -r version num_entries encoding < \
<(parse_file "en-US.pak" 0 "<IIB")
if [ "$version" != "4" ]; then
echo "Invalid version: $version" >&2
exit 1
fi
if [ "$encoding" != "1" ]; then
echo "Invalid encoding: $encoding" >&2
exit 1
fi
pos=$header_size
i=0
while [ $i -lt $num_entries ]; do
read -r id offset next_id next_offset < <(parse_file "en-US.pak" $pos "<HIHI")
let pos+=entry_size
let entry_len=next_offset-offset
echo "$id: $(dd if=en-US.pak bs=1 count=$entry_len skip=$offset 2>/dev/null)"
let i+=1
done
Copy link

ghost commented Oct 13, 2022

for Windows you can also use 7zip with grit7z placed in formats folder
or this bundle. should also work with Linux+wine.

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