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 + -
显示快捷键?