blob: c1b0a31189466c82231d50e4a20f2d54e82560bc [file] [log] [blame]
"Robert P. J. Day"63fc1a92006-07-02 19:47:05 +00001/* vi: set sw=4 ts=4: */
Rob Landleyc1d69902006-01-20 18:28:50 +00002/*
3 * Small lzma deflate implementation.
4 * Copyright (C) 2006 Aurelien Jacobs <aurel@gnuage.org>
5 *
6 * Based on LzmaDecode.c from the LZMA SDK 4.22 (http://www.7-zip.org/)
7 * Copyright (C) 1999-2005 Igor Pavlov
8 *
Rob Landleyb13fee42006-06-20 22:38:00 +00009 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
Rob Landleyc1d69902006-01-20 18:28:50 +000010 */
11
Rob Landleyc1d69902006-01-20 18:28:50 +000012#include "libbb.h"
Bernhard Reutner-Fischercfb53df2006-04-02 21:50:01 +000013#include "unarchive.h"
14
Rob Landleyb13fee42006-06-20 22:38:00 +000015#ifdef CONFIG_FEATURE_LZMA_FAST
16# define speed_inline ATTRIBUTE_ALWAYS_INLINE
17#else
18# define speed_inline
19#endif
20
21
22typedef struct {
23 int fd;
24 uint8_t *ptr;
Denis Vlasenko98b8e942007-01-05 13:59:05 +000025// uint8_t *buffer;
Rob Landleyb13fee42006-06-20 22:38:00 +000026 uint8_t *buffer_end;
27 int buffer_size;
28 uint32_t code;
29 uint32_t range;
30 uint32_t bound;
31} rc_t;
32
Denis Vlasenko98b8e942007-01-05 13:59:05 +000033//#define RC_BUFFER ((uint8_t*)(void*)(rc+1))
34#define RC_BUFFER ((uint8_t*)(rc+1))
Rob Landleyb13fee42006-06-20 22:38:00 +000035
36#define RC_TOP_BITS 24
37#define RC_MOVE_BITS 5
38#define RC_MODEL_TOTAL_BITS 11
39
40
41/* Called twice: once at startup and once in rc_normalize() */
42static void rc_read(rc_t * rc)
43{
Denis Vlasenko98b8e942007-01-05 13:59:05 +000044 rc->buffer_size = read(rc->fd, RC_BUFFER, rc->buffer_size);
Rob Landleyb13fee42006-06-20 22:38:00 +000045 if (rc->buffer_size <= 0)
46 bb_error_msg_and_die("unexpected EOF");
Denis Vlasenko98b8e942007-01-05 13:59:05 +000047 rc->ptr = RC_BUFFER;
48 rc->buffer_end = RC_BUFFER + rc->buffer_size;
Rob Landleyb13fee42006-06-20 22:38:00 +000049}
50
51/* Called once */
Denis Vlasenko98b8e942007-01-05 13:59:05 +000052static rc_t* rc_init(int fd, int buffer_size)
Rob Landleyb13fee42006-06-20 22:38:00 +000053{
54 int i;
Denis Vlasenko98b8e942007-01-05 13:59:05 +000055 rc_t* rc;
56
57 rc = xmalloc(sizeof(rc_t) + buffer_size);
Rob Landleyb13fee42006-06-20 22:38:00 +000058
59 rc->fd = fd;
Rob Landleyb13fee42006-06-20 22:38:00 +000060 rc->buffer_size = buffer_size;
Denis Vlasenko98b8e942007-01-05 13:59:05 +000061 rc->buffer_end = RC_BUFFER + rc->buffer_size;
Rob Landleyb13fee42006-06-20 22:38:00 +000062 rc->ptr = rc->buffer_end;
63
64 rc->code = 0;
65 rc->range = 0xFFFFFFFF;
66 for (i = 0; i < 5; i++) {
67 if (rc->ptr >= rc->buffer_end)
68 rc_read(rc);
69 rc->code = (rc->code << 8) | *rc->ptr++;
70 }
Denis Vlasenko98b8e942007-01-05 13:59:05 +000071 return rc;
Rob Landleyb13fee42006-06-20 22:38:00 +000072}
73
Denis Vlasenko98b8e942007-01-05 13:59:05 +000074/* Called once */
Rob Landleyb13fee42006-06-20 22:38:00 +000075static ATTRIBUTE_ALWAYS_INLINE void rc_free(rc_t * rc)
76{
77 if (ENABLE_FEATURE_CLEAN_UP)
Denis Vlasenko98b8e942007-01-05 13:59:05 +000078 free(rc);
Rob Landleyb13fee42006-06-20 22:38:00 +000079}
80
81/* Called twice, but one callsite is in speed_inline'd rc_is_bit_0_helper() */
82static void rc_do_normalize(rc_t * rc)
83{
84 if (rc->ptr >= rc->buffer_end)
85 rc_read(rc);
86 rc->range <<= 8;
87 rc->code = (rc->code << 8) | *rc->ptr++;
88}
89static ATTRIBUTE_ALWAYS_INLINE void rc_normalize(rc_t * rc)
90{
91 if (rc->range < (1 << RC_TOP_BITS)) {
92 rc_do_normalize(rc);
93 }
94}
95
96/* Called 9 times */
97/* Why rc_is_bit_0_helper exists?
98 * Because we want to always expose (rc->code < rc->bound) to optimizer
99 */
100static speed_inline uint32_t rc_is_bit_0_helper(rc_t * rc, uint16_t * p)
101{
102 rc_normalize(rc);
103 rc->bound = *p * (rc->range >> RC_MODEL_TOTAL_BITS);
104 return rc->bound;
105}
106static ATTRIBUTE_ALWAYS_INLINE int rc_is_bit_0(rc_t * rc, uint16_t * p)
107{
108 uint32_t t = rc_is_bit_0_helper(rc, p);
109 return rc->code < t;
110}
111
112/* Called ~10 times, but very small, thus inlined */
113static speed_inline void rc_update_bit_0(rc_t * rc, uint16_t * p)
114{
115 rc->range = rc->bound;
116 *p += ((1 << RC_MODEL_TOTAL_BITS) - *p) >> RC_MOVE_BITS;
117}
118static speed_inline void rc_update_bit_1(rc_t * rc, uint16_t * p)
119{
120 rc->range -= rc->bound;
121 rc->code -= rc->bound;
122 *p -= *p >> RC_MOVE_BITS;
123}
124
125/* Called 4 times in unlzma loop */
126static int rc_get_bit(rc_t * rc, uint16_t * p, int *symbol)
127{
128 if (rc_is_bit_0(rc, p)) {
129 rc_update_bit_0(rc, p);
130 *symbol *= 2;
131 return 0;
132 } else {
133 rc_update_bit_1(rc, p);
134 *symbol = *symbol * 2 + 1;
135 return 1;
136 }
137}
138
139/* Called once */
140static ATTRIBUTE_ALWAYS_INLINE int rc_direct_bit(rc_t * rc)
141{
142 rc_normalize(rc);
143 rc->range >>= 1;
144 if (rc->code >= rc->range) {
145 rc->code -= rc->range;
146 return 1;
147 }
148 return 0;
149}
150
151/* Called twice */
152static speed_inline void
153rc_bit_tree_decode(rc_t * rc, uint16_t * p, int num_levels, int *symbol)
154{
155 int i = num_levels;
156
157 *symbol = 1;
158 while (i--)
159 rc_get_bit(rc, p + *symbol, symbol);
160 *symbol -= 1 << num_levels;
161}
Rob Landleyc1d69902006-01-20 18:28:50 +0000162
163
164typedef struct {
165 uint8_t pos;
166 uint32_t dict_size;
167 uint64_t dst_size;
168} __attribute__ ((packed)) lzma_header_t;
169
170
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000171/* #defines will make compiler to compute/optimize each one with each usage.
172 * Have heart and use enum instead. */
173enum {
174 LZMA_BASE_SIZE = 1846,
175 LZMA_LIT_SIZE = 768,
Rob Landleyc1d69902006-01-20 18:28:50 +0000176
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000177 LZMA_NUM_POS_BITS_MAX = 4,
Rob Landleyc1d69902006-01-20 18:28:50 +0000178
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000179 LZMA_LEN_NUM_LOW_BITS = 3,
180 LZMA_LEN_NUM_MID_BITS = 3,
181 LZMA_LEN_NUM_HIGH_BITS = 8,
Rob Landleyc1d69902006-01-20 18:28:50 +0000182
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000183 LZMA_LEN_CHOICE = 0,
184 LZMA_LEN_CHOICE_2 = (LZMA_LEN_CHOICE + 1),
185 LZMA_LEN_LOW = (LZMA_LEN_CHOICE_2 + 1),
186 LZMA_LEN_MID = (LZMA_LEN_LOW \
187 + (1 << (LZMA_NUM_POS_BITS_MAX + LZMA_LEN_NUM_LOW_BITS))),
188 LZMA_LEN_HIGH = (LZMA_LEN_MID \
189 + (1 << (LZMA_NUM_POS_BITS_MAX + LZMA_LEN_NUM_MID_BITS))),
190 LZMA_NUM_LEN_PROBS = (LZMA_LEN_HIGH + (1 << LZMA_LEN_NUM_HIGH_BITS)),
Rob Landleyc1d69902006-01-20 18:28:50 +0000191
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000192 LZMA_NUM_STATES = 12,
193 LZMA_NUM_LIT_STATES = 7,
Rob Landleyc1d69902006-01-20 18:28:50 +0000194
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000195 LZMA_START_POS_MODEL_INDEX = 4,
196 LZMA_END_POS_MODEL_INDEX = 14,
197 LZMA_NUM_FULL_DISTANCES = (1 << (LZMA_END_POS_MODEL_INDEX >> 1)),
Rob Landleyc1d69902006-01-20 18:28:50 +0000198
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000199 LZMA_NUM_POS_SLOT_BITS = 6,
200 LZMA_NUM_LEN_TO_POS_STATES = 4,
Rob Landleyc1d69902006-01-20 18:28:50 +0000201
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000202 LZMA_NUM_ALIGN_BITS = 4,
Rob Landleyc1d69902006-01-20 18:28:50 +0000203
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000204 LZMA_MATCH_MIN_LEN = 2,
Rob Landleyc1d69902006-01-20 18:28:50 +0000205
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000206 LZMA_IS_MATCH = 0,
207 LZMA_IS_REP = (LZMA_IS_MATCH + (LZMA_NUM_STATES << LZMA_NUM_POS_BITS_MAX)),
208 LZMA_IS_REP_G0 = (LZMA_IS_REP + LZMA_NUM_STATES),
209 LZMA_IS_REP_G1 = (LZMA_IS_REP_G0 + LZMA_NUM_STATES),
210 LZMA_IS_REP_G2 = (LZMA_IS_REP_G1 + LZMA_NUM_STATES),
211 LZMA_IS_REP_0_LONG = (LZMA_IS_REP_G2 + LZMA_NUM_STATES),
212 LZMA_POS_SLOT = (LZMA_IS_REP_0_LONG \
213 + (LZMA_NUM_STATES << LZMA_NUM_POS_BITS_MAX)),
214 LZMA_SPEC_POS = (LZMA_POS_SLOT \
215 + (LZMA_NUM_LEN_TO_POS_STATES << LZMA_NUM_POS_SLOT_BITS)),
216 LZMA_ALIGN = (LZMA_SPEC_POS \
217 + LZMA_NUM_FULL_DISTANCES - LZMA_END_POS_MODEL_INDEX),
218 LZMA_LEN_CODER = (LZMA_ALIGN + (1 << LZMA_NUM_ALIGN_BITS)),
219 LZMA_REP_LEN_CODER = (LZMA_LEN_CODER + LZMA_NUM_LEN_PROBS),
220 LZMA_LITERAL = (LZMA_REP_LEN_CODER + LZMA_NUM_LEN_PROBS),
221};
222
Rob Landleyc1d69902006-01-20 18:28:50 +0000223
Denis Vlasenko97a8dd32006-10-01 15:55:11 +0000224USE_DESKTOP(long long) int
225unlzma(int src_fd, int dst_fd)
Rob Landleyc1d69902006-01-20 18:28:50 +0000226{
Denis Vlasenko97a8dd32006-10-01 15:55:11 +0000227 USE_DESKTOP(long long total_written = 0;)
Rob Landleyc1d69902006-01-20 18:28:50 +0000228 lzma_header_t header;
229 int lc, pb, lp;
230 uint32_t pos_state_mask;
231 uint32_t literal_pos_mask;
232 uint32_t pos;
233 uint16_t *p;
234 uint16_t *prob;
235 uint16_t *prob_lit;
236 int num_bits;
237 int num_probs;
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000238 rc_t *rc;
Rob Landleyc1d69902006-01-20 18:28:50 +0000239 int i, mi;
240 uint8_t *buffer;
241 uint8_t previous_byte = 0;
242 size_t buffer_pos = 0, global_pos = 0;
243 int len = 0;
244 int state = 0;
245 uint32_t rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
246
247 if (read(src_fd, &header, sizeof(header)) != sizeof(header))
248 bb_error_msg_and_die("can't read header");
249
250 if (header.pos >= (9 * 5 * 5))
251 bb_error_msg_and_die("bad header");
252 mi = header.pos / 9;
253 lc = header.pos % 9;
254 pb = mi / 5;
255 lp = mi % 5;
256 pos_state_mask = (1 << pb) - 1;
257 literal_pos_mask = (1 << lp) - 1;
258
Rob Landleybba7f082006-05-29 05:51:12 +0000259 header.dict_size = SWAP_LE32(header.dict_size);
260 header.dst_size = SWAP_LE64(header.dst_size);
Rob Landleyc1d69902006-01-20 18:28:50 +0000261
262 if (header.dict_size == 0)
263 header.dict_size = 1;
264
265 buffer = xmalloc(MIN(header.dst_size, header.dict_size));
266
267 num_probs = LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp));
268 p = xmalloc(num_probs * sizeof(*p));
269 num_probs = LZMA_LITERAL + (LZMA_LIT_SIZE << (lc + lp));
270 for (i = 0; i < num_probs; i++)
271 p[i] = (1 << RC_MODEL_TOTAL_BITS) >> 1;
272
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000273 rc = rc_init(src_fd, 0x10000);
Rob Landleyc1d69902006-01-20 18:28:50 +0000274
275 while (global_pos + buffer_pos < header.dst_size) {
276 int pos_state = (buffer_pos + global_pos) & pos_state_mask;
277
278 prob =
279 p + LZMA_IS_MATCH + (state << LZMA_NUM_POS_BITS_MAX) + pos_state;
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000280 if (rc_is_bit_0(rc, prob)) {
Rob Landleyc1d69902006-01-20 18:28:50 +0000281 mi = 1;
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000282 rc_update_bit_0(rc, prob);
Rob Landleyc1d69902006-01-20 18:28:50 +0000283 prob = (p + LZMA_LITERAL + (LZMA_LIT_SIZE
284 * ((((buffer_pos + global_pos) & literal_pos_mask) << lc)
285 + (previous_byte >> (8 - lc)))));
286
287 if (state >= LZMA_NUM_LIT_STATES) {
288 int match_byte;
289
290 pos = buffer_pos - rep0;
291 while (pos >= header.dict_size)
292 pos += header.dict_size;
293 match_byte = buffer[pos];
294 do {
295 int bit;
296
297 match_byte <<= 1;
298 bit = match_byte & 0x100;
299 prob_lit = prob + 0x100 + bit + mi;
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000300 if (rc_get_bit(rc, prob_lit, &mi)) {
Rob Landleyc1d69902006-01-20 18:28:50 +0000301 if (!bit)
302 break;
303 } else {
304 if (bit)
305 break;
306 }
307 } while (mi < 0x100);
308 }
309 while (mi < 0x100) {
310 prob_lit = prob + mi;
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000311 rc_get_bit(rc, prob_lit, &mi);
Rob Landleyc1d69902006-01-20 18:28:50 +0000312 }
313 previous_byte = (uint8_t) mi;
314
315 buffer[buffer_pos++] = previous_byte;
316 if (buffer_pos == header.dict_size) {
317 buffer_pos = 0;
318 global_pos += header.dict_size;
Denis Vlasenko97a8dd32006-10-01 15:55:11 +0000319 // FIXME: error check
Rob Landleyc1d69902006-01-20 18:28:50 +0000320 write(dst_fd, buffer, header.dict_size);
Denis Vlasenko97a8dd32006-10-01 15:55:11 +0000321 USE_DESKTOP(total_written += header.dict_size;)
Rob Landleyc1d69902006-01-20 18:28:50 +0000322 }
323 if (state < 4)
324 state = 0;
325 else if (state < 10)
326 state -= 3;
327 else
328 state -= 6;
329 } else {
330 int offset;
331 uint16_t *prob_len;
332
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000333 rc_update_bit_1(rc, prob);
Rob Landleyc1d69902006-01-20 18:28:50 +0000334 prob = p + LZMA_IS_REP + state;
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000335 if (rc_is_bit_0(rc, prob)) {
336 rc_update_bit_0(rc, prob);
Rob Landleyc1d69902006-01-20 18:28:50 +0000337 rep3 = rep2;
338 rep2 = rep1;
339 rep1 = rep0;
340 state = state < LZMA_NUM_LIT_STATES ? 0 : 3;
341 prob = p + LZMA_LEN_CODER;
342 } else {
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000343 rc_update_bit_1(rc, prob);
Rob Landleyc1d69902006-01-20 18:28:50 +0000344 prob = p + LZMA_IS_REP_G0 + state;
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000345 if (rc_is_bit_0(rc, prob)) {
346 rc_update_bit_0(rc, prob);
Rob Landleyc1d69902006-01-20 18:28:50 +0000347 prob = (p + LZMA_IS_REP_0_LONG
348 + (state << LZMA_NUM_POS_BITS_MAX) + pos_state);
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000349 if (rc_is_bit_0(rc, prob)) {
350 rc_update_bit_0(rc, prob);
Rob Landleyc1d69902006-01-20 18:28:50 +0000351
352 state = state < LZMA_NUM_LIT_STATES ? 9 : 11;
353 pos = buffer_pos - rep0;
354 while (pos >= header.dict_size)
355 pos += header.dict_size;
356 previous_byte = buffer[pos];
357 buffer[buffer_pos++] = previous_byte;
358 if (buffer_pos == header.dict_size) {
359 buffer_pos = 0;
360 global_pos += header.dict_size;
Denis Vlasenko97a8dd32006-10-01 15:55:11 +0000361 // FIXME: error check
Rob Landleyc1d69902006-01-20 18:28:50 +0000362 write(dst_fd, buffer, header.dict_size);
Denis Vlasenko97a8dd32006-10-01 15:55:11 +0000363 USE_DESKTOP(total_written += header.dict_size;)
Rob Landleyc1d69902006-01-20 18:28:50 +0000364 }
365 continue;
366 } else {
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000367 rc_update_bit_1(rc, prob);
Rob Landleyc1d69902006-01-20 18:28:50 +0000368 }
369 } else {
370 uint32_t distance;
371
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000372 rc_update_bit_1(rc, prob);
Rob Landleyc1d69902006-01-20 18:28:50 +0000373 prob = p + LZMA_IS_REP_G1 + state;
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000374 if (rc_is_bit_0(rc, prob)) {
375 rc_update_bit_0(rc, prob);
Rob Landleyc1d69902006-01-20 18:28:50 +0000376 distance = rep1;
377 } else {
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000378 rc_update_bit_1(rc, prob);
Rob Landleyc1d69902006-01-20 18:28:50 +0000379 prob = p + LZMA_IS_REP_G2 + state;
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000380 if (rc_is_bit_0(rc, prob)) {
381 rc_update_bit_0(rc, prob);
Rob Landleyc1d69902006-01-20 18:28:50 +0000382 distance = rep2;
383 } else {
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000384 rc_update_bit_1(rc, prob);
Rob Landleyc1d69902006-01-20 18:28:50 +0000385 distance = rep3;
386 rep3 = rep2;
387 }
388 rep2 = rep1;
389 }
390 rep1 = rep0;
391 rep0 = distance;
392 }
393 state = state < LZMA_NUM_LIT_STATES ? 8 : 11;
394 prob = p + LZMA_REP_LEN_CODER;
395 }
396
397 prob_len = prob + LZMA_LEN_CHOICE;
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000398 if (rc_is_bit_0(rc, prob_len)) {
399 rc_update_bit_0(rc, prob_len);
Rob Landleyc1d69902006-01-20 18:28:50 +0000400 prob_len = (prob + LZMA_LEN_LOW
401 + (pos_state << LZMA_LEN_NUM_LOW_BITS));
402 offset = 0;
403 num_bits = LZMA_LEN_NUM_LOW_BITS;
404 } else {
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000405 rc_update_bit_1(rc, prob_len);
Rob Landleyc1d69902006-01-20 18:28:50 +0000406 prob_len = prob + LZMA_LEN_CHOICE_2;
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000407 if (rc_is_bit_0(rc, prob_len)) {
408 rc_update_bit_0(rc, prob_len);
Rob Landleyc1d69902006-01-20 18:28:50 +0000409 prob_len = (prob + LZMA_LEN_MID
410 + (pos_state << LZMA_LEN_NUM_MID_BITS));
411 offset = 1 << LZMA_LEN_NUM_LOW_BITS;
412 num_bits = LZMA_LEN_NUM_MID_BITS;
413 } else {
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000414 rc_update_bit_1(rc, prob_len);
Rob Landleyc1d69902006-01-20 18:28:50 +0000415 prob_len = prob + LZMA_LEN_HIGH;
416 offset = ((1 << LZMA_LEN_NUM_LOW_BITS)
417 + (1 << LZMA_LEN_NUM_MID_BITS));
418 num_bits = LZMA_LEN_NUM_HIGH_BITS;
419 }
420 }
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000421 rc_bit_tree_decode(rc, prob_len, num_bits, &len);
Rob Landleyc1d69902006-01-20 18:28:50 +0000422 len += offset;
423
424 if (state < 4) {
425 int pos_slot;
426
427 state += LZMA_NUM_LIT_STATES;
428 prob =
429 p + LZMA_POS_SLOT +
430 ((len <
431 LZMA_NUM_LEN_TO_POS_STATES ? len :
432 LZMA_NUM_LEN_TO_POS_STATES - 1)
433 << LZMA_NUM_POS_SLOT_BITS);
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000434 rc_bit_tree_decode(rc, prob, LZMA_NUM_POS_SLOT_BITS,
Rob Landleyc1d69902006-01-20 18:28:50 +0000435 &pos_slot);
436 if (pos_slot >= LZMA_START_POS_MODEL_INDEX) {
437 num_bits = (pos_slot >> 1) - 1;
438 rep0 = 2 | (pos_slot & 1);
439 if (pos_slot < LZMA_END_POS_MODEL_INDEX) {
440 rep0 <<= num_bits;
441 prob = p + LZMA_SPEC_POS + rep0 - pos_slot - 1;
442 } else {
443 num_bits -= LZMA_NUM_ALIGN_BITS;
444 while (num_bits--)
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000445 rep0 = (rep0 << 1) | rc_direct_bit(rc);
Rob Landleyc1d69902006-01-20 18:28:50 +0000446 prob = p + LZMA_ALIGN;
447 rep0 <<= LZMA_NUM_ALIGN_BITS;
448 num_bits = LZMA_NUM_ALIGN_BITS;
449 }
450 i = 1;
451 mi = 1;
452 while (num_bits--) {
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000453 if (rc_get_bit(rc, prob + mi, &mi))
Rob Landleyc1d69902006-01-20 18:28:50 +0000454 rep0 |= i;
455 i <<= 1;
456 }
457 } else
458 rep0 = pos_slot;
459 if (++rep0 == 0)
460 break;
461 }
462
463 len += LZMA_MATCH_MIN_LEN;
464
465 do {
466 pos = buffer_pos - rep0;
467 while (pos >= header.dict_size)
468 pos += header.dict_size;
469 previous_byte = buffer[pos];
470 buffer[buffer_pos++] = previous_byte;
471 if (buffer_pos == header.dict_size) {
472 buffer_pos = 0;
473 global_pos += header.dict_size;
Denis Vlasenko97a8dd32006-10-01 15:55:11 +0000474 // FIXME: error check
Rob Landleyc1d69902006-01-20 18:28:50 +0000475 write(dst_fd, buffer, header.dict_size);
Denis Vlasenko97a8dd32006-10-01 15:55:11 +0000476 USE_DESKTOP(total_written += header.dict_size;)
Rob Landleyc1d69902006-01-20 18:28:50 +0000477 }
478 len--;
479 } while (len != 0 && buffer_pos < header.dst_size);
480 }
481 }
482
Denis Vlasenko97a8dd32006-10-01 15:55:11 +0000483 // FIXME: error check
Rob Landleyc1d69902006-01-20 18:28:50 +0000484 write(dst_fd, buffer, buffer_pos);
Denis Vlasenko97a8dd32006-10-01 15:55:11 +0000485 USE_DESKTOP(total_written += buffer_pos;)
Denis Vlasenko98b8e942007-01-05 13:59:05 +0000486 rc_free(rc);
Denis Vlasenko97a8dd32006-10-01 15:55:11 +0000487 return USE_DESKTOP(total_written) + 0;
Rob Landleyc1d69902006-01-20 18:28:50 +0000488}