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