#!/bin/bash
##############################################################################
#
# Easy Qiniu Bash SDK
#
# Module: base64.sh
#
# Author: LIANG Tao
# Weibo: @無鋒之刃
# Email: liangtao@qiniu.com
# amethyst.black@gmail.com
#
# Wiki: http://en.wikipedia.org/wiki/Base64
#
##############################################################################
QNC_BASE64_PAD="="
function __qnc_base64_chr {
printf \\$(($1/64*100 + $1%64/8*10 + $1%8))
} # __qnc_base64_chr
function __qnc_base64_encode_calc {
local map=$1
local d1=$2
local d2=$3
local d3=$4
shift 4
if [[ -z "${d1}" || "${d1}" -eq 0 ]]; then
return 0
fi
if [[ -z "${d2}" ]]; then
d2=0
fi
if [[ -z "${d3}" ]]; then
d3=0
fi
local p1=$(( (${d1} >> 2) & 0x3F ))
local p2=$(( ( (${d1} & 0x3) << 4 ) | ( (${d2} & 0xF0) >> 4 ) ))
local p3=$(( ( (${d2} & 0xF) << 2 ) | ( (${d3} & 0xC0) >> 6 ) ))
local p4=$(( ${d3} & 0x3F ))
### printf "%d %d %d %d\n" $p1 $p2 $p3 $p4
if [[ "${d2}" -eq 0 ]]; then
echo -n "${map:$p1:1}${map:$p2:1}"
return 1
fi
if [[ "${d3}" -eq 0 ]]; then
echo -n "${map:$p1:1}${map:$p2:1}${map:$p3:1}"
return 2
fi
echo -n "${map:$p1:1}${map:$p2:1}${map:$p3:1}${map:$p4:1}"
return 3
} # __qnc_base64_encode_calc
function __qnc_base64_encode_impl {
local map=$1
local buf=$2
shift 2
local len=0
local ret=""
local buf_len=${#buf}
if [[ "${buf_len}" -eq 0 ]]; then
while read d1 d2 d3; do
local output=""
output="$(__qnc_base64_encode_calc "${map}" "${d1}" "${d2}" "${d3}")"
len=$(( ${len} + $? ))
if [[ -z "${output}" ]]; then
break
fi
ret="${ret}${output}"
done
else
local i=0
while true; do
local i1=$(( $i + 1 ))
local i2=$(( $i + 2 ))
local input="$(LC_CTYPE=C printf "%d %d %d" \'${buf:$i:1} \'${buf:${i1}:1} \'${buf:${i2}:1})"
local output=""
output="$(__qnc_base64_encode_calc "${map}" ${input})"
len=$(( ${len} + $? ))
i=$(( $i + 3 ))
if [[ -z "${output}" ]]; then
break
fi
ret="${ret}${output}"
done
fi
echo -n "${ret}"
if [[ -n "${QNC_BASE64_PAD}" ]]; then
local padding_len=$(( 3 - (${len} % 3) ))
if [[ "${padding_len}" -eq 1 ]]; then
echo -n "${QNC_BASE64_PAD}"
elif [[ "${padding_len}" -eq 2 ]]; then
echo -n "${QNC_BASE64_PAD}${QNC_BASE64_PAD}"
fi
fi
return 0
} # __qnc_base64_encode_impl
function __qnc_base64_encode_wrapper {
if [[ $# -gt 1 ]]; then
__qnc_base64_encode_impl "$@"
else
od -v -tu1 -An | \
tr '\n' ' ' | \
grep -o '\([0-9]\+ *\)\{1,3\}' | \
__qnc_base64_encode_impl "$@"
fi
} # __qnc_base64_encode_wrapper
function __qnc_base64_decode_calc {
local map=$1
local c1=$2
local c2=$3
local c3=$4
local c4=$5
shift 5
local prefix=""
local chr=0
local ord=0
if [[ -z "${c1}" || "${c1}" == "${QNC_BASE64_PAD}" ]]; then
return 0
fi
### decode first byte
prefix="${map%%${c1}*}"
ord="${#prefix}"
chr=$(( (${ord} & 0x3F) << 2 ))
if [[ -z "${c2}" || "${c2}" == "${QNC_BASE64_PAD}" ]]; then
return 0
fi
### decode second byte
prefix="${map%%${c2}*}"
ord="${#prefix}"
chr=$(( ${chr} | ( (${ord} & 0x30) >> 4 ) ))
echo -n "$(__qnc_base64_chr "${chr}")"
chr=$(( (${ord} & 0xF) << 4 ))
if [[ -z "${c3}" || "${c3}" == "${QNC_BASE64_PAD}" ]]; then
return 0
fi
### decode third byte
prefix="${map%%${c3}*}"
ord="${#prefix}"
chr=$(( ${chr} | ( (${ord} & 0x3C) >> 2 ) ))
echo -n "$(__qnc_base64_chr "${chr}")"
chr=$(( (${ord} & 0x3) << 6 ))
if [[ -z "${c4}" || "${c4}" == "${QNC_BASE64_PAD}" ]]; then
return 0
fi
### decode fourth byte
prefix="${map%%${c4}*}"
ord="${#prefix}"
chr=$(( ${chr} | (${ord} & 0x3F) ))
echo -n "$(__qnc_base64_chr "${chr}")"
return 0
} # __qnc_base64_decode_calc
function __qnc_base64_decode_impl {
local map=$1
local buf=$2
shift 2
local buf_len=${#buf}
if [[ "${buf_len}" -eq 0 ]]; then
while read d1 d2 d3 d4; do
local output=""
output="$(__qnc_base64_decode_calc "${map}" "${d1}" "${d2}" "${d3}" "${d4}")"
if [[ -z "${output}" ]]; then
break
fi
echo -n "${output}"
done
else
local i=0
while true; do
local i1=$(( $i + 1 ))
local i2=$(( $i + 2 ))
local i3=$(( $i + 3 ))
local output=""
output="$(__qnc_base64_decode_calc "${map}" "${buf:$i:1}" "${buf:$i1:1}" "${buf:$i2:1}" "${buf:$i3:1}")"
if [[ -z "${output}" ]]; then
break
fi
echo -n "${output}"
i=$(( $i + 4 ))
done
fi
return 0
}; # decode_impl
function __qnc_base64_decode_wrapper {
if [[ $# -gt 1 ]]; then
__qnc_base64_decode_impl "$@"
else
grep -o '[^ ]' | \
tr '\n' ' ' | \
grep -o '\([^ ]\+ *\)\{1,4\}' | \
__qnc_base64_decode_impl "$@"
fi
} # __qnc_base64_decode_wrapper
__QNC_BASE64_URLSAFE_MAP="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
function base64_encode_urlsafe {
__qnc_base64_encode_wrapper "${__QNC_BASE64_URLSAFE_MAP}" "$@"
} # base64_encode_urlsafe
function base64_decode_urlsafe {
__qnc_base64_decode_wrapper "${__QNC_BASE64_URLSAFE_MAP}" "$@"
} # base64_decode_urlsafe
__QNC_BASE64_MAP="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
function base64_encode {
__qnc_base64_encode_wrapper "${__QNC_BASE64_MAP}" "$@"
} # base64_encode
function base64_decode {
__qnc_base64_decode_wrapper "${__QNC_BASE64_MAP}" "$@"
} # base64_decode
###echo -n "abcd" | base64_encode
###echo
###base64_encode "abcd"
###echo
###echo -n "YWJjZA==" | base64_decode
###echo
###base64_decode "YWJjZA=="
###echo