net: workaround compression leaks
(This is a reland of r151502, which was reverted in r151517 because it
broke the Linux Official build.)
This may break the Official build for a brief window while a two-sided
patch lands.
BUG=139744
Review URL: https://chromiumcodereview.appspot.com/10837057
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: 9523c88db869fc1df3b95e29a6d6a8e2fa8bad1f
diff --git a/README.chromium b/README.chromium
index aa5d4a5..81d20ef 100644
--- a/README.chromium
+++ b/README.chromium
@@ -16,3 +16,6 @@
- Added 'mozzconf.h' to mangle the function names.
- Added an #ifdef to prevent zlib.h from mangling its functions.
The 'google.patch' file represents our changes from the original zlib-1.2.5.
+
+A more significant change to support mixed-source data compression. See
+crbug.com/139744 and mixed-source.patch.
diff --git a/deflate.c b/deflate.c
index 5c4022f..02d1516 100644
--- a/deflate.c
+++ b/deflate.c
@@ -70,14 +70,15 @@
finish_done /* finish done, accept no more input or output */
} block_state;
-typedef block_state (*compress_func) OF((deflate_state *s, int flush));
+typedef block_state (*compress_func) OF((deflate_state *s, int flush,
+ int clas));
/* Compression function. Returns the block state after the call. */
local void fill_window OF((deflate_state *s));
-local block_state deflate_stored OF((deflate_state *s, int flush));
-local block_state deflate_fast OF((deflate_state *s, int flush));
+local block_state deflate_stored OF((deflate_state *s, int flush, int clas));
+local block_state deflate_fast OF((deflate_state *s, int flush, int clas));
#ifndef FASTEST
-local block_state deflate_slow OF((deflate_state *s, int flush));
+local block_state deflate_slow OF((deflate_state *s, int flush, int clas));
#endif
local block_state deflate_rle OF((deflate_state *s, int flush));
local block_state deflate_huff OF((deflate_state *s, int flush));
@@ -87,9 +88,9 @@
local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size));
#ifdef ASMV
void match_init OF((void)); /* asm code initialization */
- uInt longest_match OF((deflate_state *s, IPos cur_match));
+ uInt longest_match OF((deflate_state *s, IPos cur_match, int clas));
#else
-local uInt longest_match OF((deflate_state *s, IPos cur_match));
+local uInt longest_match OF((deflate_state *s, IPos cur_match, int clas));
#endif
#ifdef DEBUG
@@ -281,6 +282,9 @@
s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos));
s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos));
+ s->class_bitmap = NULL;
+ zmemzero(&s->cookie_locations, sizeof(s->cookie_locations));
+ strm->clas = 0;
s->high_water = 0; /* nothing written to s->window yet */
@@ -367,6 +371,8 @@
s = (deflate_state *)strm->state;
s->pending = 0;
s->pending_out = s->pending_buf;
+ TRY_FREE(strm, s->class_bitmap);
+ s->class_bitmap = NULL;
if (s->wrap < 0) {
s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */
@@ -817,9 +823,26 @@
(flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
block_state bstate;
- bstate = s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) :
- (s->strategy == Z_RLE ? deflate_rle(s, flush) :
- (*(configuration_table[s->level].func))(s, flush));
+ if (strm->clas && s->class_bitmap == NULL) {
+ /* This is the first time that we have seen alternative class
+ * data. All data up till this point has been standard class. */
+ s->class_bitmap = (Bytef*) ZALLOC(strm, s->w_size/4, sizeof(Byte));
+ zmemzero(s->class_bitmap, s->w_size/4);
+ }
+
+ if (strm->clas && s->strategy == Z_RLE) {
+ /* We haven't patched deflate_rle. */
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ if (s->strategy == Z_HUFFMAN_ONLY) {
+ bstate = deflate_huff(s, flush);
+ } else if (s->strategy == Z_RLE) {
+ bstate = deflate_rle(s, flush);
+ } else {
+ bstate = (*(configuration_table[s->level].func))
+ (s, flush, strm->clas);
+ }
if (bstate == finish_started || bstate == finish_done) {
s->status = FINISH_STATE;
@@ -915,6 +938,7 @@
TRY_FREE(strm, strm->state->head);
TRY_FREE(strm, strm->state->prev);
TRY_FREE(strm, strm->state->window);
+ TRY_FREE(strm, strm->state->class_bitmap);
ZFREE(strm, strm->state);
strm->state = Z_NULL;
@@ -1046,6 +1070,57 @@
#endif
}
+/* class_set sets bits [offset,offset+len) in s->class_bitmap to either 1 (if
+ * class != 0) or 0 (otherwise). */
+local void class_set(s, offset, len, clas)
+ deflate_state *s;
+ IPos offset;
+ uInt len;
+ int clas;
+{
+ IPos byte = offset >> 3;
+ IPos bit = offset & 7;
+ Bytef class_byte_value = clas ? 0xff : 0x00;
+ Bytef class_bit_value = clas ? 1 : 0;
+ static const Bytef mask[8] = {0xfe, 0xfd, 0xfb, 0xf7,
+ 0xef, 0xdf, 0xbf, 0x7f};
+
+ if (bit) {
+ while (len) {
+ s->class_bitmap[byte] &= mask[bit];
+ s->class_bitmap[byte] |= class_bit_value << bit;
+ bit++;
+ len--;
+ if (bit == 8) {
+ bit = 0;
+ byte++;
+ break;
+ }
+ }
+ }
+
+ while (len >= 8) {
+ s->class_bitmap[byte++] = class_byte_value;
+ len -= 8;
+ }
+
+ while (len) {
+ s->class_bitmap[byte] &= mask[bit];
+ s->class_bitmap[byte] |= class_bit_value << bit;
+ bit++;
+ len--;
+ }
+}
+
+local int class_at(s, window_offset)
+ deflate_state *s;
+ IPos window_offset;
+{
+ IPos byte = window_offset >> 3;
+ IPos bit = window_offset & 7;
+ return (s->class_bitmap[byte] >> bit) & 1;
+}
+
#ifndef FASTEST
/* ===========================================================================
* Set match_start to the longest match starting at the given string and
@@ -1060,9 +1135,10 @@
/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
* match.S. The code will be functionally equivalent.
*/
-local uInt longest_match(s, cur_match)
+local uInt longest_match(s, cur_match, clas)
deflate_state *s;
IPos cur_match; /* current match */
+ int clas;
{
unsigned chain_length = s->max_chain_length;/* max hash chain length */
register Bytef *scan = s->window + s->strstart; /* current string */
@@ -1110,6 +1186,9 @@
do {
Assert(cur_match < s->strstart, "no future");
match = s->window + cur_match;
+ /* If the matched data is in the wrong class, skip it. */
+ if (s->class_bitmap && class_at(s, cur_match) != clas)
+ continue;
/* Skip to next match if the match length cannot increase
* or if the match length is less than 2. Note that the checks below
@@ -1152,6 +1231,8 @@
len = (MAX_MATCH - 1) - (int)(strend-scan);
scan = strend - (MAX_MATCH-1);
+#error "UNALIGNED_OK hasn't been patched."
+
#else /* UNALIGNED_OK */
if (match[best_len] != scan_end ||
@@ -1168,15 +1249,23 @@
scan += 2, match++;
Assert(*scan == *match, "match[2]?");
- /* We check for insufficient lookahead only every 8th comparison;
- * the 256th check will be made at strstart+258.
- */
- do {
- } while (*++scan == *++match && *++scan == *++match &&
- *++scan == *++match && *++scan == *++match &&
- *++scan == *++match && *++scan == *++match &&
- *++scan == *++match && *++scan == *++match &&
- scan < strend);
+ if (!s->class_bitmap) {
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+ } else {
+ /* We have to be mindful of the class of the data and not stray. */
+ do {
+ } while (*++scan == *++match &&
+ class_at(s, match - s->window) == clas &&
+ scan < strend);
+ }
Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
@@ -1204,20 +1293,67 @@
}
#endif /* ASMV */
+/* cookie_match is a replacement for longest_match in the case of cookie data.
+ * Here we only wish to match the entire value so trying the partial matches in
+ * longest_match is both wasteful and often fails to find the correct match.
+ *
+ * So we take the djb2 hash of the cookie and look up the last position for a
+ * match in a special hash table. */
+local uInt cookie_match(s, start, len)
+ deflate_state *s;
+ IPos start;
+ unsigned len;
+{
+ unsigned hash = 5381;
+ Bytef *str = s->window + start;
+ unsigned i;
+ IPos cookie_location;
+
+ if (len >= MAX_MATCH)
+ return 0;
+
+ for (i = 0; i < len; i++)
+ hash = ((hash << 5) + hash) + str[i];
+
+ hash &= Z_COOKIE_HASH_MASK;
+ cookie_location = s->cookie_locations[hash];
+ s->cookie_locations[hash] = start;
+ s->match_start = 0;
+ if (cookie_location &&
+ (start - cookie_location) > len &&
+ (start - cookie_location) < MAX_DIST(s) &&
+ len <= s->lookahead) {
+ for (i = 0; i < len; i++) {
+ if (s->window[start+i] != s->window[cookie_location+i] ||
+ class_at(s, cookie_location+i) != 1) {
+ return 0;
+ }
+ }
+ s->match_start = cookie_location;
+ return len;
+ }
+
+ return 0;
+}
+
+
#else /* FASTEST */
/* ---------------------------------------------------------------------------
* Optimized version for FASTEST only
*/
-local uInt longest_match(s, cur_match)
+local uInt longest_match(s, cur_match, clas)
deflate_state *s;
IPos cur_match; /* current match */
+ int clas;
{
register Bytef *scan = s->window + s->strstart; /* current string */
register Bytef *match; /* matched string */
register int len; /* length of current match */
register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+#error "This code not patched"
+
/* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
* It is easy to get rid of this optimization if necessary.
*/
@@ -1360,6 +1496,21 @@
*/
} while (--n);
#endif
+
+ for (n = 0; n < Z_COOKIE_HASH_SIZE; n++) {
+ if (s->cookie_locations[n] > wsize) {
+ s->cookie_locations[n] -= wsize;
+ } else {
+ s->cookie_locations[n] = 0;
+ }
+ }
+
+ if (s->class_bitmap) {
+ zmemcpy(s->class_bitmap, s->class_bitmap + s->w_size/8,
+ s->w_size/8);
+ zmemzero(s->class_bitmap + s->w_size/8, s->w_size/8);
+ }
+
more += wsize;
}
if (s->strm->avail_in == 0) return;
@@ -1378,6 +1529,9 @@
Assert(more >= 2, "more < 2");
n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
+ if (s->class_bitmap != NULL) {
+ class_set(s, s->strstart + s->lookahead, n, s->strm->clas);
+ }
s->lookahead += n;
/* Initialize the hash value now that we have some input: */
@@ -1459,9 +1613,10 @@
* NOTE: this function should be optimized to avoid extra copying from
* window to pending_buf.
*/
-local block_state deflate_stored(s, flush)
+local block_state deflate_stored(s, flush, clas)
deflate_state *s;
int flush;
+ int clas;
{
/* Stored blocks are limited to 0xffff bytes, pending_buf is limited
* to pending_buf_size, and each stored block has a 5 byte header:
@@ -1517,13 +1672,19 @@
* new strings in the dictionary only for unmatched strings or for short
* matches. It is used only for the fast compression options.
*/
-local block_state deflate_fast(s, flush)
+local block_state deflate_fast(s, flush, clas)
deflate_state *s;
int flush;
+ int clas;
{
IPos hash_head; /* head of the hash chain */
int bflush; /* set if current block must be flushed */
+ if (clas != 0) {
+ /* We haven't patched this code for alternative class data. */
+ return Z_BUF_ERROR;
+ }
+
for (;;) {
/* Make sure that we always have enough lookahead, except
* at the end of the input file. We need MAX_MATCH bytes
@@ -1554,7 +1715,7 @@
* of window index 0 (in particular we have to avoid a match
* of the string with itself at the start of the input file).
*/
- s->match_length = longest_match (s, hash_head);
+ s->match_length = longest_match (s, hash_head, clas);
/* longest_match() sets match_start */
}
if (s->match_length >= MIN_MATCH) {
@@ -1613,12 +1774,25 @@
* evaluation for matches: a match is finally adopted only if there is
* no better match at the next window position.
*/
-local block_state deflate_slow(s, flush)
+local block_state deflate_slow(s, flush, clas)
deflate_state *s;
int flush;
+ int clas;
{
IPos hash_head; /* head of hash chain */
int bflush; /* set if current block must be flushed */
+ uInt input_length ;
+ int first = 1; /* first says whether this is the first iteration
+ of the loop, below. */
+
+ if (clas == Z_CLASS_COOKIE) {
+ if (s->lookahead) {
+ /* Alternative class data must always be presented at the beginning
+ * of a block. */
+ return Z_BUF_ERROR;
+ }
+ input_length = s->strm->avail_in;
+ }
/* Process the input block. */
for (;;) {
@@ -1648,13 +1822,18 @@
s->prev_length = s->match_length, s->prev_match = s->match_start;
s->match_length = MIN_MATCH-1;
- if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
- s->strstart - hash_head <= MAX_DIST(s)) {
+ if (clas == Z_CLASS_COOKIE && first) {
+ s->match_length = cookie_match(s, s->strstart, input_length);
+ } else if (clas == Z_CLASS_STANDARD &&
+ hash_head != NIL &&
+ s->prev_length < s->max_lazy_match &&
+ s->strstart - hash_head <= MAX_DIST(s)) {
/* 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).
*/
- s->match_length = longest_match (s, hash_head);
+ s->match_length = longest_match (s, hash_head, clas);
+
/* longest_match() sets match_start */
if (s->match_length <= 5 && (s->strategy == Z_FILTERED
@@ -1673,7 +1852,22 @@
/* If there was a match at the previous step and the current
* match is not better, output the previous match:
*/
- if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
+ first = 0;
+ if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length &&
+ /* We will only accept an exact match for Z_CLASS_COOKIE data and
+ * we won't match Z_CLASS_HUFFMAN_ONLY data at all. */
+ (clas == Z_CLASS_STANDARD || (clas == Z_CLASS_COOKIE &&
+ s->prev_length == input_length &&
+ s->prev_match > 0 &&
+ /* We require that a Z_CLASS_COOKIE match be
+ * preceded by either a semicolon (which cannot be
+ * part of a cookie), or non-cookie data. This is
+ * to prevent
+ * a cookie from being a prefix of another.
+ * spdy_framer.cc ensures that cookies are always
+ * terminated by a semicolon. */
+ (class_at(s, s->prev_match-1) == Z_CLASS_STANDARD ||
+ *(s->window + s->prev_match-1) == ';')))) {
uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
/* Do not insert strings in hash table beyond this. */
diff --git a/deflate.h b/deflate.h
index cbf0d1e..83b4602 100644
--- a/deflate.h
+++ b/deflate.h
@@ -91,6 +91,9 @@
* save space in the various tables. IPos is used only for parameter passing.
*/
+#define Z_COOKIE_HASH_SIZE 64
+#define Z_COOKIE_HASH_MASK (Z_COOKIE_HASH_SIZE-1)
+
typedef struct internal_state {
z_streamp strm; /* pointer back to this zlib stream */
int status; /* as the name implies */
@@ -139,6 +142,8 @@
uInt hash_mask; /* hash_size-1 */
uInt hash_shift;
+ Bytef *class_bitmap; /* bitmap of class for each byte in window */
+ IPos cookie_locations[Z_COOKIE_HASH_SIZE];
/* Number of bits by which ins_h must be shifted at each input
* step. It must be such that after MIN_MATCH steps, the oldest
* byte no longer takes part in the hash key, that is:
diff --git a/mixed-source.patch b/mixed-source.patch
new file mode 100644
index 0000000..bd55ef4
--- /dev/null
+++ b/mixed-source.patch
@@ -0,0 +1,491 @@
+diff --git a/third_party/zlib/deflate.c b/third_party/zlib/deflate.c
+index 5c4022f..02d1516 100644
+--- a/third_party/zlib/deflate.c
++++ b/third_party/zlib/deflate.c
+@@ -70,14 +70,15 @@ typedef enum {
+ finish_done /* finish done, accept no more input or output */
+ } block_state;
+
+-typedef block_state (*compress_func) OF((deflate_state *s, int flush));
++typedef block_state (*compress_func) OF((deflate_state *s, int flush,
++ int clas));
+ /* Compression function. Returns the block state after the call. */
+
+ local void fill_window OF((deflate_state *s));
+-local block_state deflate_stored OF((deflate_state *s, int flush));
+-local block_state deflate_fast OF((deflate_state *s, int flush));
++local block_state deflate_stored OF((deflate_state *s, int flush, int clas));
++local block_state deflate_fast OF((deflate_state *s, int flush, int clas));
+ #ifndef FASTEST
+-local block_state deflate_slow OF((deflate_state *s, int flush));
++local block_state deflate_slow OF((deflate_state *s, int flush, int clas));
+ #endif
+ local block_state deflate_rle OF((deflate_state *s, int flush));
+ local block_state deflate_huff OF((deflate_state *s, int flush));
+@@ -87,9 +88,9 @@ local void flush_pending OF((z_streamp strm));
+ local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size));
+ #ifdef ASMV
+ void match_init OF((void)); /* asm code initialization */
+- uInt longest_match OF((deflate_state *s, IPos cur_match));
++ uInt longest_match OF((deflate_state *s, IPos cur_match, int clas));
+ #else
+-local uInt longest_match OF((deflate_state *s, IPos cur_match));
++local uInt longest_match OF((deflate_state *s, IPos cur_match, int clas));
+ #endif
+
+ #ifdef DEBUG
+@@ -281,6 +282,9 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
+ s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
+ s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos));
+ s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos));
++ s->class_bitmap = NULL;
++ zmemzero(&s->cookie_locations, sizeof(s->cookie_locations));
++ strm->clas = 0;
+
+ s->high_water = 0; /* nothing written to s->window yet */
+
+@@ -367,6 +371,8 @@ int ZEXPORT deflateReset (strm)
+ s = (deflate_state *)strm->state;
+ s->pending = 0;
+ s->pending_out = s->pending_buf;
++ TRY_FREE(strm, s->class_bitmap);
++ s->class_bitmap = NULL;
+
+ if (s->wrap < 0) {
+ s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */
+@@ -817,9 +823,26 @@ int ZEXPORT deflate (strm, flush)
+ (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
+ block_state bstate;
+
+- bstate = s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) :
+- (s->strategy == Z_RLE ? deflate_rle(s, flush) :
+- (*(configuration_table[s->level].func))(s, flush));
++ if (strm->clas && s->class_bitmap == NULL) {
++ /* This is the first time that we have seen alternative class
++ * data. All data up till this point has been standard class. */
++ s->class_bitmap = (Bytef*) ZALLOC(strm, s->w_size/4, sizeof(Byte));
++ zmemzero(s->class_bitmap, s->w_size/4);
++ }
++
++ if (strm->clas && s->strategy == Z_RLE) {
++ /* We haven't patched deflate_rle. */
++ ERR_RETURN(strm, Z_BUF_ERROR);
++ }
++
++ if (s->strategy == Z_HUFFMAN_ONLY) {
++ bstate = deflate_huff(s, flush);
++ } else if (s->strategy == Z_RLE) {
++ bstate = deflate_rle(s, flush);
++ } else {
++ bstate = (*(configuration_table[s->level].func))
++ (s, flush, strm->clas);
++ }
+
+ if (bstate == finish_started || bstate == finish_done) {
+ s->status = FINISH_STATE;
+@@ -915,6 +938,7 @@ int ZEXPORT deflateEnd (strm)
+ TRY_FREE(strm, strm->state->head);
+ TRY_FREE(strm, strm->state->prev);
+ TRY_FREE(strm, strm->state->window);
++ TRY_FREE(strm, strm->state->class_bitmap);
+
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+@@ -1046,6 +1070,57 @@ local void lm_init (s)
+ #endif
+ }
+
++/* class_set sets bits [offset,offset+len) in s->class_bitmap to either 1 (if
++ * class != 0) or 0 (otherwise). */
++local void class_set(s, offset, len, clas)
++ deflate_state *s;
++ IPos offset;
++ uInt len;
++ int clas;
++{
++ IPos byte = offset >> 3;
++ IPos bit = offset & 7;
++ Bytef class_byte_value = clas ? 0xff : 0x00;
++ Bytef class_bit_value = clas ? 1 : 0;
++ static const Bytef mask[8] = {0xfe, 0xfd, 0xfb, 0xf7,
++ 0xef, 0xdf, 0xbf, 0x7f};
++
++ if (bit) {
++ while (len) {
++ s->class_bitmap[byte] &= mask[bit];
++ s->class_bitmap[byte] |= class_bit_value << bit;
++ bit++;
++ len--;
++ if (bit == 8) {
++ bit = 0;
++ byte++;
++ break;
++ }
++ }
++ }
++
++ while (len >= 8) {
++ s->class_bitmap[byte++] = class_byte_value;
++ len -= 8;
++ }
++
++ while (len) {
++ s->class_bitmap[byte] &= mask[bit];
++ s->class_bitmap[byte] |= class_bit_value << bit;
++ bit++;
++ len--;
++ }
++}
++
++local int class_at(s, window_offset)
++ deflate_state *s;
++ IPos window_offset;
++{
++ IPos byte = window_offset >> 3;
++ IPos bit = window_offset & 7;
++ return (s->class_bitmap[byte] >> bit) & 1;
++}
++
+ #ifndef FASTEST
+ /* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+@@ -1060,9 +1135,10 @@ local void lm_init (s)
+ /* For 80x86 and 680x0, an optimized version will be provided in match.asm or
+ * match.S. The code will be functionally equivalent.
+ */
+-local uInt longest_match(s, cur_match)
++local uInt longest_match(s, cur_match, clas)
+ deflate_state *s;
+ IPos cur_match; /* current match */
++ int clas;
+ {
+ unsigned chain_length = s->max_chain_length;/* max hash chain length */
+ register Bytef *scan = s->window + s->strstart; /* current string */
+@@ -1110,6 +1186,9 @@ local uInt longest_match(s, cur_match)
+ do {
+ Assert(cur_match < s->strstart, "no future");
+ match = s->window + cur_match;
++ /* If the matched data is in the wrong class, skip it. */
++ if (s->class_bitmap && class_at(s, cur_match) != clas)
++ continue;
+
+ /* Skip to next match if the match length cannot increase
+ * or if the match length is less than 2. Note that the checks below
+@@ -1152,6 +1231,8 @@ local uInt longest_match(s, cur_match)
+ len = (MAX_MATCH - 1) - (int)(strend-scan);
+ scan = strend - (MAX_MATCH-1);
+
++#error "UNALIGNED_OK hasn't been patched."
++
+ #else /* UNALIGNED_OK */
+
+ if (match[best_len] != scan_end ||
+@@ -1168,15 +1249,23 @@ local uInt longest_match(s, cur_match)
+ scan += 2, match++;
+ Assert(*scan == *match, "match[2]?");
+
+- /* We check for insufficient lookahead only every 8th comparison;
+- * the 256th check will be made at strstart+258.
+- */
+- do {
+- } while (*++scan == *++match && *++scan == *++match &&
+- *++scan == *++match && *++scan == *++match &&
+- *++scan == *++match && *++scan == *++match &&
+- *++scan == *++match && *++scan == *++match &&
+- scan < strend);
++ if (!s->class_bitmap) {
++ /* We check for insufficient lookahead only every 8th comparison;
++ * the 256th check will be made at strstart+258.
++ */
++ do {
++ } while (*++scan == *++match && *++scan == *++match &&
++ *++scan == *++match && *++scan == *++match &&
++ *++scan == *++match && *++scan == *++match &&
++ *++scan == *++match && *++scan == *++match &&
++ scan < strend);
++ } else {
++ /* We have to be mindful of the class of the data and not stray. */
++ do {
++ } while (*++scan == *++match &&
++ class_at(s, match - s->window) == clas &&
++ scan < strend);
++ }
+
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+@@ -1204,20 +1293,67 @@ local uInt longest_match(s, cur_match)
+ }
+ #endif /* ASMV */
+
++/* cookie_match is a replacement for longest_match in the case of cookie data.
++ * Here we only wish to match the entire value so trying the partial matches in
++ * longest_match is both wasteful and often fails to find the correct match.
++ *
++ * So we take the djb2 hash of the cookie and look up the last position for a
++ * match in a special hash table. */
++local uInt cookie_match(s, start, len)
++ deflate_state *s;
++ IPos start;
++ unsigned len;
++{
++ unsigned hash = 5381;
++ Bytef *str = s->window + start;
++ unsigned i;
++ IPos cookie_location;
++
++ if (len >= MAX_MATCH)
++ return 0;
++
++ for (i = 0; i < len; i++)
++ hash = ((hash << 5) + hash) + str[i];
++
++ hash &= Z_COOKIE_HASH_MASK;
++ cookie_location = s->cookie_locations[hash];
++ s->cookie_locations[hash] = start;
++ s->match_start = 0;
++ if (cookie_location &&
++ (start - cookie_location) > len &&
++ (start - cookie_location) < MAX_DIST(s) &&
++ len <= s->lookahead) {
++ for (i = 0; i < len; i++) {
++ if (s->window[start+i] != s->window[cookie_location+i] ||
++ class_at(s, cookie_location+i) != 1) {
++ return 0;
++ }
++ }
++ s->match_start = cookie_location;
++ return len;
++ }
++
++ return 0;
++}
++
++
+ #else /* FASTEST */
+
+ /* ---------------------------------------------------------------------------
+ * Optimized version for FASTEST only
+ */
+-local uInt longest_match(s, cur_match)
++local uInt longest_match(s, cur_match, clas)
+ deflate_state *s;
+ IPos cur_match; /* current match */
++ int clas;
+ {
+ register Bytef *scan = s->window + s->strstart; /* current string */
+ register Bytef *match; /* matched string */
+ register int len; /* length of current match */
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+
++#error "This code not patched"
++
+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+@@ -1360,6 +1496,21 @@ local void fill_window(s)
+ */
+ } while (--n);
+ #endif
++
++ for (n = 0; n < Z_COOKIE_HASH_SIZE; n++) {
++ if (s->cookie_locations[n] > wsize) {
++ s->cookie_locations[n] -= wsize;
++ } else {
++ s->cookie_locations[n] = 0;
++ }
++ }
++
++ if (s->class_bitmap) {
++ zmemcpy(s->class_bitmap, s->class_bitmap + s->w_size/8,
++ s->w_size/8);
++ zmemzero(s->class_bitmap + s->w_size/8, s->w_size/8);
++ }
++
+ more += wsize;
+ }
+ if (s->strm->avail_in == 0) return;
+@@ -1378,6 +1529,9 @@ local void fill_window(s)
+ Assert(more >= 2, "more < 2");
+
+ n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
++ if (s->class_bitmap != NULL) {
++ class_set(s, s->strstart + s->lookahead, n, s->strm->clas);
++ }
+ s->lookahead += n;
+
+ /* Initialize the hash value now that we have some input: */
+@@ -1459,9 +1613,10 @@ local void fill_window(s)
+ * NOTE: this function should be optimized to avoid extra copying from
+ * window to pending_buf.
+ */
+-local block_state deflate_stored(s, flush)
++local block_state deflate_stored(s, flush, clas)
+ deflate_state *s;
+ int flush;
++ int clas;
+ {
+ /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
+ * to pending_buf_size, and each stored block has a 5 byte header:
+@@ -1517,13 +1672,19 @@ local block_state deflate_stored(s, flush)
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+-local block_state deflate_fast(s, flush)
++local block_state deflate_fast(s, flush, clas)
+ deflate_state *s;
+ int flush;
++ int clas;
+ {
+ IPos hash_head; /* head of the hash chain */
+ int bflush; /* set if current block must be flushed */
+
++ if (clas != 0) {
++ /* We haven't patched this code for alternative class data. */
++ return Z_BUF_ERROR;
++ }
++
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+@@ -1554,7 +1715,7 @@ local block_state deflate_fast(s, flush)
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+- s->match_length = longest_match (s, hash_head);
++ s->match_length = longest_match (s, hash_head, clas);
+ /* longest_match() sets match_start */
+ }
+ if (s->match_length >= MIN_MATCH) {
+@@ -1613,12 +1774,25 @@ local block_state deflate_fast(s, flush)
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+-local block_state deflate_slow(s, flush)
++local block_state deflate_slow(s, flush, clas)
+ deflate_state *s;
+ int flush;
++ int clas;
+ {
+ IPos hash_head; /* head of hash chain */
+ int bflush; /* set if current block must be flushed */
++ uInt input_length ;
++ int first = 1; /* first says whether this is the first iteration
++ of the loop, below. */
++
++ if (clas == Z_CLASS_COOKIE) {
++ if (s->lookahead) {
++ /* Alternative class data must always be presented at the beginning
++ * of a block. */
++ return Z_BUF_ERROR;
++ }
++ input_length = s->strm->avail_in;
++ }
+
+ /* Process the input block. */
+ for (;;) {
+@@ -1648,13 +1822,18 @@ local block_state deflate_slow(s, flush)
+ s->prev_length = s->match_length, s->prev_match = s->match_start;
+ s->match_length = MIN_MATCH-1;
+
+- if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
+- s->strstart - hash_head <= MAX_DIST(s)) {
++ if (clas == Z_CLASS_COOKIE && first) {
++ s->match_length = cookie_match(s, s->strstart, input_length);
++ } else if (clas == Z_CLASS_STANDARD &&
++ hash_head != NIL &&
++ s->prev_length < s->max_lazy_match &&
++ s->strstart - hash_head <= MAX_DIST(s)) {
+ /* 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).
+ */
+- s->match_length = longest_match (s, hash_head);
++ s->match_length = longest_match (s, hash_head, clas);
++
+ /* longest_match() sets match_start */
+
+ if (s->match_length <= 5 && (s->strategy == Z_FILTERED
+@@ -1673,7 +1852,22 @@ local block_state deflate_slow(s, flush)
+ /* If there was a match at the previous step and the current
+ * match is not better, output the previous match:
+ */
+- if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
++ first = 0;
++ if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length &&
++ /* We will only accept an exact match for Z_CLASS_COOKIE data and
++ * we won't match Z_CLASS_HUFFMAN_ONLY data at all. */
++ (clas == Z_CLASS_STANDARD || (clas == Z_CLASS_COOKIE &&
++ s->prev_length == input_length &&
++ s->prev_match > 0 &&
++ /* We require that a Z_CLASS_COOKIE match be
++ * preceded by either a semicolon (which cannot be
++ * part of a cookie), or non-cookie data. This is
++ * to prevent
++ * a cookie from being a prefix of another.
++ * spdy_framer.cc ensures that cookies are always
++ * terminated by a semicolon. */
++ (class_at(s, s->prev_match-1) == Z_CLASS_STANDARD ||
++ *(s->window + s->prev_match-1) == ';')))) {
+ uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
+ /* Do not insert strings in hash table beyond this. */
+
+diff --git a/third_party/zlib/deflate.h b/third_party/zlib/deflate.h
+index cbf0d1e..83b4602 100644
+--- a/third_party/zlib/deflate.h
++++ b/third_party/zlib/deflate.h
+@@ -91,6 +91,9 @@ typedef unsigned IPos;
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
++#define Z_COOKIE_HASH_SIZE 64
++#define Z_COOKIE_HASH_MASK (Z_COOKIE_HASH_SIZE-1)
++
+ typedef struct internal_state {
+ z_streamp strm; /* pointer back to this zlib stream */
+ int status; /* as the name implies */
+@@ -139,6 +142,8 @@ typedef struct internal_state {
+ uInt hash_mask; /* hash_size-1 */
+
+ uInt hash_shift;
++ Bytef *class_bitmap; /* bitmap of class for each byte in window */
++ IPos cookie_locations[Z_COOKIE_HASH_SIZE];
+ /* Number of bits by which ins_h must be shifted at each input
+ * step. It must be such that after MIN_MATCH steps, the oldest
+ * byte no longer takes part in the hash key, that is:
+diff --git a/third_party/zlib/zlib.h b/third_party/zlib/zlib.h
+index 4d54af9..da7e971 100644
+--- a/third_party/zlib/zlib.h
++++ b/third_party/zlib/zlib.h
+@@ -101,6 +101,7 @@ typedef struct z_stream_s {
+ int data_type; /* best guess about the data type: binary or text */
+ uLong adler; /* adler32 value of the uncompressed data */
+ uLong reserved; /* reserved for future use */
++ int clas;
+ } z_stream;
+
+ typedef z_stream FAR *z_streamp;
+@@ -207,6 +208,10 @@ typedef gz_header FAR *gz_headerp;
+
+ #define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
+
++#define Z_CLASS_STANDARD 0
++#define Z_CLASS_COOKIE 1
++#define Z_CLASS_HUFFMAN_ONLY 2
++
+ #define zlib_version zlibVersion()
+ /* for compatibility with versions < 1.0.2 */
+
+@@ -1587,6 +1592,13 @@ ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,
+ ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile));
+ ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));
+ ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));
++# else
++ ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *));
++ ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int));
++ ZEXTERN z_off_t ZEXPORT gztell OF((gzFile));
++ ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile));
++ ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t));
++ ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t));
+ # endif
+ #else
+ ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *));
diff --git a/zlib.gyp b/zlib.gyp
index 5e4c200..d856897 100644
--- a/zlib.gyp
+++ b/zlib.gyp
@@ -5,12 +5,12 @@
{
'variables': {
'conditions': [
- [ 'os_posix == 1 and OS != "mac" and OS != "ios" and OS != "openbsd"', {
- # Link to system .so since we already use it due to GTK.
+ [ 'OS=="none"', {
+ # Because we have a patched zlib, we cannot use the system libz.
# TODO(pvalchev): OpenBSD is purposefully left out, as the system
# zlib brings up an incompatibility that breaks rendering.
'use_system_zlib%': 1,
- }, { # os_posix != 1 or OS == "mac" or OS == "ios" or OS == "openbsd"
+ }, {
'use_system_zlib%': 0,
}],
],
@@ -70,6 +70,8 @@
'sources!': [
'contrib/minizip/iowin32.c'
],
+ }], ['OS=="android"', {
+ 'toolsets': ['target', 'host'],
}],
],
}, {
diff --git a/zlib.h b/zlib.h
index 4d54af9..da7e971 100644
--- a/zlib.h
+++ b/zlib.h
@@ -101,6 +101,7 @@
int data_type; /* best guess about the data type: binary or text */
uLong adler; /* adler32 value of the uncompressed data */
uLong reserved; /* reserved for future use */
+ int clas;
} z_stream;
typedef z_stream FAR *z_streamp;
@@ -207,6 +208,10 @@
#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
+#define Z_CLASS_STANDARD 0
+#define Z_CLASS_COOKIE 1
+#define Z_CLASS_HUFFMAN_ONLY 2
+
#define zlib_version zlibVersion()
/* for compatibility with versions < 1.0.2 */
@@ -1587,6 +1592,13 @@
ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile));
ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));
ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));
+# else
+ ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *));
+ ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int));
+ ZEXTERN z_off_t ZEXPORT gztell OF((gzFile));
+ ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile));
+ ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t));
+ ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t));
# endif
#else
ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *));