decompress_unzip.c

来自「最新的busybox源码」· C语言 代码 · 共 1,254 行 · 第 1/3 页

C
1,254
字号
		if (i != 0) {			abort_unzip(PASS_STATE_ONLY); //return i;	/* incomplete code set */		}		/* read in literal and distance code lengths */		n = nl + nd;		m = mask_bits[bl];		i = l = 0;		while ((unsigned) i < n) {			b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, (unsigned)bl);			td = inflate_codes_tl + ((unsigned) b_dynamic & m);			j = td->b;			b_dynamic >>= j;			k_dynamic -= j;			j = td->v.n;			if (j < 16) {	/* length of code in bits (0..15) */				ll[i++] = l = j;	/* save last length in l */			} else if (j == 16) {	/* repeat last length 3 to 6 times */				b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 2);				j = 3 + ((unsigned) b_dynamic & 3);				b_dynamic >>= 2;				k_dynamic -= 2;				if ((unsigned) i + j > n) {					abort_unzip(PASS_STATE_ONLY); //return 1;				}				while (j--) {					ll[i++] = l;				}			} else if (j == 17) {	/* 3 to 10 zero length codes */				b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 3);				j = 3 + ((unsigned) b_dynamic & 7);				b_dynamic >>= 3;				k_dynamic -= 3;				if ((unsigned) i + j > n) {					abort_unzip(PASS_STATE_ONLY); //return 1;				}				while (j--) {					ll[i++] = 0;				}				l = 0;			} else {	/* j == 18: 11 to 138 zero length codes */				b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 7);				j = 11 + ((unsigned) b_dynamic & 0x7f);				b_dynamic >>= 7;				k_dynamic -= 7;				if ((unsigned) i + j > n) {					abort_unzip(PASS_STATE_ONLY); //return 1;				}				while (j--) {					ll[i++] = 0;				}				l = 0;			}		}		/* free decoding table for trees */		huft_free(inflate_codes_tl);		/* restore the global bit buffer */		gunzip_bb = b_dynamic;		gunzip_bk = k_dynamic;		/* build the decoding tables for literal/length and distance codes */		bl = lbits;		i = huft_build(ll, nl, 257, cplens, cplext, &inflate_codes_tl, &bl);		if (i != 0)			abort_unzip(PASS_STATE_ONLY);		bd = dbits;		i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &inflate_codes_td, &bd);		if (i != 0)			abort_unzip(PASS_STATE_ONLY);		/* set up data for inflate_codes() */		inflate_codes_setup(PASS_STATE bl, bd);		/* huft_free code moved into inflate_codes */		return -2;	}	default:		abort_unzip(PASS_STATE_ONLY);	}}/* Two callsites, both in inflate_get_next_window */static void calculate_gunzip_crc(STATE_PARAM_ONLY){	unsigned n;	for (n = 0; n < gunzip_outbuf_count; n++) {		gunzip_crc = gunzip_crc_table[((int) gunzip_crc ^ (gunzip_window[n])) & 0xff] ^ (gunzip_crc >> 8);	}	gunzip_bytes_out += gunzip_outbuf_count;}/* One callsite in inflate_unzip_internal */static int inflate_get_next_window(STATE_PARAM_ONLY){	gunzip_outbuf_count = 0;	while (1) {		int ret;		if (need_another_block) {			if (end_reached) {				calculate_gunzip_crc(PASS_STATE_ONLY);				end_reached = 0;				/* NB: need_another_block is still set */				return 0; /* Last block */			}			method = inflate_block(PASS_STATE &end_reached);			need_another_block = 0;		}		switch (method) {		case -1:			ret = inflate_stored(PASS_STATE_ONLY);			break;		case -2:			ret = inflate_codes(PASS_STATE_ONLY);			break;		default: /* cannot happen */			abort_unzip(PASS_STATE_ONLY);		}		if (ret == 1) {			calculate_gunzip_crc(PASS_STATE_ONLY);			return 1; /* more data left */		}		need_another_block = 1; /* end of that block */	}	/* Doesnt get here */}/* Called from unpack_gz_stream() and inflate_unzip() */static USE_DESKTOP(long long) intinflate_unzip_internal(STATE_PARAM int in, int out){	USE_DESKTOP(long long) int n = 0;	ssize_t nwrote;	/* Allocate all global buffers (for DYN_ALLOC option) */	gunzip_window = xmalloc(GUNZIP_WSIZE);	gunzip_outbuf_count = 0;	gunzip_bytes_out = 0;	gunzip_src_fd = in;	/* (re) initialize state */	method = -1;	need_another_block = 1;	resume_copy = 0;	gunzip_bk = 0;	gunzip_bb = 0;	/* Create the crc table */	gunzip_crc_table = crc32_filltable(NULL, 0);	gunzip_crc = ~0;	error_msg = "corrupted data";	if (setjmp(error_jmp)) {		/* Error from deep inside zip machinery */		n = -1;		goto ret;	}	while (1) {		int r = inflate_get_next_window(PASS_STATE_ONLY);		nwrote = full_write(out, gunzip_window, gunzip_outbuf_count);		if (nwrote != (ssize_t)gunzip_outbuf_count) {			bb_perror_msg("write");			n = -1;			goto ret;		}		USE_DESKTOP(n += nwrote;)		if (r == 0) break;	}	/* Store unused bytes in a global buffer so calling applets can access it */	if (gunzip_bk >= 8) {		/* Undo too much lookahead. The next read will be byte aligned		 * so we can discard unused bits in the last meaningful byte. */		bytebuffer_offset--;		bytebuffer[bytebuffer_offset] = gunzip_bb & 0xff;		gunzip_bb >>= 8;		gunzip_bk -= 8;	} ret:	/* Cleanup */	free(gunzip_window);	free(gunzip_crc_table);	return n;}/* External entry points *//* For unzip */USE_DESKTOP(long long) int FAST_FUNCinflate_unzip(inflate_unzip_result *res, off_t compr_size, int in, int out){	USE_DESKTOP(long long) int n;	DECLARE_STATE;	ALLOC_STATE;	to_read = compr_size;//	bytebuffer_max = 0x8000;	bytebuffer_offset = 4;	bytebuffer = xmalloc(bytebuffer_max);	n = inflate_unzip_internal(PASS_STATE in, out);	free(bytebuffer);	res->crc = gunzip_crc;	res->bytes_out = gunzip_bytes_out;	DEALLOC_STATE;	return n;}/* For gunzip *//* helpers first *//* Top up the input buffer with at least n bytes. */static int top_up(STATE_PARAM unsigned n){	int count = bytebuffer_size - bytebuffer_offset;	if (count < (int)n) {		memmove(bytebuffer, &bytebuffer[bytebuffer_offset], count);		bytebuffer_offset = 0;		bytebuffer_size = full_read(gunzip_src_fd, &bytebuffer[count], bytebuffer_max - count);		if ((int)bytebuffer_size < 0) {			bb_error_msg("read error");			return 0;		}		bytebuffer_size += count;		if (bytebuffer_size < n)			return 0;	}	return 1;}static uint16_t buffer_read_le_u16(STATE_PARAM_ONLY){	uint16_t res;#if BB_LITTLE_ENDIAN	/* gcc 4.2.1 is very clever */	memcpy(&res, &bytebuffer[bytebuffer_offset], 2);#else	res = bytebuffer[bytebuffer_offset];	res |= bytebuffer[bytebuffer_offset + 1] << 8;#endif	bytebuffer_offset += 2;	return res;}static uint32_t buffer_read_le_u32(STATE_PARAM_ONLY){	uint32_t res;#if BB_LITTLE_ENDIAN	memcpy(&res, &bytebuffer[bytebuffer_offset], 4);#else	res = bytebuffer[bytebuffer_offset];	res |= bytebuffer[bytebuffer_offset + 1] << 8;	res |= bytebuffer[bytebuffer_offset + 2] << 16;	res |= bytebuffer[bytebuffer_offset + 3] << 24;#endif	bytebuffer_offset += 4;	return res;}static int check_header_gzip(STATE_PARAM unpack_info_t *info){	union {		unsigned char raw[8];		struct {			uint8_t gz_method;			uint8_t flags;			uint32_t mtime;			uint8_t xtra_flags_UNUSED;			uint8_t os_flags_UNUSED;		} __attribute__((packed)) formatted;	} header;	struct BUG_header {		char BUG_header[sizeof(header) == 8 ? 1 : -1];	};	/*	 * Rewind bytebuffer. We use the beginning because the header has 8	 * bytes, leaving enough for unwinding afterwards.	 */	bytebuffer_size -= bytebuffer_offset;	memmove(bytebuffer, &bytebuffer[bytebuffer_offset], bytebuffer_size);	bytebuffer_offset = 0;	if (!top_up(PASS_STATE 8))		return 0;	memcpy(header.raw, &bytebuffer[bytebuffer_offset], 8);	bytebuffer_offset += 8;	/* Check the compression method */	if (header.formatted.gz_method != 8) {		return 0;	}	if (header.formatted.flags & 0x04) {		/* bit 2 set: extra field present */		unsigned extra_short;		if (!top_up(PASS_STATE 2))			return 0;		extra_short = buffer_read_le_u16(PASS_STATE_ONLY);		if (!top_up(PASS_STATE extra_short))			return 0;		/* Ignore extra field */		bytebuffer_offset += extra_short;	}	/* Discard original name and file comment if any */	/* bit 3 set: original file name present */	/* bit 4 set: file comment present */	if (header.formatted.flags & 0x18) {		while (1) {			do {				if (!top_up(PASS_STATE 1))					return 0;			} while (bytebuffer[bytebuffer_offset++] != 0);			if ((header.formatted.flags & 0x18) != 0x18)				break;			header.formatted.flags &= ~0x18;		}	}	if (info)		info->mtime = SWAP_LE32(header.formatted.mtime);	/* Read the header checksum */	if (header.formatted.flags & 0x02) {		if (!top_up(PASS_STATE 2))			return 0;		bytebuffer_offset += 2;	}	return 1;}USE_DESKTOP(long long) int FAST_FUNCunpack_gz_stream_with_info(int in, int out, unpack_info_t *info){	uint32_t v32;	USE_DESKTOP(long long) int n;	DECLARE_STATE;	n = 0;	ALLOC_STATE;	to_read = -1;//	bytebuffer_max = 0x8000;	bytebuffer = xmalloc(bytebuffer_max);	gunzip_src_fd = in; again:	if (!check_header_gzip(PASS_STATE info)) {		bb_error_msg("corrupted data");		n = -1;		goto ret;	}	n += inflate_unzip_internal(PASS_STATE in, out);	if (n < 0)		goto ret;	if (!top_up(PASS_STATE 8)) {		bb_error_msg("corrupted data");		n = -1;		goto ret;	}	/* Validate decompression - crc */	v32 = buffer_read_le_u32(PASS_STATE_ONLY);	if ((~gunzip_crc) != v32) {		bb_error_msg("crc error");		n = -1;		goto ret;	}	/* Validate decompression - size */	v32 = buffer_read_le_u32(PASS_STATE_ONLY);	if ((uint32_t)gunzip_bytes_out != v32) {		bb_error_msg("incorrect length");		n = -1;	}	if (!top_up(PASS_STATE 2))		goto ret; /* EOF */	if (bytebuffer[bytebuffer_offset] == 0x1f	 && bytebuffer[bytebuffer_offset + 1] == 0x8b	) {		bytebuffer_offset += 2;		goto again;	}	/* GNU gzip says: */	/*bb_error_msg("decompression OK, trailing garbage ignored");*/ ret:	free(bytebuffer);	DEALLOC_STATE;	return n;}USE_DESKTOP(long long) int FAST_FUNCunpack_gz_stream(int in, int out){	return unpack_gz_stream_with_info(in, out, NULL);}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?