[automerger skipped] Revert "Set apex_available property" am: 69a32df22a -s ours

am skip reason: skipped by user jiyong

Change-Id: I762074fa8eebffe87bddd763ea9e63a7e2dc83f8
diff --git a/Android.bp b/Android.bp
index c665c49..009033a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,9 +1,63 @@
+srcs_opt = [
+    "adler32_simd.c",
+    // See https://chromium-review.googlesource.com/749732.
+// TODO: causes `atest org.apache.harmony.tests.java.util.zip.DeflaterTest` failures.
+//    "contrib/optimizations/inffast_chunk.c",
+//    "contrib/optimizations/inflate.c",
+    // This file doesn't build for non-neon, so it can't be in the main srcs.
+    "cpu_features.c",
+    "crc32_simd.c",
+]
+
+cflags_arm = [
+    // Since we're building for the platform, we claim to be Linux rather than
+    // Android so we use getauxval() directly instead of the NDK
+    // android_getCpuFeatures which isn't available to us anyway.
+    "-DARMV8_OS_LINUX",
+    // Testing with zlib_bench shows -O3 is a win for ARM but a bit of a wash
+    // for x86, so match the BUILD file in only enabling this for ARM.
+    "-O3",
+]
+cflags_arm_neon = [
+    // We no longer support non-Neon platform builds, but the NDK just has one libz.
+    "-DADLER32_SIMD_NEON",
+// TODO: causes `atest org.apache.harmony.tests.java.util.zip.DeflaterTest` failures.
+//    "-DINFLATE_CHUNK_SIMD_NEON",
+    // HWCAP_CRC32 is checked at runtime, so it's okay to turn crc32
+    // acceleration on for both 32- and 64-bit.
+    "-DCRC32_ARMV8_CRC32",
+]
+cflags_arm64 = cflags_arm + cflags_arm_neon
+
+cflags_x86 = [
+    // See ARMV8_OS_LINUX above.
+    "-DX86_NOT_WINDOWS",
+    // Android's x86/x86-64 ABI includes SSE2 and SSSE3.
+    "-DADLER32_SIMD_SSSE3",
+// TODO: see arm above.
+//    "-DINFLATE_CHUNK_SIMD_SSE2",
+    // TODO: ...but the host build system defaults don't match our official ABI.
+    "-mssse3",
+    // PCLMUL isn't in the ABI, but it won't actually be used unless CPUID
+    // reports that the processor really does have the instruction.
+    "-mpclmul",
+    "-DCRC32_SIMD_SSE42_PCLMUL",
+]
+srcs_x86 = [
+    "crc_folding.c",
+    "fill_window_sse.c",
+] + srcs_opt
+
+// This optimization is applicable to arm64 and x86-64.
+cflags_64 = ["-DINFLATE_CHUNK_READ_64LE"]
+
 cc_defaults {
     name: "libz_defaults",
 
     cflags: [
-        "-O3",
+        // We do support hidden visibility, so turn that on.
         "-DHAVE_HIDDEN",
+        // We do support const, so turn that on.
         "-DZLIB_CONST",
         "-Wall",
         "-Werror",
@@ -15,7 +69,6 @@
     srcs: [
         "adler32.c",
         "compress.c",
-        "cpu_features.c",
         "crc32.c",
         "deflate.c",
         "gzclose.c",
@@ -23,9 +76,9 @@
         "gzread.c",
         "gzwrite.c",
         "infback.c",
+        "inffast.c",
         "inflate.c",
         "inftrees.c",
-        "inffast.c",
         "trees.c",
         "uncompr.c",
         "zutil.c",
@@ -33,15 +86,28 @@
 
     arch: {
         arm: {
-            // measurements show that the ARM version of ZLib is about x1.17 faster
-            // than the thumb one...
-            // TODO: re-test with zlib_bench after SIMD is enabled.
-            instruction_set: "arm",
-
             // TODO: This is to work around b/24465209. Remove after root cause
             // is fixed.
             pack_relocations: false,
             ldflags: ["-Wl,--hash-style=both"],
+
+            cflags: cflags_arm,
+            neon: {
+                cflags: cflags_arm_neon,
+                srcs: srcs_opt,
+            }
+        },
+        arm64: {
+            cflags: cflags_arm64 + cflags_64,
+            srcs: srcs_opt,
+        },
+        x86: {
+            cflags: cflags_x86,
+            srcs: srcs_x86,
+        },
+        x86_64: {
+            cflags: cflags_x86 + cflags_64,
+            srcs: srcs_x86,
         },
     },
 }
@@ -73,12 +139,6 @@
     },
 }
 
-cc_library_static {
-    name: "libz_current",
-    defaults: ["libz_defaults"],
-    sdk_version: "current",
-}
-
 cc_binary_host {
     name: "minigzip",
     srcs: ["contrib/minigzip/minigzip.c"],
@@ -93,27 +153,24 @@
     cflags: ["-Wall", "-Werror"],
     host_supported: true,
     shared_libs: ["libz"],
+    // We build zlib_bench32 and zlib_bench64 so it's easy to test LP32.
+    compile_multilib: "both",
+    multilib: {
+        lib32: { suffix: "32", },
+        lib64: { suffix: "64", },
+    },
 }
 
-// This module is defined in development/ndk/Android.bp. Updating these headers
-// to be usable for any API level is going to be some work (at the very least,
-// there's a ZLIB_VERNUM that will need to be handled since early versions of
-// Android did not have all the APIs that calling code will use if this is set
-// to the current value.
-//
-// The NDK never updated the zlib headers when the platform updated, so until we
-// solve this the NDK will continue shipping the old headers.
-//
-// ndk_headers {
-//     name: "libz_headers",
-//     from: "src",
-//     to: "",
-//     srcs: [
-//         "src/zconf.h",
-//         "src/zlib.h",
-//     ],
-//     license: "NOTICE",
-// }
+ndk_headers {
+    name: "libz_headers",
+    from: "",
+    to: "",
+    srcs: [
+        "zconf.h",
+        "zlib.h",
+    ],
+    license: "LICENSE",
+}
 
 ndk_library {
     name: "libz",
diff --git a/BUILD.gn b/BUILD.gn
index 2414c88..f8e6b4d 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -4,6 +4,10 @@
 
 import("//build/config/compiler/compiler.gni")
 
+if (build_with_chromium) {
+  import("//testing/test.gni")
+}
+
 if (current_cpu == "arm" || current_cpu == "arm64") {
   import("//build/config/arm.gni")
 }
@@ -17,7 +21,10 @@
 }
 
 use_arm_neon_optimizations = false
-if (current_cpu == "arm" || current_cpu == "arm64") {
+if ((current_cpu == "arm" || current_cpu == "arm64") &&
+    !(is_win && !is_clang)) {
+  # TODO(richard.townsend@arm.com): Optimizations temporarily disabled for
+  # Windows on Arm MSVC builds, see http://crbug.com/v8/10012.
   if (arm_use_neon) {
     use_arm_neon_optimizations = true
   }
@@ -34,7 +41,9 @@
     } else {
       defines += [ "X86_NOT_WINDOWS" ]
     }
-  } else if (use_arm_neon_optimizations) {
+  }
+
+  if (use_arm_neon_optimizations) {
     defines = [ "ADLER32_SIMD_NEON" ]
   }
 }
@@ -58,6 +67,7 @@
       "adler32_simd.c",
       "adler32_simd.h",
     ]
+
     if (!is_debug) {
       # Use optimize_speed (-O3) to output the _smallest_ code.
       configs -= [ "//build/config/compiler:default_optimization" ]
@@ -131,6 +141,7 @@
 
   if (use_arm_neon_optimizations) {
     defines = [ "INFLATE_CHUNK_SIMD_NEON" ]
+
     if (current_cpu == "arm64") {
       defines += [ "INFLATE_CHUNK_READ_64LE" ]
     }
@@ -158,11 +169,12 @@
     }
   }
 
+  configs += [ ":zlib_internal_config" ]
+
+  # Needed for MSVC, which is still supported by V8 and PDFium. zlib uses K&R C
+  # style function declarations, which triggers warning C4131.
   configs -= [ "//build/config/compiler:chromium_code" ]
-  configs += [
-    ":zlib_internal_config",
-    "//build/config/compiler:no_chromium_code",
-  ]
+  configs += [ "//build/config/compiler:no_chromium_code" ]
 
   public_configs = [ ":zlib_inflate_chunk_simd_config" ]
 }
@@ -195,6 +207,15 @@
   public_configs = [ ":zlib_crc32_simd_config" ]
 }
 
+config("zlib_x86_simd_config") {
+  if (use_x86_x64_optimizations) {
+    defines = [
+      "CRC32_SIMD_SSE42_PCLMUL",
+      "DEFLATE_FILL_WINDOW_SSE2",
+    ]
+  }
+}
+
 source_set("zlib_x86_simd") {
   visibility = [ ":*" ]
 
@@ -212,11 +233,9 @@
     }
   }
 
-  configs -= [ "//build/config/compiler:chromium_code" ]
-  configs += [
-    ":zlib_internal_config",
-    "//build/config/compiler:no_chromium_code",
-  ]
+  configs += [ ":zlib_internal_config" ]
+
+  public_configs = [ ":zlib_x86_simd_config" ]
 }
 
 config("zlib_warnings") {
@@ -265,6 +284,7 @@
 
   defines = []
   deps = []
+
   if (!use_x86_x64_optimizations && !use_arm_neon_optimizations) {
     # Apparently android_cronet bot builds with NEON disabled and
     # we also should disable optimizations for iOS@x86 (a.k.a. simulator).
@@ -274,8 +294,8 @@
   if (is_ios) {
     # iOS@ARM is a special case where we always have NEON but don't check
     # for crypto extensions.
-    # TODO(cavalcantii): verify what is the current state of CPU features shipped
-    # on latest iOS devices.
+    # TODO(cavalcantii): verify what is the current state of CPU features
+    # shipped on latest iOS devices.
     defines += [ "ARM_OS_IOS" ]
   }
 
@@ -295,6 +315,8 @@
     sources += [ "inflate.c" ]
   }
 
+  deps += [ ":zlib_x86_simd" ]
+
   if (is_android) {
     import("//build/config/android/config.gni")
     if (defined(android_ndk_root) && android_ndk_root != "") {
@@ -305,17 +327,17 @@
   }
 
   configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [ "//build/config/compiler:no_chromium_code" ]
+
+  public_configs = [ ":zlib_config" ]
+
   configs += [
     ":zlib_internal_config",
-    "//build/config/compiler:no_chromium_code",
 
     # Must be after no_chromium_code for warning flags to be ordered correctly.
     ":zlib_warnings",
   ]
 
-  public_configs = [ ":zlib_config" ]
-
-  deps += [ ":zlib_x86_simd" ]
   allow_circular_includes_from = deps
 }
 
@@ -356,14 +378,14 @@
   deps = [ ":zlib" ]
 
   configs -= [ "//build/config/compiler:chromium_code" ]
-  configs += [
-    "//build/config/compiler:no_chromium_code",
+  configs += [ "//build/config/compiler:no_chromium_code" ]
 
+  public_configs = [ ":zlib_config" ]
+
+  configs += [
     # Must be after no_chromium_code for warning flags to be ordered correctly.
     ":minizip_warnings",
   ]
-
-  public_configs = [ ":zlib_config" ]
 }
 
 executable("zlib_bench") {
@@ -376,8 +398,28 @@
     configs += [ "//build/config/compiler:optimize_speed" ]
   }
 
+  deps = [ ":zlib" ]
+
   configs -= [ "//build/config/compiler:chromium_code" ]
   configs += [ "//build/config/compiler:no_chromium_code" ]
+}
 
-  deps = [ ":zlib" ]
+if (build_with_chromium) {
+  test("zlib_unittests") {
+    testonly = true
+
+    sources = [
+      "contrib/tests/infcover.cc",
+      "contrib/tests/infcover.h",
+      "contrib/tests/utils_unittest.cc",
+      "google/compression_utils_portable.cc",
+      "google/compression_utils_portable.h",
+    ]
+
+    deps = [
+      ":zlib",
+      "//testing/gtest",
+      "//testing/gtest:gtest_main",
+    ]
+  }
 }
diff --git a/DEPS b/DEPS
new file mode 100644
index 0000000..b6dcfc6
--- /dev/null
+++ b/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+    "+testing/gtest",
+]
\ No newline at end of file
diff --git a/METADATA b/METADATA
index 10f4685..e969524 100644
--- a/METADATA
+++ b/METADATA
@@ -5,11 +5,11 @@
     type: GIT
     value: "https://chromium.googlesource.com/chromium/src/third_party/zlib/"
   }
-  version: "b9b9a5af7cca2e683e5f2aead8418e5bf9d5a7d5"
+  version: "cf333892c34ab6dbaed37c38a1d5aa6da7b2f99d"
   license_type: NOTICE
   last_upgrade_date {
     year: 2020
-    month: 2
-    day: 7
+    month: 5
+    day: 13
   }
 }
diff --git a/NOTICE b/NOTICE
deleted file mode 120000
index 7a694c9..0000000
--- a/NOTICE
+++ /dev/null
@@ -1 +0,0 @@
-LICENSE
\ No newline at end of file
diff --git a/README.chromium b/README.chromium
index 3d90f79..c3c1ef6 100644
--- a/README.chromium
+++ b/README.chromium
@@ -2,6 +2,7 @@
 Short Name: zlib
 URL: http://zlib.net/
 Version: 1.2.11
+CPEPrefix: cpe:/a:zlib:zlib:1.2.11
 Security Critical: yes
 License: Custom license
 License File: LICENSE
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 06f36fd..d69ed96 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -12,6 +12,9 @@
       "name": "recovery_unit_test"
     },
     {
+      "name": "update_engine_unittests"
+    },
+    {
       "name": "ziparchive-tests"
     },
     {
diff --git a/chromeconf.h b/chromeconf.h
index 666093d..5ecf29e 100644
--- a/chromeconf.h
+++ b/chromeconf.h
@@ -192,4 +192,8 @@
 #define arm_check_features Cr_z_arm_check_features
 #define armv8_crc32_little Cr_z_armv8_crc32_little
 
+/* Symbols added by cpu_features.c */
+#define cpu_check_features Cr_z_cpu_check_features
+#define x86_cpu_enable_sse2 Cr_z_x86_cpu_enable_sse2
+
 #endif /* THIRD_PARTY_ZLIB_CHROMECONF_H_ */
diff --git a/contrib/bench/zlib_bench.cc b/contrib/bench/zlib_bench.cc
index 5dcdef0..bc2f741 100644
--- a/contrib/bench/zlib_bench.cc
+++ b/contrib/bench/zlib_bench.cc
@@ -38,7 +38,7 @@
 }
 
 inline char* string_data(std::string* s) {
-  return s->empty() ? 0 : &*s->begin();
+  return s->empty() ? nullptr : &*s->begin();
 }
 
 struct Data {
@@ -99,10 +99,25 @@
   if (type == kWrapperZRAW)
     return "RAW";
   error_exit("bad wrapper type", int(type));
-  return 0;
+  return nullptr;
 }
 
-static int zlib_compression_level;
+static int zlib_strategy = Z_DEFAULT_STRATEGY;
+
+const char* zlib_level_strategy_name(int compression_level) {
+  if (compression_level == 0)
+    return "";  // strategy is meaningless at level 0
+  if (zlib_strategy == Z_HUFFMAN_ONLY)
+    return "huffman ";
+  if (zlib_strategy == Z_RLE)
+    return "rle ";
+  if (zlib_strategy == Z_DEFAULT_STRATEGY)
+    return "";
+  error_exit("bad strategy", zlib_strategy);
+  return nullptr;
+}
+
+static int zlib_compression_level = Z_DEFAULT_COMPRESSION;
 
 void zlib_compress(
     const zlib_wrapper type,
@@ -119,7 +134,7 @@
   memset(&stream, 0, sizeof(stream));
 
   int result = deflateInit2(&stream, zlib_compression_level, Z_DEFLATED,
-      zlib_stream_wrapper_type(type), MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
+      zlib_stream_wrapper_type(type), MAX_MEM_LEVEL, zlib_strategy);
   if (result != Z_OK)
     error_exit("deflateInit2 failed", result);
 
@@ -185,7 +200,12 @@
   const auto file = read_file_data_or_exit(name);
   const int length = static_cast<int>(file.size);
   const char* data = file.data.get();
-  printf("%-40s :\n", name);
+
+  /*
+   * Report compression strategy and file name.
+   */
+  const char* strategy = zlib_level_strategy_name(zlib_compression_level);
+  printf("%s%-40s :\n", strategy, name);
 
   /*
    * Chop the data into blocks.
@@ -276,18 +296,21 @@
 
 char* get_option(int argc, char* argv[], const char* option) {
   if (argn < argc)
-    return !strcmp(argv[argn], option) ? argv[argn++] : 0;
-  return 0;
+    return !strcmp(argv[argn], option) ? argv[argn++] : nullptr;
+  return nullptr;
 }
 
 bool get_compression(int argc, char* argv[], int* value) {
   if (argn < argc)
-    *value = atoi(argv[argn++]);
-  return *value >= 1 && *value <= 9;
+    *value = isdigit(argv[argn][0]) ? atoi(argv[argn++]) : -1;
+  return *value >= 0 && *value <= 9;
 }
 
 void usage_exit(const char* program) {
-  printf("usage: %s gzip|zlib|raw [--compression 1:9] files...\n", program);
+  printf(
+      "usage: %s gzip|zlib|raw [--compression 0:9] [--huffman|--rle] "
+      "files...\n",
+      program);
   exit(1);
 }
 
@@ -302,10 +325,18 @@
   else
     usage_exit(argv[0]);
 
-  if (!get_option(argc, argv, "--compression"))
-    zlib_compression_level = Z_DEFAULT_COMPRESSION;
-  else if (!get_compression(argc, argv, &zlib_compression_level))
-    usage_exit(argv[0]);
+  while (argn < argc && argv[argn][0] == '-') {
+    if (get_option(argc, argv, "--compression")) {
+      if (!get_compression(argc, argv, &zlib_compression_level))
+        usage_exit(argv[0]);
+    } else if (get_option(argc, argv, "--huffman")) {
+      zlib_strategy = Z_HUFFMAN_ONLY;
+    } else if (get_option(argc, argv, "--rle")) {
+      zlib_strategy = Z_RLE;
+    } else {
+      usage_exit(argv[0]);
+    }
+  }
 
   if (argn >= argc)
     usage_exit(argv[0]);
diff --git a/contrib/minizip/iowin32.c b/contrib/minizip/iowin32.c
index 246ceb9..c6bc314 100644
--- a/contrib/minizip/iowin32.c
+++ b/contrib/minizip/iowin32.c
@@ -31,14 +31,12 @@
 #define _WIN32_WINNT 0x601
 #endif
 
-#if _WIN32_WINNT >= _WIN32_WINNT_WIN8
-// see Include/shared/winapifamily.h in the Windows Kit
-#if defined(WINAPI_FAMILY_PARTITION) && (!(defined(IOWIN32_USING_WINRT_API)))
-#if WINAPI_FAMILY_ONE_PARTITION(WINAPI_FAMILY, WINAPI_PARTITION_APP)
+#if !defined(IOWIN32_USING_WINRT_API)
+#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
+// Windows Store or Universal Windows Platform
 #define IOWIN32_USING_WINRT_API 1
 #endif
 #endif
-#endif
 
 voidpf  ZCALLBACK win32_open_file_func  OF((voidpf opaque, const char* filename, int mode));
 uLong   ZCALLBACK win32_read_file_func  OF((voidpf opaque, voidpf stream, void* buf, uLong size));
diff --git a/contrib/optimizations/insert_string.h b/contrib/optimizations/insert_string.h
index 1826601..d3bc33c 100644
--- a/contrib/optimizations/insert_string.h
+++ b/contrib/optimizations/insert_string.h
@@ -4,45 +4,47 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the Chromium source repository LICENSE file.
  */
-#ifdef _MSC_VER
+
+#if defined(_MSC_VER)
 #define INLINE __inline
 #else
 #define INLINE inline
 #endif
 
 #include "cpu_features.h"
-/* Optimized insert_string block */
-#if defined(CRC32_SIMD_SSE42_PCLMUL) || defined(CRC32_ARMV8_CRC32)
-#define TARGET_CPU_WITH_CRC
+
 // clang-format off
 #if defined(CRC32_SIMD_SSE42_PCLMUL)
-  /* Required to make MSVC bot build pass. */
-  #include <smmintrin.h>
-  #if defined(__GNUC__) || defined(__clang__)
-    #undef TARGET_CPU_WITH_CRC
+  #include <smmintrin.h>  /* Required to make MSVC bot build pass. */
+
+  #if defined(__clang__) || defined(__GNUC__)
     #define TARGET_CPU_WITH_CRC __attribute__((target("sse4.2")))
+  #else
+    #define TARGET_CPU_WITH_CRC
   #endif
 
   #define _cpu_crc32_u32 _mm_crc32_u32
 
 #elif defined(CRC32_ARMV8_CRC32)
   #if defined(__clang__)
-    #undef TARGET_CPU_WITH_CRC
     #define __crc32cw __builtin_arm_crc32cw
   #endif
 
-  #define _cpu_crc32_u32 __crc32cw
-
   #if defined(__aarch64__)
     #define TARGET_CPU_WITH_CRC __attribute__((target("crc")))
   #else  // !defined(__aarch64__)
     #define TARGET_CPU_WITH_CRC __attribute__((target("armv8-a,crc")))
   #endif  // defined(__aarch64__)
+
+  #define _cpu_crc32_u32 __crc32cw
+
 #endif
 // clang-format on
+
+#if defined(TARGET_CPU_WITH_CRC)
+
 TARGET_CPU_WITH_CRC
-local INLINE Pos insert_string_optimized(deflate_state* const s,
-                                         const Pos str) {
+local INLINE Pos insert_string_simd(deflate_state* const s, const Pos str) {
   Pos ret;
   unsigned *ip, val, h = 0;
 
@@ -64,7 +66,8 @@
   s->prev[str & s->w_mask] = ret;
   return ret;
 }
-#endif /* Optimized insert_string block */
+
+#endif // TARGET_CPU_WITH_CRC
 
 /* ===========================================================================
  * Update a hash value with the given input byte
@@ -99,24 +102,22 @@
 }
 
 local INLINE Pos insert_string(deflate_state* const s, const Pos str) {
-/* String dictionary insertion: faster symbol hashing has a positive impact
- * on data compression speeds (around 20% on Intel and 36% on Arm Cortex big
- * cores).
- * A misfeature is that the generated compressed output will differ from
- * vanilla zlib (even though it is still valid 'DEFLATE-d' content).
+/* insert_string_simd string dictionary insertion: this SIMD symbol hashing
+ * significantly improves data compression speed.
  *
- * We offer here a way to disable the optimization if there is the expectation
- * that compressed content should match when compared to vanilla zlib.
+ * Note: the generated compressed output is a valid DEFLATE stream but will
+ * differ from vanilla zlib output ...
  */
-#if !defined(CHROMIUM_ZLIB_NO_CASTAGNOLI)
-  /* TODO(cavalcantii): unify CPU features code. */
-#if defined(CRC32_ARMV8_CRC32)
-  if (arm_cpu_enable_crc32)
-    return insert_string_optimized(s, str);
-#elif defined(CRC32_SIMD_SSE42_PCLMUL)
+#if defined(CHROMIUM_ZLIB_NO_CASTAGNOLI)
+/* ... so this build-time option can used to disable the SIMD symbol hasher
+ * if matching vanilla zlib DEFLATE output is required.
+ */ (;) /* FALLTHOUGH */
+#elif defined(TARGET_CPU_WITH_CRC) && defined(CRC32_SIMD_SSE42_PCLMUL)
   if (x86_cpu_enable_simd)
-    return insert_string_optimized(s, str);
-#endif
+    return insert_string_simd(s, str);
+#elif defined(TARGET_CPU_WITH_CRC) && defined(CRC32_ARMV8_CRC32)
+  if (arm_cpu_enable_crc32)
+    return insert_string_simd(s, str);
 #endif
   return insert_string_c(s, str);
 }
diff --git a/contrib/tests/OWNERS b/contrib/tests/OWNERS
index 9a2fb6f..aa6a2d1 100644
--- a/contrib/tests/OWNERS
+++ b/contrib/tests/OWNERS
@@ -1 +1,2 @@
 cblume@chromium.org
+cavalcantii@chromium.org
diff --git a/contrib/tests/infcover.cc b/contrib/tests/infcover.cc
new file mode 100644
index 0000000..a8c51c7
--- /dev/null
+++ b/contrib/tests/infcover.cc
@@ -0,0 +1,684 @@
+/* infcover.c -- test zlib's inflate routines with full code coverage
+ * Copyright (C) 2011, 2016 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* to use, do: ./configure --cover && make cover */
+// clang-format off
+#include "infcover.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "zlib.h"
+
+/* get definition of internal structure so we can mess with it (see pull()),
+   and so we can call inflate_trees() (see cover5()) */
+#define ZLIB_INTERNAL
+#include "inftrees.h"
+#include "inflate.h"
+
+/* XXX: use C++ streams instead of printf/fputs/etc due to portability
+ * as type sizes can vary between platforms.
+ */
+#include <iostream>
+#define local static
+
+/* XXX: hacking C assert and plugging into GTest. */
+#include "testing/gtest/include/gtest/gtest.h"
+#if defined(assert)
+#undef assert
+#define assert EXPECT_TRUE
+#endif
+
+/* XXX: handle what is a reserved word in C++. */
+#define try try_f
+
+/* -- memory tracking routines -- */
+
+/*
+   These memory tracking routines are provided to zlib and track all of zlib's
+   allocations and deallocations, check for LIFO operations, keep a current
+   and high water mark of total bytes requested, optionally set a limit on the
+   total memory that can be allocated, and when done check for memory leaks.
+
+   They are used as follows:
+
+   z_stream strm;
+   mem_setup(&strm)         initializes the memory tracking and sets the
+                            zalloc, zfree, and opaque members of strm to use
+                            memory tracking for all zlib operations on strm
+   mem_limit(&strm, limit)  sets a limit on the total bytes requested -- a
+                            request that exceeds this limit will result in an
+                            allocation failure (returns NULL) -- setting the
+                            limit to zero means no limit, which is the default
+                            after mem_setup()
+   mem_used(&strm, "msg")   prints to stderr "msg" and the total bytes used
+   mem_high(&strm, "msg")   prints to stderr "msg" and the high water mark
+   mem_done(&strm, "msg")   ends memory tracking, releases all allocations
+                            for the tracking as well as leaked zlib blocks, if
+                            any.  If there was anything unusual, such as leaked
+                            blocks, non-FIFO frees, or frees of addresses not
+                            allocated, then "msg" and information about the
+                            problem is printed to stderr.  If everything is
+                            normal, nothing is printed. mem_done resets the
+                            strm members to Z_NULL to use the default memory
+                            allocation routines on the next zlib initialization
+                            using strm.
+ */
+
+/* these items are strung together in a linked list, one for each allocation */
+struct mem_item {
+    void *ptr;                  /* pointer to allocated memory */
+    size_t size;                /* requested size of allocation */
+    struct mem_item *next;      /* pointer to next item in list, or NULL */
+};
+
+/* this structure is at the root of the linked list, and tracks statistics */
+struct mem_zone {
+    struct mem_item *first;     /* pointer to first item in list, or NULL */
+    size_t total, highwater;    /* total allocations, and largest total */
+    size_t limit;               /* memory allocation limit, or 0 if no limit */
+    int notlifo, rogue;         /* counts of non-LIFO frees and rogue frees */
+};
+
+/* memory allocation routine to pass to zlib */
+local void *mem_alloc(void *mem, unsigned count, unsigned size)
+{
+    void *ptr;
+    struct mem_item *item;
+    struct mem_zone *zone = static_cast<struct mem_zone *>(mem);
+    size_t len = count * (size_t)size;
+
+    /* induced allocation failure */
+    if (zone == NULL || (zone->limit && zone->total + len > zone->limit))
+        return NULL;
+
+    /* perform allocation using the standard library, fill memory with a
+       non-zero value to make sure that the code isn't depending on zeros */
+    ptr = malloc(len);
+    if (ptr == NULL)
+        return NULL;
+    memset(ptr, 0xa5, len);
+
+    /* create a new item for the list */
+    item = static_cast<struct mem_item *>(malloc(sizeof(struct mem_item)));
+    if (item == NULL) {
+        free(ptr);
+        return NULL;
+    }
+    item->ptr = ptr;
+    item->size = len;
+
+    /* insert item at the beginning of the list */
+    item->next = zone->first;
+    zone->first = item;
+
+    /* update the statistics */
+    zone->total += item->size;
+    if (zone->total > zone->highwater)
+        zone->highwater = zone->total;
+
+    /* return the allocated memory */
+    return ptr;
+}
+
+/* memory free routine to pass to zlib */
+local void mem_free(void *mem, void *ptr)
+{
+    struct mem_item *item, *next;
+    struct mem_zone *zone = static_cast<struct mem_zone *>(mem);
+
+    /* if no zone, just do a free */
+    if (zone == NULL) {
+        free(ptr);
+        return;
+    }
+
+    /* point next to the item that matches ptr, or NULL if not found -- remove
+       the item from the linked list if found */
+    next = zone->first;
+    if (next) {
+        if (next->ptr == ptr)
+            zone->first = next->next;   /* first one is it, remove from list */
+        else {
+            do {                        /* search the linked list */
+                item = next;
+                next = item->next;
+            } while (next != NULL && next->ptr != ptr);
+            if (next) {                 /* if found, remove from linked list */
+                item->next = next->next;
+                zone->notlifo++;        /* not a LIFO free */
+            }
+
+        }
+    }
+
+    /* if found, update the statistics and free the item */
+    if (next) {
+        zone->total -= next->size;
+        free(next);
+    }
+
+    /* if not found, update the rogue count */
+    else
+        zone->rogue++;
+
+    /* in any case, do the requested free with the standard library function */
+    free(ptr);
+}
+
+/* set up a controlled memory allocation space for monitoring, set the stream
+   parameters to the controlled routines, with opaque pointing to the space */
+local void mem_setup(z_stream *strm)
+{
+    struct mem_zone *zone;
+
+    zone = static_cast<struct mem_zone *>(malloc(sizeof(struct mem_zone)));
+    assert(zone != NULL);
+    zone->first = NULL;
+    zone->total = 0;
+    zone->highwater = 0;
+    zone->limit = 0;
+    zone->notlifo = 0;
+    zone->rogue = 0;
+    strm->opaque = zone;
+    strm->zalloc = mem_alloc;
+    strm->zfree = mem_free;
+}
+
+/* set a limit on the total memory allocation, or 0 to remove the limit */
+local void mem_limit(z_stream *strm, size_t limit)
+{
+    struct mem_zone *zone = static_cast<struct mem_zone *>(strm->opaque);
+
+    zone->limit = limit;
+}
+
+/* show the current total requested allocations in bytes */
+local void mem_used(z_stream *strm, const char *prefix)
+{
+    struct mem_zone *zone = static_cast<struct mem_zone *>(strm->opaque);
+
+    std::cout << prefix << ": " << zone->total << " allocated" << std::endl;
+}
+
+/* show the high water allocation in bytes */
+local void mem_high(z_stream *strm, const char *prefix)
+{
+    struct mem_zone *zone = static_cast<struct mem_zone *>(strm->opaque);
+
+    std::cout << prefix << ": " << zone->highwater << " high water mark" << std::endl;
+}
+
+/* release the memory allocation zone -- if there are any surprises, notify */
+local void mem_done(z_stream *strm, const char *prefix)
+{
+    int count = 0;
+    struct mem_item *item, *next;
+    struct mem_zone *zone = static_cast<struct mem_zone *>(strm->opaque);
+
+    /* show high water mark */
+    mem_high(strm, prefix);
+
+    /* free leftover allocations and item structures, if any */
+    item = zone->first;
+    while (item != NULL) {
+        free(item->ptr);
+        next = item->next;
+        free(item);
+        item = next;
+        count++;
+    }
+
+    /* issue alerts about anything unexpected */
+    if (count || zone->total)
+        std::cout << "** " << prefix << ": "
+                  << zone->total << " bytes in "
+                  << count << " blocks not freed"
+                  << std::endl;
+
+    if (zone->notlifo)
+        std::cout << "** " << prefix << ": "
+                  << zone->notlifo << " frees not LIFO"
+                  << std::endl;
+
+    if (zone->rogue)
+        std::cout << "** " << prefix << ": "
+                  << zone->rogue << " frees not recognized"
+                  << std::endl;
+
+    /* free the zone and delete from the stream */
+    free(zone);
+    strm->opaque = Z_NULL;
+    strm->zalloc = Z_NULL;
+    strm->zfree = Z_NULL;
+}
+
+/* -- inflate test routines -- */
+
+/* Decode a hexadecimal string, set *len to length, in[] to the bytes.  This
+   decodes liberally, in that hex digits can be adjacent, in which case two in
+   a row writes a byte.  Or they can be delimited by any non-hex character,
+   where the delimiters are ignored except when a single hex digit is followed
+   by a delimiter, where that single digit writes a byte.  The returned data is
+   allocated and must eventually be freed.  NULL is returned if out of memory.
+   If the length is not needed, then len can be NULL. */
+local unsigned char *h2b(const char *hex, unsigned *len)
+{
+    unsigned char *in, *re;
+    unsigned next, val;
+
+    in = static_cast<unsigned char *>(malloc((strlen(hex) + 1) >> 1));
+    if (in == NULL)
+        return NULL;
+    next = 0;
+    val = 1;
+    do {
+        if (*hex >= '0' && *hex <= '9')
+            val = (val << 4) + *hex - '0';
+        else if (*hex >= 'A' && *hex <= 'F')
+            val = (val << 4) + *hex - 'A' + 10;
+        else if (*hex >= 'a' && *hex <= 'f')
+            val = (val << 4) + *hex - 'a' + 10;
+        else if (val != 1 && val < 32)  /* one digit followed by delimiter */
+            val += 240;                 /* make it look like two digits */
+        if (val > 255) {                /* have two digits */
+            in[next++] = val & 0xff;    /* save the decoded byte */
+            val = 1;                    /* start over */
+        }
+    } while (*hex++);       /* go through the loop with the terminating null */
+    if (len != NULL)
+        *len = next;
+    re = static_cast<unsigned char *>(realloc(in, next));
+    return re == NULL ? in : re;
+}
+
+/* generic inflate() run, where hex is the hexadecimal input data, what is the
+   text to include in an error message, step is how much input data to feed
+   inflate() on each call, or zero to feed it all, win is the window bits
+   parameter to inflateInit2(), len is the size of the output buffer, and err
+   is the error code expected from the first inflate() call (the second
+   inflate() call is expected to return Z_STREAM_END).  If win is 47, then
+   header information is collected with inflateGetHeader().  If a zlib stream
+   is looking for a dictionary, then an empty dictionary is provided.
+   inflate() is run until all of the input data is consumed. */
+local void inf(const char *hex, const char *what, unsigned step, int win, unsigned len,
+               int err)
+{
+    int ret;
+    unsigned have;
+    unsigned char *in, *out;
+    z_stream strm, copy;
+    gz_header head;
+
+    mem_setup(&strm);
+    strm.avail_in = 0;
+    strm.next_in = Z_NULL;
+    ret = inflateInit2(&strm, win);
+    if (ret != Z_OK) {
+        mem_done(&strm, what);
+        return;
+    }
+    out = static_cast<unsigned char *>(malloc(len));                          assert(out != NULL);
+    if (win == 47) {
+        head.extra = out;
+        head.extra_max = len;
+        head.name = out;
+        head.name_max = len;
+        head.comment = out;
+        head.comm_max = len;
+        ret = inflateGetHeader(&strm, &head);   assert(ret == Z_OK);
+    }
+    in = h2b(hex, &have);                       assert(in != NULL);
+    if (step == 0 || step > have)
+        step = have;
+    strm.avail_in = step;
+    have -= step;
+    strm.next_in = in;
+    do {
+        strm.avail_out = len;
+        strm.next_out = out;
+        ret = inflate(&strm, Z_NO_FLUSH);       assert(err == 9 || ret == err);
+        if (ret != Z_OK && ret != Z_BUF_ERROR && ret != Z_NEED_DICT)
+            break;
+        if (ret == Z_NEED_DICT) {
+            ret = inflateSetDictionary(&strm, in, 1);
+                                                assert(ret == Z_DATA_ERROR);
+            mem_limit(&strm, 1);
+            ret = inflateSetDictionary(&strm, out, 0);
+                                                assert(ret == Z_MEM_ERROR);
+            mem_limit(&strm, 0);
+            ((struct inflate_state *)strm.state)->mode = DICT;
+            ret = inflateSetDictionary(&strm, out, 0);
+                                                assert(ret == Z_OK);
+            ret = inflate(&strm, Z_NO_FLUSH);   assert(ret == Z_BUF_ERROR);
+        }
+        ret = inflateCopy(&copy, &strm);        assert(ret == Z_OK);
+        ret = inflateEnd(&copy);                assert(ret == Z_OK);
+        err = 9;                        /* don't care next time around */
+        have += strm.avail_in;
+        strm.avail_in = step > have ? have : step;
+        have -= strm.avail_in;
+    } while (strm.avail_in);
+    free(in);
+    free(out);
+    ret = inflateReset2(&strm, -8);             assert(ret == Z_OK);
+    ret = inflateEnd(&strm);                    assert(ret == Z_OK);
+    mem_done(&strm, what);
+}
+
+/* cover all of the lines in inflate.c up to inflate() */
+void cover_support(void)
+{
+    int ret;
+    z_stream strm;
+
+    mem_setup(&strm);
+    strm.avail_in = 0;
+    strm.next_in = Z_NULL;
+    ret = inflateInit(&strm);                   assert(ret == Z_OK);
+    mem_used(&strm, "inflate init");
+    ret = inflatePrime(&strm, 5, 31);           assert(ret == Z_OK);
+    ret = inflatePrime(&strm, -1, 0);           assert(ret == Z_OK);
+    ret = inflateSetDictionary(&strm, Z_NULL, 0);
+                                                assert(ret == Z_STREAM_ERROR);
+    ret = inflateEnd(&strm);                    assert(ret == Z_OK);
+    mem_done(&strm, "prime");
+
+    inf("63 0", "force window allocation", 0, -15, 1, Z_OK);
+    inf("63 18 5", "force window replacement", 0, -8, 259, Z_OK);
+    inf("63 18 68 30 d0 0 0", "force split window update", 4, -8, 259, Z_OK);
+    inf("3 0", "use fixed blocks", 0, -15, 1, Z_STREAM_END);
+    inf("", "bad window size", 0, 1, 0, Z_STREAM_ERROR);
+
+    mem_setup(&strm);
+    strm.avail_in = 0;
+    strm.next_in = Z_NULL;
+    ret = inflateInit_(&strm, ZLIB_VERSION - 1, (int)sizeof(z_stream));
+                                                assert(ret == Z_VERSION_ERROR);
+    mem_done(&strm, "wrong version");
+
+    strm.avail_in = 0;
+    strm.next_in = Z_NULL;
+    ret = inflateInit(&strm);                   assert(ret == Z_OK);
+    ret = inflateEnd(&strm);                    assert(ret == Z_OK);
+    std::cout << "inflate built-in memory routines" << std::endl;;
+}
+
+/* cover all inflate() header and trailer cases and code after inflate() */
+void cover_wrap(void)
+{
+    int ret;
+    z_stream strm, copy;
+    unsigned char dict[257];
+
+    ret = inflate(Z_NULL, 0);                   assert(ret == Z_STREAM_ERROR);
+    ret = inflateEnd(Z_NULL);                   assert(ret == Z_STREAM_ERROR);
+    ret = inflateCopy(Z_NULL, Z_NULL);          assert(ret == Z_STREAM_ERROR);
+    std::cout << "inflate bad parameters" << std::endl;
+
+    inf("1f 8b 0 0", "bad gzip method", 0, 31, 0, Z_DATA_ERROR);
+    inf("1f 8b 8 80", "bad gzip flags", 0, 31, 0, Z_DATA_ERROR);
+    inf("77 85", "bad zlib method", 0, 15, 0, Z_DATA_ERROR);
+    inf("8 99", "set window size from header", 0, 0, 0, Z_OK);
+    inf("78 9c", "bad zlib window size", 0, 8, 0, Z_DATA_ERROR);
+    inf("78 9c 63 0 0 0 1 0 1", "check adler32", 0, 15, 1, Z_STREAM_END);
+    inf("1f 8b 8 1e 0 0 0 0 0 0 1 0 0 0 0 0 0", "bad header crc", 0, 47, 1,
+        Z_DATA_ERROR);
+    inf("1f 8b 8 2 0 0 0 0 0 0 1d 26 3 0 0 0 0 0 0 0 0 0", "check gzip length",
+        0, 47, 0, Z_STREAM_END);
+    inf("78 90", "bad zlib header check", 0, 47, 0, Z_DATA_ERROR);
+    inf("8 b8 0 0 0 1", "need dictionary", 0, 8, 0, Z_NEED_DICT);
+    inf("78 9c 63 0", "compute adler32", 0, 15, 1, Z_OK);
+
+    mem_setup(&strm);
+    strm.avail_in = 0;
+    strm.next_in = Z_NULL;
+    ret = inflateInit2(&strm, -8);
+    strm.avail_in = 2;
+    strm.next_in = (Bytef *)"\x63";
+    strm.avail_out = 1;
+    strm.next_out = (Bytef *)&ret;
+    mem_limit(&strm, 1);
+    ret = inflate(&strm, Z_NO_FLUSH);           assert(ret == Z_MEM_ERROR);
+    ret = inflate(&strm, Z_NO_FLUSH);           assert(ret == Z_MEM_ERROR);
+    mem_limit(&strm, 0);
+    memset(dict, 0, 257);
+    ret = inflateSetDictionary(&strm, dict, 257);
+                                                assert(ret == Z_OK);
+    mem_limit(&strm, (sizeof(struct inflate_state) << 1) + 256);
+    ret = inflatePrime(&strm, 16, 0);           assert(ret == Z_OK);
+    strm.avail_in = 2;
+    strm.next_in = (Bytef *)"\x80";
+    ret = inflateSync(&strm);                   assert(ret == Z_DATA_ERROR);
+    ret = inflate(&strm, Z_NO_FLUSH);           assert(ret == Z_STREAM_ERROR);
+    strm.avail_in = 4;
+    strm.next_in = (Bytef *)"\0\0\xff\xff";
+    ret = inflateSync(&strm);                   assert(ret == Z_OK);
+    (void)inflateSyncPoint(&strm);
+    ret = inflateCopy(&copy, &strm);            assert(ret == Z_MEM_ERROR);
+    mem_limit(&strm, 0);
+    ret = inflateUndermine(&strm, 1);           assert(ret == Z_DATA_ERROR);
+    (void)inflateMark(&strm);
+    ret = inflateEnd(&strm);                    assert(ret == Z_OK);
+    mem_done(&strm, "miscellaneous, force memory errors");
+}
+
+/* input and output functions for inflateBack() */
+local unsigned pull(void *desc, unsigned char **buf)
+{
+    static unsigned int next = 0;
+    static unsigned char dat[] = {0x63, 0, 2, 0};
+    struct inflate_state *state;
+
+    if (desc == Z_NULL) {
+        next = 0;
+        return 0;   /* no input (already provided at next_in) */
+    }
+    state = reinterpret_cast<struct inflate_state *>(((z_stream *)desc)->state);
+    if (state != Z_NULL)
+        state->mode = SYNC;     /* force an otherwise impossible situation */
+    return next < sizeof(dat) ? (*buf = dat + next++, 1) : 0;
+}
+
+local int push(void *desc, unsigned char *buf, unsigned len)
+{
+    buf += len;
+    return desc != Z_NULL;      /* force error if desc not null */
+}
+
+/* cover inflateBack() up to common deflate data cases and after those */
+void cover_back(void)
+{
+    int ret;
+    z_stream strm;
+    unsigned char win[32768];
+
+    ret = inflateBackInit_(Z_NULL, 0, win, 0, 0);
+                                                assert(ret == Z_VERSION_ERROR);
+    ret = inflateBackInit(Z_NULL, 0, win);      assert(ret == Z_STREAM_ERROR);
+    ret = inflateBack(Z_NULL, Z_NULL, Z_NULL, Z_NULL, Z_NULL);
+                                                assert(ret == Z_STREAM_ERROR);
+    ret = inflateBackEnd(Z_NULL);               assert(ret == Z_STREAM_ERROR);
+    std::cout << "inflateBack bad parameters" << std::endl;;
+
+    mem_setup(&strm);
+    ret = inflateBackInit(&strm, 15, win);      assert(ret == Z_OK);
+    strm.avail_in = 2;
+    strm.next_in = (Bytef *)"\x03";
+    ret = inflateBack(&strm, pull, Z_NULL, push, Z_NULL);
+                                                assert(ret == Z_STREAM_END);
+        /* force output error */
+    strm.avail_in = 3;
+    strm.next_in = (Bytef *)"\x63\x00";
+    ret = inflateBack(&strm, pull, Z_NULL, push, &strm);
+                                                assert(ret == Z_BUF_ERROR);
+        /* force mode error by mucking with state */
+    ret = inflateBack(&strm, pull, &strm, push, Z_NULL);
+                                                assert(ret == Z_STREAM_ERROR);
+    ret = inflateBackEnd(&strm);                assert(ret == Z_OK);
+    mem_done(&strm, "inflateBack bad state");
+
+    ret = inflateBackInit(&strm, 15, win);      assert(ret == Z_OK);
+    ret = inflateBackEnd(&strm);                assert(ret == Z_OK);
+    std::cout << "inflateBack built-in memory routines" << std::endl;;
+}
+
+/* do a raw inflate of data in hexadecimal with both inflate and inflateBack */
+local int try(const char *hex, const char *id, int err)
+{
+    int ret;
+    unsigned len, size;
+    unsigned char *in, *out, *win;
+    char *prefix;
+    z_stream strm;
+
+    /* convert to hex */
+    in = h2b(hex, &len);
+    assert(in != NULL);
+
+    /* allocate work areas */
+    size = len << 3;
+    out = static_cast<unsigned char *>(malloc(size));
+    assert(out != NULL);
+    win = static_cast<unsigned char *>(malloc(32768));
+    assert(win != NULL);
+    prefix = static_cast<char *>(malloc(strlen(id) + 6));
+    assert(prefix != NULL);
+
+    /* first with inflate */
+    strcpy(prefix, id);
+    strcat(prefix, "-late");
+    mem_setup(&strm);
+    strm.avail_in = 0;
+    strm.next_in = Z_NULL;
+    ret = inflateInit2(&strm, err < 0 ? 47 : -15);
+    assert(ret == Z_OK);
+    strm.avail_in = len;
+    strm.next_in = in;
+    do {
+        strm.avail_out = size;
+        strm.next_out = out;
+        ret = inflate(&strm, Z_TREES);
+        assert(ret != Z_STREAM_ERROR && ret != Z_MEM_ERROR);
+        if (ret == Z_DATA_ERROR || ret == Z_NEED_DICT)
+            break;
+    } while (strm.avail_in || strm.avail_out == 0);
+    if (err) {
+        assert(ret == Z_DATA_ERROR);
+        assert(strcmp(id, strm.msg) == 0);
+    }
+    inflateEnd(&strm);
+    mem_done(&strm, prefix);
+
+    /* then with inflateBack */
+    if (err >= 0) {
+        strcpy(prefix, id);
+        strcat(prefix, "-back");
+        mem_setup(&strm);
+        ret = inflateBackInit(&strm, 15, win);
+        assert(ret == Z_OK);
+        strm.avail_in = len;
+        strm.next_in = in;
+        ret = inflateBack(&strm, pull, Z_NULL, push, Z_NULL);
+        assert(ret != Z_STREAM_ERROR);
+        if (err) {
+            assert(ret == Z_DATA_ERROR);
+            assert(strcmp(id, strm.msg) == 0);
+        }
+        inflateBackEnd(&strm);
+        mem_done(&strm, prefix);
+    }
+
+    /* clean up */
+    free(prefix);
+    free(win);
+    free(out);
+    free(in);
+    return ret;
+}
+
+/* cover deflate data cases in both inflate() and inflateBack() */
+void cover_inflate(void)
+{
+    try("0 0 0 0 0", "invalid stored block lengths", 1);
+    try("3 0", "fixed", 0);
+    try("6", "invalid block type", 1);
+    try("1 1 0 fe ff 0", "stored", 0);
+    try("fc 0 0", "too many length or distance symbols", 1);
+    try("4 0 fe ff", "invalid code lengths set", 1);
+    try("4 0 24 49 0", "invalid bit length repeat", 1);
+    try("4 0 24 e9 ff ff", "invalid bit length repeat", 1);
+    try("4 0 24 e9 ff 6d", "invalid code -- missing end-of-block", 1);
+    try("4 80 49 92 24 49 92 24 71 ff ff 93 11 0",
+        "invalid literal/lengths set", 1);
+    try("4 80 49 92 24 49 92 24 f b4 ff ff c3 84", "invalid distances set", 1);
+    try("4 c0 81 8 0 0 0 0 20 7f eb b 0 0", "invalid literal/length code", 1);
+    try("2 7e ff ff", "invalid distance code", 1);
+    try("c c0 81 0 0 0 0 0 90 ff 6b 4 0", "invalid distance too far back", 1);
+
+    /* also trailer mismatch just in inflate() */
+    try("1f 8b 8 0 0 0 0 0 0 0 3 0 0 0 0 1", "incorrect data check", -1);
+    try("1f 8b 8 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 1",
+        "incorrect length check", -1);
+    try("5 c0 21 d 0 0 0 80 b0 fe 6d 2f 91 6c", "pull 17", 0);
+    try("5 e0 81 91 24 cb b2 2c 49 e2 f 2e 8b 9a 47 56 9f fb fe ec d2 ff 1f",
+        "long code", 0);
+    try("ed c0 1 1 0 0 0 40 20 ff 57 1b 42 2c 4f", "length extra", 0);
+    try("ed cf c1 b1 2c 47 10 c4 30 fa 6f 35 1d 1 82 59 3d fb be 2e 2a fc f c",
+        "long distance and extra", 0);
+    try("ed c0 81 0 0 0 0 80 a0 fd a9 17 a9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "
+        "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6", "window end", 0);
+    inf("2 8 20 80 0 3 0", "inflate_fast TYPE return", 0, -15, 258,
+        Z_STREAM_END);
+    inf("63 18 5 40 c 0", "window wrap", 3, -8, 300, Z_OK);
+}
+
+/* XXX(cavalcantii): fix linking error due inflate_table. */
+/* cover remaining lines in inftrees.c */
+/* void cover_trees(void) */
+/* { */
+/*     int ret; */
+/*     unsigned bits; */
+/*     unsigned short lens[16], work[16]; */
+/*     code *next, table[ENOUGH_DISTS]; */
+
+/*     /\* we need to call inflate_table() directly in order to manifest not- */
+/*        enough errors, since zlib insures that enough is always enough *\/ */
+/*     for (bits = 0; bits < 15; bits++) */
+/*         lens[bits] = (unsigned short)(bits + 1); */
+/*     lens[15] = 15; */
+/*     next = table; */
+/*     bits = 15; */
+/*     ret = inflate_table(DISTS, lens, 16, &next, &bits, work); */
+/*                                                 assert(ret == 1); */
+/*     next = table; */
+/*     bits = 1; */
+/*     ret = inflate_table(DISTS, lens, 16, &next, &bits, work); */
+/*                                                 assert(ret == 1); */
+/*     fputs("inflate_table not enough errors\n", stderr); */
+/* } */
+
+/* cover remaining inffast.c decoding and window copying */
+void cover_fast(void)
+{
+    inf("e5 e0 81 ad 6d cb b2 2c c9 01 1e 59 63 ae 7d ee fb 4d fd b5 35 41 68"
+        " ff 7f 0f 0 0 0", "fast length extra bits", 0, -8, 258, Z_DATA_ERROR);
+    inf("25 fd 81 b5 6d 59 b6 6a 49 ea af 35 6 34 eb 8c b9 f6 b9 1e ef 67 49"
+        " 50 fe ff ff 3f 0 0", "fast distance extra bits", 0, -8, 258,
+        Z_DATA_ERROR);
+    inf("3 7e 0 0 0 0 0", "fast invalid distance code", 0, -8, 258,
+        Z_DATA_ERROR);
+    inf("1b 7 0 0 0 0 0", "fast invalid literal/length code", 0, -8, 258,
+        Z_DATA_ERROR);
+    inf("d c7 1 ae eb 38 c 4 41 a0 87 72 de df fb 1f b8 36 b1 38 5d ff ff 0",
+        "fast 2nd level codes and too far back", 0, -8, 258, Z_DATA_ERROR);
+    inf("63 18 5 8c 10 8 0 0 0 0", "very common case", 0, -8, 259, Z_OK);
+    inf("63 60 60 18 c9 0 8 18 18 18 26 c0 28 0 29 0 0 0",
+        "contiguous and wrap around window", 6, -8, 259, Z_OK);
+    inf("63 0 3 0 0 0 0 0", "copy direct from output", 0, -8, 259,
+        Z_STREAM_END);
+}
+
+// clang-format on
diff --git a/contrib/tests/infcover.h b/contrib/tests/infcover.h
new file mode 100644
index 0000000..b3e112f
--- /dev/null
+++ b/contrib/tests/infcover.h
@@ -0,0 +1,11 @@
+#ifndef __INF_COVER_H__
+#define __INF_COVER_H__
+
+void cover_support(void);
+void cover_wrap(void);
+void cover_back(void);
+void cover_inflate(void);
+void cover_trees(void);
+void cover_fast(void);
+
+#endif
diff --git a/contrib/tests/utils_unittest.cc b/contrib/tests/utils_unittest.cc
new file mode 100644
index 0000000..9782650
--- /dev/null
+++ b/contrib/tests/utils_unittest.cc
@@ -0,0 +1,90 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the Chromium source repository LICENSE file.
+
+#include <cstddef>
+#include <vector>
+
+#include "infcover.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/zlib/google/compression_utils_portable.h"
+#include "zlib.h"
+
+void TestPayloads(size_t input_size, zlib_internal::WrapperType type) {
+  std::vector<unsigned char> input;
+  input.reserve(input_size);
+  for (size_t i = 1; i <= input_size; ++i)
+    input.push_back(i & 0xff);
+
+  // If it is big enough for GZIP, will work for other wrappers.
+  std::vector<unsigned char> compressed(
+      zlib_internal::GzipExpectedCompressedSize(input.size()));
+  std::vector<unsigned char> decompressed(input.size());
+
+  // Libcores's java/util/zip/Deflater default settings: ZLIB,
+  // DEFAULT_COMPRESSION and DEFAULT_STRATEGY.
+  unsigned long compressed_size = static_cast<unsigned long>(compressed.size());
+  int result = zlib_internal::CompressHelper(
+      type, compressed.data(), &compressed_size, input.data(), input.size(),
+      Z_DEFAULT_COMPRESSION, nullptr, nullptr);
+  ASSERT_EQ(result, Z_OK);
+
+  unsigned long decompressed_size =
+      static_cast<unsigned long>(decompressed.size());
+  result = zlib_internal::UncompressHelper(type, decompressed.data(),
+                                           &decompressed_size,
+                                           compressed.data(), compressed_size);
+  ASSERT_EQ(result, Z_OK);
+  EXPECT_EQ(input, decompressed);
+}
+
+TEST(ZlibTest, ZlibWrapper) {
+  // Minimal ZLIB wrapped short stream size is about 8 bytes.
+  for (size_t i = 1; i < 1024; ++i)
+    TestPayloads(i, zlib_internal::WrapperType::ZLIB);
+}
+
+TEST(ZlibTest, GzipWrapper) {
+  // GZIP should be 12 bytes bigger than ZLIB wrapper.
+  for (size_t i = 1; i < 1024; ++i)
+    TestPayloads(i, zlib_internal::WrapperType::GZIP);
+}
+
+TEST(ZlibTest, RawWrapper) {
+  // RAW has no wrapper (V8 Blobs is a known user), size
+  // should be payload_size + 2 for short payloads.
+  for (size_t i = 1; i < 1024; ++i)
+    TestPayloads(i, zlib_internal::WrapperType::ZRAW);
+}
+
+TEST(ZlibTest, InflateCover) {
+  cover_support();
+  cover_wrap();
+  cover_back();
+  cover_inflate();
+  // TODO(cavalcantii): enable this last test.
+  // cover_trees();
+  cover_fast();
+}
+
+TEST(ZlibTest, DeflateStored) {
+  const int no_compression = 0;
+  const zlib_internal::WrapperType type = zlib_internal::WrapperType::GZIP;
+  std::vector<unsigned char> input(1 << 10, 42);
+  std::vector<unsigned char> compressed(
+      zlib_internal::GzipExpectedCompressedSize(input.size()));
+  std::vector<unsigned char> decompressed(input.size());
+  unsigned long compressed_size = static_cast<unsigned long>(compressed.size());
+  int result = zlib_internal::CompressHelper(
+      type, compressed.data(), &compressed_size, input.data(), input.size(),
+      no_compression, nullptr, nullptr);
+  ASSERT_EQ(result, Z_OK);
+
+  unsigned long decompressed_size =
+      static_cast<unsigned long>(decompressed.size());
+  result = zlib_internal::UncompressHelper(type, decompressed.data(),
+                                           &decompressed_size,
+                                           compressed.data(), compressed_size);
+  ASSERT_EQ(result, Z_OK);
+  EXPECT_EQ(input, decompressed);
+}
diff --git a/cpu_features.c b/cpu_features.c
index 8a25dd2..0c10a00 100644
--- a/cpu_features.c
+++ b/cpu_features.c
@@ -19,9 +19,12 @@
  */
 int ZLIB_INTERNAL arm_cpu_enable_crc32 = 0;
 int ZLIB_INTERNAL arm_cpu_enable_pmull = 0;
+int ZLIB_INTERNAL x86_cpu_enable_sse2 = 0;
 int ZLIB_INTERNAL x86_cpu_enable_ssse3 = 0;
 int ZLIB_INTERNAL x86_cpu_enable_simd = 0;
 
+#ifndef CPU_NO_SIMD
+
 #if defined(ARMV8_OS_ANDROID) || defined(ARMV8_OS_LINUX) || defined(ARMV8_OS_FUCHSIA)
 #include <pthread.h>
 #endif
@@ -125,16 +128,20 @@
     int x86_cpu_has_sse42;
     int x86_cpu_has_pclmulqdq;
     int abcd[4];
+
 #ifdef _MSC_VER
     __cpuid(abcd, 1);
 #else
     __cpuid(1, abcd[0], abcd[1], abcd[2], abcd[3]);
 #endif
+
     x86_cpu_has_sse2 = abcd[3] & 0x4000000;
     x86_cpu_has_ssse3 = abcd[2] & 0x000200;
     x86_cpu_has_sse42 = abcd[2] & 0x100000;
     x86_cpu_has_pclmulqdq = abcd[2] & 0x2;
 
+    x86_cpu_enable_sse2 = x86_cpu_has_sse2;
+
     x86_cpu_enable_ssse3 = x86_cpu_has_ssse3;
 
     x86_cpu_enable_simd = x86_cpu_has_sse2 &&
@@ -143,3 +150,4 @@
 }
 #endif
 #endif
+#endif
diff --git a/cpu_features.h b/cpu_features.h
index 2a4a797..c7b15c5 100644
--- a/cpu_features.h
+++ b/cpu_features.h
@@ -11,6 +11,7 @@
  */
 extern int arm_cpu_enable_crc32;
 extern int arm_cpu_enable_pmull;
+extern int x86_cpu_enable_sse2;
 extern int x86_cpu_enable_ssse3;
 extern int x86_cpu_enable_simd;
 
diff --git a/crc32.c b/crc32.c
index bd69647..d4c3248 100644
--- a/crc32.c
+++ b/crc32.c
@@ -497,7 +497,7 @@
 
 ZLIB_INTERNAL void crc_reset(deflate_state *const s)
 {
-#ifdef ADLER32_SIMD_SSSE3
+#ifdef CRC32_SIMD_SSE42_PCLMUL
     if (x86_cpu_enable_simd) {
         crc_fold_init(s);
         return;
@@ -508,7 +508,7 @@
 
 ZLIB_INTERNAL void crc_finalize(deflate_state *const s)
 {
-#ifdef ADLER32_SIMD_SSSE3
+#ifdef CRC32_SIMD_SSE42_PCLMUL
     if (x86_cpu_enable_simd)
         s->strm->adler = crc_fold_512to32(s);
 #endif
@@ -516,7 +516,7 @@
 
 ZLIB_INTERNAL void copy_with_crc(z_streamp strm, Bytef *dst, long size)
 {
-#ifdef ADLER32_SIMD_SSSE3
+#ifdef CRC32_SIMD_SSE42_PCLMUL
     if (x86_cpu_enable_simd) {
         crc_fold_copy(strm->state, dst, strm->next_in, size);
         return;
diff --git a/crc_folding.c b/crc_folding.c
index 48d7774..ee31d49 100644
--- a/crc_folding.c
+++ b/crc_folding.c
@@ -18,6 +18,8 @@
 
 #include "deflate.h"
 
+#ifdef CRC32_SIMD_SSE42_PCLMUL
+
 #include <inttypes.h>
 #include <emmintrin.h>
 #include <immintrin.h>
@@ -283,7 +285,7 @@
         goto partial;
     }
 
-    algn_diff = 0 - (uintptr_t)src & 0xF;
+    algn_diff = (0 - (uintptr_t)src) & 0xF;
     if (algn_diff) {
         xmm_crc_part = _mm_loadu_si128((__m128i *)src);
         _mm_storeu_si128((__m128i *)dst, xmm_crc_part);
@@ -491,3 +493,5 @@
     return ~crc;
     CRC_SAVE(s)
 }
+
+#endif  /* CRC32_SIMD_SSE42_PCLMUL */
diff --git a/deflate.c b/deflate.c
index 744d855..1597196 100644
--- a/deflate.c
+++ b/deflate.c
@@ -1213,7 +1213,7 @@
 #ifdef GZIP
     if (strm->state->wrap == 2)
         copy_with_crc(strm, buf, len);
-    else 
+    else
 #endif
     {
         zmemcpy(buf, strm->next_in, len);
@@ -1521,7 +1521,7 @@
 
 local void fill_window(deflate_state *s)
 {
-#ifdef ADLER32_SIMD_SSSE3
+#ifdef DEFLATE_FILL_WINDOW_SSE2
     if (x86_cpu_enable_simd) {
         fill_window_sse(s);
         return;
diff --git a/fill_window_sse.c b/fill_window_sse.c
index ed1e5d1..a841c99 100644
--- a/fill_window_sse.c
+++ b/fill_window_sse.c
@@ -9,9 +9,10 @@
  * For conditions of distribution and use, see copyright notice in zlib.h
  */
 
-#include <immintrin.h>
 #include "deflate.h"
 
+#ifdef DEFLATE_FILL_WINDOW_SSE2
+
 #define UPDATE_HASH(s,h,i) \
     {\
         if (s->level < 6) { \
@@ -28,6 +29,8 @@
 
 extern int deflate_read_buf OF((z_streamp strm, Bytef *buf, unsigned size));
 
+#include <immintrin.h>
+
 void fill_window_sse(deflate_state *s)
 {
     const __m128i xmm_wsize = _mm_set1_epi16(s->w_size);
@@ -175,3 +178,5 @@
     Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,
            "not enough room for search");
 }
+
+#endif  /* DEFLATE_FILL_WINDOW_SSE2 */
diff --git a/google/BUILD.gn b/google/BUILD.gn
index a628d2f..4eddc61 100644
--- a/google/BUILD.gn
+++ b/google/BUILD.gn
@@ -21,18 +21,18 @@
       "//third_party/zlib:minizip",
     ]
   }
+}
 
-  static_library("compression_utils") {
-    sources = [
-      "compression_utils.cc",
-      "compression_utils.h",
-    ]
-    deps = [
-      ":compression_utils_portable",
-      "//base",
-      "//third_party/zlib",
-    ]
-  }
+static_library("compression_utils") {
+  sources = [
+    "compression_utils.cc",
+    "compression_utils.h",
+  ]
+  deps = [
+    ":compression_utils_portable",
+    "//base",
+    "//third_party/zlib",
+  ]
 }
 
 # This allows other users of Chromium's zlib library, but don't use Chromium's
diff --git a/google/OWNERS b/google/OWNERS
index 1ca2531..868af3c 100644
--- a/google/OWNERS
+++ b/google/OWNERS
@@ -3,3 +3,4 @@
 # compression_utils*
 asvitkine@chromium.org
 isherman@chromium.org
+cavalcantii@chromium.org
diff --git a/google/compression_utils_portable.cc b/google/compression_utils_portable.cc
index 191e349..2926810 100644
--- a/google/compression_utils_portable.cc
+++ b/google/compression_utils_portable.cc
@@ -84,7 +84,7 @@
                    int compression_level,
                    void* (*malloc_fn)(size_t),
                    void (*free_fn)(void*)) {
-  if (compression_level < 1 || compression_level > 9) {
+  if (compression_level < 0 || compression_level > 9) {
     compression_level = Z_DEFAULT_COMPRESSION;
   }
 
diff --git a/google/zip_internal.cc b/google/zip_internal.cc
index 314740f..a67b6c9 100644
--- a/google/zip_internal.cc
+++ b/google/zip_internal.cc
@@ -5,6 +5,7 @@
 #include "third_party/zlib/google/zip_internal.h"
 
 #include <stddef.h>
+#include <string.h>
 
 #include <algorithm>
 
diff --git a/libz.map.txt b/libz.map.txt
index 0059aa7..850bbf8 100644
--- a/libz.map.txt
+++ b/libz.map.txt
@@ -79,7 +79,7 @@
     inflateResetKeep;
 } ZLIB_1.2.5.1;
 
-ZLIB_1.2.7.1 { # introduced=18
+ZLIB_1.2.7.1 { # introduced=19
     inflateGetDictionary;
     gzvprintf;
 } ZLIB_1.2.5.2;
diff --git a/patches/0004-fix-uwp.patch b/patches/0004-fix-uwp.patch
new file mode 100644
index 0000000..23145a7
--- /dev/null
+++ b/patches/0004-fix-uwp.patch
@@ -0,0 +1,22 @@
+diff --git a/third_party/zlib/contrib/minizip/iowin32.c b/third_party/zlib/contrib/minizip/iowin32.c
+index 246ceb91a139..c6bc314b3c28 100644
+--- a/third_party/zlib/contrib/minizip/iowin32.c
++++ b/third_party/zlib/contrib/minizip/iowin32.c
+@@ -31,14 +31,12 @@
+ #define _WIN32_WINNT 0x601
+ #endif
+ 
+-#if _WIN32_WINNT >= _WIN32_WINNT_WIN8
+-// see Include/shared/winapifamily.h in the Windows Kit
+-#if defined(WINAPI_FAMILY_PARTITION) && (!(defined(IOWIN32_USING_WINRT_API)))
+-#if WINAPI_FAMILY_ONE_PARTITION(WINAPI_FAMILY, WINAPI_PARTITION_APP)
++#if !defined(IOWIN32_USING_WINRT_API)
++#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
++// Windows Store or Universal Windows Platform
+ #define IOWIN32_USING_WINRT_API 1
+ #endif
+ #endif
+-#endif
+ 
+ voidpf  ZCALLBACK win32_open_file_func  OF((voidpf opaque, const char* filename, int mode));
+ uLong   ZCALLBACK win32_read_file_func  OF((voidpf opaque, voidpf stream, void* buf, uLong size));
diff --git a/patches/0005-infcover-gtest.patch b/patches/0005-infcover-gtest.patch
new file mode 100644
index 0000000..d963a3a
--- /dev/null
+++ b/patches/0005-infcover-gtest.patch
@@ -0,0 +1,405 @@
+From 409594639f15d825202971db7a275023e05772ff Mon Sep 17 00:00:00 2001
+From: Adenilson Cavalcanti <adenilson.cavalcanti@arm.com>
+Date: Tue, 28 Apr 2020 10:48:01 -0700
+Subject: [PATCH] Local Changes:   - make C tests build as C++ code so we can
+ use gtest.   - use gtest EXPECT_TRUE instead of C assert.   - replace C
+ streams for C++ (portability issues).
+
+---
+ test/infcover.c | 167 ++++++++++++++++++++++++++----------------------
+ 1 file changed, 90 insertions(+), 77 deletions(-)
+
+diff --git a/test/infcover.c b/test/infcover.c
+index 2be0164..a8c51c7 100644
+--- a/test/infcover.c
++++ b/test/infcover.c
+@@ -4,11 +4,12 @@
+  */
+ 
+ /* to use, do: ./configure --cover && make cover */
+-
++// clang-format off
++#include "infcover.h"
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+-#include <assert.h>
++
+ #include "zlib.h"
+ 
+ /* get definition of internal structure so we can mess with it (see pull()),
+@@ -17,8 +18,22 @@
+ #include "inftrees.h"
+ #include "inflate.h"
+ 
++/* XXX: use C++ streams instead of printf/fputs/etc due to portability
++ * as type sizes can vary between platforms.
++ */
++#include <iostream>
+ #define local static
+ 
++/* XXX: hacking C assert and plugging into GTest. */
++#include "testing/gtest/include/gtest/gtest.h"
++#if defined(assert)
++#undef assert
++#define assert EXPECT_TRUE
++#endif
++
++/* XXX: handle what is a reserved word in C++. */
++#define try try_f
++
+ /* -- memory tracking routines -- */
+ 
+ /*
+@@ -72,7 +87,7 @@ local void *mem_alloc(void *mem, unsigned count, unsigned size)
+ {
+     void *ptr;
+     struct mem_item *item;
+-    struct mem_zone *zone = mem;
++    struct mem_zone *zone = static_cast<struct mem_zone *>(mem);
+     size_t len = count * (size_t)size;
+ 
+     /* induced allocation failure */
+@@ -87,7 +102,7 @@ local void *mem_alloc(void *mem, unsigned count, unsigned size)
+     memset(ptr, 0xa5, len);
+ 
+     /* create a new item for the list */
+-    item = malloc(sizeof(struct mem_item));
++    item = static_cast<struct mem_item *>(malloc(sizeof(struct mem_item)));
+     if (item == NULL) {
+         free(ptr);
+         return NULL;
+@@ -112,7 +127,7 @@ local void *mem_alloc(void *mem, unsigned count, unsigned size)
+ local void mem_free(void *mem, void *ptr)
+ {
+     struct mem_item *item, *next;
+-    struct mem_zone *zone = mem;
++    struct mem_zone *zone = static_cast<struct mem_zone *>(mem);
+ 
+     /* if no zone, just do a free */
+     if (zone == NULL) {
+@@ -159,7 +174,7 @@ local void mem_setup(z_stream *strm)
+ {
+     struct mem_zone *zone;
+ 
+-    zone = malloc(sizeof(struct mem_zone));
++    zone = static_cast<struct mem_zone *>(malloc(sizeof(struct mem_zone)));
+     assert(zone != NULL);
+     zone->first = NULL;
+     zone->total = 0;
+@@ -175,33 +190,33 @@ local void mem_setup(z_stream *strm)
+ /* set a limit on the total memory allocation, or 0 to remove the limit */
+ local void mem_limit(z_stream *strm, size_t limit)
+ {
+-    struct mem_zone *zone = strm->opaque;
++    struct mem_zone *zone = static_cast<struct mem_zone *>(strm->opaque);
+ 
+     zone->limit = limit;
+ }
+ 
+ /* show the current total requested allocations in bytes */
+-local void mem_used(z_stream *strm, char *prefix)
++local void mem_used(z_stream *strm, const char *prefix)
+ {
+-    struct mem_zone *zone = strm->opaque;
++    struct mem_zone *zone = static_cast<struct mem_zone *>(strm->opaque);
+ 
+-    fprintf(stderr, "%s: %lu allocated\n", prefix, zone->total);
++    std::cout << prefix << ": " << zone->total << " allocated" << std::endl;
+ }
+ 
+ /* show the high water allocation in bytes */
+-local void mem_high(z_stream *strm, char *prefix)
++local void mem_high(z_stream *strm, const char *prefix)
+ {
+-    struct mem_zone *zone = strm->opaque;
++    struct mem_zone *zone = static_cast<struct mem_zone *>(strm->opaque);
+ 
+-    fprintf(stderr, "%s: %lu high water mark\n", prefix, zone->highwater);
++    std::cout << prefix << ": " << zone->highwater << " high water mark" << std::endl;
+ }
+ 
+ /* release the memory allocation zone -- if there are any surprises, notify */
+-local void mem_done(z_stream *strm, char *prefix)
++local void mem_done(z_stream *strm, const char *prefix)
+ {
+     int count = 0;
+     struct mem_item *item, *next;
+-    struct mem_zone *zone = strm->opaque;
++    struct mem_zone *zone = static_cast<struct mem_zone *>(strm->opaque);
+ 
+     /* show high water mark */
+     mem_high(strm, prefix);
+@@ -218,13 +233,20 @@ local void mem_done(z_stream *strm, char *prefix)
+ 
+     /* issue alerts about anything unexpected */
+     if (count || zone->total)
+-        fprintf(stderr, "** %s: %lu bytes in %d blocks not freed\n",
+-                prefix, zone->total, count);
++        std::cout << "** " << prefix << ": "
++                  << zone->total << " bytes in "
++                  << count << " blocks not freed"
++                  << std::endl;
++
+     if (zone->notlifo)
+-        fprintf(stderr, "** %s: %d frees not LIFO\n", prefix, zone->notlifo);
++        std::cout << "** " << prefix << ": "
++                  << zone->notlifo << " frees not LIFO"
++                  << std::endl;
++
+     if (zone->rogue)
+-        fprintf(stderr, "** %s: %d frees not recognized\n",
+-                prefix, zone->rogue);
++        std::cout << "** " << prefix << ": "
++                  << zone->rogue << " frees not recognized"
++                  << std::endl;
+ 
+     /* free the zone and delete from the stream */
+     free(zone);
+@@ -247,7 +269,7 @@ local unsigned char *h2b(const char *hex, unsigned *len)
+     unsigned char *in, *re;
+     unsigned next, val;
+ 
+-    in = malloc((strlen(hex) + 1) >> 1);
++    in = static_cast<unsigned char *>(malloc((strlen(hex) + 1) >> 1));
+     if (in == NULL)
+         return NULL;
+     next = 0;
+@@ -268,7 +290,7 @@ local unsigned char *h2b(const char *hex, unsigned *len)
+     } while (*hex++);       /* go through the loop with the terminating null */
+     if (len != NULL)
+         *len = next;
+-    re = realloc(in, next);
++    re = static_cast<unsigned char *>(realloc(in, next));
+     return re == NULL ? in : re;
+ }
+ 
+@@ -281,7 +303,7 @@ local unsigned char *h2b(const char *hex, unsigned *len)
+    header information is collected with inflateGetHeader().  If a zlib stream
+    is looking for a dictionary, then an empty dictionary is provided.
+    inflate() is run until all of the input data is consumed. */
+-local void inf(char *hex, char *what, unsigned step, int win, unsigned len,
++local void inf(const char *hex, const char *what, unsigned step, int win, unsigned len,
+                int err)
+ {
+     int ret;
+@@ -298,7 +320,7 @@ local void inf(char *hex, char *what, unsigned step, int win, unsigned len,
+         mem_done(&strm, what);
+         return;
+     }
+-    out = malloc(len);                          assert(out != NULL);
++    out = static_cast<unsigned char *>(malloc(len));                          assert(out != NULL);
+     if (win == 47) {
+         head.extra = out;
+         head.extra_max = len;
+@@ -347,7 +369,7 @@ local void inf(char *hex, char *what, unsigned step, int win, unsigned len,
+ }
+ 
+ /* cover all of the lines in inflate.c up to inflate() */
+-local void cover_support(void)
++void cover_support(void)
+ {
+     int ret;
+     z_stream strm;
+@@ -381,11 +403,11 @@ local void cover_support(void)
+     strm.next_in = Z_NULL;
+     ret = inflateInit(&strm);                   assert(ret == Z_OK);
+     ret = inflateEnd(&strm);                    assert(ret == Z_OK);
+-    fputs("inflate built-in memory routines\n", stderr);
++    std::cout << "inflate built-in memory routines" << std::endl;;
+ }
+ 
+ /* cover all inflate() header and trailer cases and code after inflate() */
+-local void cover_wrap(void)
++void cover_wrap(void)
+ {
+     int ret;
+     z_stream strm, copy;
+@@ -394,7 +416,7 @@ local void cover_wrap(void)
+     ret = inflate(Z_NULL, 0);                   assert(ret == Z_STREAM_ERROR);
+     ret = inflateEnd(Z_NULL);                   assert(ret == Z_STREAM_ERROR);
+     ret = inflateCopy(Z_NULL, Z_NULL);          assert(ret == Z_STREAM_ERROR);
+-    fputs("inflate bad parameters\n", stderr);
++    std::cout << "inflate bad parameters" << std::endl;
+ 
+     inf("1f 8b 0 0", "bad gzip method", 0, 31, 0, Z_DATA_ERROR);
+     inf("1f 8b 8 80", "bad gzip flags", 0, 31, 0, Z_DATA_ERROR);
+@@ -415,9 +437,9 @@ local void cover_wrap(void)
+     strm.next_in = Z_NULL;
+     ret = inflateInit2(&strm, -8);
+     strm.avail_in = 2;
+-    strm.next_in = (void *)"\x63";
++    strm.next_in = (Bytef *)"\x63";
+     strm.avail_out = 1;
+-    strm.next_out = (void *)&ret;
++    strm.next_out = (Bytef *)&ret;
+     mem_limit(&strm, 1);
+     ret = inflate(&strm, Z_NO_FLUSH);           assert(ret == Z_MEM_ERROR);
+     ret = inflate(&strm, Z_NO_FLUSH);           assert(ret == Z_MEM_ERROR);
+@@ -428,11 +450,11 @@ local void cover_wrap(void)
+     mem_limit(&strm, (sizeof(struct inflate_state) << 1) + 256);
+     ret = inflatePrime(&strm, 16, 0);           assert(ret == Z_OK);
+     strm.avail_in = 2;
+-    strm.next_in = (void *)"\x80";
++    strm.next_in = (Bytef *)"\x80";
+     ret = inflateSync(&strm);                   assert(ret == Z_DATA_ERROR);
+     ret = inflate(&strm, Z_NO_FLUSH);           assert(ret == Z_STREAM_ERROR);
+     strm.avail_in = 4;
+-    strm.next_in = (void *)"\0\0\xff\xff";
++    strm.next_in = (Bytef *)"\0\0\xff\xff";
+     ret = inflateSync(&strm);                   assert(ret == Z_OK);
+     (void)inflateSyncPoint(&strm);
+     ret = inflateCopy(&copy, &strm);            assert(ret == Z_MEM_ERROR);
+@@ -454,7 +476,7 @@ local unsigned pull(void *desc, unsigned char **buf)
+         next = 0;
+         return 0;   /* no input (already provided at next_in) */
+     }
+-    state = (void *)((z_stream *)desc)->state;
++    state = reinterpret_cast<struct inflate_state *>(((z_stream *)desc)->state);
+     if (state != Z_NULL)
+         state->mode = SYNC;     /* force an otherwise impossible situation */
+     return next < sizeof(dat) ? (*buf = dat + next++, 1) : 0;
+@@ -467,7 +489,7 @@ local int push(void *desc, unsigned char *buf, unsigned len)
+ }
+ 
+ /* cover inflateBack() up to common deflate data cases and after those */
+-local void cover_back(void)
++void cover_back(void)
+ {
+     int ret;
+     z_stream strm;
+@@ -479,17 +501,17 @@ local void cover_back(void)
+     ret = inflateBack(Z_NULL, Z_NULL, Z_NULL, Z_NULL, Z_NULL);
+                                                 assert(ret == Z_STREAM_ERROR);
+     ret = inflateBackEnd(Z_NULL);               assert(ret == Z_STREAM_ERROR);
+-    fputs("inflateBack bad parameters\n", stderr);
++    std::cout << "inflateBack bad parameters" << std::endl;;
+ 
+     mem_setup(&strm);
+     ret = inflateBackInit(&strm, 15, win);      assert(ret == Z_OK);
+     strm.avail_in = 2;
+-    strm.next_in = (void *)"\x03";
++    strm.next_in = (Bytef *)"\x03";
+     ret = inflateBack(&strm, pull, Z_NULL, push, Z_NULL);
+                                                 assert(ret == Z_STREAM_END);
+         /* force output error */
+     strm.avail_in = 3;
+-    strm.next_in = (void *)"\x63\x00";
++    strm.next_in = (Bytef *)"\x63\x00";
+     ret = inflateBack(&strm, pull, Z_NULL, push, &strm);
+                                                 assert(ret == Z_BUF_ERROR);
+         /* force mode error by mucking with state */
+@@ -500,11 +522,11 @@ local void cover_back(void)
+ 
+     ret = inflateBackInit(&strm, 15, win);      assert(ret == Z_OK);
+     ret = inflateBackEnd(&strm);                assert(ret == Z_OK);
+-    fputs("inflateBack built-in memory routines\n", stderr);
++    std::cout << "inflateBack built-in memory routines" << std::endl;;
+ }
+ 
+ /* do a raw inflate of data in hexadecimal with both inflate and inflateBack */
+-local int try(char *hex, char *id, int err)
++local int try(const char *hex, const char *id, int err)
+ {
+     int ret;
+     unsigned len, size;
+@@ -518,11 +540,11 @@ local int try(char *hex, char *id, int err)
+ 
+     /* allocate work areas */
+     size = len << 3;
+-    out = malloc(size);
++    out = static_cast<unsigned char *>(malloc(size));
+     assert(out != NULL);
+-    win = malloc(32768);
++    win = static_cast<unsigned char *>(malloc(32768));
+     assert(win != NULL);
+-    prefix = malloc(strlen(id) + 6);
++    prefix = static_cast<char *>(malloc(strlen(id) + 6));
+     assert(prefix != NULL);
+ 
+     /* first with inflate */
+@@ -578,7 +600,7 @@ local int try(char *hex, char *id, int err)
+ }
+ 
+ /* cover deflate data cases in both inflate() and inflateBack() */
+-local void cover_inflate(void)
++void cover_inflate(void)
+ {
+     try("0 0 0 0 0", "invalid stored block lengths", 1);
+     try("3 0", "fixed", 0);
+@@ -613,32 +635,33 @@ local void cover_inflate(void)
+     inf("63 18 5 40 c 0", "window wrap", 3, -8, 300, Z_OK);
+ }
+ 
++/* XXX(cavalcantii): fix linking error due inflate_table. */
+ /* cover remaining lines in inftrees.c */
+-local void cover_trees(void)
+-{
+-    int ret;
+-    unsigned bits;
+-    unsigned short lens[16], work[16];
+-    code *next, table[ENOUGH_DISTS];
+-
+-    /* we need to call inflate_table() directly in order to manifest not-
+-       enough errors, since zlib insures that enough is always enough */
+-    for (bits = 0; bits < 15; bits++)
+-        lens[bits] = (unsigned short)(bits + 1);
+-    lens[15] = 15;
+-    next = table;
+-    bits = 15;
+-    ret = inflate_table(DISTS, lens, 16, &next, &bits, work);
+-                                                assert(ret == 1);
+-    next = table;
+-    bits = 1;
+-    ret = inflate_table(DISTS, lens, 16, &next, &bits, work);
+-                                                assert(ret == 1);
+-    fputs("inflate_table not enough errors\n", stderr);
+-}
++/* void cover_trees(void) */
++/* { */
++/*     int ret; */
++/*     unsigned bits; */
++/*     unsigned short lens[16], work[16]; */
++/*     code *next, table[ENOUGH_DISTS]; */
++
++/*     /\* we need to call inflate_table() directly in order to manifest not- */
++/*        enough errors, since zlib insures that enough is always enough *\/ */
++/*     for (bits = 0; bits < 15; bits++) */
++/*         lens[bits] = (unsigned short)(bits + 1); */
++/*     lens[15] = 15; */
++/*     next = table; */
++/*     bits = 15; */
++/*     ret = inflate_table(DISTS, lens, 16, &next, &bits, work); */
++/*                                                 assert(ret == 1); */
++/*     next = table; */
++/*     bits = 1; */
++/*     ret = inflate_table(DISTS, lens, 16, &next, &bits, work); */
++/*                                                 assert(ret == 1); */
++/*     fputs("inflate_table not enough errors\n", stderr); */
++/* } */
+ 
+ /* cover remaining inffast.c decoding and window copying */
+-local void cover_fast(void)
++void cover_fast(void)
+ {
+     inf("e5 e0 81 ad 6d cb b2 2c c9 01 1e 59 63 ae 7d ee fb 4d fd b5 35 41 68"
+         " ff 7f 0f 0 0 0", "fast length extra bits", 0, -8, 258, Z_DATA_ERROR);
+@@ -658,14 +681,4 @@ local void cover_fast(void)
+         Z_STREAM_END);
+ }
+ 
+-int main(void)
+-{
+-    fprintf(stderr, "%s\n", zlibVersion());
+-    cover_support();
+-    cover_wrap();
+-    cover_back();
+-    cover_inflate();
+-    cover_trees();
+-    cover_fast();
+-    return 0;
+-}
++// clang-format on
+-- 
+2.21.1 (Apple Git-122.3)
+
diff --git a/zlib.h b/zlib.h
index 99fd467..d640451 100644
--- a/zlib.h
+++ b/zlib.h
@@ -45,6 +45,49 @@
 #define ZLIB_VER_SUBREVISION 0
 
 /*
+ * In Android's NDK we have one zlib.h for all the versions.
+ * zlib users tend to use ZLIB_VERNUM to check API availability,
+ * so we need to translate __ANDROID_API__ appropriately.
+ *
+ * ZLIB_1.2.7.1 and ZLIB_1.2.9 are the only API changes in the NDK's
+ * supported range of API levels.
+ *
+ * jb-mr2-dev (18): 1.2.7 (but not 1.2.7.1, where the APIs were added!)
+ * https://android.googlesource.com/platform/external/zlib/+/refs/heads/jb-mr2-dev/src/zlib.h
+ * kitkat-dev (19): 1.2.8
+ * https://android.googlesource.com/platform/external/zlib/+/refs/heads/kitkat-dev/src/zlib.h
+ *
+ * oreo-mr1-dev (27): 1.2.8
+ * https://android.googlesource.com/platform/external/zlib/+/refs/heads/oreo-mr1-dev/src/zlib.h
+ * pie-dev (28): 1.2.11
+ * https://android.googlesource.com/platform/external/zlib/+/refs/heads/pie-dev/src/zlib.h
+ *
+ * So:
+ *  >= 28 --> 1.2.11
+ *  >= 19 --> 1.2.8
+ *   < 19 --> 1.2.7
+ */
+#if defined(__ANDROID__)
+#  if __ANDROID_API__ >= 28
+     /* Already okay. */
+#  elif __ANDROID_API__ >= 19
+#    undef ZLIB_VERSION
+#    define ZLIB_VERSION "1.2.8"
+#    undef ZLIB_VERNUM
+#    define ZLIB_VERNUM 0x1280
+#    undef ZLIB_VER_REVISION
+#    define ZLIB_VER_REVISION 8
+#  else
+#    undef ZLIB_VERSION
+#    define ZLIB_VERSION "1.2.6"
+#    undef ZLIB_VERNUM
+#    define ZLIB_VERNUM 0x1260
+#    undef ZLIB_VER_REVISION
+#    define ZLIB_VER_REVISION 6
+#  endif
+#endif
+
+/*
     The 'zlib' compression library provides in-memory compression and
   decompression functions, including integrity checks of the uncompressed data.
   This version of the library supports only one compression method (deflation)
@@ -652,9 +695,11 @@
    not perform any compression: this will be done by deflate().
 */
 
+#if !defined(__ANDROID__) || __ANDROID_API__ >= 28
 ZEXTERN int ZEXPORT deflateGetDictionary OF((z_streamp strm,
                                              Bytef *dictionary,
                                              uInt  *dictLength));
+#endif
 /*
      Returns the sliding dictionary being maintained by deflate.  dictLength is
    set to the number of bytes in the dictionary, and that many bytes are copied
@@ -904,9 +949,11 @@
    inflate().
 */
 
+#if !defined(__ANDROID__) || __ANDROID_API__ >= 19
 ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm,
                                              Bytef *dictionary,
                                              uInt  *dictLength));
+#endif
 /*
      Returns the sliding dictionary being maintained by inflate.  dictLength is
    set to the number of bytes in the dictionary, and that many bytes are copied
@@ -1280,8 +1327,10 @@
    buffer with the uncompressed data up to that point.
 */
 
+#if !defined(__ANDROID__) || __ANDROID_API__ >= 28
 ZEXTERN int ZEXPORT uncompress2 OF((Bytef *dest,   uLongf *destLen,
                                     const Bytef *source, uLong *sourceLen));
+#endif
 /*
      Same as uncompress, except that sourceLen is a pointer, where the
    length of the source is *sourceLen.  On return, *sourceLen is the number of
@@ -1417,8 +1466,10 @@
    Z_STREAM_ERROR.
 */
 
+#if !defined(__ANDROID__) || __ANDROID_API__ >= 28
 ZEXTERN z_size_t ZEXPORT gzfread OF((voidp buf, z_size_t size, z_size_t nitems,
                                      gzFile file));
+#endif
 /*
      Read up to nitems items of size size from file to buf, otherwise operating
    as gzread() does.  This duplicates the interface of stdio's fread(), with
@@ -1451,8 +1502,10 @@
    error.
 */
 
+#if !defined(__ANDROID__) || __ANDROID_API__ >= 28
 ZEXTERN z_size_t ZEXPORT gzfwrite OF((voidpc buf, z_size_t size,
                                       z_size_t nitems, gzFile file));
+#endif
 /*
      gzfwrite() writes nitems items of size size from buf to file, duplicating
    the interface of stdio's fwrite(), with size_t request and return types.  If
@@ -1704,8 +1757,10 @@
      if (adler != original_adler) error();
 */
 
+#if !defined(__ANDROID__) || __ANDROID_API__ >= 28
 ZEXTERN uLong ZEXPORT adler32_z OF((uLong adler, const Bytef *buf,
                                     z_size_t len));
+#endif
 /*
      Same as adler32(), but with a size_t length.
 */
@@ -1739,8 +1794,10 @@
      if (crc != original_crc) error();
 */
 
+#if !defined(__ANDROID__) || __ANDROID_API__ >= 28
 ZEXTERN uLong ZEXPORT crc32_z OF((uLong adler, const Bytef *buf,
                                   z_size_t len));
+#endif
 /*
      Same as crc32(), but with a size_t length.
 */
@@ -1912,8 +1969,12 @@
 ZEXTERN int            ZEXPORT inflateSyncPoint OF((z_streamp));
 ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table    OF((void));
 ZEXTERN int            ZEXPORT inflateUndermine OF((z_streamp, int));
+#if !defined(__ANDROID__) || __ANDROID_API__ >= 28
 ZEXTERN int            ZEXPORT inflateValidate OF((z_streamp, int));
+#endif
+#if !defined(__ANDROID__) || __ANDROID_API__ >= 28
 ZEXTERN unsigned long  ZEXPORT inflateCodesUsed OF ((z_streamp));
+#endif
 ZEXTERN int            ZEXPORT inflateResetKeep OF((z_streamp));
 ZEXTERN int            ZEXPORT deflateResetKeep OF((z_streamp));
 #if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(Z_SOLO)
@@ -1922,9 +1983,11 @@
 #endif
 #if defined(STDC) || defined(Z_HAVE_STDARG_H)
 #  ifndef Z_SOLO
+#    if !defined(__ANDROID__) || __ANDROID_API__ >= 19
 ZEXTERN int            ZEXPORTVA gzvprintf Z_ARG((gzFile file,
                                                   const char *format,
                                                   va_list va));
+#    endif
 #  endif
 #endif