Home | History | Annotate | Line # | Download | only in gzip
      1 /*	$NetBSD: unlz.c,v 1.11 2026/01/10 00:48:44 mrg Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2018 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Christos Zoulas.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 /*  Lzd - Educational decompressor for the lzip format
     33     Copyright (C) 2013-2018 Antonio Diaz Diaz.
     34 
     35     This program is free software. Redistribution and use in source and
     36     binary forms, with or without modification, are permitted provided
     37     that the following conditions are met:
     38 
     39     1. Redistributions of source code must retain the above copyright
     40     notice, this list of conditions and the following disclaimer.
     41 
     42     2. Redistributions in binary form must reproduce the above copyright
     43     notice, this list of conditions and the following disclaimer in the
     44     documentation and/or other materials provided with the distribution.
     45 
     46     This program is distributed in the hope that it will be useful,
     47     but WITHOUT ANY WARRANTY; without even the implied warranty of
     48     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     49 */
     50 
     51 #include <sys/param.h>
     52 #include <stdio.h>
     53 #include <string.h>
     54 #include <stdlib.h>
     55 #include <stdint.h>
     56 #include <stdbool.h>
     57 #include <errno.h>
     58 #include <unistd.h>
     59 
     60 #define LZ_STATES		12
     61 
     62 #define LITERAL_CONTEXT_BITS	3
     63 #define POS_STATE_BITS		2
     64 #define POS_STATES		(1 << POS_STATE_BITS)
     65 #define POS_STATE_MASK 		(POS_STATES - 1)
     66 
     67 #define STATES			4
     68 #define DIS_SLOT_BITS		6
     69 
     70 #define DIS_MODEL_START		4
     71 #define DIS_MODEL_END		14
     72 
     73 #define MODELED_DISTANCES	(1 << (DIS_MODEL_END / 2))
     74 #define DIS_ALIGN_BITS		4
     75 #define DIS_ALIGN_SIZE		(1 << DIS_ALIGN_BITS)
     76 
     77 #define LOW_BITS		3
     78 #define MID_BITS		3
     79 #define HIGH_BITS		8
     80 
     81 #define LOW_SYMBOLS		(1 << LOW_BITS)
     82 #define MID_SYMBOLS		(1 << MID_BITS)
     83 #define HIGH_SYMBOLS		(1 << HIGH_BITS)
     84 
     85 #define MAX_SYMBOLS 		(LOW_SYMBOLS + MID_SYMBOLS + HIGH_SYMBOLS)
     86 
     87 #define MIN_MATCH_LEN		2
     88 
     89 #define BIT_MODEL_MOVE_BITS	5
     90 #define BIT_MODEL_TOTAL_BITS 	11
     91 #define BIT_MODEL_TOTAL 	(1 << BIT_MODEL_TOTAL_BITS)
     92 #define BIT_MODEL_INIT		(BIT_MODEL_TOTAL / 2)
     93 
     94 static const int lz_st_next[] = {
     95 	0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5,
     96 };
     97 
     98 static bool
     99 lz_st_is_char(int st) {
    100 	return st < 7;
    101 }
    102 
    103 static int
    104 lz_st_get_char(int st) {
    105 	return lz_st_next[st];
    106 }
    107 
    108 static int
    109 lz_st_get_match(int st) {
    110 	return st < 7 ? 7 : 10;
    111 }
    112 
    113 static int
    114 lz_st_get_rep(int st) {
    115 	return st < 7 ? 8 : 11;
    116 }
    117 
    118 static int
    119 lz_st_get_short_rep(int st) {
    120 	return st < 7 ? 9 : 11;
    121 }
    122 
    123 struct lz_len_model {
    124 	int choice1;
    125 	int choice2;
    126 	int bm_low[POS_STATES][LOW_SYMBOLS];
    127 	int bm_mid[POS_STATES][MID_SYMBOLS];
    128 	int bm_high[HIGH_SYMBOLS];
    129 };
    130 
    131 static uint32_t lz_crc[256];
    132 
    133 static void
    134 lz_crc_init(void)
    135 {
    136 	for (unsigned i = 0; i < __arraycount(lz_crc); i++) {
    137 		unsigned c = i;
    138 		for (unsigned j = 0; j < 8; j++) {
    139 			if (c & 1)
    140 				c = 0xEDB88320U ^ (c >> 1);
    141 			else
    142 				c >>= 1;
    143 		}
    144 		lz_crc[i] = c;
    145       }
    146 }
    147 
    148 static void
    149 lz_crc_update(uint32_t *crc, const uint8_t *buf, size_t len)
    150 {
    151 	for (size_t i = 0; i < len; i++)
    152 		*crc = lz_crc[(*crc ^ buf[i]) & 0xFF] ^ (*crc >> 8);
    153 }
    154 
    155 struct lz_range_decoder {
    156 	FILE *fp;
    157 	uint32_t code;
    158 	uint32_t range;
    159 };
    160 
    161 static int
    162 lz_rd_create(struct lz_range_decoder *rd, FILE *fp)
    163 {
    164 	rd->fp = fp;
    165 	rd->code = 0;
    166 	rd->range = ~0;
    167 	for (int i = 0; i < 5; i++)
    168 		rd->code = (rd->code << 8) | (uint8_t)getc(rd->fp);
    169 	return ferror(rd->fp) ? -1 : 0;
    170 }
    171 
    172 static unsigned
    173 lz_rd_decode(struct lz_range_decoder *rd, int num_bits)
    174 {
    175 	unsigned symbol = 0;
    176 
    177 	for (int i = num_bits; i > 0; i--) {
    178 		rd->range >>= 1;
    179 		symbol <<= 1;
    180 		if (rd->code >= rd->range) {
    181 			rd->code -= rd->range;
    182 			symbol |= 1;
    183 		}
    184 		if (rd->range <= 0x00FFFFFFU) {
    185 			rd->range <<= 8;
    186 			rd->code = (rd->code << 8) | (uint8_t)getc(rd->fp);
    187 		}
    188 	}
    189 
    190 	return symbol;
    191 }
    192 
    193 static unsigned
    194 lz_rd_decode_bit(struct lz_range_decoder *rd, int *bm)
    195 {
    196 	unsigned symbol;
    197 	const uint32_t bound = (rd->range >> BIT_MODEL_TOTAL_BITS) * *bm;
    198 
    199 	if(rd->code < bound) {
    200 		rd->range = bound;
    201 		*bm += (BIT_MODEL_TOTAL - *bm) >> BIT_MODEL_MOVE_BITS;
    202 		symbol = 0;
    203 	}
    204 	else {
    205 		rd->range -= bound;
    206 		rd->code -= bound;
    207 		*bm -= *bm >> BIT_MODEL_MOVE_BITS;
    208 		symbol = 1;
    209 	}
    210 
    211 	if (rd->range <= 0x00FFFFFFU) {
    212 		rd->range <<= 8;
    213 		rd->code = (rd->code << 8) | (uint8_t)getc(rd->fp);
    214 	}
    215 	return symbol;
    216 }
    217 
    218 static unsigned
    219 lz_rd_decode_tree(struct lz_range_decoder *rd, int *bm, int num_bits)
    220 {
    221 	unsigned symbol = 1;
    222 
    223 	for (int i = 0; i < num_bits; i++)
    224 		symbol = (symbol << 1) | lz_rd_decode_bit(rd, &bm[symbol]);
    225 
    226 	return symbol - (1 << num_bits);
    227 }
    228 
    229 static unsigned
    230 lz_rd_decode_tree_reversed(struct lz_range_decoder *rd, int *bm, int num_bits)
    231 {
    232 	unsigned symbol = lz_rd_decode_tree(rd, bm, num_bits);
    233 	unsigned reversed_symbol = 0;
    234 
    235 	for (int i = 0; i < num_bits; i++) {
    236 		reversed_symbol = (reversed_symbol << 1) | (symbol & 1);
    237 		symbol >>= 1;
    238 	}
    239 
    240 	return reversed_symbol;
    241 }
    242 
    243 static unsigned
    244 lz_rd_decode_matched(struct lz_range_decoder *rd, int *bm, int match_byte)
    245 {
    246 	unsigned symbol = 1;
    247 
    248 	for (int i = 7; i >= 0; i--) {
    249 		const unsigned match_bit = (match_byte >> i) & 1;
    250 		const unsigned bit = lz_rd_decode_bit(rd,
    251 		    &bm[symbol + (match_bit << 8) + 0x100]);
    252 		symbol = (symbol << 1) | bit;
    253 		if (match_bit != bit) {
    254 			while (symbol < 0x100) {
    255 				symbol = (symbol << 1) |
    256 				    lz_rd_decode_bit(rd, &bm[symbol]);
    257 			}
    258 			break;
    259 		}
    260 	}
    261 	return symbol & 0xFF;
    262 }
    263 
    264 static unsigned
    265 lz_rd_decode_len(struct lz_range_decoder *rd, struct lz_len_model *lm,
    266     int pos_state)
    267 {
    268 	if (lz_rd_decode_bit(rd, &lm->choice1) == 0)
    269 		return lz_rd_decode_tree(rd, lm->bm_low[pos_state], LOW_BITS);
    270 
    271 	if (lz_rd_decode_bit(rd, &lm->choice2) == 0) {
    272 		return LOW_SYMBOLS +
    273 		    lz_rd_decode_tree(rd, lm->bm_mid[pos_state], MID_BITS);
    274 	}
    275 
    276 	return LOW_SYMBOLS + MID_SYMBOLS +
    277            lz_rd_decode_tree(rd, lm->bm_high, HIGH_BITS);
    278 }
    279 
    280 struct lz_decoder {
    281 	FILE *fin, *fout;
    282 	FILE *prein;
    283 	off_t pos, ppos, spos, dict_size;
    284 	bool wrapped;
    285 	uint32_t crc;
    286 	uint8_t *obuf;
    287 	struct lz_range_decoder rdec;
    288 	char *pre;
    289 	size_t prelen;
    290 };
    291 
    292 static int
    293 lz_flush(struct lz_decoder *lz)
    294 {
    295 	off_t offs = lz->pos - lz->spos;
    296 	if (offs <= 0)
    297 		return -1;
    298 
    299 	size_t size = (size_t)offs;
    300 	lz_crc_update(&lz->crc, lz->obuf + lz->spos, size);
    301 	if (!tflag && fwrite(lz->obuf + lz->spos, 1, size, lz->fout) != size)
    302 		return -1;
    303 
    304 	lz->wrapped = lz->pos >= lz->dict_size;
    305 	if (lz->wrapped) {
    306 		lz->ppos += lz->pos;
    307 		lz->pos = 0;
    308 	}
    309 	lz->spos = lz->pos;
    310 	return 0;
    311 }
    312 
    313 static int
    314 lz_read(void *cookie, char *rbp, int num)
    315 {
    316 	int copylen = 0;
    317 	struct lz_decoder *lz = cookie;
    318 
    319 	if (lz->prelen) {
    320 		copylen = MIN(num, (int)lz->prelen);
    321 		memcpy(rbp, lz->pre, copylen);
    322 
    323 		lz->pre    += copylen;
    324 		lz->prelen -= copylen;
    325 		rbp        += copylen;
    326 		num        -= copylen;
    327 	}
    328 
    329 	if (num)
    330 		copylen += fread(rbp, 1, num, lz->prein);
    331 
    332 	return copylen;
    333 }
    334 
    335 static int
    336 lz_close(void *cookie)
    337 {
    338 	struct lz_decoder *lz = cookie;
    339 
    340 	fclose(lz->prein);
    341 
    342 	return 0;
    343 }
    344 
    345 static void
    346 lz_destroy(struct lz_decoder *lz)
    347 {
    348 	if (lz->fin)
    349 		fclose(lz->fin);
    350 	if (lz->fout)
    351 		fclose(lz->fout);
    352 	free(lz->obuf);
    353 }
    354 
    355 static int
    356 lz_create(struct lz_decoder *lz, int fin, int fdout, int dict_size,
    357     char *pre, size_t prelen)
    358 {
    359 	memset(lz, 0, sizeof(*lz));
    360 
    361 	if (prelen == 0) {
    362 		lz->fin = fdopen(dup(fin), "r");
    363 		if (lz->fin == NULL)
    364 			goto out;
    365 	} else {
    366 		/* Need to drain the pre-buffer first. */
    367 		lz->prein = fdopen(dup(fin), "r");
    368 		if (lz->prein == NULL)
    369 			goto out;
    370 
    371 		lz->fin = funopen(lz, lz_read, NULL, NULL, lz_close);
    372 		if (lz->fin == NULL) {
    373 			fclose(lz->prein);
    374 			goto out;
    375 		}
    376 
    377 		lz->pre = pre;
    378 		lz->prelen = prelen;
    379 	}
    380 
    381 	lz->fout = fdopen(dup(fdout), "w");
    382 	if (lz->fout == NULL)
    383 		goto out;
    384 
    385 	lz->pos = lz->ppos = lz->spos = 0;
    386 	lz->crc = ~0;
    387 	lz->dict_size = dict_size;
    388 	lz->wrapped = false;
    389 
    390 	lz->obuf = malloc(dict_size);
    391 	if (lz->obuf == NULL)
    392 		goto out;
    393 
    394 	if (lz_rd_create(&lz->rdec, lz->fin) == -1)
    395 		goto out;
    396 	return 0;
    397 out:
    398 	lz_destroy(lz);
    399 	return -1;
    400 }
    401 
    402 static uint8_t
    403 lz_peek(const struct lz_decoder *lz, unsigned ahead)
    404 {
    405 	off_t diff = lz->pos - ahead - 1;
    406 
    407 	if (diff >= 0)
    408 		return lz->obuf[diff];
    409 
    410 	if (lz->wrapped)
    411 		return lz->obuf[lz->dict_size + diff];
    412 
    413 	return 0;
    414 }
    415 
    416 static void
    417 lz_put(struct lz_decoder *lz, uint8_t b)
    418 {
    419 	lz->obuf[lz->pos++] = b;
    420 	if (lz->dict_size == lz->pos)
    421 		lz_flush(lz);
    422 }
    423 
    424 static off_t
    425 lz_get_data_position(const struct lz_decoder *lz)
    426 {
    427 	return lz->ppos + lz->pos;
    428 }
    429 
    430 static unsigned
    431 lz_get_crc(const struct lz_decoder *lz)
    432 {
    433 	return lz->crc ^ 0xffffffffU;
    434 }
    435 
    436 static void
    437 lz_bm_init(int *a, size_t l)
    438 {
    439 	for (size_t i = 0; i < l; i++)
    440 		a[i] = BIT_MODEL_INIT;
    441 }
    442 
    443 #define LZ_BM_INIT(a)	lz_bm_init(a, __arraycount(a))
    444 #define LZ_BM_INIT2(a)	do { \
    445 	size_t l = __arraycount(a[0]); \
    446 	for (size_t i = 0; i < __arraycount(a); i++) \
    447 		lz_bm_init(a[i], l); \
    448 } while (0)
    449 
    450 #define LZ_MODEL_INIT(a) do { \
    451 	a.choice1 = BIT_MODEL_INIT; \
    452 	a.choice2 = BIT_MODEL_INIT; \
    453 	LZ_BM_INIT2(a.bm_low); \
    454 	LZ_BM_INIT2(a.bm_mid); \
    455 	LZ_BM_INIT(a.bm_high); \
    456 } while (0)
    457 
    458 static bool
    459 lz_decode_member(struct lz_decoder *lz)
    460 {
    461 	int bm_literal[1 << LITERAL_CONTEXT_BITS][0x300];
    462 	int bm_match[LZ_STATES][POS_STATES];
    463 	int bm_rep[4][LZ_STATES];
    464 	int bm_len[LZ_STATES][POS_STATES];
    465 	int bm_dis_slot[LZ_STATES][1 << DIS_SLOT_BITS];
    466 	int bm_dis[MODELED_DISTANCES - DIS_MODEL_END + 1];
    467 	int bm_align[DIS_ALIGN_SIZE];
    468 
    469 	LZ_BM_INIT2(bm_literal);
    470 	LZ_BM_INIT2(bm_match);
    471 	LZ_BM_INIT2(bm_rep);
    472 	LZ_BM_INIT2(bm_len);
    473 	LZ_BM_INIT2(bm_dis_slot);
    474 	LZ_BM_INIT(bm_dis);
    475 	LZ_BM_INIT(bm_align);
    476 
    477 	struct lz_len_model match_len_model;
    478 	struct lz_len_model rep_len_model;
    479 
    480 	LZ_MODEL_INIT(match_len_model);
    481 	LZ_MODEL_INIT(rep_len_model);
    482 
    483 	struct lz_range_decoder *rd = &lz->rdec;
    484 	unsigned rep[4] = { 0 };
    485 
    486 
    487 	int state = 0;
    488 
    489 	while (!feof(lz->fin) && !ferror(lz->fin)) {
    490 		const int pos_state = lz_get_data_position(lz) & POS_STATE_MASK;
    491 		// bit 1
    492 		if (lz_rd_decode_bit(rd, &bm_match[state][pos_state]) == 0) {
    493 			const uint8_t prev_byte = lz_peek(lz, 0);
    494 			const int literal_state =
    495 			    prev_byte >> (8 - LITERAL_CONTEXT_BITS);
    496 			int *bm = bm_literal[literal_state];
    497 			if (lz_st_is_char(state))
    498 				lz_put(lz, lz_rd_decode_tree(rd, bm, 8));
    499 			else {
    500 				int peek = lz_peek(lz, rep[0]);
    501 				lz_put(lz, lz_rd_decode_matched(rd, bm, peek));
    502 			}
    503 			state = lz_st_get_char(state);
    504 			continue;
    505 		}
    506 		int len;
    507 		// bit 2
    508 		if (lz_rd_decode_bit(rd, &bm_rep[0][state]) != 0) {
    509 			// bit 3
    510 			if (lz_rd_decode_bit(rd, &bm_rep[1][state]) == 0) {
    511 				// bit 4
    512 				if (lz_rd_decode_bit(rd,
    513 				    &bm_len[state][pos_state]) == 0)
    514 				{
    515 					state = lz_st_get_short_rep(state);
    516 					lz_put(lz, lz_peek(lz, rep[0]));
    517 					continue;
    518 				}
    519 			} else {
    520 				unsigned distance;
    521 				// bit 4
    522 				if (lz_rd_decode_bit(rd, &bm_rep[2][state])
    523 				    == 0)
    524 					distance = rep[1];
    525 				else {
    526 					// bit 5
    527 					if (lz_rd_decode_bit(rd,
    528 					    &bm_rep[3][state]) == 0)
    529 						distance = rep[2];
    530 					else {
    531 						distance = rep[3];
    532 						rep[3] = rep[2];
    533 					}
    534 					rep[2] = rep[1];
    535 				}
    536 				rep[1] = rep[0];
    537 				rep[0] = distance;
    538 			}
    539 			state = lz_st_get_rep(state);
    540 			len = MIN_MATCH_LEN +
    541 			    lz_rd_decode_len(rd, &rep_len_model, pos_state);
    542 		} else {
    543 			rep[3] = rep[2]; rep[2] = rep[1]; rep[1] = rep[0];
    544 			len = MIN_MATCH_LEN +
    545 			    lz_rd_decode_len(rd, &match_len_model, pos_state);
    546 			const int len_state =
    547 			    MIN(len - MIN_MATCH_LEN, STATES - 1);
    548 			rep[0] = lz_rd_decode_tree(rd, bm_dis_slot[len_state],
    549 			    DIS_SLOT_BITS);
    550 			if (rep[0] >= DIS_MODEL_START) {
    551 				const unsigned dis_slot = rep[0];
    552 				const int direct_bits = (dis_slot >> 1) - 1;
    553 			        rep[0] = (2 | (dis_slot & 1)) << direct_bits;
    554 				if (dis_slot < DIS_MODEL_END)
    555 					rep[0] += lz_rd_decode_tree_reversed(rd,
    556 					    &bm_dis[rep[0] - dis_slot],
    557                                             direct_bits);
    558 				else {
    559 					rep[0] += lz_rd_decode(rd, direct_bits
    560 					    - DIS_ALIGN_BITS) << DIS_ALIGN_BITS;
    561 					rep[0] += lz_rd_decode_tree_reversed(rd,
    562 					    bm_align, DIS_ALIGN_BITS);
    563 					if (rep[0] == 0xFFFFFFFFU) {
    564 						lz_flush(lz);
    565 						return len == MIN_MATCH_LEN;
    566 					}
    567 				}
    568 			}
    569 			state = lz_st_get_match(state);
    570 			if (rep[0] >= lz->dict_size ||
    571 			    (rep[0] >= lz->pos && !lz->wrapped)) {
    572 				lz_flush(lz);
    573 				return false;
    574 			}
    575 		}
    576 		for (int i = 0; i < len; i++)
    577 			lz_put(lz, lz_peek(lz, rep[0]));
    578     	}
    579 	lz_flush(lz);
    580 	return false;
    581 }
    582 
    583 /*
    584  * 0-3	CRC32 of the uncompressed data
    585  * 4-11 size of the uncompressed data
    586  * 12-19 member size including header and trailer
    587  */
    588 #define TRAILER_SIZE 20
    589 
    590 
    591 static off_t
    592 lz_decode(int fin, int fdout, unsigned dict_size, off_t *insize,
    593     char *pre, size_t prelen)
    594 {
    595 	struct lz_decoder lz;
    596 	off_t rv = -1;
    597 
    598 	if (lz_create(&lz, fin, fdout, dict_size, pre, prelen) == -1)
    599 		return -1;
    600 
    601 	if (!lz_decode_member(&lz))
    602 		goto out;
    603 
    604 	uint8_t trailer[TRAILER_SIZE];
    605 
    606 	for(size_t i = 0; i < __arraycount(trailer); i++)
    607 		trailer[i] = (uint8_t)getc(lz.fin);
    608 
    609 	unsigned crc = 0;
    610 	for (int i = 3; i >= 0; --i) {
    611 		crc <<= 8;
    612 		crc += trailer[i];
    613 	}
    614 
    615 	int64_t data_size = 0;
    616 	for (int i = 11; i >= 4; --i) {
    617 		data_size <<= 8;
    618 		data_size += trailer[i];
    619 	}
    620 
    621 	if (crc != lz_get_crc(&lz) || data_size != lz_get_data_position(&lz))
    622 		goto out;
    623 
    624 	rv = 0;
    625 	for (int i = 19; i >= 12; --i) {
    626 		rv <<= 8;
    627 		rv += trailer[i];
    628 	}
    629 	if (insize)
    630 		*insize = rv;
    631 #if 0
    632 	/* Does not work with pipes */
    633 	rv = ftello(lz.fout);
    634 #else
    635 	rv = data_size;
    636 #endif
    637 out:
    638 	lz_destroy(&lz);
    639 	return rv;
    640 }
    641 
    642 
    643 /*
    644  * 0-3 magic
    645  * 4 version
    646  * 5 coded dict_size
    647  */
    648 #define HDR_SIZE 6
    649 #define MIN_DICTIONARY_SIZE (1 << 12)
    650 #define MAX_DICTIONARY_SIZE (1 << 29)
    651 
    652 static const char hdrmagic[] = { 'L', 'Z', 'I', 'P', 1 };
    653 
    654 static unsigned
    655 lz_get_dict_size(unsigned char c)
    656 {
    657 	unsigned dict_size = 1 << (c & 0x1f);
    658 	dict_size -= (dict_size >> 4) * ( (c >> 5) & 0x7);
    659 	if (dict_size < MIN_DICTIONARY_SIZE || dict_size > MAX_DICTIONARY_SIZE)
    660 		return 0;
    661 	return dict_size;
    662 }
    663 
    664 static off_t
    665 unlz(int fin, int fout, char *pre, size_t prelen, off_t *bytes_in)
    666 {
    667 	if (lz_crc[0] == 0)
    668 		lz_crc_init();
    669 	size_t copylen = 0;
    670 
    671 	char header[HDR_SIZE];
    672 
    673 	if (pre && prelen) {
    674 		copylen = MIN(prelen, sizeof header);
    675 		memcpy(header, pre, copylen);
    676 
    677 		pre += copylen;
    678 		prelen -= copylen;
    679 	}
    680 
    681 	if (copylen < sizeof header) {
    682 		ssize_t nr = read(fin, header + copylen,
    683 		    sizeof(header) - copylen);
    684 
    685 		switch (nr) {
    686 		case -1:
    687 			return -1;
    688 		case 0:
    689 			return prelen ? -1 : 0;
    690 		default:
    691 			if ((size_t)nr != sizeof(header) - copylen)
    692 				return -1;
    693 			break;
    694 		}
    695 	}
    696 
    697 	if (memcmp(header, hdrmagic, sizeof(hdrmagic)) != 0)
    698 		return -1;
    699 
    700 	unsigned dict_size = lz_get_dict_size(header[5]);
    701 	if (dict_size == 0)
    702 		return -1;
    703 
    704 	return lz_decode(fin, fout, dict_size, bytes_in, pre, prelen);
    705 }
    706