📄 deflate.java
字号:
// negative and the data will be gone: if (strstart - block_start >= w_size - MIN_LOOKAHEAD) { flush_block_only(false); if (strm.avail_out == 0) return NeedMore; } } flush_block_only(flush == Z_FINISH); if (strm.avail_out == 0) return (flush == Z_FINISH) ? FinishStarted : NeedMore; return flush == Z_FINISH ? FinishDone : BlockDone; } // Send a stored block void _tr_stored_block(int buf, // input block int stored_len, // length of input block boolean eof // true if this is the last block for a file ) { send_bits((STORED_BLOCK << 1) + (eof ? 1 : 0), 3); // send block type copy_block(buf, stored_len, true); // with header } // Determine the best encoding for the current block: dynamic trees, static // trees or store, and output the encoded block to the zip file. void _tr_flush_block(int buf, // input block, or NULL if too old int stored_len, // length of input block boolean eof // true if this is the last block for a file ) { int opt_lenb, static_lenb;// opt_len and static_len in bytes int max_blindex = 0; // index of last bit length code of non zero // freq // Build the Huffman trees unless a stored block is forced if (level > 0) { // Check if the file is ascii or binary if (data_type == Z_UNKNOWN) set_data_type(); // Construct the literal and distance trees l_desc.build_tree(this); d_desc.build_tree(this); // At this point, opt_len and static_len are the total bit lengths // of // the compressed block data, excluding the tree representations. // Build the bit length tree for the above two trees, and get the // index // in bl_order of the last bit length code to send. max_blindex = build_bl_tree(); // Determine the best encoding. Compute first the block length in // bytes opt_lenb = (opt_len + 3 + 7) >>> 3; static_lenb = (static_len + 3 + 7) >>> 3; if (static_lenb <= opt_lenb) opt_lenb = static_lenb; } else { opt_lenb = static_lenb = stored_len + 5; // force a stored block } if (stored_len + 4 <= opt_lenb && buf != -1) { // 4: two words for the lengths // The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. // Otherwise we can't have processed more than WSIZE input bytes // since // the last block flush, because compression would have been // successful. If LIT_BUFSIZE <= WSIZE, it is never too late to // transform a block into a stored block. _tr_stored_block(buf, stored_len, eof); } else if (static_lenb == opt_lenb) { send_bits((STATIC_TREES << 1) + (eof ? 1 : 0), 3); compress_block(StaticTree.static_ltree, StaticTree.static_dtree); } else { send_bits((DYN_TREES << 1) + (eof ? 1 : 0), 3); send_all_trees(l_desc.max_code + 1, d_desc.max_code + 1, max_blindex + 1); compress_block(dyn_ltree, dyn_dtree); } // The above check is made mod 2^32, for files larger than 512 MB // and uLong implemented on 32 bits. init_block(); if (eof) { bi_windup(); } } // Fill the window when the lookahead becomes insufficient. // Updates strstart and lookahead. // // IN assertion: lookahead < MIN_LOOKAHEAD // OUT assertions: strstart <= window_size-MIN_LOOKAHEAD // At least one byte has been read, or avail_in == 0; reads are // performed for at least two bytes (required for the zip translate_eol // option -- not supported here). void fill_window() { int n, m; int p; int more; // Amount of free space at the end of the window. do { more = (window_size - lookahead - strstart); // Deal with !@#$% 64K limit: if (more == 0 && strstart == 0 && lookahead == 0) { more = w_size; } else if (more == -1) { // Very unlikely, but possible on 16 bit machine if strstart == // 0 // and lookahead == 1 (input done one byte at time) more--; // If the window is almost full and there is insufficient // lookahead, // move the upper half to the lower one to make room in the // upper half. } else if (strstart >= w_size + w_size - MIN_LOOKAHEAD) { System.arraycopy(window, w_size, window, 0, w_size); match_start -= w_size; strstart -= w_size; // we now have strstart >= MAX_DIST block_start -= w_size; // Slide the hash table (could be avoided with 32 bit values // at the expense of memory usage). We slide even when level == // 0 // to keep the hash table consistent if we switch back to level // > 0 // later. (Using level 0 permanently is not an optimal usage of // zlib, so we don't care about this pathological case.) n = hash_size; p = n; do { m = (head[--p] & 0xffff); head[p] = (m >= w_size ? (short) (m - w_size) : 0); } while (--n != 0); n = w_size; p = n; do { m = (prev[--p] & 0xffff); prev[p] = (m >= w_size ? (short) (m - w_size) : 0); // If n is not on any hash chain, prev[n] is garbage but // its value will never be used. } while (--n != 0); more += w_size; } if (strm.avail_in == 0) return; // If there was no sliding: // strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && // more == window_size - lookahead - strstart // => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) // => more >= window_size - 2*WSIZE + 2 // In the BIG_MEM or MMAP case (not yet supported), // window_size == input_size + MIN_LOOKAHEAD && // strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. // Otherwise, window_size == 2*WSIZE so more >= 2. // If there was sliding, more >= WSIZE. So in all cases, more >= 2. n = strm.read_buf(window, strstart + lookahead, more); lookahead += n; // Initialize the hash value now that we have some input: if (lookahead >= MIN_MATCH) { ins_h = window[strstart] & 0xff; ins_h = (((ins_h) << hash_shift) ^ (window[strstart + 1] & 0xff)) & hash_mask; } // If the whole input has less than MIN_MATCH bytes, ins_h is // garbage, // but this is not important since only literal bytes will be // emitted. } while (lookahead < MIN_LOOKAHEAD && strm.avail_in != 0); } // Compress as much as possible from the input stream, return the current // block state. // This function does not perform lazy evaluation of matches and inserts // new strings in the dictionary only for unmatched strings or for short // matches. It is used only for the fast compression options. int deflate_fast(int flush) { // short hash_head = 0; // head of the hash chain int hash_head = 0; // head of the hash chain boolean bflush; // set if current block must be flushed while (true) { // Make sure that we always have enough lookahead, except // at the end of the input file. We need MAX_MATCH bytes // for the next match, plus MIN_MATCH bytes to insert the // string following the next match. if (lookahead < MIN_LOOKAHEAD) { fill_window(); if (lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { return NeedMore; } if (lookahead == 0) break; // flush the current block } // Insert the string window[strstart .. strstart+2] in the // dictionary, and set hash_head to the head of the hash chain: if (lookahead >= MIN_MATCH) { ins_h = (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask; // prev[strstart&w_mask]=hash_head=head[ins_h]; hash_head = (head[ins_h] & 0xffff); prev[strstart & w_mask] = head[ins_h]; head[ins_h] = (short) strstart; } // Find the longest match, discarding those <= prev_length. // At this point we have always match_length < MIN_MATCH if (hash_head != 0L && ((strstart - hash_head) & 0xffff) <= w_size - MIN_LOOKAHEAD) { // To simplify the code, we prevent matches with the string // of window index 0 (in particular we have to avoid a match // of the string with itself at the start of the input file). if (strategy != Z_HUFFMAN_ONLY) { match_length = longest_match(hash_head); } // longest_match() sets match_start } if (match_length >= MIN_MATCH) { // check_match(strstart, match_start, match_length); bflush = _tr_tally(strstart - match_start, match_length - MIN_MATCH); lookahead -= match_length; // Insert new strings in the hash table only if the match length // is not too large. This saves time but degrades compression. if (match_length <= max_lazy_match && lookahead >= MIN_MATCH) { match_length--; // string at strstart already in hash table do { strstart++; ins_h = ((ins_h << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask; // prev[strstart&w_mask]=hash_head=head[ins_h]; hash_head = (head[ins_h] & 0xffff); prev[strstart & w_mask] = head[ins_h]; head[ins_h] = (short) strstart; // strstart never exceeds WSIZE-MAX_MATCH, so there are // always MIN_MATCH bytes ahead. } while (--match_length != 0); strstart++; } else { strstart += match_length; match_length = 0; ins_h = window[strstart] & 0xff; ins_h = (((ins_h) << hash_shift) ^ (window[strstart + 1] & 0xff)) & hash_mask; // If lookahead < MIN_MATCH, ins_h is garbage, but it does // not // matter since it will be recomputed at next deflate call. } } else { // No match, output a literal byte bflush = _tr_tally(0, window[strstart] & 0xff); lookahead--; strstart++; } if (bflush) { flush_block_only(false); if (strm.avail_out == 0) return NeedMore; } } flush_block_only(flush == Z_FINISH); if (strm.avail_out == 0) { if (flush == Z_FINISH) return FinishStarted; else return NeedMore; } return flush == Z_FINISH ? FinishDone : BlockDone; } // Same as above, but achieves better compression. We use a lazy // evaluation for matches: a match is finally adopted only if there is // no better match at the next window position. int deflate_slow(int flush) { // short hash_head = 0; // head of hash chain int hash_head = 0; // head of hash chain boolean bflush; // set if current block must be flushed // Process the input block. while (true) { // Make sure that we always have enough lookahead, except // at the end of the input file. We need MAX_MATCH bytes // for the next match, plus MIN_MATCH bytes to insert the // string following the next match. if (lookahead < MIN_LOOKAHEAD) { fill_window(); if (lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { return NeedMore; } if (lookahead == 0) break; // flush the current block } // Insert the string window[strstart .. strstart+2] in the // dictionary, and set hash_head to the head of the hash chain: if (lookahead >= MIN_MATCH) { ins_h = (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask; // prev[strstart&w_mask]=hash_head=head[ins_h]; hash_head = (head[ins_h] & 0xffff); prev[strstart & w_mask] = head[ins_h]; head[ins_h] = (short) strstart; } // Find the longest match, discarding those <= prev_length. prev_length = match_length; prev_match = match_start; match_length = MIN_MATCH - 1; if (hash_head != 0 && prev_length < max_lazy_match && ((strstart - hash_head) & 0xffff) <= w_size - MIN_LOOKAHEAD) { // To simplify the code, we prevent matches with the string // of window index 0 (in particular we have to avoid a match // of the string with itself at the start of the input file). if (strategy != Z_HUFFMAN_ONLY) { match_length = longest_match(hash_head); } // longest_match() sets match_start if (match_length <= 5 && (strategy == Z_FILTERED || (match_length == MIN_MATCH && strstart - match_start > 4096))) { // If prev_match is also MIN_MATCH, match_start is garbage // but we will ignore the current match anyway. match_length = MIN_MATCH - 1; } } // If there was a match at the previous step and the current // match is not better, output the previous match: if (prev_length >= MIN_MATCH && match_length <= prev_length) { int max_insert = strstart + lookahead - MIN_MATCH; // Do not insert strings in hash table beyond this. // check_match(strstart-1, prev_match, prev_length); bflush = _tr_tally(strstart - 1 - prev_match, prev_length - MIN_MATCH); // Insert in hash table all strings up to the end of the match. // strstart-1 and strstart are already inserted. If there is not // enough lookahead, the last two strings are not inserted in // the hash table. lookahead -= prev_length - 1; prev_length -= 2; do { if (++strstart <= max_insert) { ins_h = (((ins_h) << hash_shift) ^ (window[(strstart) + (MIN_MATCH - 1)] & 0xff)) & hash_mask; // prev[strstart&w_mask]=hash_head=head[ins_h]; hash_head = (head[ins_h] & 0xffff); prev[strstart & w_mask] = head[ins_h]; head[ins_h] = (short) strstart; } } while (--prev_length != 0); match_available = 0; match_length = MIN_MATCH - 1; strstart++; if (bflush) { flush_block_only(false); if (strm.avail_out == 0) return NeedMore; } } else if (match_available != 0) { // If there was no match at the previous position, output a // single literal. If there was a match but the current match // is longer, truncate the previous match to a single literal. bflush = _tr_tally(0, window[strstart - 1] & 0xff); if (bflush) { flush_block_only(false); } strstart++; lookahead--; if (strm.avail_out == 0) return NeedMore; } else { // There is no previous match to compare with, wait for // the next step to decide. match_available = 1; strstart++; lookahead--; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -