aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2006-01-20 18:28:50 +0000
committerRob Landley <rob@landley.net>2006-01-20 18:28:50 +0000
commitc1d69906a0c5f28f3d84c14afb3b74c8f19f81c1 (patch)
tree5e3796c33b995720bcd69f2b969e409e85bff119
parent7a43bd07e64e6db795d4661321da1cab14d9c4f6 (diff)
downloadbusybox-w32-c1d69906a0c5f28f3d84c14afb3b74c8f19f81c1.tar.gz
busybox-w32-c1d69906a0c5f28f3d84c14afb3b74c8f19f81c1.tar.bz2
busybox-w32-c1d69906a0c5f28f3d84c14afb3b74c8f19f81c1.zip
Patch from Aurelien Jacobs to add unlzma. (A new decompression type,
see www.7-zip.org)
-rw-r--r--archival/Config.in42
-rw-r--r--archival/Makefile.in1
-rw-r--r--archival/libunarchive/Makefile.in3
-rw-r--r--archival/libunarchive/decompress_unlzma.c347
-rw-r--r--archival/libunarchive/filter_accept_list_reassign.c4
-rw-r--r--archival/libunarchive/get_header_tar_lzma.c23
-rw-r--r--archival/libunarchive/rangecoder.h158
-rw-r--r--archival/tar.c24
-rw-r--r--archival/unlzma.c65
-rw-r--r--include/applets.h6
-rw-r--r--include/unarchive.h2
-rw-r--r--include/usage.h21
12 files changed, 691 insertions, 5 deletions
diff --git a/archival/Config.in b/archival/Config.in
index db358db08..e7d5debb0 100644
--- a/archival/Config.in
+++ b/archival/Config.in
@@ -157,6 +157,14 @@ config CONFIG_FEATURE_TAR_BZIP2
157 If you enable this option you'll be able to extract 157 If you enable this option you'll be able to extract
158 archives compressed with bzip2. 158 archives compressed with bzip2.
159 159
160config CONFIG_FEATURE_TAR_LZMA
161 bool " Enable -a option to handle .tar.lzma files"
162 default n
163 depends on CONFIG_TAR
164 help
165 If you enable this option you'll be able to extract
166 archives compressed with lzma.
167
160config CONFIG_FEATURE_TAR_FROM 168config CONFIG_FEATURE_TAR_FROM
161 bool " Enable -X (exclude from) and -T (include from) options)" 169 bool " Enable -X (exclude from) and -T (include from) options)"
162 default n 170 default n
@@ -212,6 +220,29 @@ config CONFIG_UNCOMPRESS
212 uncompress is used to decompress archives created by compress. 220 uncompress is used to decompress archives created by compress.
213 Not much used anymore, replaced by gzip/gunzip. 221 Not much used anymore, replaced by gzip/gunzip.
214 222
223config CONFIG_UNLZMA
224 bool "unlzma"
225 default n
226 help
227 unlzma is a compression utility using the Lempel-Ziv-Markov chain
228 compression algorithm, and range coding. Compression
229 is generally considerably better than that achieved by the bzip2
230 compressors.
231
232 The BusyBox unlzma applet is limited to de-compression only.
233 On an x86 system, this applet adds about 4K.
234
235 Unless you have a specific application which requires unlzma, you
236 should probably say N here.
237
238config CONFIG_FEATURE_LZMA_FAST
239 bool " Optimze unlzma for speed"
240 default n
241 depends on CONFIG_UNLZMA
242 help
243 This option reduce decompression time by about 33% at the cost of
244 a 2K bigger binary.
245
215config CONFIG_UNZIP 246config CONFIG_UNZIP
216 bool "unzip" 247 bool "unzip"
217 default n 248 default n
@@ -255,4 +286,15 @@ config CONFIG_FEATURE_DEB_TAR_BZ2
255 You only want this if you are creating your own custom debian packages that 286 You only want this if you are creating your own custom debian packages that
256 use an internal control.tar.bz2 or data.tar.bz2. 287 use an internal control.tar.bz2 or data.tar.bz2.
257 288
289config CONFIG_FEATURE_DEB_TAR_LZMA
290 bool " lzma debian packages"
291 default n
292 depends on CONFIG_DPKG || CONFIG_DPKG_DEB
293 help
294 This allows dpkg and dpkg-deb to extract deb's that are compressed
295 internally with lzma instead of gzip.
296
297 You only want this if you are creating your own custom debian
298 packages that use an internal control.tar.lzma or data.tar.lzma.
299
258endmenu 300endmenu
diff --git a/archival/Makefile.in b/archival/Makefile.in
index 735b659e0..b4fcabf04 100644
--- a/archival/Makefile.in
+++ b/archival/Makefile.in
@@ -14,6 +14,7 @@ ARCHIVAL-y:=
14ARCHIVAL-$(CONFIG_APT_GET) += 14ARCHIVAL-$(CONFIG_APT_GET) +=
15ARCHIVAL-$(CONFIG_AR) += ar.o 15ARCHIVAL-$(CONFIG_AR) += ar.o
16ARCHIVAL-$(CONFIG_BUNZIP2) += bunzip2.o 16ARCHIVAL-$(CONFIG_BUNZIP2) += bunzip2.o
17ARCHIVAL-$(CONFIG_UNLZMA) += unlzma.o
17ARCHIVAL-$(CONFIG_CPIO) += cpio.o 18ARCHIVAL-$(CONFIG_CPIO) += cpio.o
18ARCHIVAL-$(CONFIG_DPKG) += dpkg.o 19ARCHIVAL-$(CONFIG_DPKG) += dpkg.o
19ARCHIVAL-$(CONFIG_DPKG_DEB) += dpkg_deb.o 20ARCHIVAL-$(CONFIG_DPKG_DEB) += dpkg_deb.o
diff --git a/archival/libunarchive/Makefile.in b/archival/libunarchive/Makefile.in
index 99eb6386d..2b49398df 100644
--- a/archival/libunarchive/Makefile.in
+++ b/archival/libunarchive/Makefile.in
@@ -51,17 +51,20 @@ DPKG_FILES:= \
51 51
52LIBUNARCHIVE-$(CONFIG_AR) += get_header_ar.o unpack_ar_archive.o 52LIBUNARCHIVE-$(CONFIG_AR) += get_header_ar.o unpack_ar_archive.o
53LIBUNARCHIVE-$(CONFIG_BUNZIP2) += decompress_bunzip2.o 53LIBUNARCHIVE-$(CONFIG_BUNZIP2) += decompress_bunzip2.o
54LIBUNARCHIVE-$(CONFIG_UNLZMA) += decompress_unlzma.o
54LIBUNARCHIVE-$(CONFIG_CPIO) += get_header_cpio.o 55LIBUNARCHIVE-$(CONFIG_CPIO) += get_header_cpio.o
55LIBUNARCHIVE-$(CONFIG_DPKG) += $(DPKG_FILES) 56LIBUNARCHIVE-$(CONFIG_DPKG) += $(DPKG_FILES)
56LIBUNARCHIVE-$(CONFIG_DPKG_DEB) += $(DPKG_FILES) 57LIBUNARCHIVE-$(CONFIG_DPKG_DEB) += $(DPKG_FILES)
57LIBUNARCHIVE-$(CONFIG_FEATURE_DEB_TAR_GZ) += $(GUNZIP_FILES) get_header_tar_gz.o 58LIBUNARCHIVE-$(CONFIG_FEATURE_DEB_TAR_GZ) += $(GUNZIP_FILES) get_header_tar_gz.o
58LIBUNARCHIVE-$(CONFIG_FEATURE_DEB_TAR_BZ2) += decompress_bunzip2.o get_header_tar_bz2.o 59LIBUNARCHIVE-$(CONFIG_FEATURE_DEB_TAR_BZ2) += decompress_bunzip2.o get_header_tar_bz2.o
60LIBUNARCHIVE-$(CONFIG_FEATURE_DEB_TAR_LZMA) += decompress_unlzma.o get_header_tar_lzma.o
59LIBUNARCHIVE-$(CONFIG_GUNZIP) += $(GUNZIP_FILES) 61LIBUNARCHIVE-$(CONFIG_GUNZIP) += $(GUNZIP_FILES)
60LIBUNARCHIVE-$(CONFIG_FEATURE_GUNZIP_UNCOMPRESS) += decompress_uncompress.o 62LIBUNARCHIVE-$(CONFIG_FEATURE_GUNZIP_UNCOMPRESS) += decompress_uncompress.o
61LIBUNARCHIVE-$(CONFIG_RPM2CPIO) += $(GUNZIP_FILES) get_header_cpio.o 63LIBUNARCHIVE-$(CONFIG_RPM2CPIO) += $(GUNZIP_FILES) get_header_cpio.o
62LIBUNARCHIVE-$(CONFIG_RPM) += $(GUNZIP_FILES) get_header_cpio.o 64LIBUNARCHIVE-$(CONFIG_RPM) += $(GUNZIP_FILES) get_header_cpio.o
63LIBUNARCHIVE-$(CONFIG_TAR) += get_header_tar.o 65LIBUNARCHIVE-$(CONFIG_TAR) += get_header_tar.o
64LIBUNARCHIVE-$(CONFIG_FEATURE_TAR_BZIP2) += decompress_bunzip2.o get_header_tar_bz2.o 66LIBUNARCHIVE-$(CONFIG_FEATURE_TAR_BZIP2) += decompress_bunzip2.o get_header_tar_bz2.o
67LIBUNARCHIVE-$(CONFIG_FEATURE_TAR_LZMA) += decompress_unlzma.o get_header_tar_lzma.o
65LIBUNARCHIVE-$(CONFIG_FEATURE_TAR_GZIP) += $(GUNZIP_FILES) get_header_tar_gz.o 68LIBUNARCHIVE-$(CONFIG_FEATURE_TAR_GZIP) += $(GUNZIP_FILES) get_header_tar_gz.o
66LIBUNARCHIVE-$(CONFIG_FEATURE_TAR_COMPRESS) += decompress_uncompress.o 69LIBUNARCHIVE-$(CONFIG_FEATURE_TAR_COMPRESS) += decompress_uncompress.o
67LIBUNARCHIVE-$(CONFIG_UNCOMPRESS) += decompress_uncompress.o 70LIBUNARCHIVE-$(CONFIG_UNCOMPRESS) += decompress_uncompress.o
diff --git a/archival/libunarchive/decompress_unlzma.c b/archival/libunarchive/decompress_unlzma.c
new file mode 100644
index 000000000..977cb48d0
--- /dev/null
+++ b/archival/libunarchive/decompress_unlzma.c
@@ -0,0 +1,347 @@
1/*
2 * Small lzma deflate implementation.
3 * Copyright (C) 2006 Aurelien Jacobs <aurel@gnuage.org>
4 *
5 * Based on LzmaDecode.c from the LZMA SDK 4.22 (http://www.7-zip.org/)
6 * Copyright (C) 1999-2005 Igor Pavlov
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23#include <stdint.h>
24#include <unistd.h>
25#include <stdio.h>
26#include <byteswap.h>
27
28#include "libbb.h"
29
30#include "rangecoder.h"
31
32
33typedef struct {
34 uint8_t pos;
35 uint32_t dict_size;
36 uint64_t dst_size;
37} __attribute__ ((packed)) lzma_header_t;
38
39
40#define LZMA_BASE_SIZE 1846
41#define LZMA_LIT_SIZE 768
42
43#define LZMA_NUM_POS_BITS_MAX 4
44
45#define LZMA_LEN_NUM_LOW_BITS 3
46#define LZMA_LEN_NUM_MID_BITS 3
47#define LZMA_LEN_NUM_HIGH_BITS 8
48
49#define LZMA_LEN_CHOICE 0
50#define LZMA_LEN_CHOICE_2 (LZMA_LEN_CHOICE + 1)
51#define LZMA_LEN_LOW (LZMA_LEN_CHOICE_2 + 1)
52#define LZMA_LEN_MID (LZMA_LEN_LOW \
53 + (1 << (LZMA_NUM_POS_BITS_MAX + LZMA_LEN_NUM_LOW_BITS)))
54#define LZMA_LEN_HIGH (LZMA_LEN_MID \
55 +(1 << (LZMA_NUM_POS_BITS_MAX + LZMA_LEN_NUM_MID_BITS)))
56#define LZMA_NUM_LEN_PROBS (LZMA_LEN_HIGH + (1 << LZMA_LEN_NUM_HIGH_BITS))
57
58#define LZMA_NUM_STATES 12
59#define LZMA_NUM_LIT_STATES 7
60
61#define LZMA_START_POS_MODEL_INDEX 4
62#define LZMA_END_POS_MODEL_INDEX 14
63#define LZMA_NUM_FULL_DISTANCES (1 << (LZMA_END_POS_MODEL_INDEX >> 1))
64
65#define LZMA_NUM_POS_SLOT_BITS 6
66#define LZMA_NUM_LEN_TO_POS_STATES 4
67
68#define LZMA_NUM_ALIGN_BITS 4
69
70#define LZMA_MATCH_MIN_LEN 2
71
72#define LZMA_IS_MATCH 0
73#define LZMA_IS_REP (LZMA_IS_MATCH + (LZMA_NUM_STATES <<LZMA_NUM_POS_BITS_MAX))
74#define LZMA_IS_REP_G0 (LZMA_IS_REP + LZMA_NUM_STATES)
75#define LZMA_IS_REP_G1 (LZMA_IS_REP_G0 + LZMA_NUM_STATES)
76#define LZMA_IS_REP_G2 (LZMA_IS_REP_G1 + LZMA_NUM_STATES)
77#define LZMA_IS_REP_0_LONG (LZMA_IS_REP_G2 + LZMA_NUM_STATES)
78#define LZMA_POS_SLOT (LZMA_IS_REP_0_LONG \
79 + (LZMA_NUM_STATES << LZMA_NUM_POS_BITS_MAX))
80#define LZMA_SPEC_POS (LZMA_POS_SLOT \
81 +(LZMA_NUM_LEN_TO_POS_STATES << LZMA_NUM_POS_SLOT_BITS))
82#define LZMA_ALIGN (LZMA_SPEC_POS \
83 + LZMA_NUM_FULL_DISTANCES - LZMA_END_POS_MODEL_INDEX)
84#define LZMA_LEN_CODER (LZMA_ALIGN + (1 << LZMA_NUM_ALIGN_BITS))
85#define LZMA_REP_LEN_CODER (LZMA_LEN_CODER + LZMA_NUM_LEN_PROBS)
86#define LZMA_LITERAL (LZMA_REP_LEN_CODER + LZMA_NUM_LEN_PROBS)
87
88
89int unlzma(int src_fd, int dst_fd)
90{
91 lzma_header_t header;
92 int lc, pb, lp;
93 uint32_t pos_state_mask;
94 uint32_t literal_pos_mask;
95 uint32_t pos;
96 uint16_t *p;
97 uint16_t *prob;
98 uint16_t *prob_lit;
99 int num_bits;
100 int num_probs;
101 rc_t rc;
102 int i, mi;
103 uint8_t *buffer;
104 uint8_t previous_byte = 0;
105 size_t buffer_pos = 0, global_pos = 0;
106 int len = 0;
107 int state = 0;
108 uint32_t rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
109
110 if (read(src_fd, &header, sizeof(header)) != sizeof(header))
111 bb_error_msg_and_die("can't read header");
112
113 if (header.pos >= (9 * 5 * 5))
114 bb_error_msg_and_die("bad header");
115 mi = header.pos / 9;
116 lc = header.pos % 9;
117 pb = mi / 5;
118 lp = mi % 5;
119 pos_state_mask = (1 << pb) - 1;
120 literal_pos_mask = (1 << lp) - 1;
121
122#if __BYTE_ORDER == __BIG_ENDIAN
123 header.dict_size = bswap_32(header.dict_size);
124 header.dst_size = bswap_64(header.dst_size);
125#endif /* __BYTE_ORDER */
126
127 if (header.dict_size == 0)
128 header.dict_size = 1;
129
130 buffer = xmalloc(MIN(header.dst_size, header.dict_size));
131
132 num_probs = LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp));
133 p = xmalloc(num_probs * sizeof(*p));
134 num_probs = LZMA_LITERAL + (LZMA_LIT_SIZE << (lc + lp));
135 for (i = 0; i < num_probs; i++)
136 p[i] = (1 << RC_MODEL_TOTAL_BITS) >> 1;
137
138 rc_init(&rc, src_fd, 0x10000);
139
140 while (global_pos + buffer_pos < header.dst_size) {
141 int pos_state = (buffer_pos + global_pos) & pos_state_mask;
142
143 prob =
144 p + LZMA_IS_MATCH + (state << LZMA_NUM_POS_BITS_MAX) + pos_state;
145 if (rc_is_bit_0(&rc, prob)) {
146 mi = 1;
147 rc_update_bit_0(&rc, prob);
148 prob = (p + LZMA_LITERAL + (LZMA_LIT_SIZE
149 * ((((buffer_pos + global_pos) & literal_pos_mask) << lc)
150 + (previous_byte >> (8 - lc)))));
151
152 if (state >= LZMA_NUM_LIT_STATES) {
153 int match_byte;
154
155 pos = buffer_pos - rep0;
156 while (pos >= header.dict_size)
157 pos += header.dict_size;
158 match_byte = buffer[pos];
159 do {
160 int bit;
161
162 match_byte <<= 1;
163 bit = match_byte & 0x100;
164 prob_lit = prob + 0x100 + bit + mi;
165 if (rc_get_bit(&rc, prob_lit, &mi)) {
166 if (!bit)
167 break;
168 } else {
169 if (bit)
170 break;
171 }
172 } while (mi < 0x100);
173 }
174 while (mi < 0x100) {
175 prob_lit = prob + mi;
176 rc_get_bit(&rc, prob_lit, &mi);
177 }
178 previous_byte = (uint8_t) mi;
179
180 buffer[buffer_pos++] = previous_byte;
181 if (buffer_pos == header.dict_size) {
182 buffer_pos = 0;
183 global_pos += header.dict_size;
184 write(dst_fd, buffer, header.dict_size);
185 }
186 if (state < 4)
187 state = 0;
188 else if (state < 10)
189 state -= 3;
190 else
191 state -= 6;
192 } else {
193 int offset;
194 uint16_t *prob_len;
195
196 rc_update_bit_1(&rc, prob);
197 prob = p + LZMA_IS_REP + state;
198 if (rc_is_bit_0(&rc, prob)) {
199 rc_update_bit_0(&rc, prob);
200 rep3 = rep2;
201 rep2 = rep1;
202 rep1 = rep0;
203 state = state < LZMA_NUM_LIT_STATES ? 0 : 3;
204 prob = p + LZMA_LEN_CODER;
205 } else {
206 rc_update_bit_1(&rc, prob);
207 prob = p + LZMA_IS_REP_G0 + state;
208 if (rc_is_bit_0(&rc, prob)) {
209 rc_update_bit_0(&rc, prob);
210 prob = (p + LZMA_IS_REP_0_LONG
211 + (state << LZMA_NUM_POS_BITS_MAX) + pos_state);
212 if (rc_is_bit_0(&rc, prob)) {
213 rc_update_bit_0(&rc, prob);
214
215 state = state < LZMA_NUM_LIT_STATES ? 9 : 11;
216 pos = buffer_pos - rep0;
217 while (pos >= header.dict_size)
218 pos += header.dict_size;
219 previous_byte = buffer[pos];
220 buffer[buffer_pos++] = previous_byte;
221 if (buffer_pos == header.dict_size) {
222 buffer_pos = 0;
223 global_pos += header.dict_size;
224 write(dst_fd, buffer, header.dict_size);
225 }
226 continue;
227 } else {
228 rc_update_bit_1(&rc, prob);
229 }
230 } else {
231 uint32_t distance;
232
233 rc_update_bit_1(&rc, prob);
234 prob = p + LZMA_IS_REP_G1 + state;
235 if (rc_is_bit_0(&rc, prob)) {
236 rc_update_bit_0(&rc, prob);
237 distance = rep1;
238 } else {
239 rc_update_bit_1(&rc, prob);
240 prob = p + LZMA_IS_REP_G2 + state;
241 if (rc_is_bit_0(&rc, prob)) {
242 rc_update_bit_0(&rc, prob);
243 distance = rep2;
244 } else {
245 rc_update_bit_1(&rc, prob);
246 distance = rep3;
247 rep3 = rep2;
248 }
249 rep2 = rep1;
250 }
251 rep1 = rep0;
252 rep0 = distance;
253 }
254 state = state < LZMA_NUM_LIT_STATES ? 8 : 11;
255 prob = p + LZMA_REP_LEN_CODER;
256 }
257
258 prob_len = prob + LZMA_LEN_CHOICE;
259 if (rc_is_bit_0(&rc, prob_len)) {
260 rc_update_bit_0(&rc, prob_len);
261 prob_len = (prob + LZMA_LEN_LOW
262 + (pos_state << LZMA_LEN_NUM_LOW_BITS));
263 offset = 0;
264 num_bits = LZMA_LEN_NUM_LOW_BITS;
265 } else {
266 rc_update_bit_1(&rc, prob_len);
267 prob_len = prob + LZMA_LEN_CHOICE_2;
268 if (rc_is_bit_0(&rc, prob_len)) {
269 rc_update_bit_0(&rc, prob_len);
270 prob_len = (prob + LZMA_LEN_MID
271 + (pos_state << LZMA_LEN_NUM_MID_BITS));
272 offset = 1 << LZMA_LEN_NUM_LOW_BITS;
273 num_bits = LZMA_LEN_NUM_MID_BITS;
274 } else {
275 rc_update_bit_1(&rc, prob_len);
276 prob_len = prob + LZMA_LEN_HIGH;
277 offset = ((1 << LZMA_LEN_NUM_LOW_BITS)
278 + (1 << LZMA_LEN_NUM_MID_BITS));
279 num_bits = LZMA_LEN_NUM_HIGH_BITS;
280 }
281 }
282 rc_bit_tree_decode(&rc, prob_len, num_bits, &len);
283 len += offset;
284
285 if (state < 4) {
286 int pos_slot;
287
288 state += LZMA_NUM_LIT_STATES;
289 prob =
290 p + LZMA_POS_SLOT +
291 ((len <
292 LZMA_NUM_LEN_TO_POS_STATES ? len :
293 LZMA_NUM_LEN_TO_POS_STATES - 1)
294 << LZMA_NUM_POS_SLOT_BITS);
295 rc_bit_tree_decode(&rc, prob, LZMA_NUM_POS_SLOT_BITS,
296 &pos_slot);
297 if (pos_slot >= LZMA_START_POS_MODEL_INDEX) {
298 num_bits = (pos_slot >> 1) - 1;
299 rep0 = 2 | (pos_slot & 1);
300 if (pos_slot < LZMA_END_POS_MODEL_INDEX) {
301 rep0 <<= num_bits;
302 prob = p + LZMA_SPEC_POS + rep0 - pos_slot - 1;
303 } else {
304 num_bits -= LZMA_NUM_ALIGN_BITS;
305 while (num_bits--)
306 rep0 = (rep0 << 1) | rc_direct_bit(&rc);
307 prob = p + LZMA_ALIGN;
308 rep0 <<= LZMA_NUM_ALIGN_BITS;
309 num_bits = LZMA_NUM_ALIGN_BITS;
310 }
311 i = 1;
312 mi = 1;
313 while (num_bits--) {
314 if (rc_get_bit(&rc, prob + mi, &mi))
315 rep0 |= i;
316 i <<= 1;
317 }
318 } else
319 rep0 = pos_slot;
320 if (++rep0 == 0)
321 break;
322 }
323
324 len += LZMA_MATCH_MIN_LEN;
325
326 do {
327 pos = buffer_pos - rep0;
328 while (pos >= header.dict_size)
329 pos += header.dict_size;
330 previous_byte = buffer[pos];
331 buffer[buffer_pos++] = previous_byte;
332 if (buffer_pos == header.dict_size) {
333 buffer_pos = 0;
334 global_pos += header.dict_size;
335 write(dst_fd, buffer, header.dict_size);
336 }
337 len--;
338 } while (len != 0 && buffer_pos < header.dst_size);
339 }
340 }
341
342 write(dst_fd, buffer, buffer_pos);
343 rc_free(&rc);
344 return 0;
345}
346
347/* vi:set ts=4: */
diff --git a/archival/libunarchive/filter_accept_list_reassign.c b/archival/libunarchive/filter_accept_list_reassign.c
index d0436549b..a09f564a3 100644
--- a/archival/libunarchive/filter_accept_list_reassign.c
+++ b/archival/libunarchive/filter_accept_list_reassign.c
@@ -50,6 +50,10 @@ extern char filter_accept_list_reassign(archive_handle_t *archive_handle)
50 return(EXIT_SUCCESS); 50 return(EXIT_SUCCESS);
51 } 51 }
52#endif 52#endif
53 if (ENABLE_FEATURE_DEB_TAR_LZMA && !strcmp(name_ptr, ".lzma")) {
54 archive_handle->action_data_subarchive = get_header_tar_lzma;
55 return(EXIT_SUCCESS);
56 }
53 } 57 }
54 return(EXIT_FAILURE); 58 return(EXIT_FAILURE);
55} 59}
diff --git a/archival/libunarchive/get_header_tar_lzma.c b/archival/libunarchive/get_header_tar_lzma.c
new file mode 100644
index 000000000..63dc8bc2c
--- /dev/null
+++ b/archival/libunarchive/get_header_tar_lzma.c
@@ -0,0 +1,23 @@
1/*
2 * Small lzma deflate implementation.
3 * Copyright (C) 2006 Aurelien Jacobs <aurel@gnuage.org>
4 *
5 * Licensed under GPL v2, see file LICENSE in this tarball for details.
6 */
7
8#include "unarchive.h"
9
10char get_header_tar_lzma(archive_handle_t * archive_handle)
11{
12 /* Can't lseek over pipes */
13 archive_handle->seek = seek_by_char;
14
15 archive_handle->src_fd = open_transformer(archive_handle->src_fd, unlzma);
16 archive_handle->offset = 0;
17 while (get_header_tar(archive_handle) == EXIT_SUCCESS);
18
19 /* Can only do one file at a time */
20 return EXIT_FAILURE;
21}
22
23/* vi:set ts=4: */
diff --git a/archival/libunarchive/rangecoder.h b/archival/libunarchive/rangecoder.h
new file mode 100644
index 000000000..bb4159112
--- /dev/null
+++ b/archival/libunarchive/rangecoder.h
@@ -0,0 +1,158 @@
1/*
2 * Small range coder implementation for lzma.
3 * Copyright (C) 2006 Aurelien Jacobs <aurel@gnuage.org>
4 *
5 * Based on LzmaDecode.c from the LZMA SDK 4.22 (http://www.7-zip.org/)
6 * Copyright (c) 1999-2005 Igor Pavlov
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23#include <stdint.h>
24
25#include "libbb.h"
26
27#ifndef always_inline
28# if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ >0)
29# define always_inline __attribute__((always_inline)) inline
30# else
31# define always_inline inline
32# endif
33#endif
34
35#ifdef CONFIG_FEATURE_LZMA_FAST
36# define speed_inline always_inline
37#else
38# define speed_inline
39#endif
40
41
42typedef struct {
43 int fd;
44 uint8_t *ptr;
45 uint8_t *buffer;
46 uint8_t *buffer_end;
47 int buffer_size;
48 uint32_t code;
49 uint32_t range;
50 uint32_t bound;
51} rc_t;
52
53
54#define RC_TOP_BITS 24
55#define RC_MOVE_BITS 5
56#define RC_MODEL_TOTAL_BITS 11
57
58
59static speed_inline void rc_read(rc_t * rc)
60{
61 rc->buffer_size = read(rc->fd, rc->buffer, rc->buffer_size);
62 if (rc->buffer_size <= 0)
63 bb_error_msg_and_die("unexpected EOF");
64 rc->ptr = rc->buffer;
65 rc->buffer_end = rc->buffer + rc->buffer_size;
66}
67
68static always_inline void rc_init(rc_t * rc, int fd, int buffer_size)
69{
70 int i;
71
72 rc->fd = fd;
73 rc->buffer = malloc(buffer_size);
74 rc->buffer_size = buffer_size;
75 rc->buffer_end = rc->buffer + rc->buffer_size;
76 rc->ptr = rc->buffer_end;
77
78 rc->code = 0;
79 rc->range = 0xFFFFFFFF;
80 for (i = 0; i < 5; i++) {
81 if (rc->ptr >= rc->buffer_end)
82 rc_read(rc);
83 rc->code = (rc->code << 8) | *rc->ptr++;
84 }
85}
86
87static always_inline void rc_free(rc_t * rc)
88{
89 if (ENABLE_FEATURE_CLEAN_UP)
90 free(rc->buffer);
91}
92
93static always_inline void rc_normalize(rc_t * rc)
94{
95 if (rc->range < (1 << RC_TOP_BITS)) {
96 if (rc->ptr >= rc->buffer_end)
97 rc_read(rc);
98 rc->range <<= 8;
99 rc->code = (rc->code << 8) | *rc->ptr++;
100 }
101}
102
103static speed_inline int rc_is_bit_0(rc_t * rc, uint16_t * p)
104{
105 rc_normalize(rc);
106 rc->bound = *p * (rc->range >> RC_MODEL_TOTAL_BITS);
107 return rc->code < rc->bound;
108}
109
110static speed_inline void rc_update_bit_0(rc_t * rc, uint16_t * p)
111{
112 rc->range = rc->bound;
113 *p += ((1 << RC_MODEL_TOTAL_BITS) - *p) >> RC_MOVE_BITS;
114}
115
116static speed_inline void rc_update_bit_1(rc_t * rc, uint16_t * p)
117{
118 rc->range -= rc->bound;
119 rc->code -= rc->bound;
120 *p -= *p >> RC_MOVE_BITS;
121}
122
123static speed_inline int rc_get_bit(rc_t * rc, uint16_t * p, int *symbol)
124{
125 if (rc_is_bit_0(rc, p)) {
126 rc_update_bit_0(rc, p);
127 *symbol *= 2;
128 return 0;
129 } else {
130 rc_update_bit_1(rc, p);
131 *symbol = *symbol * 2 + 1;
132 return 1;
133 }
134}
135
136static always_inline int rc_direct_bit(rc_t * rc)
137{
138 rc_normalize(rc);
139 rc->range >>= 1;
140 if (rc->code >= rc->range) {
141 rc->code -= rc->range;
142 return 1;
143 }
144 return 0;
145}
146
147static speed_inline void
148rc_bit_tree_decode(rc_t * rc, uint16_t * p, int num_levels, int *symbol)
149{
150 int i = num_levels;
151
152 *symbol = 1;
153 while (i--)
154 rc_get_bit(rc, p + *symbol, symbol);
155 *symbol -= 1 << num_levels;
156}
157
158/* vi:set ts=4: */
diff --git a/archival/tar.c b/archival/tar.c
index d5fa954d2..a4b13b5de 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -615,14 +615,23 @@ static char get_header_tar_Z(archive_handle_t *archive_handle)
615# define TAR_OPT_AFTER_BZIP2 TAR_OPT_AFTER_CREATE 615# define TAR_OPT_AFTER_BZIP2 TAR_OPT_AFTER_CREATE
616#endif 616#endif
617 617
618#define TAR_OPT_INCLUDE_FROM (1 << (TAR_OPT_AFTER_BZIP2)) 618#define TAR_OPT_LZMA (1 << (TAR_OPT_AFTER_BZIP2))
619#define TAR_OPT_EXCLUDE_FROM (1 << (TAR_OPT_AFTER_BZIP2 + 1)) 619#ifdef CONFIG_FEATURE_TAR_LZMA
620# define TAR_OPT_STR_LZMA "a"
621# define TAR_OPT_AFTER_LZMA TAR_OPT_AFTER_BZIP2 + 1
622#else
623# define TAR_OPT_STR_LZMA ""
624# define TAR_OPT_AFTER_LZMA TAR_OPT_AFTER_BZIP2
625#endif
626
627#define TAR_OPT_INCLUDE_FROM (1 << (TAR_OPT_AFTER_LZMA))
628#define TAR_OPT_EXCLUDE_FROM (1 << (TAR_OPT_AFTER_LZMA + 1))
620#ifdef CONFIG_FEATURE_TAR_FROM 629#ifdef CONFIG_FEATURE_TAR_FROM
621# define TAR_OPT_STR_FROM "T:X:" 630# define TAR_OPT_STR_FROM "T:X:"
622# define TAR_OPT_AFTER_FROM TAR_OPT_AFTER_BZIP2 + 2 631# define TAR_OPT_AFTER_FROM TAR_OPT_AFTER_LZMA + 2
623#else 632#else
624# define TAR_OPT_STR_FROM "" 633# define TAR_OPT_STR_FROM ""
625# define TAR_OPT_AFTER_FROM TAR_OPT_AFTER_BZIP2 634# define TAR_OPT_AFTER_FROM TAR_OPT_AFTER_LZMA
626#endif 635#endif
627 636
628#define TAR_OPT_GZIP (1 << (TAR_OPT_AFTER_FROM)) 637#define TAR_OPT_GZIP (1 << (TAR_OPT_AFTER_FROM))
@@ -651,6 +660,7 @@ static char get_header_tar_Z(archive_handle_t *archive_handle)
651static const char tar_options[]="txC:f:Opvk" \ 660static const char tar_options[]="txC:f:Opvk" \
652 TAR_OPT_STR_CREATE \ 661 TAR_OPT_STR_CREATE \
653 TAR_OPT_STR_BZIP2 \ 662 TAR_OPT_STR_BZIP2 \
663 TAR_OPT_STR_LZMA \
654 TAR_OPT_STR_FROM \ 664 TAR_OPT_STR_FROM \
655 TAR_OPT_STR_GZIP \ 665 TAR_OPT_STR_GZIP \
656 TAR_OPT_STR_COMPRESS \ 666 TAR_OPT_STR_COMPRESS \
@@ -675,6 +685,9 @@ static const struct option tar_long_options[] = {
675# ifdef CONFIG_FEATURE_TAR_BZIP2 685# ifdef CONFIG_FEATURE_TAR_BZIP2
676 { "bzip2", 0, NULL, 'j' }, 686 { "bzip2", 0, NULL, 'j' },
677# endif 687# endif
688# ifdef CONFIG_FEATURE_TAR_LZMA
689 { "lzma", 0, NULL, 'a' },
690# endif
678# ifdef CONFIG_FEATURE_TAR_FROM 691# ifdef CONFIG_FEATURE_TAR_FROM
679 { "files-from", 1, NULL, 'T' }, 692 { "files-from", 1, NULL, 'T' },
680 { "exclude-from", 1, NULL, 'X' }, 693 { "exclude-from", 1, NULL, 'X' },
@@ -757,6 +770,9 @@ int tar_main(int argc, char **argv)
757 if (ENABLE_FEATURE_TAR_BZIP2 && (opt & TAR_OPT_BZIP2)) 770 if (ENABLE_FEATURE_TAR_BZIP2 && (opt & TAR_OPT_BZIP2))
758 get_header_ptr = get_header_tar_bz2; 771 get_header_ptr = get_header_tar_bz2;
759 772
773 if (ENABLE_FEATURE_TAR_LZMA && (opt & TAR_OPT_LZMA))
774 get_header_ptr = get_header_tar_lzma;
775
760 if (ENABLE_FEATURE_TAR_COMPRESS && (opt & TAR_OPT_UNCOMPRESS)) 776 if (ENABLE_FEATURE_TAR_COMPRESS && (opt & TAR_OPT_UNCOMPRESS))
761 get_header_ptr = get_header_tar_Z; 777 get_header_ptr = get_header_tar_Z;
762 778
diff --git a/archival/unlzma.c b/archival/unlzma.c
new file mode 100644
index 000000000..dc85cb25e
--- /dev/null
+++ b/archival/unlzma.c
@@ -0,0 +1,65 @@
1/*
2 * Small lzma deflate implementation.
3 * Copyright (C) 2006 Aurelien Jacobs <aurel@gnuage.org>
4 *
5 * Based on bunzip.c from busybox
6 *
7 * Licensed under GPL v2, see file LICENSE in this tarball for details.
8 */
9
10#include <fcntl.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include <unistd.h>
15
16#include "busybox.h"
17#include "unarchive.h"
18
19#define UNLZMA_OPT_STDOUT 1
20
21int unlzma_main(int argc, char **argv)
22{
23 char *filename;
24 unsigned long opt;
25 int status, src_fd, dst_fd;
26
27 opt = bb_getopt_ulflags(argc, argv, "c");
28
29 /* Set input filename and number */
30 filename = argv[optind];
31 if ((filename) && (filename[0] != '-') && (filename[1] != '\0')) {
32 /* Open input file */
33 src_fd = bb_xopen(filename, O_RDONLY);
34 } else {
35 src_fd = STDIN_FILENO;
36 filename = 0;
37 }
38
39 /* if called as lzmacat force the stdout flag */
40 if ((opt & UNLZMA_OPT_STDOUT) || bb_applet_name[4] == 'c')
41 filename = 0;
42
43 if (filename) {
44 char *extension = filename + strlen(filename) - 5;
45
46 if (strcmp(extension, ".lzma") != 0) {
47 bb_error_msg_and_die("Invalid extension");
48 }
49 *extension = 0;
50 dst_fd = bb_xopen(filename, O_WRONLY | O_CREAT);
51 } else
52 dst_fd = STDOUT_FILENO;
53 status = unlzma(src_fd, dst_fd);
54 if (filename) {
55 if (!status)
56 filename[strlen(filename)] = '.';
57 if (unlink(filename) < 0) {
58 bb_error_msg_and_die("Couldn't remove %s", filename);
59 }
60 }
61
62 return status;
63}
64
65/* vi:set ts=4: */
diff --git a/include/applets.h b/include/applets.h
index 47376c624..c6f54e157 100644
--- a/include/applets.h
+++ b/include/applets.h
@@ -408,6 +408,9 @@
408#ifdef CONFIG_LSMOD 408#ifdef CONFIG_LSMOD
409 APPLET(lsmod, lsmod_main, _BB_DIR_SBIN, _BB_SUID_NEVER) 409 APPLET(lsmod, lsmod_main, _BB_DIR_SBIN, _BB_SUID_NEVER)
410#endif 410#endif
411#ifdef CONFIG_UNLZMA
412 APPLET(lzmacat, unlzma_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
413#endif
411#ifdef CONFIG_MAKEDEVS 414#ifdef CONFIG_MAKEDEVS
412 APPLET(makedevs, makedevs_main, _BB_DIR_SBIN, _BB_SUID_NEVER) 415 APPLET(makedevs, makedevs_main, _BB_DIR_SBIN, _BB_SUID_NEVER)
413#endif 416#endif
@@ -712,6 +715,9 @@
712#ifdef CONFIG_UNIX2DOS 715#ifdef CONFIG_UNIX2DOS
713 APPLET(unix2dos, dos2unix_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER) 716 APPLET(unix2dos, dos2unix_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
714#endif 717#endif
718#ifdef CONFIG_UNLZMA
719 APPLET(unlzma, unlzma_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
720#endif
715#ifdef CONFIG_UNZIP 721#ifdef CONFIG_UNZIP
716 APPLET(unzip, unzip_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER) 722 APPLET(unzip, unzip_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
717#endif 723#endif
diff --git a/include/unarchive.h b/include/unarchive.h
index 72a803f16..2075ca2ac 100644
--- a/include/unarchive.h
+++ b/include/unarchive.h
@@ -87,6 +87,7 @@ extern char get_header_ar(archive_handle_t *archive_handle);
87extern char get_header_cpio(archive_handle_t *archive_handle); 87extern char get_header_cpio(archive_handle_t *archive_handle);
88extern char get_header_tar(archive_handle_t *archive_handle); 88extern char get_header_tar(archive_handle_t *archive_handle);
89extern char get_header_tar_bz2(archive_handle_t *archive_handle); 89extern char get_header_tar_bz2(archive_handle_t *archive_handle);
90extern char get_header_tar_lzma(archive_handle_t *archive_handle);
90extern char get_header_tar_gz(archive_handle_t *archive_handle); 91extern char get_header_tar_gz(archive_handle_t *archive_handle);
91 92
92extern void seek_by_jump(const archive_handle_t *archive_handle, const unsigned int amount); 93extern void seek_by_jump(const archive_handle_t *archive_handle, const unsigned int amount);
@@ -103,6 +104,7 @@ extern void inflate_init(unsigned int bufsize);
103extern void inflate_cleanup(void); 104extern void inflate_cleanup(void);
104extern int inflate_unzip(int in, int out); 105extern int inflate_unzip(int in, int out);
105extern int inflate_gunzip(int in, int out); 106extern int inflate_gunzip(int in, int out);
107extern int unlzma(int src_fd, int dst_fd);
106 108
107extern int open_transformer(int src_fd, int (*transformer)(int src_fd, int dst_fd)); 109extern int open_transformer(int src_fd, int (*transformer)(int src_fd, int dst_fd));
108 110
diff --git a/include/usage.h b/include/usage.h
index e6287c8a3..8982f8dd2 100644
--- a/include/usage.h
+++ b/include/usage.h
@@ -102,6 +102,19 @@
102#define bzcat_full_usage \ 102#define bzcat_full_usage \
103 "Uncompress to stdout." 103 "Uncompress to stdout."
104 104
105#define unlzma_trivial_usage \
106 "[OPTION]... [FILE]"
107#define unlzma_full_usage \
108 "Uncompress FILE (or standard input if FILE is '-' or omitted).\n\n" \
109 "Options:\n" \
110 "\t-c\tWrite output to standard output\n" \
111 "\t-f\tForce"
112
113#define lzmacat_trivial_usage \
114 "FILE"
115#define lzmacat_full_usage \
116 "Uncompress to stdout."
117
105#define cal_trivial_usage \ 118#define cal_trivial_usage \
106 "[-jy] [[month] year]" 119 "[-jy] [[month] year]"
107#define cal_full_usage \ 120#define cal_full_usage \
@@ -2964,6 +2977,11 @@
2964#else 2977#else
2965# define USAGE_TAR_BZIP2(a) 2978# define USAGE_TAR_BZIP2(a)
2966#endif 2979#endif
2980#ifdef CONFIG_FEATURE_TAR_LZMA
2981# define USAGE_TAR_LZMA(a) a
2982#else
2983# define USAGE_TAR_LZMA(a)
2984#endif
2967#ifdef CONFIG_FEATURE_TAR_COMPRESS 2985#ifdef CONFIG_FEATURE_TAR_COMPRESS
2968# define USAGE_TAR_COMPRESS(a) a 2986# define USAGE_TAR_COMPRESS(a) a
2969#else 2987#else
@@ -2971,7 +2989,7 @@
2971#endif 2989#endif
2972 2990
2973#define tar_trivial_usage \ 2991#define tar_trivial_usage \
2974 "-[" USAGE_TAR_CREATE("c") USAGE_TAR_GZIP("z") USAGE_TAR_BZIP2("j") USAGE_TAR_COMPRESS("Z") "xtvO] " \ 2992 "-[" USAGE_TAR_CREATE("c") USAGE_TAR_GZIP("z") USAGE_TAR_BZIP2("j") USAGE_TAR_LZMA("a") USAGE_TAR_COMPRESS("Z") "xtvO] " \
2975 USAGE_TAR_EXCLUDE("[-X FILE]") \ 2993 USAGE_TAR_EXCLUDE("[-X FILE]") \
2976 "[-f TARFILE] [-C DIR] [FILE(s)] ..." 2994 "[-f TARFILE] [-C DIR] [FILE(s)] ..."
2977#define tar_full_usage \ 2995#define tar_full_usage \
@@ -2983,6 +3001,7 @@
2983 "\nArchive format selection:\n" \ 3001 "\nArchive format selection:\n" \
2984 USAGE_TAR_GZIP("\tz\t\tFilter the archive through gzip\n") \ 3002 USAGE_TAR_GZIP("\tz\t\tFilter the archive through gzip\n") \
2985 USAGE_TAR_BZIP2("\tj\t\tFilter the archive through bzip2\n") \ 3003 USAGE_TAR_BZIP2("\tj\t\tFilter the archive through bzip2\n") \
3004 USAGE_TAR_LZMA("\ta\t\tFilter the archive through lzma\n") \
2986 USAGE_TAR_COMPRESS("\tZ\t\tFilter the archive through compress\n") \ 3005 USAGE_TAR_COMPRESS("\tZ\t\tFilter the archive through compress\n") \
2987 "\nFile selection:\n" \ 3006 "\nFile selection:\n" \
2988 "\tf\t\tname of TARFILE or \"-\" for stdin\n" \ 3007 "\tf\t\tname of TARFILE or \"-\" for stdin\n" \