OLD | NEW |
(Empty) | |
| 1 #!/bin/bash |
| 2 # |
| 3 ############################################################################# |
| 4 # |
| 5 # 7z2lzma.bash is very primitive .7z to .lzma converter. The input file must |
| 6 # have exactly one LZMA compressed stream, which has been created with the |
| 7 # default lc, lp, and pb values. The CRC32 in the .7z archive is not checked, |
| 8 # and the script may seem to succeed while it actually created a corrupt .lzma |
| 9 # file. You should always try uncompressing both the original .7z and the |
| 10 # created .lzma and compare that the output is identical. |
| 11 # |
| 12 # This script requires basic GNU tools and 7z or 7za tool from p7zip. |
| 13 # |
| 14 # Last modified: 2009-01-15 14:25+0200 |
| 15 # |
| 16 ############################################################################# |
| 17 # |
| 18 # Author: Lasse Collin <lasse.collin@tukaani.org> |
| 19 # |
| 20 # This file has been put into the public domain. |
| 21 # You can do whatever you want with this file. |
| 22 # |
| 23 ############################################################################# |
| 24 |
| 25 # You can use 7z or 7za, both will work. |
| 26 SEVENZIP=7za |
| 27 |
| 28 if [ $# != 2 -o -z "$1" -o -z "$2" ]; then |
| 29 echo "Usage: $0 input.7z output.lzma" |
| 30 exit 1 |
| 31 fi |
| 32 |
| 33 # Converts an integer variable to little endian binary integer. |
| 34 int2bin() |
| 35 { |
| 36 local LEN=$1 |
| 37 local NUM=$2 |
| 38 local HEX=(0 1 2 3 4 5 6 7 8 9 A B C D E F) |
| 39 local I |
| 40 for ((I=0; I < "$LEN"; ++I)); do |
| 41 printf "\\x${HEX[(NUM >> 4) & 0x0F]}${HEX[NUM & 0x0F]}" |
| 42 NUM=$((NUM >> 8)) |
| 43 done |
| 44 } |
| 45 |
| 46 # Make sure we get possible errors from pipes. |
| 47 set -o pipefail |
| 48 |
| 49 # Get information about the input file. At least older 7z and 7za versions |
| 50 # may return with zero exit status even when an error occurred, so check |
| 51 # if the output has any lines beginning with "Error". |
| 52 INFO=$("$SEVENZIP" l -slt "$1") |
| 53 if [ $? != 0 ] || printf '%s\n' "$INFO" | grep -q ^Error; then |
| 54 printf '%s\n' "$INFO" |
| 55 exit 1 |
| 56 fi |
| 57 |
| 58 # Check if the input file has more than one compressed block. |
| 59 if printf '%s\n' "$INFO" | grep -q '^Block = 1'; then |
| 60 echo "Cannot convert, because the input file has more than" |
| 61 echo "one compressed block." |
| 62 exit 1 |
| 63 fi |
| 64 |
| 65 # Get compressed, uncompressed, and dictionary size. |
| 66 CSIZE=$(printf '%s\n' "$INFO" | sed -rn 's|^Packed Size = ([0-9]+$)|\1|p') |
| 67 USIZE=$(printf '%s\n' "$INFO" | sed -rn 's|^Size = ([0-9]+$)|\1|p') |
| 68 DICT=$(printf '%s\n' "$INFO" | sed -rn 's|^Method = LZMA:([0-9]+[bkm]?)$|\1|p') |
| 69 |
| 70 if [ -z "$CSIZE" -o -z "$USIZE" -o -z "$DICT" ]; then |
| 71 echo "Parsing output of $SEVENZIP failed. Maybe the file uses some" |
| 72 echo "other compression method than plain LZMA." |
| 73 exit 1 |
| 74 fi |
| 75 |
| 76 # The following assumes that the default lc, lp, and pb settings were used. |
| 77 # Otherwise the output will be corrupt. |
| 78 printf '\x5D' > "$2" |
| 79 |
| 80 # Dictionary size can be either was power of two, bytes, kibibytes, or |
| 81 # mebibytes. We need to convert it to bytes. |
| 82 case $DICT in |
| 83 *b) |
| 84 DICT=${DICT%b} |
| 85 ;; |
| 86 *k) |
| 87 DICT=${DICT%k} |
| 88 DICT=$((DICT << 10)) |
| 89 ;; |
| 90 *m) |
| 91 DICT=${DICT%m} |
| 92 DICT=$((DICT << 20)) |
| 93 ;; |
| 94 *) |
| 95 DICT=$((1 << DICT)) |
| 96 ;; |
| 97 esac |
| 98 int2bin 4 "$DICT" >> "$2" |
| 99 |
| 100 # Uncompressed size |
| 101 int2bin 8 "$USIZE" >> "$2" |
| 102 |
| 103 # Copy the actual compressed data. Using multiple dd commands to avoid |
| 104 # copying large amount of data with one-byte block size, which would be |
| 105 # annoyingly slow. |
| 106 BS=8192 |
| 107 BIGSIZE=$((CSIZE / BS)) |
| 108 CSIZE=$((CSIZE % BS)) |
| 109 { |
| 110 dd of=/dev/null bs=32 count=1 \ |
| 111 && dd bs="$BS" count="$BIGSIZE" \ |
| 112 && dd bs=1 count="$CSIZE" |
| 113 } < "$1" >> "$2" |
| 114 |
| 115 exit $? |
OLD | NEW |