115 lines
3.9 KiB
Bash
115 lines
3.9 KiB
Bash
|
#!/bin/bash
|
||
|
#
|
||
|
#############################################################################
|
||
|
#
|
||
|
# 7z2lzma.bash is very primitive .7z to .lzma converter. The input file must
|
||
|
# have exactly one LZMA compressed stream, which has been created with the
|
||
|
# default lc, lp, and pb values. The CRC32 in the .7z archive is not checked,
|
||
|
# and the script may seem to succeed while it actually created a corrupt .lzma
|
||
|
# file. You should always try uncompressing both the original .7z and the
|
||
|
# created .lzma and compare that the output is identical.
|
||
|
#
|
||
|
# This script requires basic GNU tools and 7z or 7za tool from p7zip.
|
||
|
#
|
||
|
# Last modified: 2008-09-27 11:05+0300
|
||
|
#
|
||
|
#############################################################################
|
||
|
#
|
||
|
# Copyright (C) 2008 Lasse Collin <lasse.collin@tukaani.org>
|
||
|
#
|
||
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||
|
# a copy of this software and associated documentation files (the
|
||
|
# "Software"), to deal in the Software without restriction, including
|
||
|
# without limitation the rights to use, copy, modify, merge, publish,
|
||
|
# distribute, sublicense, and/or sell copies of the Software, and to
|
||
|
# permit persons to whom the Software is furnished to do so, subject to
|
||
|
# the following conditions:
|
||
|
#
|
||
|
# The above copyright notice and this permission notice shall be
|
||
|
# included in all copies or substantial portions of the Software.
|
||
|
#
|
||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||
|
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||
|
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||
|
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||
|
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||
|
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||
|
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||
|
#
|
||
|
#############################################################################
|
||
|
|
||
|
# You can use 7z or 7za, both will work.
|
||
|
SEVENZIP=7za
|
||
|
|
||
|
if [ $# != 2 -o -z "$1" -o -z "$2" ]; then
|
||
|
echo "Usage: $0 input.7z output.lzma"
|
||
|
exit 1
|
||
|
fi
|
||
|
|
||
|
# Converts an integer variable to little endian binary integer.
|
||
|
int2bin()
|
||
|
{
|
||
|
local LEN=$1
|
||
|
local NUM=$2
|
||
|
local HEX=(0 1 2 3 4 5 6 7 8 9 A B C D E F)
|
||
|
local I
|
||
|
for ((I=0; I < "$LEN"; ++I)); do
|
||
|
printf "\\x${HEX[(NUM >> 4) & 0x0F]}${HEX[NUM & 0x0F]}"
|
||
|
NUM=$((NUM >> 8))
|
||
|
done
|
||
|
}
|
||
|
|
||
|
# Make sure we get possible errors from pipes.
|
||
|
set -o pipefail
|
||
|
|
||
|
# Get information about the input file. At least older 7z and 7za versions
|
||
|
# may return with zero exit status even when an error occurred, so check
|
||
|
# if the output has any lines beginning with "Error".
|
||
|
INFO=$("$SEVENZIP" l -slt "$1")
|
||
|
if [ $? != 0 ] || printf '%s\n' "$INFO" | grep -q ^Error; then
|
||
|
printf '%s\n' "$INFO"
|
||
|
exit 1
|
||
|
fi
|
||
|
|
||
|
# Check if the input file has more than one compressed block.
|
||
|
if printf '%s\n' "$INFO" | grep -q '^Block = 1'; then
|
||
|
echo "Cannot convert, because the input file has more than"
|
||
|
echo "one compressed block."
|
||
|
exit 1
|
||
|
fi
|
||
|
|
||
|
# Get copmressed, uncompressed, and dictionary size.
|
||
|
CSIZE=$(printf '%s\n' "$INFO" | sed -rn 's|^Packed Size = ([0-9]+$)|\1|p')
|
||
|
USIZE=$(printf '%s\n' "$INFO" | sed -rn 's|^Size = ([0-9]+$)|\1|p')
|
||
|
DICT=$(printf '%s\n' "$INFO" | sed -rn 's|^Method = LZMA:([0-9]+)$|\1|p')
|
||
|
|
||
|
if [ -z "$CSIZE" -o -z "$USIZE" -o -z "$DICT" ]; then
|
||
|
echo "Parsing output of $SEVENZIP failed. Maybe the file uses some"
|
||
|
echo "other compression method than plain LZMA."
|
||
|
exit 1
|
||
|
fi
|
||
|
|
||
|
# The following assumes that the default lc, lp, and pb settings were used.
|
||
|
# Otherwise the output will be corrupt.
|
||
|
printf '\x5D' > "$2"
|
||
|
|
||
|
# Dictionary size
|
||
|
int2bin 4 "$((1 << DICT))" >> "$2"
|
||
|
|
||
|
# Uncompressed size
|
||
|
int2bin 8 "$USIZE" >> "$2"
|
||
|
|
||
|
# Copy the actual compressed data. Using multiple dd commands to avoid
|
||
|
# copying large amount of data with one-byte block size, which would be
|
||
|
# annoyingly slow.
|
||
|
BS=8192
|
||
|
BIGSIZE=$((CSIZE / BS))
|
||
|
CSIZE=$((CSIZE % BS))
|
||
|
{
|
||
|
dd of=/dev/null bs=32 count=1 \
|
||
|
&& dd bs="$BS" count="$BIGSIZE" \
|
||
|
&& dd bs=1 count="$CSIZE"
|
||
|
} < "$1" >> "$2"
|
||
|
|
||
|
exit $?
|