]> icculus.org git repositories - icculus/xz.git/blob - extra/7z2lzma/7z2lzma.bash
Fixed Stream decoder to actually use the first_stream variable.
[icculus/xz.git] / extra / 7z2lzma / 7z2lzma.bash
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: 2008-09-27 11:05+0300
15 #
16 #############################################################################
17 #
18 # Copyright (C) 2008 Lasse Collin <lasse.collin@tukaani.org>
19 #
20 # Permission is hereby granted, free of charge, to any person obtaining
21 # a copy of this software and associated documentation files (the
22 # "Software"), to deal in the Software without restriction, including
23 # without limitation the rights to use, copy, modify, merge, publish,
24 # distribute, sublicense, and/or sell copies of the Software, and to
25 # permit persons to whom the Software is furnished to do so, subject to
26 # the following conditions:
27 #
28 # The above copyright notice and this permission notice shall be
29 # included in all copies or substantial portions of the Software.
30 #
31 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
34 # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
35 # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
36 # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
37 # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 #
39 #############################################################################
40
41 # You can use 7z or 7za, both will work.
42 SEVENZIP=7za
43
44 if [ $# != 2 -o -z "$1" -o -z "$2" ]; then
45         echo "Usage: $0 input.7z output.lzma"
46         exit 1
47 fi
48
49 # Converts an integer variable to little endian binary integer.
50 int2bin()
51 {
52         local LEN=$1
53         local NUM=$2
54         local HEX=(0 1 2 3 4 5 6 7 8 9 A B C D E F)
55         local I
56         for ((I=0; I < "$LEN"; ++I)); do
57                 printf "\\x${HEX[(NUM >> 4) & 0x0F]}${HEX[NUM & 0x0F]}"
58                 NUM=$((NUM >> 8))
59         done
60 }
61
62 # Make sure we get possible errors from pipes.
63 set -o pipefail
64
65 # Get information about the input file. At least older 7z and 7za versions
66 # may return with zero exit status even when an error occurred, so check
67 # if the output has any lines beginning with "Error".
68 INFO=$("$SEVENZIP" l -slt "$1")
69 if [ $? != 0 ] || printf '%s\n' "$INFO" | grep -q ^Error; then
70         printf '%s\n' "$INFO"
71         exit 1
72 fi
73
74 # Check if the input file has more than one compressed block.
75 if printf '%s\n' "$INFO" | grep -q '^Block = 1'; then
76         echo "Cannot convert, because the input file has more than"
77         echo "one compressed block."
78         exit 1
79 fi
80
81 # Get copmressed, uncompressed, and dictionary size.
82 CSIZE=$(printf '%s\n' "$INFO" | sed -rn 's|^Packed Size = ([0-9]+$)|\1|p')
83 USIZE=$(printf '%s\n' "$INFO" | sed -rn 's|^Size = ([0-9]+$)|\1|p')
84 DICT=$(printf '%s\n' "$INFO" | sed -rn 's|^Method = LZMA:([0-9]+)$|\1|p')
85
86 if [ -z "$CSIZE" -o -z "$USIZE" -o -z "$DICT" ]; then
87         echo "Parsing output of $SEVENZIP failed. Maybe the file uses some"
88         echo "other compression method than plain LZMA."
89         exit 1
90 fi
91
92 # The following assumes that the default lc, lp, and pb settings were used.
93 # Otherwise the output will be corrupt.
94 printf '\x5D' > "$2"
95
96 # Dictionary size
97 int2bin 4 "$((1 << DICT))" >> "$2"
98
99 # Uncompressed size
100 int2bin 8 "$USIZE" >> "$2"
101
102 # Copy the actual compressed data. Using multiple dd commands to avoid
103 # copying large amount of data with one-byte block size, which would be
104 # annoyingly slow.
105 BS=8192
106 BIGSIZE=$((CSIZE / BS))
107 CSIZE=$((CSIZE % BS))
108 {
109         dd of=/dev/null bs=32 count=1 \
110                 && dd bs="$BS" count="$BIGSIZE" \
111                 && dd bs=1 count="$CSIZE"
112 } < "$1" >> "$2"
113
114 exit $?