#!/bin/bash
#
# Copyright (C) 2013, 2020, 2023, 2026  Etersoft
# Copyright (C) 2013, 2020, 2023, 2026  Vitaly Lipatov <lav@etersoft.ru>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#

PROGDIR=$(dirname "$0")
[ "$PROGDIR" = "." ] && PROGDIR=$(pwd)

# will replaced to /usr/share/erc during install
SHAREDIR=/usr/share/erc

load_helper()
{
    local CMD="$SHAREDIR/$1"
    [ -r "$CMD" ] || fatal "Have no $CMD helper file"
    . "$CMD"
}

load_helper erc-sh-functions
load_helper erc-sh-archive

check_tty

phelp()
{
	echo "$Descr
$Usage
 Commands:
$(get_help HELPCMD)

 Options:
$(get_help HELPOPT)
"
}

print_version()
{
        echo "Etersoft uncompressor version 1.1.9-alt1"
        echo "Copyright (c) Etersoft 2013, 2020, 2023, 2026"
        echo "This program may be freely redistributed under the terms of the GNU AGPLv3."
}

# Run decompressor on $file (from caller scope) or stdin
decomp()
{
    local prg="$1"
    local pkg="$2"
    shift 2
    if ! is_command "$prg" ; then
        epm assure "$prg" "$pkg" || fatal "Try install $pkg package for $prg unpack command."
    fi
    if [ -n "$file" ] ; then
        docmd "$prg" "$@" "$file" || fatal
    else
        docmd "$prg" "$@" || fatal
    fi
}

# Decompress to stdout
# Usage: unpack_type TYPE [FILE]
# Without FILE, reads from stdin
unpack_type()
{
    local file="$2"
    case $1 in
        gz|gzip)
            if is_command pigz ; then
                decomp pigz pigz -dc
            else
                decomp gunzip gzip -c
            fi
            ;;
        bz2|bzip2)
            if is_command pbzip2 ; then
                decomp pbzip2 pbzip2 -dc
            else
                decomp bzcat bzip2
            fi
            ;;
        xz)
            if [ -n "$file" ] && is_command pixz ; then
                docmd pixz -d < "$file"
            else
                decomp xzcat xz
            fi
            ;;
        Z|compress)
            decomp zcat gzip
            ;;
        lzma)
            decomp lzcat xz
            ;;
        zst|zstd)
            decomp zstdcat zstd
            ;;
        lz4)
            decomp lz4 lz4 -dc
            ;;
        plain)
            if [ -n "$file" ] ; then
                docmd cat "$file" || fatal
            else
                cat
            fi
            ;;
        *)
            fatal "Unsupported compression format $1"
            ;;
    esac
}

# Read from stdin, detect format via file(1), decompress to stdout
process_stdin()
{
    local hex mime TYPE

    # Read first 14 bytes as hex (enough for file(1) to detect all formats)
    hex=$(dd bs=1 count=14 2>/dev/null | bytes_to_hex)

    if [ -z "$hex" ] ; then
        return 0
    fi

    mime=$(hex_to_bytes "$hex" | file --mime-type -b -)

    if TYPE=$(mime_to_type "$mime") ; then
        { hex_to_bytes "$hex"; cat; } | unpack_type "$TYPE"
    else
        fatal "Unknown binary data on stdin ($mime), cannot detect compression format"
    fi
}

progname="${0##*/}"

Usage="Usage: $progname [options] [file(s)...|-]"
Descr="ercat - universal file uncompressor (supports stdin)"

quiet=
cmd=$1

# No args: read from stdin if piped, otherwise show help
if [ -z "$cmd" ] ; then
    if [ -t 0 ] ; then
        print_version
        echo
        fatal "Run $ $progname --help for get help"
    else
        process_stdin
        exit $?
    fi
fi

case $cmd in
    -h|--help|help)       # HELPOPT: this help
        phelp
        exit
        ;;
    -q|--quiet)           # HELPOPT: be silent
        quiet=--quiet
        shift
        cmd=$1
        ;;
    -v|--version)         # HELPOPT: print version
        print_version
        exit
        ;;
esac

for f in "$@" ; do
    if [ "$f" = "-" ] ; then
        process_stdin || fatal
        continue
    fi
    TYPE=$(get_archive_ext "$f") || TYPE=$(detect_by_content "$f") || { warning "Skipping unrecognized $f" ; continue ; }
    ( unpack_type "$TYPE" "$f" ) || warning "Failed to unpack $f, skipping..."
done
