deps: update zlib to upstream 8bbd6c31
Updated as described in doc/contributing/maintaining-zlib.md. PR-URL: https://github.com/nodejs/node/pull/45387 Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
This commit is contained in:
parent
8f9dc2732e
commit
b6c108f092
@ -1237,6 +1237,7 @@ def configure_node(o):
|
||||
# Enable branch protection for arm64
|
||||
if target_arch == 'arm64':
|
||||
o['cflags']+=['-msign-return-address=all']
|
||||
o['variables']['arm_fpu'] = options.arm_fpu or 'neon'
|
||||
|
||||
if options.node_snapshot_main is not None:
|
||||
if options.shared:
|
||||
|
309
deps/zlib/BUILD.gn
vendored
309
deps/zlib/BUILD.gn
vendored
@ -1,9 +1,13 @@
|
||||
# Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
# Copyright 2013 The Chromium Authors
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
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")
|
||||
}
|
||||
@ -14,10 +18,49 @@ config("zlib_config") {
|
||||
|
||||
config("zlib_internal_config") {
|
||||
defines = [ "ZLIB_IMPLEMENTATION" ]
|
||||
|
||||
if (!is_debug) {
|
||||
# Build code using -O3, see: crbug.com/1084371.
|
||||
configs = [ "//build/config/compiler:optimize_speed" ]
|
||||
}
|
||||
if (is_debug || use_libfuzzer) {
|
||||
# Enable zlib's asserts in debug and fuzzer builds.
|
||||
defines += [ "ZLIB_DEBUG" ]
|
||||
}
|
||||
|
||||
if (is_win && !is_clang) {
|
||||
# V8 supports building with msvc, these silence some warnings that
|
||||
# causes compilation to fail (https://crbug.com/1255096).
|
||||
cflags = [
|
||||
"/wd4244",
|
||||
"/wd4100",
|
||||
"/wd4702",
|
||||
"/wd4127",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
source_set("zlib_common_headers") {
|
||||
visibility = [ ":*" ]
|
||||
|
||||
sources = [
|
||||
"chromeconf.h",
|
||||
"deflate.h",
|
||||
"inffast.h",
|
||||
"inffixed.h",
|
||||
"inflate.h",
|
||||
"inftrees.h",
|
||||
"zconf.h",
|
||||
"zlib.h",
|
||||
"zutil.h",
|
||||
]
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
@ -29,6 +72,11 @@ use_x86_x64_optimizations =
|
||||
config("zlib_adler32_simd_config") {
|
||||
if (use_x86_x64_optimizations) {
|
||||
defines = [ "ADLER32_SIMD_SSSE3" ]
|
||||
if (is_win) {
|
||||
defines += [ "X86_WINDOWS" ]
|
||||
} else {
|
||||
defines += [ "X86_NOT_WINDOWS" ]
|
||||
}
|
||||
}
|
||||
|
||||
if (use_arm_neon_optimizations) {
|
||||
@ -55,16 +103,13 @@ source_set("zlib_adler32_simd") {
|
||||
"adler32_simd.c",
|
||||
"adler32_simd.h",
|
||||
]
|
||||
if (!is_debug) {
|
||||
# Use optimize_speed (-O3) to output the _smallest_ code.
|
||||
configs -= [ "//build/config/compiler:default_optimization" ]
|
||||
configs += [ "//build/config/compiler:optimize_speed" ]
|
||||
}
|
||||
}
|
||||
|
||||
configs += [ ":zlib_internal_config" ]
|
||||
|
||||
public_configs = [ ":zlib_adler32_simd_config" ]
|
||||
|
||||
public_deps = [ ":zlib_common_headers" ]
|
||||
}
|
||||
|
||||
if (use_arm_neon_optimizations) {
|
||||
@ -78,6 +123,8 @@ if (use_arm_neon_optimizations) {
|
||||
defines += [ "ARMV8_OS_ANDROID" ]
|
||||
} else if (is_linux || is_chromeos) {
|
||||
defines += [ "ARMV8_OS_LINUX" ]
|
||||
} else if (is_mac) {
|
||||
defines += [ "ARMV8_OS_MACOS" ]
|
||||
} else if (is_fuchsia) {
|
||||
defines += [ "ARMV8_OS_FUCHSIA" ]
|
||||
} else if (is_win) {
|
||||
@ -94,37 +141,23 @@ if (use_arm_neon_optimizations) {
|
||||
if (!is_ios) {
|
||||
include_dirs = [ "." ]
|
||||
|
||||
if (is_android) {
|
||||
import("//build/config/android/config.gni")
|
||||
if (defined(android_ndk_root) && android_ndk_root != "") {
|
||||
deps = [
|
||||
"//third_party/android_ndk:cpu_features",
|
||||
]
|
||||
} else {
|
||||
assert(false, "CPU detection requires the Android NDK")
|
||||
}
|
||||
} else if (!is_win && !is_clang) {
|
||||
if (!is_win && !is_clang) {
|
||||
assert(!use_thin_lto,
|
||||
"ThinLTO fails mixing different module-level targets")
|
||||
cflags_c = [ "-march=armv8-a+crc" ]
|
||||
cflags_c = [ "-march=armv8-a+aes+crc" ]
|
||||
}
|
||||
|
||||
sources = [
|
||||
"arm_features.c",
|
||||
"arm_features.h",
|
||||
"crc32_simd.c",
|
||||
"crc32_simd.h",
|
||||
]
|
||||
|
||||
if (!is_debug) {
|
||||
configs -= [ "//build/config/compiler:default_optimization" ]
|
||||
configs += [ "//build/config/compiler:optimize_speed" ]
|
||||
}
|
||||
}
|
||||
|
||||
configs += [ ":zlib_internal_config" ]
|
||||
|
||||
public_configs = [ ":zlib_arm_crc32_config" ]
|
||||
|
||||
public_deps = [ ":zlib_common_headers" ]
|
||||
}
|
||||
}
|
||||
|
||||
@ -139,6 +172,7 @@ config("zlib_inflate_chunk_simd_config") {
|
||||
|
||||
if (use_arm_neon_optimizations) {
|
||||
defines = [ "INFLATE_CHUNK_SIMD_NEON" ]
|
||||
|
||||
if (current_cpu == "arm64") {
|
||||
defines += [ "INFLATE_CHUNK_READ_64LE" ]
|
||||
}
|
||||
@ -157,22 +191,19 @@ source_set("zlib_inflate_chunk_simd") {
|
||||
"contrib/optimizations/inffast_chunk.h",
|
||||
"contrib/optimizations/inflate.c",
|
||||
]
|
||||
|
||||
if (use_arm_neon_optimizations && !is_debug) {
|
||||
# Here we trade better performance on newer/bigger ARMv8 cores
|
||||
# for less perf on ARMv7, per crbug.com/772870#c40
|
||||
configs -= [ "//build/config/compiler:default_optimization" ]
|
||||
configs += [ "//build/config/compiler:optimize_speed" ]
|
||||
}
|
||||
}
|
||||
|
||||
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" ]
|
||||
configs += [ ":zlib_warnings" ]
|
||||
|
||||
public_configs = [ ":zlib_inflate_chunk_simd_config" ]
|
||||
|
||||
public_deps = [ ":zlib_common_headers" ]
|
||||
}
|
||||
|
||||
config("zlib_crc32_simd_config") {
|
||||
@ -188,6 +219,7 @@ source_set("zlib_crc32_simd") {
|
||||
sources = [
|
||||
"crc32_simd.c",
|
||||
"crc32_simd.h",
|
||||
"crc_folding.c",
|
||||
]
|
||||
|
||||
if (!is_win || is_clang) {
|
||||
@ -201,39 +233,45 @@ source_set("zlib_crc32_simd") {
|
||||
configs += [ ":zlib_internal_config" ]
|
||||
|
||||
public_configs = [ ":zlib_crc32_simd_config" ]
|
||||
|
||||
public_deps = [ ":zlib_common_headers" ]
|
||||
}
|
||||
|
||||
source_set("zlib_x86_simd") {
|
||||
config("zlib_slide_hash_simd_config") {
|
||||
if (use_x86_x64_optimizations) {
|
||||
defines = [ "DEFLATE_SLIDE_HASH_SSE2" ]
|
||||
}
|
||||
|
||||
if (use_arm_neon_optimizations) {
|
||||
defines = [ "DEFLATE_SLIDE_HASH_NEON" ]
|
||||
}
|
||||
}
|
||||
|
||||
source_set("zlib_slide_hash_simd") {
|
||||
visibility = [ ":*" ]
|
||||
|
||||
if (use_x86_x64_optimizations) {
|
||||
sources = [
|
||||
"crc_folding.c",
|
||||
"fill_window_sse.c",
|
||||
]
|
||||
|
||||
if (!is_win || is_clang) {
|
||||
cflags = [
|
||||
"-msse4.2",
|
||||
"-mpclmul",
|
||||
]
|
||||
}
|
||||
} else {
|
||||
sources = [
|
||||
"simd_stub.c",
|
||||
]
|
||||
sources = [ "slide_hash_simd.h" ]
|
||||
}
|
||||
|
||||
configs -= [ "//build/config/compiler:chromium_code" ]
|
||||
configs += [
|
||||
":zlib_internal_config",
|
||||
"//build/config/compiler:no_chromium_code",
|
||||
]
|
||||
if (use_arm_neon_optimizations) {
|
||||
sources = [ "slide_hash_simd.h" ]
|
||||
}
|
||||
|
||||
configs += [ ":zlib_internal_config" ]
|
||||
|
||||
public_configs = [ ":zlib_slide_hash_simd_config" ]
|
||||
|
||||
public_deps = [ ":zlib_common_headers" ]
|
||||
}
|
||||
|
||||
config("zlib_warnings") {
|
||||
if (is_clang && use_x86_x64_optimizations) {
|
||||
cflags = [ "-Wno-incompatible-pointer-types" ]
|
||||
if (is_clang) {
|
||||
cflags = [
|
||||
"-Wno-deprecated-non-prototype",
|
||||
"-Wno-incompatible-pointer-types",
|
||||
"-Wunused-variable",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -248,6 +286,8 @@ component("zlib") {
|
||||
"chromeconf.h",
|
||||
"compress.c",
|
||||
"contrib/optimizations/insert_string.h",
|
||||
"cpu_features.c",
|
||||
"cpu_features.h",
|
||||
"crc32.c",
|
||||
"crc32.h",
|
||||
"deflate.c",
|
||||
@ -267,7 +307,6 @@ component("zlib") {
|
||||
"trees.c",
|
||||
"trees.h",
|
||||
"uncompr.c",
|
||||
"x86.h",
|
||||
"zconf.h",
|
||||
"zlib.h",
|
||||
"zutil.c",
|
||||
@ -277,35 +316,57 @@ component("zlib") {
|
||||
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).
|
||||
defines += [ "CPU_NO_SIMD" ]
|
||||
}
|
||||
|
||||
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.
|
||||
defines += [ "ARM_OS_IOS" ]
|
||||
}
|
||||
|
||||
if (use_x86_x64_optimizations || use_arm_neon_optimizations) {
|
||||
deps += [
|
||||
":zlib_adler32_simd",
|
||||
":zlib_inflate_chunk_simd",
|
||||
":zlib_slide_hash_simd",
|
||||
]
|
||||
|
||||
if (use_x86_x64_optimizations) {
|
||||
sources += [ "x86.c" ]
|
||||
deps += [ ":zlib_crc32_simd" ]
|
||||
} else if (use_arm_neon_optimizations) {
|
||||
sources += [ "contrib/optimizations/slide_hash_neon.h" ]
|
||||
deps += [ ":zlib_arm_crc32" ]
|
||||
}
|
||||
} else {
|
||||
sources += [ "inflate.c" ]
|
||||
}
|
||||
|
||||
if (is_android) {
|
||||
import("//build/config/android/config.gni")
|
||||
if (defined(android_ndk_root) && android_ndk_root != "") {
|
||||
deps += [ "//third_party/android_ndk:cpu_features" ]
|
||||
} else {
|
||||
assert(false, "CPU detection requires the Android NDK")
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@ -313,8 +374,11 @@ config("minizip_warnings") {
|
||||
visibility = [ ":*" ]
|
||||
|
||||
if (is_clang) {
|
||||
# zlib uses `if ((a == b))` for some reason.
|
||||
cflags = [ "-Wno-parentheses-equality" ]
|
||||
cflags = [
|
||||
# zlib uses `if ((a == b))` for some reason.
|
||||
"-Wno-parentheses-equality",
|
||||
"-Wno-deprecated-non-prototype",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -337,43 +401,120 @@ static_library("minizip") {
|
||||
]
|
||||
}
|
||||
|
||||
if (is_mac || is_ios || is_android || is_nacl) {
|
||||
if (is_apple || is_android || is_nacl) {
|
||||
# Mac, Android and the BSDs don't have fopen64, ftello64, or fseeko64. We
|
||||
# use fopen, ftell, and fseek instead on these systems.
|
||||
defines = [ "USE_FILE32API" ]
|
||||
}
|
||||
|
||||
deps = [
|
||||
":zlib",
|
||||
]
|
||||
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") {
|
||||
include_dirs = [ "." ]
|
||||
|
||||
sources = [
|
||||
"contrib/bench/zlib_bench.cc",
|
||||
]
|
||||
|
||||
sources = [ "contrib/bench/zlib_bench.cc" ]
|
||||
if (!is_debug) {
|
||||
configs -= [ "//build/config/compiler:default_optimization" ]
|
||||
configs += [ "//build/config/compiler:optimize_speed" ]
|
||||
}
|
||||
|
||||
deps = [ ":zlib" ]
|
||||
|
||||
configs -= [ "//build/config/compiler:chromium_code" ]
|
||||
configs += [ "//build/config/compiler:no_chromium_code" ]
|
||||
|
||||
deps = [
|
||||
":zlib",
|
||||
]
|
||||
}
|
||||
|
||||
if (!is_win || target_os != "winuwp") {
|
||||
executable("minizip_bin") {
|
||||
include_dirs = [ "." ]
|
||||
|
||||
sources = [ "contrib/minizip/minizip.c" ]
|
||||
|
||||
if (is_clang) {
|
||||
cflags = [
|
||||
"-Wno-incompatible-pointer-types-discards-qualifiers",
|
||||
|
||||
"-Wno-deprecated-non-prototype",
|
||||
]
|
||||
}
|
||||
|
||||
if (!is_debug) {
|
||||
configs -= [ "//build/config/compiler:default_optimization" ]
|
||||
configs += [ "//build/config/compiler:optimize_speed" ]
|
||||
}
|
||||
|
||||
deps = [ ":minizip" ]
|
||||
|
||||
configs -= [ "//build/config/compiler:chromium_code" ]
|
||||
configs += [ "//build/config/compiler:no_chromium_code" ]
|
||||
}
|
||||
|
||||
executable("miniunz_bin") {
|
||||
include_dirs = [ "." ]
|
||||
|
||||
sources = [ "contrib/minizip/miniunz.c" ]
|
||||
|
||||
if (is_clang) {
|
||||
cflags = [
|
||||
"-Wno-incompatible-pointer-types-discards-qualifiers",
|
||||
"-Wno-deprecated-non-prototype",
|
||||
]
|
||||
}
|
||||
|
||||
if (!is_debug) {
|
||||
configs -= [ "//build/config/compiler:default_optimization" ]
|
||||
configs += [ "//build/config/compiler:optimize_speed" ]
|
||||
}
|
||||
|
||||
deps = [ ":minizip" ]
|
||||
|
||||
configs -= [ "//build/config/compiler:chromium_code" ]
|
||||
configs += [ "//build/config/compiler:no_chromium_code" ]
|
||||
}
|
||||
}
|
||||
|
||||
if (build_with_chromium) {
|
||||
test("zlib_unittests") {
|
||||
testonly = true
|
||||
|
||||
sources = [
|
||||
"contrib/tests/infcover.cc",
|
||||
"contrib/tests/infcover.h",
|
||||
"contrib/tests/run_all_unittests.cc",
|
||||
"contrib/tests/utils_unittest.cc",
|
||||
"google/compression_utils_unittest.cc",
|
||||
"google/zip_reader_unittest.cc",
|
||||
"google/zip_unittest.cc",
|
||||
]
|
||||
|
||||
data = [ "google/test/data/" ]
|
||||
|
||||
deps = [
|
||||
":zlib",
|
||||
"google:compression_utils",
|
||||
"google:zip",
|
||||
"//base/test:test_support",
|
||||
"//testing/gtest",
|
||||
]
|
||||
|
||||
configs -= [ "//build/config/compiler:chromium_code" ]
|
||||
configs += [ "//build/config/compiler:no_chromium_code" ]
|
||||
|
||||
include_dirs = [
|
||||
"//third_party/googletest/src/googletest/include/gtest",
|
||||
".",
|
||||
"google",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
3
deps/zlib/DIR_METADATA
vendored
Normal file
3
deps/zlib/DIR_METADATA
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
monorail: {
|
||||
component: "Internals"
|
||||
}
|
4
deps/zlib/LICENSE
vendored
4
deps/zlib/LICENSE
vendored
@ -1,6 +1,6 @@
|
||||
version 1.2.11, January 15th, 2017
|
||||
version 1.2.12, March 27th, 2022
|
||||
|
||||
Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler
|
||||
Copyright (C) 1995-2022 Jean-loup Gailly and Mark Adler
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
6
deps/zlib/OWNERS
vendored
6
deps/zlib/OWNERS
vendored
@ -1,7 +1,5 @@
|
||||
agl@chromium.org
|
||||
cavalcantii@chromium.org
|
||||
cblume@chromium.org
|
||||
mtklein@chromium.org
|
||||
scroggo@chromium.org
|
||||
|
||||
# COMPONENT: Internals
|
||||
noel@chromium.org
|
||||
scroggo@google.com
|
||||
|
6
deps/zlib/README.chromium
vendored
6
deps/zlib/README.chromium
vendored
@ -1,7 +1,8 @@
|
||||
Name: zlib
|
||||
Short Name: zlib
|
||||
URL: http://zlib.net/
|
||||
Version: 1.2.11
|
||||
Version: 1.2.13
|
||||
CPEPrefix: cpe:/a:zlib:zlib:1.2.13
|
||||
Security Critical: yes
|
||||
License: Custom license
|
||||
License File: LICENSE
|
||||
@ -26,3 +27,6 @@ Local Modifications:
|
||||
- Plus the changes in 'patches' folder.
|
||||
- Code in contrib/ other than contrib/minizip was added to match zlib's
|
||||
contributor layout.
|
||||
- In sync with 1.2.13 official release
|
||||
- ZIP reader modified to allow for progress callbacks during extraction.
|
||||
- ZIP reader modified to add detection of AES encrypted content.
|
||||
|
12
deps/zlib/adler32.c
vendored
12
deps/zlib/adler32.c
vendored
@ -59,10 +59,8 @@ local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2));
|
||||
# define MOD63(a) a %= BASE
|
||||
#endif
|
||||
|
||||
#if defined(ADLER32_SIMD_SSSE3)
|
||||
#include "adler32_simd.h"
|
||||
#include "x86.h"
|
||||
#elif defined(ADLER32_SIMD_NEON)
|
||||
#include "cpu_features.h"
|
||||
#if defined(ADLER32_SIMD_SSSE3) || defined(ADLER32_SIMD_NEON)
|
||||
#include "adler32_simd.h"
|
||||
#endif
|
||||
|
||||
@ -76,10 +74,10 @@ uLong ZEXPORT adler32_z(adler, buf, len)
|
||||
unsigned n;
|
||||
|
||||
#if defined(ADLER32_SIMD_SSSE3)
|
||||
if (x86_cpu_enable_ssse3 && buf && len >= 64)
|
||||
if (buf != Z_NULL && len >= 64 && x86_cpu_enable_ssse3)
|
||||
return adler32_simd_(adler, buf, len);
|
||||
#elif defined(ADLER32_SIMD_NEON)
|
||||
if (buf && len >= 64)
|
||||
if (buf != Z_NULL && len >= 64)
|
||||
return adler32_simd_(adler, buf, len);
|
||||
#endif
|
||||
|
||||
@ -108,7 +106,7 @@ uLong ZEXPORT adler32_z(adler, buf, len)
|
||||
*/
|
||||
if (buf == Z_NULL) {
|
||||
if (!len) /* Assume user is calling adler32(0, NULL, 0); */
|
||||
x86_check_features();
|
||||
cpu_check_features();
|
||||
return 1L;
|
||||
}
|
||||
#else
|
||||
|
6
deps/zlib/adler32_simd.c
vendored
6
deps/zlib/adler32_simd.c
vendored
@ -1,6 +1,6 @@
|
||||
/* adler32_simd.c
|
||||
*
|
||||
* Copyright 2017 The Chromium Authors. All rights reserved.
|
||||
* Copyright 2017 The Chromium Authors
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the Chromium source repository LICENSE file.
|
||||
*
|
||||
@ -50,13 +50,9 @@
|
||||
#define NMAX 5552
|
||||
|
||||
#if defined(ADLER32_SIMD_SSSE3)
|
||||
#ifndef __GNUC__
|
||||
#define __attribute__()
|
||||
#endif
|
||||
|
||||
#include <tmmintrin.h>
|
||||
|
||||
__attribute__((target("ssse3")))
|
||||
uint32_t ZLIB_INTERNAL adler32_simd_( /* SSSE3 */
|
||||
uint32_t adler,
|
||||
const unsigned char *buf,
|
||||
|
2
deps/zlib/adler32_simd.h
vendored
2
deps/zlib/adler32_simd.h
vendored
@ -1,6 +1,6 @@
|
||||
/* adler32_simd.h
|
||||
*
|
||||
* Copyright 2017 The Chromium Authors. All rights reserved.
|
||||
* Copyright 2017 The Chromium Authors
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the Chromium source repository LICENSE file.
|
||||
*/
|
||||
|
90
deps/zlib/arm_features.c
vendored
90
deps/zlib/arm_features.c
vendored
@ -1,90 +0,0 @@
|
||||
/* arm_features.c -- ARM processor features detection.
|
||||
*
|
||||
* Copyright 2018 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 "arm_features.h"
|
||||
#include "zutil.h"
|
||||
#include <stdint.h>
|
||||
|
||||
int ZLIB_INTERNAL arm_cpu_enable_crc32 = 0;
|
||||
int ZLIB_INTERNAL arm_cpu_enable_pmull = 0;
|
||||
|
||||
#if defined(ARMV8_OS_ANDROID) || defined(ARMV8_OS_LINUX) || defined(ARMV8_OS_FUCHSIA)
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#if defined(ARMV8_OS_ANDROID)
|
||||
#include <cpu-features.h>
|
||||
#elif defined(ARMV8_OS_LINUX)
|
||||
#include <asm/hwcap.h>
|
||||
#include <sys/auxv.h>
|
||||
#elif defined(ARMV8_OS_FUCHSIA)
|
||||
#include <zircon/features.h>
|
||||
#include <zircon/syscalls.h>
|
||||
#include <zircon/types.h>
|
||||
#elif defined(ARMV8_OS_WINDOWS)
|
||||
#include <windows.h>
|
||||
#else
|
||||
#error arm_features.c ARM feature detection in not defined for your platform
|
||||
#endif
|
||||
|
||||
static void _arm_check_features(void);
|
||||
|
||||
#if defined(ARMV8_OS_ANDROID) || defined(ARMV8_OS_LINUX) || defined(ARMV8_OS_FUCHSIA)
|
||||
static pthread_once_t cpu_check_inited_once = PTHREAD_ONCE_INIT;
|
||||
void ZLIB_INTERNAL arm_check_features(void)
|
||||
{
|
||||
pthread_once(&cpu_check_inited_once, _arm_check_features);
|
||||
}
|
||||
#elif defined(ARMV8_OS_WINDOWS)
|
||||
static INIT_ONCE cpu_check_inited_once = INIT_ONCE_STATIC_INIT;
|
||||
static BOOL CALLBACK _arm_check_features_forwarder(PINIT_ONCE once, PVOID param, PVOID* context)
|
||||
{
|
||||
_arm_check_features();
|
||||
return TRUE;
|
||||
}
|
||||
void ZLIB_INTERNAL arm_check_features(void)
|
||||
{
|
||||
InitOnceExecuteOnce(&cpu_check_inited_once, _arm_check_features_forwarder,
|
||||
NULL, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* See http://bit.ly/2CcoEsr for run-time detection of ARM features and also
|
||||
* crbug.com/931275 for android_getCpuFeatures() use in the Android sandbox.
|
||||
*/
|
||||
static void _arm_check_features(void)
|
||||
{
|
||||
#if defined(ARMV8_OS_ANDROID) && defined(__aarch64__)
|
||||
uint64_t features = android_getCpuFeatures();
|
||||
arm_cpu_enable_crc32 = !!(features & ANDROID_CPU_ARM64_FEATURE_CRC32);
|
||||
arm_cpu_enable_pmull = !!(features & ANDROID_CPU_ARM64_FEATURE_PMULL);
|
||||
#elif defined(ARMV8_OS_ANDROID) /* aarch32 */
|
||||
uint64_t features = android_getCpuFeatures();
|
||||
arm_cpu_enable_crc32 = !!(features & ANDROID_CPU_ARM_FEATURE_CRC32);
|
||||
arm_cpu_enable_pmull = !!(features & ANDROID_CPU_ARM_FEATURE_PMULL);
|
||||
#elif defined(ARMV8_OS_LINUX) && defined(__aarch64__)
|
||||
unsigned long features = getauxval(AT_HWCAP);
|
||||
arm_cpu_enable_crc32 = !!(features & HWCAP_CRC32);
|
||||
arm_cpu_enable_pmull = !!(features & HWCAP_PMULL);
|
||||
#elif defined(ARMV8_OS_LINUX) && (defined(__ARM_NEON) || defined(__ARM_NEON__))
|
||||
/* Query HWCAP2 for ARMV8-A SoCs running in aarch32 mode */
|
||||
unsigned long features = getauxval(AT_HWCAP2);
|
||||
arm_cpu_enable_crc32 = !!(features & HWCAP2_CRC32);
|
||||
arm_cpu_enable_pmull = !!(features & HWCAP2_PMULL);
|
||||
#elif defined(ARMV8_OS_FUCHSIA)
|
||||
uint32_t features;
|
||||
zx_status_t rc = zx_system_get_features(ZX_FEATURE_KIND_CPU, &features);
|
||||
if (rc != ZX_OK || (features & ZX_ARM64_FEATURE_ISA_ASIMD) == 0)
|
||||
return; /* Report nothing if ASIMD(NEON) is missing */
|
||||
arm_cpu_enable_crc32 = !!(features & ZX_ARM64_FEATURE_ISA_CRC32);
|
||||
arm_cpu_enable_pmull = !!(features & ZX_ARM64_FEATURE_ISA_PMULL);
|
||||
#elif defined(ARMV8_OS_WINDOWS)
|
||||
arm_cpu_enable_crc32 = IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE);
|
||||
arm_cpu_enable_pmull = IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
|
||||
#endif
|
||||
}
|
13
deps/zlib/arm_features.h
vendored
13
deps/zlib/arm_features.h
vendored
@ -1,13 +0,0 @@
|
||||
/* arm_features.h -- ARM processor features detection.
|
||||
*
|
||||
* Copyright 2018 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 "zlib.h"
|
||||
|
||||
extern int arm_cpu_enable_crc32;
|
||||
extern int arm_cpu_enable_pmull;
|
||||
|
||||
void arm_check_features(void);
|
10
deps/zlib/chromeconf.h
vendored
10
deps/zlib/chromeconf.h
vendored
@ -1,4 +1,4 @@
|
||||
/* Copyright 2017 The Chromium Authors. All rights reserved.
|
||||
/* Copyright 2017 The Chromium Authors
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file. */
|
||||
|
||||
@ -49,6 +49,9 @@
|
||||
#define crc32 Cr_z_crc32
|
||||
#define crc32_combine Cr_z_crc32_combine
|
||||
#define crc32_combine64 Cr_z_crc32_combine64
|
||||
#define crc32_combine_gen64 Cr_z_crc32_combine_gen64
|
||||
#define crc32_combine_gen Cr_z_crc32_combine_gen
|
||||
#define crc32_combine_op Cr_z_crc32_combine_op
|
||||
#define crc32_z Cr_z_crc32_z
|
||||
#define deflate Cr_z_deflate
|
||||
#define deflateBound Cr_z_deflateBound
|
||||
@ -191,5 +194,10 @@
|
||||
#define arm_cpu_enable_pmull Cr_z_arm_cpu_enable_pmull
|
||||
#define arm_check_features Cr_z_arm_check_features
|
||||
#define armv8_crc32_little Cr_z_armv8_crc32_little
|
||||
#define armv8_crc32_pmull_little Cr_z_armv8_crc32_pmull_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_ */
|
||||
|
6
deps/zlib/compress.c
vendored
6
deps/zlib/compress.c
vendored
@ -19,7 +19,7 @@
|
||||
memory, Z_BUF_ERROR if there was not enough room in the output buffer,
|
||||
Z_STREAM_ERROR if the level parameter is invalid.
|
||||
*/
|
||||
int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)
|
||||
int ZEXPORT compress2(dest, destLen, source, sourceLen, level)
|
||||
Bytef *dest;
|
||||
uLongf *destLen;
|
||||
const Bytef *source;
|
||||
@ -65,7 +65,7 @@ int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)
|
||||
|
||||
/* ===========================================================================
|
||||
*/
|
||||
int ZEXPORT compress (dest, destLen, source, sourceLen)
|
||||
int ZEXPORT compress(dest, destLen, source, sourceLen)
|
||||
Bytef *dest;
|
||||
uLongf *destLen;
|
||||
const Bytef *source;
|
||||
@ -78,7 +78,7 @@ int ZEXPORT compress (dest, destLen, source, sourceLen)
|
||||
If the default memLevel or windowBits for deflateInit() is changed, then
|
||||
this function needs to be updated.
|
||||
*/
|
||||
uLong ZEXPORT compressBound (sourceLen)
|
||||
uLong ZEXPORT compressBound(sourceLen)
|
||||
uLong sourceLen;
|
||||
{
|
||||
sourceLen = sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
|
||||
|
35
deps/zlib/contrib/bench/check.sh
vendored
Executable file
35
deps/zlib/contrib/bench/check.sh
vendored
Executable file
@ -0,0 +1,35 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Copyright 2022 The Chromium Authors
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the chromium source repository LICENSE file.
|
||||
#
|
||||
# Given a zlib_bench executable and some data files, run zlib_bench --check
|
||||
# over those data files, for all zlib types (gzip|zlib|raw) and compression
|
||||
# levels 1..9 for each type. Example:
|
||||
#
|
||||
# check.sh ./out/Release/zlib_bench [--check-binary] ~/snappy/testdata/*
|
||||
#
|
||||
# The --check-binary option modifies --check output: the compressed data is
|
||||
# also written to the program output.
|
||||
|
||||
ZLIB_BENCH="$1" && shift
|
||||
|
||||
CHECK_TYPE="--check"
|
||||
if [[ "${1}" == "--check-binary" ]]; then
|
||||
CHECK_TYPE="$1" && shift # output compressed data too
|
||||
fi
|
||||
|
||||
DATA_FILES="$*"
|
||||
|
||||
echo ${ZLIB_BENCH} | grep -E "/(zlib_bench|a.out)$" > /dev/null
|
||||
if [[ $? != 0 ]] || [[ -z "${DATA_FILES}" ]]; then
|
||||
echo "usage: check.sh zlib_bench [--check-binary] files ..." >&2
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
for type in gzip zlib raw; do
|
||||
for level in $(seq 1 9); do
|
||||
${ZLIB_BENCH} $type --compression $level ${CHECK_TYPE} ${DATA_FILES}
|
||||
done
|
||||
done
|
145
deps/zlib/contrib/bench/zlib_bench.cc
vendored
145
deps/zlib/contrib/bench/zlib_bench.cc
vendored
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2018 The Chromium Authors. All rights reserved.
|
||||
* Copyright 2018 The Chromium Authors
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the Chromium source repository LICENSE file.
|
||||
*
|
||||
@ -15,7 +15,7 @@
|
||||
* Note this code can be compiled outside of the Chromium build system against
|
||||
* the system zlib (-lz) with g++ or clang++ as follows:
|
||||
*
|
||||
* g++|clang++ -O3 -Wall -std=c++11 -lstdc++ -lz zlib_bench.cc
|
||||
* g++|clang++ -O3 -Wall -std=c++11 zlib_bench.cc -lstdc++ -lz
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
@ -38,13 +38,14 @@ void error_exit(const char* error, int code) {
|
||||
}
|
||||
|
||||
inline char* string_data(std::string* s) {
|
||||
return s->empty() ? 0 : &*s->begin();
|
||||
return s->empty() ? nullptr : &*s->begin();
|
||||
}
|
||||
|
||||
struct Data {
|
||||
Data(size_t s) { data.reset(new (std::nothrow) char[size = s]); }
|
||||
std::unique_ptr<char[]> data;
|
||||
size_t size;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
Data read_file_data_or_exit(const char* name) {
|
||||
@ -66,6 +67,7 @@ Data read_file_data_or_exit(const char* name) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
data.name = std::string(name);
|
||||
return data;
|
||||
}
|
||||
|
||||
@ -99,10 +101,25 @@ const char* zlib_wrapper_name(zlib_wrapper type) {
|
||||
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 +136,7 @@ void zlib_compress(
|
||||
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);
|
||||
|
||||
@ -129,6 +146,8 @@ void zlib_compress(
|
||||
stream.avail_in = (uInt)input_size;
|
||||
|
||||
result = deflate(&stream, Z_FINISH);
|
||||
if (stream.avail_in > 0)
|
||||
error_exit("compress: input was not consumed", Z_DATA_ERROR);
|
||||
if (result == Z_STREAM_END)
|
||||
output_size = stream.total_out;
|
||||
result |= deflateEnd(&stream);
|
||||
@ -178,14 +197,67 @@ void verify_equal(const char* input, size_t size, std::string* output) {
|
||||
exit(3);
|
||||
}
|
||||
|
||||
void zlib_file(const char* name, const zlib_wrapper type) {
|
||||
void check_file(const Data& file, zlib_wrapper type, int mode) {
|
||||
printf("%s %d %s%s\n", zlib_wrapper_name(type), zlib_compression_level,
|
||||
zlib_level_strategy_name(zlib_compression_level), file.name.c_str());
|
||||
|
||||
// Compress the file data.
|
||||
std::string compressed;
|
||||
zlib_compress(type, file.data.get(), file.size, &compressed, true);
|
||||
|
||||
// Output compressed data integrity check: the data crc32.
|
||||
unsigned long check = crc32_z(0, Z_NULL, 0);
|
||||
const Bytef* data = (const Bytef*)compressed.data();
|
||||
static_assert(sizeof(z_size_t) == sizeof(size_t), "z_size_t size");
|
||||
check = crc32_z(check, data, (z_size_t)compressed.size());
|
||||
|
||||
const size_t compressed_length = compressed.size();
|
||||
printf("data crc32 %.8lx length %zu\n", check, compressed_length);
|
||||
|
||||
// Output gzip or zlib DEFLATE stream internal check data.
|
||||
if (type == kWrapperGZIP) {
|
||||
uint32_t prev_word, last_word;
|
||||
data += compressed_length - 8;
|
||||
prev_word = data[3] << 24 | data[2] << 16 | data[1] << 8 | data[0];
|
||||
data += 4; // last compressed data word
|
||||
last_word = data[3] << 24 | data[2] << 16 | data[1] << 8 | data[0];
|
||||
printf("gzip crc32 %.8x length %u\n", prev_word, last_word);
|
||||
} else if (type == kWrapperZLIB) {
|
||||
uint32_t last_word;
|
||||
data += compressed_length - 4;
|
||||
last_word = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
|
||||
printf("zlib adler %.8x\n", last_word);
|
||||
}
|
||||
|
||||
if (mode == 2) // --check-binary: output compressed data.
|
||||
fwrite(compressed.data(), compressed_length, 1, stdout);
|
||||
|
||||
if (fflush(stdout), ferror(stdout))
|
||||
error_exit("check file: error writing output", 3);
|
||||
}
|
||||
|
||||
void zlib_file(const char* name, zlib_wrapper type, int width, int check) {
|
||||
/*
|
||||
* Read the file data.
|
||||
*/
|
||||
const auto file = read_file_data_or_exit(name);
|
||||
struct Data 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);
|
||||
|
||||
/*
|
||||
* Compress file: report output data checks and return.
|
||||
*/
|
||||
if (check) {
|
||||
file.name = file.name.substr(file.name.find_last_of("/\\") + 1);
|
||||
check_file(file, type, check);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
@ -263,9 +335,9 @@ void zlib_file(const char* name, const zlib_wrapper type) {
|
||||
double inflate_rate_max = length * repeats / mega_byte / utime[0];
|
||||
|
||||
// type, block size, compression ratio, etc
|
||||
printf("%s: [b %dM] bytes %6d -> %6u %4.1f%%",
|
||||
zlib_wrapper_name(type), block_size / (1 << 20), length,
|
||||
static_cast<unsigned>(output_length), output_length * 100.0 / length);
|
||||
printf("%s: [b %dM] bytes %*d -> %*u %4.2f%%",
|
||||
zlib_wrapper_name(type), block_size / (1 << 20), width, length, width,
|
||||
unsigned(output_length), output_length * 100.0 / length);
|
||||
|
||||
// compress / uncompress median (max) rates
|
||||
printf(" comp %5.1f (%5.1f) MB/s uncomp %5.1f (%5.1f) MB/s\n",
|
||||
@ -276,18 +348,25 @@ static int argn = 1;
|
||||
|
||||
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) {
|
||||
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 get_field_width(int argc, char* argv[], int& value) {
|
||||
value = atoi(argv[argn++]);
|
||||
}
|
||||
|
||||
void usage_exit(const char* program) {
|
||||
printf("usage: %s gzip|zlib|raw [--compression 1:9] files...\n", program);
|
||||
static auto* options = "gzip|zlib|raw"
|
||||
" [--compression 0:9] [--huffman|--rle] [--field width] [--check]";
|
||||
printf("usage: %s %s files ...\n", program, options);
|
||||
printf("zlib version: %s\n", ZLIB_VERSION);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -302,15 +381,35 @@ int main(int argc, char* argv[]) {
|
||||
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]);
|
||||
int size_field_width = 0;
|
||||
int file_check = 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 if (get_option(argc, argv, "--check")) {
|
||||
file_check = 1;
|
||||
} else if (get_option(argc, argv, "--check-binary")) {
|
||||
file_check = 2;
|
||||
} else if (get_option(argc, argv, "--field")) {
|
||||
get_field_width(argc, argv, size_field_width);
|
||||
} else {
|
||||
usage_exit(argv[0]);
|
||||
}
|
||||
}
|
||||
|
||||
if (argn >= argc)
|
||||
usage_exit(argv[0]);
|
||||
|
||||
if (size_field_width < 6)
|
||||
size_field_width = 6;
|
||||
while (argn < argc)
|
||||
zlib_file(argv[argn++], type);
|
||||
zlib_file(argv[argn++], type, size_field_width, file_check);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
15
deps/zlib/contrib/minizip/README.chromium
vendored
Normal file
15
deps/zlib/contrib/minizip/README.chromium
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
Name: ZIP file API for reading file entries in a ZIP archive
|
||||
Short Name: minizip
|
||||
URL: https://github.com/madler/zlib/tree/master/contrib/minizip
|
||||
Version: 1.2.12
|
||||
License: Zlib
|
||||
Security Critical: yes
|
||||
|
||||
Description:
|
||||
Minizip provides API on top of zlib that can enumerate and extract ZIP archive
|
||||
files. See minizip.md for chromium build instructions.
|
||||
|
||||
Local Modifications:
|
||||
- Add parsing of the 'Info-ZIP Unicode Path Extra Field' as described in
|
||||
https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT section 4.6.9.
|
||||
(see crrev.com/1002476)
|
8
deps/zlib/contrib/minizip/iowin32.c
vendored
8
deps/zlib/contrib/minizip/iowin32.c
vendored
@ -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));
|
||||
|
13
deps/zlib/contrib/minizip/miniunz.c
vendored
13
deps/zlib/contrib/minizip/miniunz.c
vendored
@ -12,7 +12,7 @@
|
||||
Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
|
||||
*/
|
||||
|
||||
#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__))
|
||||
#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__)) && (!defined(__ANDROID_API__))
|
||||
#ifndef __USE_FILE_OFFSET64
|
||||
#define __USE_FILE_OFFSET64
|
||||
#endif
|
||||
@ -27,7 +27,7 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#if defined(__APPLE__) || defined(__Fuchsia__) || defined(__ANDROID_API__)
|
||||
// In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions
|
||||
#define FOPEN_FUNC(filename, mode) fopen(filename, mode)
|
||||
#define FTELLO_FUNC(stream) ftello(stream)
|
||||
@ -45,6 +45,7 @@
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <direct.h>
|
||||
@ -97,7 +98,7 @@ void change_file_date(filename,dosdate,tmu_date)
|
||||
SetFileTime(hFile,&ftm,&ftLastAcc,&ftm);
|
||||
CloseHandle(hFile);
|
||||
#else
|
||||
#ifdef unix || __APPLE__
|
||||
#if defined(unix) || defined(__APPLE__) || defined(__Fuchsia__) || defined(__ANDROID_API__)
|
||||
struct utimbuf ut;
|
||||
struct tm newdate;
|
||||
newdate.tm_sec = tmu_date.tm_sec;
|
||||
@ -125,11 +126,9 @@ int mymkdir(dirname)
|
||||
const char* dirname;
|
||||
{
|
||||
int ret=0;
|
||||
#ifdef _WIN32
|
||||
#if defined(_WIN32)
|
||||
ret = _mkdir(dirname);
|
||||
#elif unix
|
||||
ret = mkdir (dirname,0775);
|
||||
#elif __APPLE__
|
||||
#elif defined(unix) || defined(__APPLE__) || defined(__Fuchsia__) || defined(__ANDROID_API__)
|
||||
ret = mkdir (dirname,0775);
|
||||
#endif
|
||||
return ret;
|
||||
|
7
deps/zlib/contrib/minizip/minizip.c
vendored
7
deps/zlib/contrib/minizip/minizip.c
vendored
@ -12,8 +12,7 @@
|
||||
Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
|
||||
*/
|
||||
|
||||
|
||||
#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__))
|
||||
#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__)) && (!defined(__ANDROID_API__))
|
||||
#ifndef __USE_FILE_OFFSET64
|
||||
#define __USE_FILE_OFFSET64
|
||||
#endif
|
||||
@ -28,7 +27,7 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
#if defined(__APPLE__) || defined(__Fuchsia__) || defined(__ANDROID_API__)
|
||||
// In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions
|
||||
#define FOPEN_FUNC(filename, mode) fopen(filename, mode)
|
||||
#define FTELLO_FUNC(stream) ftello(stream)
|
||||
@ -94,7 +93,7 @@ uLong filetime(f, tmzip, dt)
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
#ifdef unix || __APPLE__
|
||||
#if defined(unix) || defined(__APPLE__) || defined(__Fuchsia__) || defined(__ANDROID_API__)
|
||||
uLong filetime(f, tmzip, dt)
|
||||
char *f; /* name of file to get info on */
|
||||
tm_zip *tmzip; /* return value: access, modific. and creation times */
|
||||
|
9
deps/zlib/contrib/minizip/minizip.md
vendored
Normal file
9
deps/zlib/contrib/minizip/minizip.md
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
Minizip is a library provided by //third_party/zlib [1]. Its zip and unzip
|
||||
tools can be built in a developer checkout for testing purposes with:
|
||||
|
||||
```shell
|
||||
autoninja -C out/Release minizip_bin
|
||||
autoninja -C out/Release miniunz_bin
|
||||
```
|
||||
|
||||
[1] Upstream is https://github.com/madler/zlib/tree/master/contrib/minizip
|
106
deps/zlib/contrib/minizip/unzip.c
vendored
106
deps/zlib/contrib/minizip/unzip.c
vendored
@ -1023,46 +1023,102 @@ local int unz64local_GetCurrentFileInfoInternal (unzFile file,
|
||||
while(acc < file_info.size_file_extra)
|
||||
{
|
||||
uLong headerId;
|
||||
uLong dataSize;
|
||||
uLong dataSize;
|
||||
|
||||
if (unz64local_getShort(&s->z_filefunc, s->filestream,&headerId) != UNZ_OK)
|
||||
err=UNZ_ERRNO;
|
||||
|
||||
if (unz64local_getShort(&s->z_filefunc, s->filestream,&dataSize) != UNZ_OK)
|
||||
err=UNZ_ERRNO;
|
||||
|
||||
|
||||
/* ZIP64 extra fields */
|
||||
if (headerId == 0x0001)
|
||||
{
|
||||
uLong uL;
|
||||
uLong uL;
|
||||
|
||||
if(file_info.uncompressed_size == MAXU32)
|
||||
{
|
||||
if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK)
|
||||
err=UNZ_ERRNO;
|
||||
}
|
||||
if(file_info.uncompressed_size == MAXU32)
|
||||
{
|
||||
if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK)
|
||||
err=UNZ_ERRNO;
|
||||
}
|
||||
|
||||
if(file_info.compressed_size == MAXU32)
|
||||
{
|
||||
if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK)
|
||||
err=UNZ_ERRNO;
|
||||
}
|
||||
if(file_info.compressed_size == MAXU32)
|
||||
{
|
||||
if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK)
|
||||
err=UNZ_ERRNO;
|
||||
}
|
||||
|
||||
if(file_info_internal.offset_curfile == MAXU32)
|
||||
{
|
||||
/* Relative Header offset */
|
||||
if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK)
|
||||
err=UNZ_ERRNO;
|
||||
}
|
||||
if(file_info_internal.offset_curfile == MAXU32)
|
||||
{
|
||||
/* Relative Header offset */
|
||||
if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK)
|
||||
err=UNZ_ERRNO;
|
||||
}
|
||||
|
||||
if(file_info.disk_num_start == MAXU32)
|
||||
{
|
||||
/* Disk Start Number */
|
||||
if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)
|
||||
err=UNZ_ERRNO;
|
||||
}
|
||||
if(file_info.disk_num_start == MAXU32)
|
||||
{
|
||||
/* Disk Start Number */
|
||||
if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)
|
||||
err=UNZ_ERRNO;
|
||||
}
|
||||
|
||||
}
|
||||
else if (headerId == 0x7075) /* Info-ZIP Unicode Path Extra Field */
|
||||
{
|
||||
int version = 0;
|
||||
|
||||
if (unz64local_getByte(&s->z_filefunc, s->filestream, &version) != UNZ_OK)
|
||||
{
|
||||
err = UNZ_ERRNO;
|
||||
}
|
||||
if (version != 1)
|
||||
{
|
||||
if (ZSEEK64(s->z_filefunc, s->filestream,dataSize - 1, ZLIB_FILEFUNC_SEEK_CUR) != 0)
|
||||
{
|
||||
err = UNZ_ERRNO;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uLong uCrc, uHeaderCrc, fileNameSize;
|
||||
|
||||
if (unz64local_getLong(&s->z_filefunc, s->filestream, &uCrc) != UNZ_OK)
|
||||
{
|
||||
err = UNZ_ERRNO;
|
||||
}
|
||||
uHeaderCrc = crc32(0, (const unsigned char *)szFileName, file_info.size_filename);
|
||||
fileNameSize = dataSize - (2 * sizeof (short) + 1);
|
||||
/* Check CRC against file name in the header. */
|
||||
if (uHeaderCrc != uCrc)
|
||||
{
|
||||
if (ZSEEK64(s->z_filefunc, s->filestream, fileNameSize, ZLIB_FILEFUNC_SEEK_CUR) != 0)
|
||||
{
|
||||
err = UNZ_ERRNO;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uLong uSizeRead;
|
||||
|
||||
if (fileNameSize < fileNameBufferSize)
|
||||
{
|
||||
*(szFileName + fileNameSize) = '\0';
|
||||
uSizeRead = fileNameSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
uSizeRead = fileNameBufferSize;
|
||||
}
|
||||
if ((fileNameSize > 0) && (fileNameBufferSize > 0))
|
||||
{
|
||||
if (ZREAD64(s->z_filefunc, s->filestream, szFileName, uSizeRead) != uSizeRead)
|
||||
{
|
||||
err = UNZ_ERRNO;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ZSEEK64(s->z_filefunc, s->filestream,dataSize,ZLIB_FILEFUNC_SEEK_CUR)!=0)
|
||||
|
52
deps/zlib/contrib/optimizations/chunkcopy.h
vendored
52
deps/zlib/contrib/optimizations/chunkcopy.h
vendored
@ -1,6 +1,6 @@
|
||||
/* chunkcopy.h -- fast chunk copy and set operations
|
||||
* Copyright (C) 2017 ARM, Inc.
|
||||
* Copyright 2017 The Chromium Authors. All rights reserved.
|
||||
* Copyright 2017 The Chromium Authors
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the Chromium source repository LICENSE file.
|
||||
*/
|
||||
@ -29,13 +29,23 @@
|
||||
#include <arm_neon.h>
|
||||
typedef uint8x16_t z_vec128i_t;
|
||||
#elif defined(INFLATE_CHUNK_SIMD_SSE2)
|
||||
#pragma GCC target ("sse2")
|
||||
#include <emmintrin.h>
|
||||
typedef __m128i z_vec128i_t;
|
||||
#else
|
||||
#error chunkcopy.h inflate chunk SIMD is not defined for your build target
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Suppress MSan errors about copying uninitialized bytes (crbug.com/1376033).
|
||||
*/
|
||||
#define Z_DISABLE_MSAN
|
||||
#if defined(__has_feature)
|
||||
#if __has_feature(memory_sanitizer)
|
||||
#undef Z_DISABLE_MSAN
|
||||
#define Z_DISABLE_MSAN __attribute__((no_sanitize("memory")))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* chunk copy type: the z_vec128i_t type size should be exactly 128-bits
|
||||
* and equal to CHUNKCOPY_CHUNK_SIZE.
|
||||
@ -83,7 +93,7 @@ static inline void storechunk(
|
||||
static inline unsigned char FAR* chunkcopy_core(
|
||||
unsigned char FAR* out,
|
||||
const unsigned char FAR* from,
|
||||
unsigned len) {
|
||||
unsigned len) Z_DISABLE_MSAN {
|
||||
const int bump = (--len % CHUNKCOPY_CHUNK_SIZE) + 1;
|
||||
storechunk(out, loadchunk(from));
|
||||
out += bump;
|
||||
@ -113,6 +123,10 @@ static inline unsigned char FAR* chunkcopy_core_safe(
|
||||
Assert(out + len <= limit, "chunk copy exceeds safety limit");
|
||||
if ((limit - out) < (ptrdiff_t)CHUNKCOPY_CHUNK_SIZE) {
|
||||
const unsigned char FAR* Z_RESTRICT rfrom = from;
|
||||
Assert((uintptr_t)out - (uintptr_t)from >= len,
|
||||
"invalid restrict in chunkcopy_core_safe");
|
||||
Assert((uintptr_t)from - (uintptr_t)out >= len,
|
||||
"invalid restrict in chunkcopy_core_safe");
|
||||
if (len & 8) {
|
||||
Z_BUILTIN_MEMCPY(out, rfrom, 8);
|
||||
out += 8;
|
||||
@ -149,7 +163,7 @@ static inline unsigned char FAR* chunkcopy_core_safe(
|
||||
static inline unsigned char FAR* chunkunroll_relaxed(
|
||||
unsigned char FAR* out,
|
||||
unsigned FAR* dist,
|
||||
unsigned FAR* len) {
|
||||
unsigned FAR* len) Z_DISABLE_MSAN {
|
||||
const unsigned char FAR* from = out - *dist;
|
||||
while (*dist < *len && *dist < CHUNKCOPY_CHUNK_SIZE) {
|
||||
storechunk(out, loadchunk(from));
|
||||
@ -339,6 +353,10 @@ static inline unsigned char FAR* chunkcopy_relaxed(
|
||||
unsigned char FAR* Z_RESTRICT out,
|
||||
const unsigned char FAR* Z_RESTRICT from,
|
||||
unsigned len) {
|
||||
Assert((uintptr_t)out - (uintptr_t)from >= len,
|
||||
"invalid restrict in chunkcopy_relaxed");
|
||||
Assert((uintptr_t)from - (uintptr_t)out >= len,
|
||||
"invalid restrict in chunkcopy_relaxed");
|
||||
return chunkcopy_core(out, from, len);
|
||||
}
|
||||
|
||||
@ -361,6 +379,11 @@ static inline unsigned char FAR* chunkcopy_safe(
|
||||
unsigned len,
|
||||
unsigned char FAR* limit) {
|
||||
Assert(out + len <= limit, "chunk copy exceeds safety limit");
|
||||
Assert((uintptr_t)out - (uintptr_t)from >= len,
|
||||
"invalid restrict in chunkcopy_safe");
|
||||
Assert((uintptr_t)from - (uintptr_t)out >= len,
|
||||
"invalid restrict in chunkcopy_safe");
|
||||
|
||||
return chunkcopy_core_safe(out, from, len, limit);
|
||||
}
|
||||
|
||||
@ -407,6 +430,26 @@ static inline unsigned char FAR* chunkcopy_lapped_safe(
|
||||
return chunkcopy_lapped_relaxed(out, dist, len);
|
||||
}
|
||||
|
||||
/* TODO(cavalcanti): see crbug.com/1110083. */
|
||||
static inline unsigned char FAR* chunkcopy_safe_ugly(unsigned char FAR* out,
|
||||
unsigned dist,
|
||||
unsigned len,
|
||||
unsigned char FAR* limit) {
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
/* Speed is the same as using chunkcopy_safe
|
||||
w/ GCC on ARM (tested gcc 6.3 and 7.5) and avoids
|
||||
undefined behavior.
|
||||
*/
|
||||
return chunkcopy_core_safe(out, out - dist, len, limit);
|
||||
#elif defined(__clang__) && defined(ARMV8_OS_ANDROID) && !defined(__aarch64__)
|
||||
/* Seems to perform better on 32bit (i.e. Android). */
|
||||
return chunkcopy_core_safe(out, out - dist, len, limit);
|
||||
#else
|
||||
/* Seems to perform better on 64bit. */
|
||||
return chunkcopy_lapped_safe(out, dist, len, limit);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* The chunk-copy code above deals with writing the decoded DEFLATE data to
|
||||
* the output with SIMD methods to increase decode speed. Reading the input
|
||||
@ -441,5 +484,6 @@ typedef unsigned long inflate_holder_t;
|
||||
#undef Z_STATIC_ASSERT
|
||||
#undef Z_RESTRICT
|
||||
#undef Z_BUILTIN_MEMCPY
|
||||
#undef Z_DISABLE_MSAN
|
||||
|
||||
#endif /* CHUNKCOPY_H */
|
||||
|
31
deps/zlib/contrib/optimizations/inffast_chunk.c
vendored
31
deps/zlib/contrib/optimizations/inffast_chunk.c
vendored
@ -95,7 +95,7 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
|
||||
code const FAR *dcode; /* local strm->distcode */
|
||||
unsigned lmask; /* mask for first level of length codes */
|
||||
unsigned dmask; /* mask for first level of distance codes */
|
||||
code here; /* retrieved table entry */
|
||||
code const *here; /* retrieved table entry */
|
||||
unsigned op; /* code bits, operation, extra bits, or */
|
||||
/* window position, window bytes to copy */
|
||||
unsigned len; /* match length, unused bytes */
|
||||
@ -139,20 +139,20 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
|
||||
bits += 8;
|
||||
#endif
|
||||
}
|
||||
here = lcode[hold & lmask];
|
||||
here = lcode + (hold & lmask);
|
||||
dolen:
|
||||
op = (unsigned)(here.bits);
|
||||
op = (unsigned)(here->bits);
|
||||
hold >>= op;
|
||||
bits -= op;
|
||||
op = (unsigned)(here.op);
|
||||
op = (unsigned)(here->op);
|
||||
if (op == 0) { /* literal */
|
||||
Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
|
||||
Tracevv((stderr, here->val >= 0x20 && here->val < 0x7f ?
|
||||
"inflate: literal '%c'\n" :
|
||||
"inflate: literal 0x%02x\n", here.val));
|
||||
*out++ = (unsigned char)(here.val);
|
||||
"inflate: literal 0x%02x\n", here->val));
|
||||
*out++ = (unsigned char)(here->val);
|
||||
}
|
||||
else if (op & 16) { /* length base */
|
||||
len = (unsigned)(here.val);
|
||||
len = (unsigned)(here->val);
|
||||
op &= 15; /* number of extra bits */
|
||||
if (op) {
|
||||
if (bits < op) {
|
||||
@ -182,14 +182,14 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
|
||||
bits += 8;
|
||||
#endif
|
||||
}
|
||||
here = dcode[hold & dmask];
|
||||
here = dcode + (hold & dmask);
|
||||
dodist:
|
||||
op = (unsigned)(here.bits);
|
||||
op = (unsigned)(here->bits);
|
||||
hold >>= op;
|
||||
bits -= op;
|
||||
op = (unsigned)(here.op);
|
||||
op = (unsigned)(here->op);
|
||||
if (op & 16) { /* distance base */
|
||||
dist = (unsigned)(here.val);
|
||||
dist = (unsigned)(here->val);
|
||||
op &= 15; /* number of extra bits */
|
||||
if (bits < op) {
|
||||
#ifdef INFLATE_CHUNK_READ_64LE
|
||||
@ -276,7 +276,7 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
|
||||
the main copy is near the end.
|
||||
*/
|
||||
out = chunkunroll_relaxed(out, &dist, &len);
|
||||
out = chunkcopy_safe(out, out - dist, len, limit);
|
||||
out = chunkcopy_safe_ugly(out, dist, len, limit);
|
||||
} else {
|
||||
/* from points to window, so there is no risk of
|
||||
overlapping pointers requiring memset-like behaviour
|
||||
@ -295,7 +295,7 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
|
||||
}
|
||||
}
|
||||
else if ((op & 64) == 0) { /* 2nd level distance code */
|
||||
here = dcode[here.val + (hold & ((1U << op) - 1))];
|
||||
here = dcode + here->val + (hold & ((1U << op) - 1));
|
||||
goto dodist;
|
||||
}
|
||||
else {
|
||||
@ -305,7 +305,7 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
|
||||
}
|
||||
}
|
||||
else if ((op & 64) == 0) { /* 2nd level length code */
|
||||
here = lcode[here.val + (hold & ((1U << op) - 1))];
|
||||
here = lcode + here->val + (hold & ((1U << op) - 1));
|
||||
goto dolen;
|
||||
}
|
||||
else if (op & 32) { /* end-of-block */
|
||||
@ -339,7 +339,6 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
|
||||
state->bits = bits;
|
||||
|
||||
Assert((state->hold >> state->bits) == 0, "invalid input data state");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
|
77
deps/zlib/contrib/optimizations/inflate.c
vendored
77
deps/zlib/contrib/optimizations/inflate.c
vendored
@ -1,5 +1,5 @@
|
||||
/* inflate.c -- zlib decompression
|
||||
* Copyright (C) 1995-2016 Mark Adler
|
||||
* Copyright (C) 1995-2022 Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
@ -131,6 +131,7 @@ z_streamp strm;
|
||||
state->mode = HEAD;
|
||||
state->last = 0;
|
||||
state->havedict = 0;
|
||||
state->flags = -1;
|
||||
state->dmax = 32768U;
|
||||
state->head = Z_NULL;
|
||||
state->hold = 0;
|
||||
@ -168,6 +169,8 @@ int windowBits;
|
||||
|
||||
/* extract wrap request from windowBits parameter */
|
||||
if (windowBits < 0) {
|
||||
if (windowBits < -15)
|
||||
return Z_STREAM_ERROR;
|
||||
wrap = 0;
|
||||
windowBits = -windowBits;
|
||||
}
|
||||
@ -459,10 +462,10 @@ unsigned copy;
|
||||
|
||||
/* check function to use adler32() for zlib or crc32() for gzip */
|
||||
#ifdef GUNZIP
|
||||
# define UPDATE(check, buf, len) \
|
||||
# define UPDATE_CHECK(check, buf, len) \
|
||||
(state->flags ? crc32(check, buf, len) : adler32(check, buf, len))
|
||||
#else
|
||||
# define UPDATE(check, buf, len) adler32(check, buf, len)
|
||||
# define UPDATE_CHECK(check, buf, len) adler32(check, buf, len)
|
||||
#endif
|
||||
|
||||
/* check macros for header crc */
|
||||
@ -682,7 +685,6 @@ int flush;
|
||||
state->mode = FLAGS;
|
||||
break;
|
||||
}
|
||||
state->flags = 0; /* expect zlib header */
|
||||
if (state->head != Z_NULL)
|
||||
state->head->done = -1;
|
||||
if (!(state->wrap & 1) || /* check if zlib header allowed */
|
||||
@ -709,6 +711,7 @@ int flush;
|
||||
break;
|
||||
}
|
||||
state->dmax = 1U << len;
|
||||
state->flags = 0; /* indicate zlib header */
|
||||
Tracev((stderr, "inflate: zlib header ok\n"));
|
||||
strm->adler = state->check = adler32(0L, Z_NULL, 0);
|
||||
state->mode = hold & 0x200 ? DICTID : TYPE;
|
||||
@ -734,6 +737,7 @@ int flush;
|
||||
CRC2(state->check, hold);
|
||||
INITBITS();
|
||||
state->mode = TIME;
|
||||
/* fallthrough */
|
||||
case TIME:
|
||||
NEEDBITS(32);
|
||||
if (state->head != Z_NULL)
|
||||
@ -742,6 +746,7 @@ int flush;
|
||||
CRC4(state->check, hold);
|
||||
INITBITS();
|
||||
state->mode = OS;
|
||||
/* fallthrough */
|
||||
case OS:
|
||||
NEEDBITS(16);
|
||||
if (state->head != Z_NULL) {
|
||||
@ -752,6 +757,7 @@ int flush;
|
||||
CRC2(state->check, hold);
|
||||
INITBITS();
|
||||
state->mode = EXLEN;
|
||||
/* fallthrough */
|
||||
case EXLEN:
|
||||
if (state->flags & 0x0400) {
|
||||
NEEDBITS(16);
|
||||
@ -765,14 +771,16 @@ int flush;
|
||||
else if (state->head != Z_NULL)
|
||||
state->head->extra = Z_NULL;
|
||||
state->mode = EXTRA;
|
||||
/* fallthrough */
|
||||
case EXTRA:
|
||||
if (state->flags & 0x0400) {
|
||||
copy = state->length;
|
||||
if (copy > have) copy = have;
|
||||
if (copy) {
|
||||
if (state->head != Z_NULL &&
|
||||
state->head->extra != Z_NULL) {
|
||||
len = state->head->extra_len - state->length;
|
||||
state->head->extra != Z_NULL &&
|
||||
(len = state->head->extra_len - state->length) <
|
||||
state->head->extra_max) {
|
||||
zmemcpy(state->head->extra + len, next,
|
||||
len + copy > state->head->extra_max ?
|
||||
state->head->extra_max - len : copy);
|
||||
@ -787,6 +795,7 @@ int flush;
|
||||
}
|
||||
state->length = 0;
|
||||
state->mode = NAME;
|
||||
/* fallthrough */
|
||||
case NAME:
|
||||
if (state->flags & 0x0800) {
|
||||
if (have == 0) goto inf_leave;
|
||||
@ -808,6 +817,7 @@ int flush;
|
||||
state->head->name = Z_NULL;
|
||||
state->length = 0;
|
||||
state->mode = COMMENT;
|
||||
/* fallthrough */
|
||||
case COMMENT:
|
||||
if (state->flags & 0x1000) {
|
||||
if (have == 0) goto inf_leave;
|
||||
@ -828,6 +838,7 @@ int flush;
|
||||
else if (state->head != Z_NULL)
|
||||
state->head->comment = Z_NULL;
|
||||
state->mode = HCRC;
|
||||
/* fallthrough */
|
||||
case HCRC:
|
||||
if (state->flags & 0x0200) {
|
||||
NEEDBITS(16);
|
||||
@ -851,6 +862,7 @@ int flush;
|
||||
strm->adler = state->check = ZSWAP32(hold);
|
||||
INITBITS();
|
||||
state->mode = DICT;
|
||||
/* fallthrough */
|
||||
case DICT:
|
||||
if (state->havedict == 0) {
|
||||
RESTORE();
|
||||
@ -858,8 +870,10 @@ int flush;
|
||||
}
|
||||
strm->adler = state->check = adler32(0L, Z_NULL, 0);
|
||||
state->mode = TYPE;
|
||||
/* fallthrough */
|
||||
case TYPE:
|
||||
if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave;
|
||||
/* fallthrough */
|
||||
case TYPEDO:
|
||||
if (state->last) {
|
||||
BYTEBITS();
|
||||
@ -910,8 +924,10 @@ int flush;
|
||||
INITBITS();
|
||||
state->mode = COPY_;
|
||||
if (flush == Z_TREES) goto inf_leave;
|
||||
/* fallthrough */
|
||||
case COPY_:
|
||||
state->mode = COPY;
|
||||
/* fallthrough */
|
||||
case COPY:
|
||||
copy = state->length;
|
||||
if (copy) {
|
||||
@ -947,6 +963,7 @@ int flush;
|
||||
Tracev((stderr, "inflate: table sizes ok\n"));
|
||||
state->have = 0;
|
||||
state->mode = LENLENS;
|
||||
/* fallthrough */
|
||||
case LENLENS:
|
||||
while (state->have < state->ncode) {
|
||||
NEEDBITS(3);
|
||||
@ -968,6 +985,7 @@ int flush;
|
||||
Tracev((stderr, "inflate: code lengths ok\n"));
|
||||
state->have = 0;
|
||||
state->mode = CODELENS;
|
||||
/* fallthrough */
|
||||
case CODELENS:
|
||||
while (state->have < state->nlen + state->ndist) {
|
||||
for (;;) {
|
||||
@ -1027,11 +1045,11 @@ int flush;
|
||||
}
|
||||
|
||||
/* build code tables -- note: do not change the lenbits or distbits
|
||||
values here (9 and 6) without reading the comments in inftrees.h
|
||||
values here (10 and 9) without reading the comments in inftrees.h
|
||||
concerning the ENOUGH constants, which depend on those values */
|
||||
state->next = state->codes;
|
||||
state->lencode = (const code FAR *)(state->next);
|
||||
state->lenbits = 9;
|
||||
state->lenbits = 10;
|
||||
ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
|
||||
&(state->lenbits), state->work);
|
||||
if (ret) {
|
||||
@ -1040,7 +1058,7 @@ int flush;
|
||||
break;
|
||||
}
|
||||
state->distcode = (const code FAR *)(state->next);
|
||||
state->distbits = 6;
|
||||
state->distbits = 9;
|
||||
ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
|
||||
&(state->next), &(state->distbits), state->work);
|
||||
if (ret) {
|
||||
@ -1051,8 +1069,10 @@ int flush;
|
||||
Tracev((stderr, "inflate: codes ok\n"));
|
||||
state->mode = LEN_;
|
||||
if (flush == Z_TREES) goto inf_leave;
|
||||
/* fallthrough */
|
||||
case LEN_:
|
||||
state->mode = LEN;
|
||||
/* fallthrough */
|
||||
case LEN:
|
||||
if (have >= INFLATE_FAST_MIN_INPUT &&
|
||||
left >= INFLATE_FAST_MIN_OUTPUT) {
|
||||
@ -1103,6 +1123,7 @@ int flush;
|
||||
}
|
||||
state->extra = (unsigned)(here.op) & 15;
|
||||
state->mode = LENEXT;
|
||||
/* fallthrough */
|
||||
case LENEXT:
|
||||
if (state->extra) {
|
||||
NEEDBITS(state->extra);
|
||||
@ -1113,6 +1134,7 @@ int flush;
|
||||
Tracevv((stderr, "inflate: length %u\n", state->length));
|
||||
state->was = state->length;
|
||||
state->mode = DIST;
|
||||
/* fallthrough */
|
||||
case DIST:
|
||||
for (;;) {
|
||||
here = state->distcode[BITS(state->distbits)];
|
||||
@ -1140,6 +1162,7 @@ int flush;
|
||||
state->offset = (unsigned)here.val;
|
||||
state->extra = (unsigned)(here.op) & 15;
|
||||
state->mode = DISTEXT;
|
||||
/* fallthrough */
|
||||
case DISTEXT:
|
||||
if (state->extra) {
|
||||
NEEDBITS(state->extra);
|
||||
@ -1156,6 +1179,7 @@ int flush;
|
||||
#endif
|
||||
Tracevv((stderr, "inflate: distance %u\n", state->offset));
|
||||
state->mode = MATCH;
|
||||
/* fallthrough */
|
||||
case MATCH:
|
||||
if (left == 0) goto inf_leave;
|
||||
copy = out - left;
|
||||
@ -1214,7 +1238,7 @@ int flush;
|
||||
state->total += out;
|
||||
if ((state->wrap & 4) && out)
|
||||
strm->adler = state->check =
|
||||
UPDATE(state->check, put - out, out);
|
||||
UPDATE_CHECK(state->check, put - out, out);
|
||||
out = left;
|
||||
if ((state->wrap & 4) && (
|
||||
#ifdef GUNZIP
|
||||
@ -1230,10 +1254,11 @@ int flush;
|
||||
}
|
||||
#ifdef GUNZIP
|
||||
state->mode = LENGTH;
|
||||
/* fallthrough */
|
||||
case LENGTH:
|
||||
if (state->wrap && state->flags) {
|
||||
NEEDBITS(32);
|
||||
if (hold != (state->total & 0xffffffffUL)) {
|
||||
if ((state->wrap & 4) && hold != (state->total & 0xffffffff)) {
|
||||
strm->msg = (char *)"incorrect length check";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
@ -1243,6 +1268,7 @@ int flush;
|
||||
}
|
||||
#endif
|
||||
state->mode = DONE;
|
||||
/* fallthrough */
|
||||
case DONE:
|
||||
ret = Z_STREAM_END;
|
||||
goto inf_leave;
|
||||
@ -1252,6 +1278,7 @@ int flush;
|
||||
case MEM:
|
||||
return Z_MEM_ERROR;
|
||||
case SYNC:
|
||||
/* fallthrough */
|
||||
default:
|
||||
return Z_STREAM_ERROR;
|
||||
}
|
||||
@ -1263,16 +1290,29 @@ int flush;
|
||||
Note: a memory error from inflate() is non-recoverable.
|
||||
*/
|
||||
inf_leave:
|
||||
/* We write a defined value in the unused space to help mark
|
||||
#if defined(ZLIB_DEBUG)
|
||||
/* XXX(cavalcantii): I put this in place back in 2017 to help debug faulty
|
||||
* client code relying on undefined behavior when chunk_copy first landed.
|
||||
*
|
||||
* It is save to say after all these years that Chromium code is well
|
||||
* behaved and works fine with the optimization, therefore we can enable
|
||||
* this only for DEBUG builds.
|
||||
*
|
||||
* We write a defined value in the unused space to help mark
|
||||
* where the stream has ended. We don't use zeros as that can
|
||||
* mislead clients relying on undefined behavior (i.e. assuming
|
||||
* that the data is over when the buffer has a zero/null value).
|
||||
*
|
||||
* The basic idea is that if client code is not relying on the zlib context
|
||||
* to inform the amount of decompressed data, but instead reads the output
|
||||
* buffer until a zero/null is found, it will fail faster and harder
|
||||
* when the remaining of the buffer is marked with a symbol (e.g. 0x55).
|
||||
*/
|
||||
if (left >= CHUNKCOPY_CHUNK_SIZE)
|
||||
memset(put, 0x55, CHUNKCOPY_CHUNK_SIZE);
|
||||
else
|
||||
memset(put, 0x55, left);
|
||||
|
||||
#endif
|
||||
RESTORE();
|
||||
if (state->wsize || (out != strm->avail_out && state->mode < BAD &&
|
||||
(state->mode < CHECK || flush != Z_FINISH)))
|
||||
@ -1287,7 +1327,7 @@ int flush;
|
||||
state->total += out;
|
||||
if ((state->wrap & 4) && out)
|
||||
strm->adler = state->check =
|
||||
UPDATE(state->check, strm->next_out - out, out);
|
||||
UPDATE_CHECK(state->check, strm->next_out - out, out);
|
||||
strm->data_type = (int)state->bits + (state->last ? 64 : 0) +
|
||||
(state->mode == TYPE ? 128 : 0) +
|
||||
(state->mode == LEN_ || state->mode == COPY_ ? 256 : 0);
|
||||
@ -1423,6 +1463,7 @@ int ZEXPORT inflateSync(strm)
|
||||
z_streamp strm;
|
||||
{
|
||||
unsigned len; /* number of bytes to look at or looked at */
|
||||
int flags; /* temporary to save header status */
|
||||
unsigned long in, out; /* temporary to save total_in and total_out */
|
||||
unsigned char buf[4]; /* to restore bit buffer to byte string */
|
||||
struct inflate_state FAR *state;
|
||||
@ -1455,9 +1496,15 @@ z_streamp strm;
|
||||
|
||||
/* return no joy or set up to restart inflate() on a new block */
|
||||
if (state->have != 4) return Z_DATA_ERROR;
|
||||
if (state->flags == -1)
|
||||
state->wrap = 0; /* if no header yet, treat as raw */
|
||||
else
|
||||
state->wrap &= ~4; /* no point in computing a check value now */
|
||||
flags = state->flags;
|
||||
in = strm->total_in; out = strm->total_out;
|
||||
inflateReset(strm);
|
||||
strm->total_in = in; strm->total_out = out;
|
||||
state->flags = flags;
|
||||
state->mode = TYPE;
|
||||
return Z_OK;
|
||||
}
|
||||
@ -1553,7 +1600,7 @@ int check;
|
||||
|
||||
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
|
||||
state = (struct inflate_state FAR *)strm->state;
|
||||
if (check)
|
||||
if (check && state->wrap)
|
||||
state->wrap |= 4;
|
||||
else
|
||||
state->wrap &= ~4;
|
||||
|
108
deps/zlib/contrib/optimizations/insert_string.h
vendored
108
deps/zlib/contrib/optimizations/insert_string.h
vendored
@ -1,48 +1,61 @@
|
||||
/* insert_string.h
|
||||
*
|
||||
* Copyright 2019 The Chromium Authors. All rights reserved.
|
||||
* Copyright 2019 The Chromium Authors
|
||||
* 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
|
||||
|
||||
#ifndef INSERT_STRING_H
|
||||
#define INSERT_STRING_H
|
||||
|
||||
#ifndef INLINE
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#define INLINE __inline
|
||||
#else
|
||||
#define INLINE inline
|
||||
#endif
|
||||
#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
|
||||
/* CRC32C uint32_t */
|
||||
#define _cpu_crc32c_hash_u32 _mm_crc32_u32
|
||||
|
||||
#elif defined(CRC32_ARMV8_CRC32)
|
||||
#include "arm_features.h"
|
||||
#if defined(__clang__)
|
||||
#undef TARGET_CPU_WITH_CRC
|
||||
#define __crc32cw __builtin_arm_crc32cw
|
||||
#elif defined(__GNUC__)
|
||||
#define __crc32cw __builtin_aarch64_crc32cw
|
||||
#endif
|
||||
|
||||
#define _cpu_crc32_u32 __crc32cw
|
||||
|
||||
#if defined(__aarch64__)
|
||||
#if defined(__aarch64__) && defined(__clang__)
|
||||
#define TARGET_CPU_WITH_CRC __attribute__((target("crc")))
|
||||
#else // !defined(__aarch64__)
|
||||
#elif defined(__aarch64__) && defined(__GNUC__)
|
||||
#define TARGET_CPU_WITH_CRC __attribute__((target("+crc")))
|
||||
#elif defined(__clang__) // !defined(__aarch64__)
|
||||
#define TARGET_CPU_WITH_CRC __attribute__((target("armv8-a,crc")))
|
||||
#endif // defined(__aarch64__)
|
||||
|
||||
/* CRC32C uint32_t */
|
||||
#define _cpu_crc32c_hash_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;
|
||||
|
||||
@ -52,22 +65,33 @@ local INLINE Pos insert_string_optimized(deflate_state* const s,
|
||||
if (s->level >= 6)
|
||||
val &= 0xFFFFFF;
|
||||
|
||||
/* Unlike the case of data integrity checks for GZIP format where the
|
||||
* polynomial used is defined (https://tools.ietf.org/html/rfc1952#page-11),
|
||||
* here it is just a hash function for the hash table used while
|
||||
* performing compression.
|
||||
*/
|
||||
h = _cpu_crc32_u32(h, val);
|
||||
/* Compute hash from the CRC32C of |val|. */
|
||||
h = _cpu_crc32c_hash_u32(h, val);
|
||||
|
||||
ret = s->head[h & s->hash_mask];
|
||||
s->head[h & s->hash_mask] = str;
|
||||
s->prev[str & s->w_mask] = ret;
|
||||
return ret;
|
||||
}
|
||||
#endif /* Optimized insert_string block */
|
||||
|
||||
#endif // TARGET_CPU_WITH_CRC
|
||||
|
||||
/**
|
||||
* Some applications need to match zlib DEFLATE output exactly [3]. Use the
|
||||
* canonical zlib Rabin-Karp rolling hash [1,2] in that case.
|
||||
*
|
||||
* [1] For a description of the Rabin and Karp algorithm, see "Algorithms"
|
||||
* book by R. Sedgewick, Addison-Wesley, p252.
|
||||
* [2] https://www.euccas.me/zlib/#zlib_rabin_karp and also "rolling hash"
|
||||
* https://en.wikipedia.org/wiki/Rolling_hash
|
||||
* [3] crbug.com/1316541 AOSP incremental client APK package OTA upgrades.
|
||||
*/
|
||||
#ifdef CHROMIUM_ZLIB_NO_CASTAGNOLI
|
||||
#define USE_ZLIB_RABIN_KARP_ROLLING_HASH
|
||||
#endif
|
||||
|
||||
/* ===========================================================================
|
||||
* Update a hash value with the given input byte
|
||||
* Update a hash value with the given input byte (Rabin-Karp rolling hash).
|
||||
* IN assertion: all calls to UPDATE_HASH are made with consecutive input
|
||||
* characters, so that a running hash key can be computed from the previous
|
||||
* key instead of complete recalculation each time.
|
||||
@ -99,24 +123,24 @@ local INLINE Pos insert_string_c(deflate_state* const s, const Pos str) {
|
||||
}
|
||||
|
||||
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: SIMD crc32c symbol hasher
|
||||
* 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 canonical 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(USE_ZLIB_RABIN_KARP_ROLLING_HASH)
|
||||
/* So this build-time option can be used to disable the crc32c hash, and use
|
||||
* the Rabin-Karp hash instead.
|
||||
*/ /* FALLTHROUGH Rabin-Karp */
|
||||
#elif defined(TARGET_CPU_WITH_CRC) && defined(CRC32_SIMD_SSE42_PCLMUL)
|
||||
if (x86_cpu_enable_simd)
|
||||
return insert_string_optimized(s, str);
|
||||
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
|
||||
#endif
|
||||
return insert_string_c(s, str);
|
||||
return insert_string_c(s, str); /* Rabin-Karp */
|
||||
}
|
||||
|
||||
#endif /* INSERT_STRING_H */
|
||||
|
@ -1,65 +0,0 @@
|
||||
/* Copyright 2018 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.
|
||||
*/
|
||||
#ifndef __SLIDE_HASH__NEON__
|
||||
#define __SLIDE_HASH__NEON__
|
||||
|
||||
#include "deflate.h"
|
||||
#include <arm_neon.h>
|
||||
|
||||
inline static void ZLIB_INTERNAL neon_slide_hash_update(Posf *hash,
|
||||
const uInt hash_size,
|
||||
const ush w_size)
|
||||
{
|
||||
/* NEON 'Q' registers allow to store 128 bits, so we can load 8x16-bits
|
||||
* values. For further details, check:
|
||||
* ARM DHT 0002A, section 1.3.2 NEON Registers.
|
||||
*/
|
||||
const size_t chunk = sizeof(uint16x8_t) / sizeof(uint16_t);
|
||||
/* Unrolling the operation yielded a compression performance boost in both
|
||||
* ARMv7 (from 11.7% to 13.4%) and ARMv8 (from 3.7% to 7.5%) for HTML4
|
||||
* content. For full benchmarking data, check: http://crbug.com/863257.
|
||||
*/
|
||||
const size_t stride = 2*chunk;
|
||||
const uint16x8_t v = vdupq_n_u16(w_size);
|
||||
|
||||
for (Posf *end = hash + hash_size; hash != end; hash += stride) {
|
||||
uint16x8_t m_low = vld1q_u16(hash);
|
||||
uint16x8_t m_high = vld1q_u16(hash + chunk);
|
||||
|
||||
/* The first 'q' in vqsubq_u16 makes these subtracts saturate to zero,
|
||||
* replacing the ternary operator expression in the original code:
|
||||
* (m >= wsize ? m - wsize : NIL).
|
||||
*/
|
||||
m_low = vqsubq_u16(m_low, v);
|
||||
m_high = vqsubq_u16(m_high, v);
|
||||
|
||||
vst1q_u16(hash, m_low);
|
||||
vst1q_u16(hash + chunk, m_high);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline static void ZLIB_INTERNAL neon_slide_hash(Posf *head, Posf *prev,
|
||||
const unsigned short w_size,
|
||||
const uInt hash_size)
|
||||
{
|
||||
/*
|
||||
* SIMD implementation for hash table rebase assumes:
|
||||
* 1. hash chain offset (Pos) is 2 bytes.
|
||||
* 2. hash table size is multiple of 32 bytes.
|
||||
* #1 should be true as Pos is defined as "ush"
|
||||
* #2 should be true as hash_bits are greater than 7
|
||||
*/
|
||||
const size_t size = hash_size * sizeof(head[0]);
|
||||
Assert(sizeof(Pos) == 2, "Wrong Pos size.");
|
||||
Assert((size % sizeof(uint16x8_t) * 2) == 0, "Hash table size error.");
|
||||
|
||||
neon_slide_hash_update(head, hash_size, w_size);
|
||||
#ifndef FASTEST
|
||||
neon_slide_hash_update(prev, w_size, w_size);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
4
deps/zlib/contrib/tests/DEPS
vendored
Normal file
4
deps/zlib/contrib/tests/DEPS
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
include_rules = [
|
||||
"+testing/gtest",
|
||||
"+base",
|
||||
]
|
1
deps/zlib/contrib/tests/OWNERS
vendored
1
deps/zlib/contrib/tests/OWNERS
vendored
@ -1 +1,2 @@
|
||||
cblume@chromium.org
|
||||
cavalcantii@chromium.org
|
||||
|
45
deps/zlib/contrib/tests/fuzzers/BUILD.gn
vendored
45
deps/zlib/contrib/tests/fuzzers/BUILD.gn
vendored
@ -1,4 +1,4 @@
|
||||
# Copyright 2017 The Chromium Authors. All rights reserved.
|
||||
# Copyright 2017 The Chromium Authors
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
@ -9,37 +9,32 @@ group("fuzzers") {
|
||||
}
|
||||
|
||||
fuzzer_test("zlib_uncompress_fuzzer") {
|
||||
sources = [
|
||||
"uncompress_fuzzer.cc",
|
||||
]
|
||||
deps = [
|
||||
"../../../:zlib",
|
||||
]
|
||||
sources = [ "uncompress_fuzzer.cc" ]
|
||||
deps = [ "../../../:zlib" ]
|
||||
}
|
||||
|
||||
fuzzer_test("zlib_inflate_fuzzer") {
|
||||
sources = [
|
||||
"inflate_fuzzer.cc",
|
||||
]
|
||||
deps = [
|
||||
"../../../:zlib",
|
||||
]
|
||||
sources = [ "inflate_fuzzer.cc" ]
|
||||
deps = [ "../../../:zlib" ]
|
||||
}
|
||||
|
||||
fuzzer_test("zlib_inflate_with_header_fuzzer") {
|
||||
sources = [ "inflate_with_header_fuzzer.cc" ]
|
||||
deps = [ "../../../:zlib" ]
|
||||
}
|
||||
|
||||
fuzzer_test("zlib_streaming_inflate_fuzzer") {
|
||||
sources = [ "streaming_inflate_fuzzer.cc" ]
|
||||
deps = [ "../../../:zlib" ]
|
||||
libfuzzer_options = [ "max_len=256000" ]
|
||||
}
|
||||
|
||||
fuzzer_test("zlib_deflate_set_dictionary_fuzzer") {
|
||||
sources = [
|
||||
"deflate_set_dictionary_fuzzer.cc",
|
||||
]
|
||||
deps = [
|
||||
"../../../:zlib",
|
||||
]
|
||||
sources = [ "deflate_set_dictionary_fuzzer.cc" ]
|
||||
deps = [ "../../../:zlib" ]
|
||||
}
|
||||
|
||||
fuzzer_test("zlib_deflate_fuzzer") {
|
||||
sources = [
|
||||
"deflate_fuzzer.cc",
|
||||
]
|
||||
deps = [
|
||||
"../../../:zlib",
|
||||
]
|
||||
sources = [ "deflate_fuzzer.cc" ]
|
||||
deps = [ "../../../:zlib" ]
|
||||
}
|
||||
|
3
deps/zlib/contrib/tests/fuzzers/OWNERS
vendored
3
deps/zlib/contrib/tests/fuzzers/OWNERS
vendored
@ -1,2 +1,3 @@
|
||||
cblume@chromium.org
|
||||
mmoroz@chromium.org
|
||||
hans@chromium.org
|
||||
noel@chromium.org
|
||||
|
@ -1,47 +1,74 @@
|
||||
// Copyright 2017 The Chromium Authors. All rights reserved.
|
||||
// Copyright 2017 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <fuzzer/FuzzedDataProvider.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
|
||||
#include "third_party/zlib/zlib.h"
|
||||
|
||||
static Bytef buffer[256 * 1024] = {0};
|
||||
// Fuzzer builds often have NDEBUG set, so roll our own assert macro.
|
||||
#define ASSERT(cond) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
fprintf(stderr, "%s:%d Assert failed: %s\n", __FILE__, __LINE__, #cond); \
|
||||
exit(1); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// Entry point for LibFuzzer.
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
// zlib's deflate requires non-zero input sizes
|
||||
if (!size)
|
||||
return 0;
|
||||
|
||||
// We need to strip the 'const' for zlib.
|
||||
std::vector<unsigned char> input_buffer{data, data+size};
|
||||
|
||||
uLongf buffer_length = static_cast<uLongf>(sizeof(buffer));
|
||||
FuzzedDataProvider fdp(data, size);
|
||||
int level = fdp.PickValueInArray({0, 1, 2, 3, 4, 5, 6, 7, 8, 9});
|
||||
int windowBits = fdp.PickValueInArray({9, 10, 11, 12, 13, 14, 15});
|
||||
int memLevel = fdp.PickValueInArray({1, 2, 3, 4, 5, 6, 7, 8, 9});
|
||||
int strategy = fdp.PickValueInArray(
|
||||
{Z_DEFAULT_STRATEGY, Z_FILTERED, Z_HUFFMAN_ONLY, Z_RLE, Z_FIXED});
|
||||
std::vector<uint8_t> src = fdp.ConsumeRemainingBytes<uint8_t>();
|
||||
|
||||
z_stream stream;
|
||||
stream.next_in = input_buffer.data();
|
||||
stream.avail_in = size;
|
||||
stream.total_in = size;
|
||||
stream.next_out = buffer;
|
||||
stream.avail_out = buffer_length;
|
||||
stream.total_out = buffer_length;
|
||||
stream.zalloc = Z_NULL;
|
||||
stream.zfree = Z_NULL;
|
||||
|
||||
if (Z_OK != deflateInit(&stream, Z_DEFAULT_COMPRESSION)) {
|
||||
deflateEnd(&stream);
|
||||
assert(false);
|
||||
// Compress the data one byte at a time to exercise the streaming code.
|
||||
int ret =
|
||||
deflateInit2(&stream, level, Z_DEFLATED, windowBits, memLevel, strategy);
|
||||
ASSERT(ret == Z_OK);
|
||||
std::vector<uint8_t> compressed(src.size() * 2 + 1000);
|
||||
stream.next_out = compressed.data();
|
||||
stream.avail_out = compressed.size();
|
||||
for (uint8_t b : src) {
|
||||
stream.next_in = &b;
|
||||
stream.avail_in = 1;
|
||||
ret = deflate(&stream, Z_NO_FLUSH);
|
||||
ASSERT(ret == Z_OK);
|
||||
}
|
||||
|
||||
auto deflate_result = deflate(&stream, Z_NO_FLUSH);
|
||||
stream.next_in = Z_NULL;
|
||||
stream.avail_in = 0;
|
||||
ret = deflate(&stream, Z_FINISH);
|
||||
ASSERT(ret == Z_STREAM_END);
|
||||
compressed.resize(compressed.size() - stream.avail_out);
|
||||
deflateEnd(&stream);
|
||||
if (Z_OK != deflate_result)
|
||||
assert(false);
|
||||
|
||||
// Verify that the data decompresses correctly.
|
||||
ret = inflateInit2(&stream, windowBits);
|
||||
ASSERT(ret == Z_OK);
|
||||
// Make room for at least one byte so it's never empty.
|
||||
std::vector<uint8_t> decompressed(src.size() + 1);
|
||||
stream.next_in = compressed.data();
|
||||
stream.avail_in = compressed.size();
|
||||
stream.next_out = decompressed.data();
|
||||
stream.avail_out = decompressed.size();
|
||||
ret = inflate(&stream, Z_FINISH);
|
||||
ASSERT(ret == Z_STREAM_END);
|
||||
decompressed.resize(decompressed.size() - stream.avail_out);
|
||||
inflateEnd(&stream);
|
||||
|
||||
ASSERT(decompressed == src);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2017 The Chromium Authors. All rights reserved.
|
||||
// Copyright 2017 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2017 The Chromium Authors. All rights reserved.
|
||||
// Copyright 2017 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
|
95
deps/zlib/contrib/tests/fuzzers/inflate_with_header_fuzzer.cc
vendored
Normal file
95
deps/zlib/contrib/tests/fuzzers/inflate_with_header_fuzzer.cc
vendored
Normal file
@ -0,0 +1,95 @@
|
||||
// Copyright 2022 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <fuzzer/FuzzedDataProvider.h>
|
||||
|
||||
#include "third_party/zlib/zlib.h"
|
||||
|
||||
// Fuzzer builds often have NDEBUG set, so roll our own assert macro.
|
||||
#define ASSERT(cond) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
fprintf(stderr, "%s:%d Assert failed: %s\n", __FILE__, __LINE__, #cond); \
|
||||
exit(1); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static void chunked_inflate(gz_header* header,
|
||||
uint8_t* data,
|
||||
size_t size,
|
||||
size_t in_chunk_size,
|
||||
size_t out_chunk_size) {
|
||||
z_stream stream;
|
||||
stream.next_in = data;
|
||||
stream.avail_in = 0;
|
||||
stream.zalloc = Z_NULL;
|
||||
stream.zfree = Z_NULL;
|
||||
|
||||
static const int kDefaultWindowBits = MAX_WBITS;
|
||||
static const int kGzipOrZlibHeader = 32;
|
||||
ASSERT(inflateInit2(&stream, kDefaultWindowBits + kGzipOrZlibHeader) == Z_OK);
|
||||
ASSERT(inflateGetHeader(&stream, header) == Z_OK);
|
||||
|
||||
auto out_buffer = std::make_unique<uint8_t[]>(out_chunk_size);
|
||||
while (true) {
|
||||
stream.next_in = &data[stream.total_in];
|
||||
stream.avail_in =
|
||||
std::min(in_chunk_size, size - static_cast<size_t>(stream.total_in));
|
||||
stream.next_out = out_buffer.get();
|
||||
stream.avail_out = out_chunk_size;
|
||||
|
||||
if (inflate(&stream, stream.avail_in == 0 ? Z_SYNC_FLUSH : Z_NO_FLUSH) !=
|
||||
Z_OK) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inflateEnd(&stream);
|
||||
}
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
if (size > 250 * 1024) {
|
||||
// Cap the input size so the fuzzer doesn't time out. For example,
|
||||
// crbug.com/1362206 saw timeouts with 450 KB input, so use a limit that's
|
||||
// well below that but still large enough to hit most code.
|
||||
return 0;
|
||||
}
|
||||
|
||||
FuzzedDataProvider fdp(data, size);
|
||||
|
||||
// Fuzz zlib's inflate() with inflateGetHeader() enabled, various sizes for
|
||||
// the gz_header field sizes, and various-sized chunks for input/output. This
|
||||
// would have found CVE-2022-37434 which was a heap buffer read overflow when
|
||||
// filling in gz_header's extra field.
|
||||
|
||||
gz_header header;
|
||||
header.extra_max = fdp.ConsumeIntegralInRange(0, 100000);
|
||||
header.name_max = fdp.ConsumeIntegralInRange(0, 100000);
|
||||
header.comm_max = fdp.ConsumeIntegralInRange(0, 100000);
|
||||
|
||||
auto extra_buf = std::make_unique<uint8_t[]>(header.extra_max);
|
||||
auto name_buf = std::make_unique<uint8_t[]>(header.name_max);
|
||||
auto comment_buf = std::make_unique<uint8_t[]>(header.comm_max);
|
||||
|
||||
header.extra = extra_buf.get();
|
||||
header.name = name_buf.get();
|
||||
header.comment = comment_buf.get();
|
||||
|
||||
size_t in_chunk_size = fdp.ConsumeIntegralInRange(1, 4097);
|
||||
size_t out_chunk_size = fdp.ConsumeIntegralInRange(1, 4097);
|
||||
std::vector<uint8_t> remaining_data = fdp.ConsumeRemainingBytes<uint8_t>();
|
||||
|
||||
chunked_inflate(&header, remaining_data.data(), remaining_data.size(),
|
||||
in_chunk_size, out_chunk_size);
|
||||
|
||||
return 0;
|
||||
}
|
74
deps/zlib/contrib/tests/fuzzers/streaming_inflate_fuzzer.cc
vendored
Normal file
74
deps/zlib/contrib/tests/fuzzers/streaming_inflate_fuzzer.cc
vendored
Normal file
@ -0,0 +1,74 @@
|
||||
// Copyright 2020 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "third_party/zlib/zlib.h"
|
||||
|
||||
// Fuzzer builds often have NDEBUG set, so roll our own assert macro.
|
||||
#define ASSERT(cond) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
fprintf(stderr, "%s:%d Assert failed: %s\n", __FILE__, __LINE__, #cond); \
|
||||
exit(1); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// Entry point for LibFuzzer.
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||
// Deflate data.
|
||||
z_stream comp_strm;
|
||||
comp_strm.zalloc = Z_NULL;
|
||||
comp_strm.zfree = Z_NULL;
|
||||
comp_strm.opaque = Z_NULL;
|
||||
int ret = deflateInit(&comp_strm, Z_DEFAULT_COMPRESSION);
|
||||
ASSERT(ret == Z_OK);
|
||||
|
||||
size_t comp_buf_cap = deflateBound(&comp_strm, size);
|
||||
uint8_t* comp_buf = (uint8_t*)malloc(comp_buf_cap);
|
||||
ASSERT(comp_buf != nullptr);
|
||||
comp_strm.next_out = comp_buf;
|
||||
comp_strm.avail_out = comp_buf_cap;
|
||||
comp_strm.next_in = (unsigned char*)data;
|
||||
comp_strm.avail_in = size;
|
||||
ret = deflate(&comp_strm, Z_FINISH);
|
||||
ASSERT(ret == Z_STREAM_END);
|
||||
size_t comp_sz = comp_buf_cap - comp_strm.avail_out;
|
||||
|
||||
// Inflate comp_buf one chunk at a time.
|
||||
z_stream decomp_strm;
|
||||
decomp_strm.zalloc = Z_NULL;
|
||||
decomp_strm.zfree = Z_NULL;
|
||||
decomp_strm.opaque = Z_NULL;
|
||||
ret = inflateInit(&decomp_strm);
|
||||
ASSERT(ret == Z_OK);
|
||||
decomp_strm.next_in = comp_buf;
|
||||
decomp_strm.avail_in = comp_sz;
|
||||
|
||||
while (decomp_strm.avail_in > 0) {
|
||||
uint8_t decomp_buf[1024];
|
||||
decomp_strm.next_out = decomp_buf;
|
||||
decomp_strm.avail_out = sizeof(decomp_buf);
|
||||
ret = inflate(&decomp_strm, Z_FINISH);
|
||||
ASSERT(ret == Z_OK || ret == Z_STREAM_END || ret == Z_BUF_ERROR);
|
||||
|
||||
// Verify the output bytes.
|
||||
size_t num_out = sizeof(decomp_buf) - decomp_strm.avail_out;
|
||||
for (size_t i = 0; i < num_out; i++) {
|
||||
ASSERT(decomp_buf[i] == data[decomp_strm.total_out - num_out + i]);
|
||||
}
|
||||
}
|
||||
|
||||
ret = deflateEnd(&comp_strm);
|
||||
ASSERT(ret == Z_OK);
|
||||
free(comp_buf);
|
||||
|
||||
inflateEnd(&decomp_strm);
|
||||
ASSERT(ret == Z_OK);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Copyright 2015 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
|
746
deps/zlib/contrib/tests/infcover.cc
vendored
Normal file
746
deps/zlib/contrib/tests/infcover.cc
vendored
Normal file
@ -0,0 +1,746 @@
|
||||
/* 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 "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(©, &strm); assert(ret == Z_OK);
|
||||
ret = inflateEnd(©); 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;
|
||||
char versioncpy[] = ZLIB_VERSION;
|
||||
versioncpy[0] -= 1;
|
||||
ret = inflateInit_(&strm, versioncpy, (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(©, &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);
|
||||
}
|
||||
|
||||
/* Adapted from Evgeny Legerov PoC (https://github.com/ivd38/zlib_overflow)
|
||||
* this test case crashes in ASAN builds with the correct payload.
|
||||
*/
|
||||
local void inf_cve_2022_37434(char *hex, 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);
|
||||
if (ret != Z_OK && ret != Z_BUF_ERROR && ret != Z_NEED_DICT)
|
||||
break;
|
||||
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);
|
||||
ret = inflateEnd(&strm);
|
||||
mem_done(&strm, what);
|
||||
}
|
||||
|
||||
void cover_CVE_2022_37434(void)
|
||||
{
|
||||
char payload[] = "1f 8b 08 04 61 62 63 64 61 62 52 51 1f 8b 08 04 61 62 63 64 61 62 52 51 1f 8b 08 04 61 62 63 64 61 62 52 51 1f 8b 08 04 61 62 63 64 61 62 52 51";
|
||||
char cve[] = "wtf";
|
||||
inf_cve_2022_37434(payload, cve, 13, 47, 12, Z_OK);
|
||||
}
|
||||
|
||||
// clang-format on
|
12
deps/zlib/contrib/tests/infcover.h
vendored
Normal file
12
deps/zlib/contrib/tests/infcover.h
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
#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);
|
||||
|
||||
void cover_CVE_2022_37434(void);
|
||||
#endif
|
14
deps/zlib/contrib/tests/run_all_unittests.cc
vendored
Normal file
14
deps/zlib/contrib/tests/run_all_unittests.cc
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright 2020 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "base/bind.h"
|
||||
#include "base/test/launcher/unit_test_launcher.h"
|
||||
#include "base/test/test_suite.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
base::TestSuite test_suite(argc, argv);
|
||||
return base::LaunchUnitTests(
|
||||
argc, argv,
|
||||
base::BindOnce(&base::TestSuite::Run, base::Unretained(&test_suite)));
|
||||
}
|
1017
deps/zlib/contrib/tests/utils_unittest.cc
vendored
Normal file
1017
deps/zlib/contrib/tests/utils_unittest.cc
vendored
Normal file
File diff suppressed because it is too large
Load Diff
170
deps/zlib/cpu_features.c
vendored
Normal file
170
deps/zlib/cpu_features.c
vendored
Normal file
@ -0,0 +1,170 @@
|
||||
/* cpu_features.c -- Processor features detection.
|
||||
*
|
||||
* Copyright 2018 The Chromium Authors
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the Chromium source repository LICENSE file.
|
||||
*/
|
||||
|
||||
#include "cpu_features.h"
|
||||
#include "zutil.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#if defined(_MSC_VER)
|
||||
#include <intrin.h>
|
||||
#elif defined(ADLER32_SIMD_SSSE3)
|
||||
#include <cpuid.h>
|
||||
#endif
|
||||
|
||||
/* TODO(cavalcantii): remove checks for x86_flags on deflate.
|
||||
*/
|
||||
#if defined(ARMV8_OS_MACOS)
|
||||
/* Crypto extensions (crc32/pmull) are a baseline feature in ARMv8.1-A, and
|
||||
* OSX running on arm64 is new enough that these can be assumed without
|
||||
* runtime detection.
|
||||
*/
|
||||
int ZLIB_INTERNAL arm_cpu_enable_crc32 = 1;
|
||||
int ZLIB_INTERNAL arm_cpu_enable_pmull = 1;
|
||||
#else
|
||||
int ZLIB_INTERNAL arm_cpu_enable_crc32 = 0;
|
||||
int ZLIB_INTERNAL arm_cpu_enable_pmull = 0;
|
||||
#endif
|
||||
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
|
||||
|
||||
#if defined(ARMV8_OS_ANDROID)
|
||||
#include <cpu-features.h>
|
||||
#elif defined(ARMV8_OS_LINUX)
|
||||
#include <asm/hwcap.h>
|
||||
#include <sys/auxv.h>
|
||||
#elif defined(ARMV8_OS_FUCHSIA)
|
||||
#include <zircon/features.h>
|
||||
#include <zircon/syscalls.h>
|
||||
#include <zircon/types.h>
|
||||
#elif defined(ARMV8_OS_WINDOWS) || defined(X86_WINDOWS)
|
||||
#include <windows.h>
|
||||
#elif !defined(_MSC_VER)
|
||||
#include <pthread.h>
|
||||
#else
|
||||
#error cpu_features.c CPU feature detection in not defined for your platform
|
||||
#endif
|
||||
|
||||
#if !defined(CPU_NO_SIMD) && !defined(ARMV8_OS_MACOS) && !defined(ARM_OS_IOS)
|
||||
static void _cpu_check_features(void);
|
||||
#endif
|
||||
|
||||
#if defined(ARMV8_OS_ANDROID) || defined(ARMV8_OS_LINUX) || defined(ARMV8_OS_MACOS) || defined(ARMV8_OS_FUCHSIA) || defined(X86_NOT_WINDOWS)
|
||||
#if !defined(ARMV8_OS_MACOS)
|
||||
// _cpu_check_features() doesn't need to do anything on mac/arm since all
|
||||
// features are known at build time, so don't call it.
|
||||
// Do provide cpu_check_features() (with a no-op implementation) so that we
|
||||
// don't have to make all callers of it check for mac/arm.
|
||||
static pthread_once_t cpu_check_inited_once = PTHREAD_ONCE_INIT;
|
||||
#endif
|
||||
void ZLIB_INTERNAL cpu_check_features(void)
|
||||
{
|
||||
#if !defined(ARMV8_OS_MACOS)
|
||||
pthread_once(&cpu_check_inited_once, _cpu_check_features);
|
||||
#endif
|
||||
}
|
||||
#elif defined(ARMV8_OS_WINDOWS) || defined(X86_WINDOWS)
|
||||
static INIT_ONCE cpu_check_inited_once = INIT_ONCE_STATIC_INIT;
|
||||
static BOOL CALLBACK _cpu_check_features_forwarder(PINIT_ONCE once, PVOID param, PVOID* context)
|
||||
{
|
||||
_cpu_check_features();
|
||||
return TRUE;
|
||||
}
|
||||
void ZLIB_INTERNAL cpu_check_features(void)
|
||||
{
|
||||
InitOnceExecuteOnce(&cpu_check_inited_once, _cpu_check_features_forwarder,
|
||||
NULL, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (defined(__ARM_NEON__) || defined(__ARM_NEON))
|
||||
/*
|
||||
* iOS@ARM is a special case where we always have NEON but don't check
|
||||
* for crypto extensions.
|
||||
*/
|
||||
#if !defined(ARMV8_OS_MACOS) && !defined(ARM_OS_IOS)
|
||||
/*
|
||||
* See http://bit.ly/2CcoEsr for run-time detection of ARM features and also
|
||||
* crbug.com/931275 for android_getCpuFeatures() use in the Android sandbox.
|
||||
*/
|
||||
static void _cpu_check_features(void)
|
||||
{
|
||||
#if defined(ARMV8_OS_ANDROID) && defined(__aarch64__)
|
||||
uint64_t features = android_getCpuFeatures();
|
||||
arm_cpu_enable_crc32 = !!(features & ANDROID_CPU_ARM64_FEATURE_CRC32);
|
||||
arm_cpu_enable_pmull = !!(features & ANDROID_CPU_ARM64_FEATURE_PMULL);
|
||||
#elif defined(ARMV8_OS_ANDROID) /* aarch32 */
|
||||
uint64_t features = android_getCpuFeatures();
|
||||
arm_cpu_enable_crc32 = !!(features & ANDROID_CPU_ARM_FEATURE_CRC32);
|
||||
arm_cpu_enable_pmull = !!(features & ANDROID_CPU_ARM_FEATURE_PMULL);
|
||||
#elif defined(ARMV8_OS_LINUX) && defined(__aarch64__)
|
||||
unsigned long features = getauxval(AT_HWCAP);
|
||||
arm_cpu_enable_crc32 = !!(features & HWCAP_CRC32);
|
||||
arm_cpu_enable_pmull = !!(features & HWCAP_PMULL);
|
||||
#elif defined(ARMV8_OS_LINUX) && (defined(__ARM_NEON) || defined(__ARM_NEON__))
|
||||
/* Query HWCAP2 for ARMV8-A SoCs running in aarch32 mode */
|
||||
unsigned long features = getauxval(AT_HWCAP2);
|
||||
arm_cpu_enable_crc32 = !!(features & HWCAP2_CRC32);
|
||||
arm_cpu_enable_pmull = !!(features & HWCAP2_PMULL);
|
||||
#elif defined(ARMV8_OS_FUCHSIA)
|
||||
uint32_t features;
|
||||
zx_status_t rc = zx_system_get_features(ZX_FEATURE_KIND_CPU, &features);
|
||||
if (rc != ZX_OK || (features & ZX_ARM64_FEATURE_ISA_ASIMD) == 0)
|
||||
return; /* Report nothing if ASIMD(NEON) is missing */
|
||||
arm_cpu_enable_crc32 = !!(features & ZX_ARM64_FEATURE_ISA_CRC32);
|
||||
arm_cpu_enable_pmull = !!(features & ZX_ARM64_FEATURE_ISA_PMULL);
|
||||
#elif defined(ARMV8_OS_WINDOWS)
|
||||
arm_cpu_enable_crc32 = IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE);
|
||||
arm_cpu_enable_pmull = IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#elif defined(X86_NOT_WINDOWS) || defined(X86_WINDOWS)
|
||||
/*
|
||||
* iOS@x86 (i.e. emulator) is another special case where we disable
|
||||
* SIMD optimizations.
|
||||
*/
|
||||
#ifndef CPU_NO_SIMD
|
||||
/* On x86 we simply use a instruction to check the CPU features.
|
||||
* (i.e. CPUID).
|
||||
*/
|
||||
static void _cpu_check_features(void)
|
||||
{
|
||||
int x86_cpu_has_sse2;
|
||||
int x86_cpu_has_ssse3;
|
||||
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 &&
|
||||
x86_cpu_has_sse42 &&
|
||||
x86_cpu_has_pclmulqdq;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
18
deps/zlib/cpu_features.h
vendored
Normal file
18
deps/zlib/cpu_features.h
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
/* cpu_features.h -- Processor features detection.
|
||||
*
|
||||
* Copyright 2018 The Chromium Authors
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the Chromium source repository LICENSE file.
|
||||
*/
|
||||
|
||||
#include "zlib.h"
|
||||
|
||||
/* TODO(cavalcantii): remove checks for x86_flags on deflate.
|
||||
*/
|
||||
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;
|
||||
|
||||
void cpu_check_features(void);
|
1371
deps/zlib/crc32.c
vendored
1371
deps/zlib/crc32.c
vendored
File diff suppressed because it is too large
Load Diff
9877
deps/zlib/crc32.h
vendored
9877
deps/zlib/crc32.h
vendored
File diff suppressed because it is too large
Load Diff
206
deps/zlib/crc32_simd.c
vendored
206
deps/zlib/crc32_simd.c
vendored
@ -1,6 +1,6 @@
|
||||
/* crc32_simd.c
|
||||
*
|
||||
* Copyright 2017 The Chromium Authors. All rights reserved.
|
||||
* Copyright 2017 The Chromium Authors
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the Chromium source repository LICENSE file.
|
||||
*/
|
||||
@ -8,9 +8,6 @@
|
||||
#include "crc32_simd.h"
|
||||
|
||||
#if defined(CRC32_SIMD_SSE42_PCLMUL)
|
||||
#ifndef __GNUC__
|
||||
#define __attribute__()
|
||||
#endif
|
||||
|
||||
/*
|
||||
* crc32_sse42_simd_(): compute the crc32 of the buffer, where the buffer
|
||||
@ -24,7 +21,6 @@
|
||||
#include <smmintrin.h>
|
||||
#include <wmmintrin.h>
|
||||
|
||||
__attribute__((target("sse4.2,pclmul")))
|
||||
uint32_t ZLIB_INTERNAL crc32_sse42_simd_( /* SSE4.2+PCLMUL */
|
||||
const unsigned char *buf,
|
||||
z_size_t len,
|
||||
@ -161,11 +157,16 @@ uint32_t ZLIB_INTERNAL crc32_sse42_simd_( /* SSE4.2+PCLMUL */
|
||||
#elif defined(CRC32_ARMV8_CRC32)
|
||||
|
||||
/* CRC32 checksums using ARMv8-a crypto instructions.
|
||||
*
|
||||
* TODO: implement a version using the PMULL instruction.
|
||||
*/
|
||||
|
||||
#if defined(__clang__)
|
||||
/* We need some extra types for using PMULL.
|
||||
*/
|
||||
#if defined(__aarch64__)
|
||||
#include <arm_neon.h>
|
||||
#include <arm_acle.h>
|
||||
#endif
|
||||
|
||||
/* CRC32 intrinsics are #ifdef'ed out of arm_acle.h unless we build with an
|
||||
* armv8 target, which is incompatible with ThinLTO optimizations on Android.
|
||||
* (Namely, mixing and matching different module-level targets makes ThinLTO
|
||||
@ -181,14 +182,21 @@ uint32_t ZLIB_INTERNAL crc32_sse42_simd_( /* SSE4.2+PCLMUL */
|
||||
* NOTE: clang currently complains that "'+soft-float-abi' is not a recognized
|
||||
* feature for this target (ignoring feature)." This appears to be a harmless
|
||||
* bug in clang.
|
||||
*
|
||||
* These definitions must appear *after* including arm_acle.h otherwise that
|
||||
* header may end up defining functions named __builtin_arm_crc32* that call
|
||||
* themselves, creating an infinite loop when the intrinsic is called.
|
||||
*/
|
||||
/* XXX: Cannot hook into builtins with XCode for arm64. */
|
||||
#if !defined(ARMV8_OS_MACOS)
|
||||
#define __crc32b __builtin_arm_crc32b
|
||||
#define __crc32d __builtin_arm_crc32d
|
||||
#define __crc32w __builtin_arm_crc32w
|
||||
#define __crc32cw __builtin_arm_crc32cw
|
||||
#endif
|
||||
|
||||
#if defined(__aarch64__)
|
||||
#define TARGET_ARMV8_WITH_CRC __attribute__((target("crc")))
|
||||
#define TARGET_ARMV8_WITH_CRC __attribute__((target("aes,crc")))
|
||||
#else // !defined(__aarch64__)
|
||||
#define TARGET_ARMV8_WITH_CRC __attribute__((target("armv8-a,crc")))
|
||||
#endif // defined(__aarch64__)
|
||||
@ -198,15 +206,17 @@ uint32_t ZLIB_INTERNAL crc32_sse42_simd_( /* SSE4.2+PCLMUL */
|
||||
* allowed. We can just include arm_acle.h.
|
||||
*/
|
||||
#include <arm_acle.h>
|
||||
#include <arm_neon.h>
|
||||
#define TARGET_ARMV8_WITH_CRC
|
||||
#else // !defined(__GNUC__) && !defined(_aarch64__)
|
||||
#error ARM CRC32 SIMD extensions only supported for Clang and GCC
|
||||
#endif
|
||||
|
||||
TARGET_ARMV8_WITH_CRC
|
||||
uint32_t ZLIB_INTERNAL armv8_crc32_little(unsigned long crc,
|
||||
const unsigned char *buf,
|
||||
z_size_t len)
|
||||
uint32_t ZLIB_INTERNAL armv8_crc32_little(
|
||||
const unsigned char *buf,
|
||||
z_size_t len,
|
||||
uint32_t crc)
|
||||
{
|
||||
uint32_t c = (uint32_t) ~crc;
|
||||
|
||||
@ -244,4 +254,178 @@ uint32_t ZLIB_INTERNAL armv8_crc32_little(unsigned long crc,
|
||||
return ~c;
|
||||
}
|
||||
|
||||
#if defined(__aarch64__) || defined(ARMV8_OS_MACOS) /* aarch64 specific code. */
|
||||
|
||||
/*
|
||||
* crc32_pmull_simd_(): compute the crc32 of the buffer, where the buffer
|
||||
* length must be at least 64, and a multiple of 16. Based on:
|
||||
*
|
||||
* "Fast CRC Computation for Generic Polynomials Using PCLMULQDQ Instruction"
|
||||
* V. Gopal, E. Ozturk, et al., 2009, http://intel.ly/2ySEwL0
|
||||
*/
|
||||
TARGET_ARMV8_WITH_CRC
|
||||
static inline uint8x16_t pmull_lo(const uint64x2_t a, const uint64x2_t b)
|
||||
{
|
||||
uint8x16_t r;
|
||||
__asm__ __volatile__ ("pmull %0.1q, %1.1d, %2.1d \n\t"
|
||||
: "=w" (r) : "w" (a), "w" (b) );
|
||||
return r;
|
||||
}
|
||||
|
||||
TARGET_ARMV8_WITH_CRC
|
||||
static inline uint8x16_t pmull_01(const uint64x2_t a, const uint64x2_t b)
|
||||
{
|
||||
uint8x16_t r;
|
||||
__asm__ __volatile__ ("pmull %0.1q, %1.1d, %2.1d \n\t"
|
||||
: "=w" (r) : "w" (a), "w" (vgetq_lane_u64(b, 1)) );
|
||||
return r;
|
||||
}
|
||||
|
||||
TARGET_ARMV8_WITH_CRC
|
||||
static inline uint8x16_t pmull_hi(const uint64x2_t a, const uint64x2_t b)
|
||||
{
|
||||
uint8x16_t r;
|
||||
__asm__ __volatile__ ("pmull2 %0.1q, %1.2d, %2.2d \n\t"
|
||||
: "=w" (r) : "w" (a), "w" (b) );
|
||||
return r;
|
||||
}
|
||||
|
||||
TARGET_ARMV8_WITH_CRC
|
||||
uint32_t ZLIB_INTERNAL armv8_crc32_pmull_little(
|
||||
const unsigned char *buf,
|
||||
z_size_t len,
|
||||
uint32_t crc)
|
||||
{
|
||||
/*
|
||||
* Definitions of the bit-reflected domain constants k1,k2,k3, etc and
|
||||
* the CRC32+Barrett polynomials given at the end of the paper.
|
||||
*/
|
||||
static const uint64_t zalign(16) k1k2[] = { 0x0154442bd4, 0x01c6e41596 };
|
||||
static const uint64_t zalign(16) k3k4[] = { 0x01751997d0, 0x00ccaa009e };
|
||||
static const uint64_t zalign(16) k5k0[] = { 0x0163cd6124, 0x0000000000 };
|
||||
static const uint64_t zalign(16) poly[] = { 0x01db710641, 0x01f7011641 };
|
||||
|
||||
uint64x2_t x0, x1, x2, x3, x4, x5, x6, x7, x8, y5, y6, y7, y8;
|
||||
|
||||
/*
|
||||
* There's at least one block of 64.
|
||||
*/
|
||||
x1 = vld1q_u64((const uint64_t *)(buf + 0x00));
|
||||
x2 = vld1q_u64((const uint64_t *)(buf + 0x10));
|
||||
x3 = vld1q_u64((const uint64_t *)(buf + 0x20));
|
||||
x4 = vld1q_u64((const uint64_t *)(buf + 0x30));
|
||||
|
||||
x1 = veorq_u64(x1, (uint64x2_t) vsetq_lane_u32(crc, vdupq_n_u32(0), 0));
|
||||
|
||||
x0 = vld1q_u64(k1k2);
|
||||
|
||||
buf += 64;
|
||||
len -= 64;
|
||||
|
||||
/*
|
||||
* Parallel fold blocks of 64, if any.
|
||||
*/
|
||||
while (len >= 64)
|
||||
{
|
||||
x5 = (uint64x2_t) pmull_lo(x1, x0);
|
||||
x6 = (uint64x2_t) pmull_lo(x2, x0);
|
||||
x7 = (uint64x2_t) pmull_lo(x3, x0);
|
||||
x8 = (uint64x2_t) pmull_lo(x4, x0);
|
||||
|
||||
y5 = vld1q_u64((const uint64_t *)(buf + 0x00));
|
||||
y6 = vld1q_u64((const uint64_t *)(buf + 0x10));
|
||||
y7 = vld1q_u64((const uint64_t *)(buf + 0x20));
|
||||
y8 = vld1q_u64((const uint64_t *)(buf + 0x30));
|
||||
|
||||
x1 = (uint64x2_t) pmull_hi(x1, x0);
|
||||
x2 = (uint64x2_t) pmull_hi(x2, x0);
|
||||
x3 = (uint64x2_t) pmull_hi(x3, x0);
|
||||
x4 = (uint64x2_t) pmull_hi(x4, x0);
|
||||
|
||||
x1 = veorq_u64(x1, x5);
|
||||
x2 = veorq_u64(x2, x6);
|
||||
x3 = veorq_u64(x3, x7);
|
||||
x4 = veorq_u64(x4, x8);
|
||||
|
||||
x1 = veorq_u64(x1, y5);
|
||||
x2 = veorq_u64(x2, y6);
|
||||
x3 = veorq_u64(x3, y7);
|
||||
x4 = veorq_u64(x4, y8);
|
||||
|
||||
buf += 64;
|
||||
len -= 64;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fold into 128-bits.
|
||||
*/
|
||||
x0 = vld1q_u64(k3k4);
|
||||
|
||||
x5 = (uint64x2_t) pmull_lo(x1, x0);
|
||||
x1 = (uint64x2_t) pmull_hi(x1, x0);
|
||||
x1 = veorq_u64(x1, x2);
|
||||
x1 = veorq_u64(x1, x5);
|
||||
|
||||
x5 = (uint64x2_t) pmull_lo(x1, x0);
|
||||
x1 = (uint64x2_t) pmull_hi(x1, x0);
|
||||
x1 = veorq_u64(x1, x3);
|
||||
x1 = veorq_u64(x1, x5);
|
||||
|
||||
x5 = (uint64x2_t) pmull_lo(x1, x0);
|
||||
x1 = (uint64x2_t) pmull_hi(x1, x0);
|
||||
x1 = veorq_u64(x1, x4);
|
||||
x1 = veorq_u64(x1, x5);
|
||||
|
||||
/*
|
||||
* Single fold blocks of 16, if any.
|
||||
*/
|
||||
while (len >= 16)
|
||||
{
|
||||
x2 = vld1q_u64((const uint64_t *)buf);
|
||||
|
||||
x5 = (uint64x2_t) pmull_lo(x1, x0);
|
||||
x1 = (uint64x2_t) pmull_hi(x1, x0);
|
||||
x1 = veorq_u64(x1, x2);
|
||||
x1 = veorq_u64(x1, x5);
|
||||
|
||||
buf += 16;
|
||||
len -= 16;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fold 128-bits to 64-bits.
|
||||
*/
|
||||
static uint32_t zalign(16) mask[] = { ~0u, 0u, ~0u, 0u };
|
||||
|
||||
x2 = (uint64x2_t) pmull_01(x1, x0);
|
||||
x1 = (uint64x2_t) vextq_u8(vreinterpretq_u8_u64(x1), vdupq_n_u8(0), 8);
|
||||
x3 = (uint64x2_t) vld1q_u32(mask);
|
||||
x1 = veorq_u64(x1, x2);
|
||||
|
||||
x0 = vld1q_u64(k5k0);
|
||||
|
||||
x2 = (uint64x2_t) pmull_01(x2, x0);
|
||||
x2 = (uint64x2_t) vextq_u8(vreinterpretq_u8_u64(x1), vdupq_n_u8(0), 4);
|
||||
x1 = vandq_u64(x1, x3);
|
||||
x1 = (uint64x2_t) pmull_lo(x1, x0);
|
||||
x1 = veorq_u64(x1, x2);
|
||||
|
||||
/*
|
||||
* Barret reduce to 32-bits.
|
||||
*/
|
||||
x0 = vld1q_u64(poly);
|
||||
|
||||
x2 = vandq_u64(x1, x3);
|
||||
x2 = (uint64x2_t) pmull_01(x2, x0);
|
||||
x2 = vandq_u64(x2, x3);
|
||||
x2 = (uint64x2_t) pmull_lo(x2, x0);
|
||||
x1 = veorq_u64(x1, x2);
|
||||
|
||||
/*
|
||||
* Return the crc32.
|
||||
*/
|
||||
return vgetq_lane_u32(vreinterpretq_u32_u64(x1), 1);
|
||||
}
|
||||
#endif /* aarch64 specific code. */
|
||||
|
||||
#endif
|
||||
|
31
deps/zlib/crc32_simd.h
vendored
31
deps/zlib/crc32_simd.h
vendored
@ -1,6 +1,6 @@
|
||||
/* crc32_simd.h
|
||||
*
|
||||
* Copyright 2017 The Chromium Authors. All rights reserved.
|
||||
* Copyright 2017 The Chromium Authors
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the Chromium source repository LICENSE file.
|
||||
*/
|
||||
@ -15,10 +15,9 @@
|
||||
* crc32_sse42_simd_(): compute the crc32 of the buffer, where the buffer
|
||||
* length must be at least 64, and a multiple of 16.
|
||||
*/
|
||||
uint32_t ZLIB_INTERNAL crc32_sse42_simd_(
|
||||
const unsigned char *buf,
|
||||
z_size_t len,
|
||||
uint32_t crc);
|
||||
uint32_t ZLIB_INTERNAL crc32_sse42_simd_(const unsigned char* buf,
|
||||
z_size_t len,
|
||||
uint32_t crc);
|
||||
|
||||
/*
|
||||
* crc32_sse42_simd_ buffer size constraints: see the use in zlib/crc32.c
|
||||
@ -30,7 +29,23 @@ uint32_t ZLIB_INTERNAL crc32_sse42_simd_(
|
||||
/*
|
||||
* CRC32 checksums using ARMv8-a crypto instructions.
|
||||
*/
|
||||
uint32_t ZLIB_INTERNAL armv8_crc32_little(unsigned long crc,
|
||||
const unsigned char* buf,
|
||||
z_size_t len);
|
||||
uint32_t ZLIB_INTERNAL armv8_crc32_little(const unsigned char* buf,
|
||||
z_size_t len,
|
||||
uint32_t crc);
|
||||
|
||||
/* aarch64 specific code. */
|
||||
#if defined(__aarch64__)
|
||||
|
||||
/* 128 is the sweet spot at the time of coding (late 2020). */
|
||||
#define Z_CRC32_PMULL_MINIMUM_LENGTH 128
|
||||
#define Z_CRC32_PMULL_CHUNKSIZE_MASK 15
|
||||
|
||||
/*
|
||||
* CRC32 checksums using ARMv8-a PMULL instructions, where the buffer
|
||||
* length must be at least 64, and a multiple of 16.
|
||||
*/
|
||||
uint32_t ZLIB_INTERNAL armv8_crc32_pmull_little(const unsigned char* buf,
|
||||
z_size_t len,
|
||||
uint32_t crc);
|
||||
|
||||
#endif
|
||||
|
18
deps/zlib/crc_folding.c
vendored
18
deps/zlib/crc_folding.c
vendored
@ -18,15 +18,13 @@
|
||||
|
||||
#include "deflate.h"
|
||||
|
||||
#ifdef CRC32_SIMD_SSE42_PCLMUL
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <emmintrin.h>
|
||||
#include <immintrin.h>
|
||||
#include <wmmintrin.h>
|
||||
|
||||
#ifndef __GNUC__
|
||||
#define __attribute__()
|
||||
#endif
|
||||
|
||||
#define CRC_LOAD(s) \
|
||||
do { \
|
||||
__m128i xmm_crc0 = _mm_loadu_si128((__m128i *)s->crc0 + 0);\
|
||||
@ -43,7 +41,6 @@
|
||||
_mm_storeu_si128((__m128i *)s->crc0 + 4, xmm_crc_part);\
|
||||
} while (0);
|
||||
|
||||
__attribute__((target("sse4.2,pclmul")))
|
||||
ZLIB_INTERNAL void crc_fold_init(deflate_state *const s)
|
||||
{
|
||||
CRC_LOAD(s)
|
||||
@ -58,7 +55,6 @@ ZLIB_INTERNAL void crc_fold_init(deflate_state *const s)
|
||||
s->strm->adler = 0;
|
||||
}
|
||||
|
||||
__attribute__((target("sse4.2,pclmul")))
|
||||
local void fold_1(deflate_state *const s,
|
||||
__m128i *xmm_crc0, __m128i *xmm_crc1,
|
||||
__m128i *xmm_crc2, __m128i *xmm_crc3)
|
||||
@ -85,7 +81,6 @@ local void fold_1(deflate_state *const s,
|
||||
*xmm_crc3 = _mm_castps_si128(ps_res);
|
||||
}
|
||||
|
||||
__attribute__((target("sse4.2,pclmul")))
|
||||
local void fold_2(deflate_state *const s,
|
||||
__m128i *xmm_crc0, __m128i *xmm_crc1,
|
||||
__m128i *xmm_crc2, __m128i *xmm_crc3)
|
||||
@ -120,7 +115,6 @@ local void fold_2(deflate_state *const s,
|
||||
*xmm_crc3 = _mm_castps_si128(ps_res31);
|
||||
}
|
||||
|
||||
__attribute__((target("sse4.2,pclmul")))
|
||||
local void fold_3(deflate_state *const s,
|
||||
__m128i *xmm_crc0, __m128i *xmm_crc1,
|
||||
__m128i *xmm_crc2, __m128i *xmm_crc3)
|
||||
@ -161,7 +155,6 @@ local void fold_3(deflate_state *const s,
|
||||
*xmm_crc3 = _mm_castps_si128(ps_res32);
|
||||
}
|
||||
|
||||
__attribute__((target("sse4.2,pclmul")))
|
||||
local void fold_4(deflate_state *const s,
|
||||
__m128i *xmm_crc0, __m128i *xmm_crc1,
|
||||
__m128i *xmm_crc2, __m128i *xmm_crc3)
|
||||
@ -228,7 +221,6 @@ local const unsigned zalign(32) pshufb_shf_table[60] = {
|
||||
0x0201008f,0x06050403,0x0a090807,0x0e0d0c0b /* shl 1 (16 -15)/shr15*/
|
||||
};
|
||||
|
||||
__attribute__((target("sse4.2,pclmul")))
|
||||
local void partial_fold(deflate_state *const s, const size_t len,
|
||||
__m128i *xmm_crc0, __m128i *xmm_crc1,
|
||||
__m128i *xmm_crc2, __m128i *xmm_crc3,
|
||||
@ -279,7 +271,6 @@ local void partial_fold(deflate_state *const s, const size_t len,
|
||||
*xmm_crc3 = _mm_castps_si128(ps_res);
|
||||
}
|
||||
|
||||
__attribute__((target("sse4.2,pclmul")))
|
||||
ZLIB_INTERNAL void crc_fold_copy(deflate_state *const s,
|
||||
unsigned char *dst, const unsigned char *src, long len)
|
||||
{
|
||||
@ -294,7 +285,7 @@ ZLIB_INTERNAL void crc_fold_copy(deflate_state *const s,
|
||||
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);
|
||||
@ -436,7 +427,6 @@ local const unsigned zalign(16) crc_mask2[4] = {
|
||||
0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
|
||||
};
|
||||
|
||||
__attribute__((target("sse4.2,pclmul")))
|
||||
unsigned ZLIB_INTERNAL crc_fold_512to32(deflate_state *const s)
|
||||
{
|
||||
const __m128i xmm_mask = _mm_load_si128((__m128i *)crc_mask);
|
||||
@ -503,3 +493,5 @@ unsigned ZLIB_INTERNAL crc_fold_512to32(deflate_state *const s)
|
||||
return ~crc;
|
||||
CRC_SAVE(s)
|
||||
}
|
||||
|
||||
#endif /* CRC32_SIMD_SSE42_PCLMUL */
|
||||
|
379
deps/zlib/deflate.c
vendored
379
deps/zlib/deflate.c
vendored
@ -1,5 +1,5 @@
|
||||
/* deflate.c -- compress data using the deflation algorithm
|
||||
* Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler
|
||||
* Copyright (C) 1995-2022 Jean-loup Gailly and Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
@ -50,18 +50,22 @@
|
||||
/* @(#) $Id$ */
|
||||
#include <assert.h>
|
||||
#include "deflate.h"
|
||||
#include "x86.h"
|
||||
|
||||
#include "cpu_features.h"
|
||||
|
||||
#if defined(DEFLATE_SLIDE_HASH_SSE2) || defined(DEFLATE_SLIDE_HASH_NEON)
|
||||
#include "slide_hash_simd.h"
|
||||
#endif
|
||||
|
||||
#include "contrib/optimizations/insert_string.h"
|
||||
|
||||
#if (defined(__ARM_NEON__) || defined(__ARM_NEON))
|
||||
#include "contrib/optimizations/slide_hash_neon.h"
|
||||
#endif
|
||||
#if defined(CRC32_ARMV8_CRC32)
|
||||
#include "crc32_simd.h"
|
||||
#ifdef FASTEST
|
||||
/* See http://crbug.com/1113596 */
|
||||
#error "FASTEST is not supported in Chromium's zlib."
|
||||
#endif
|
||||
|
||||
const char deflate_copyright[] =
|
||||
" deflate 1.2.11 Copyright 1995-2017 Jean-loup Gailly and Mark Adler ";
|
||||
" deflate 1.2.13 Copyright 1995-2022 Jean-loup Gailly and Mark Adler ";
|
||||
/*
|
||||
If you use the zlib library in a product, an acknowledgment is welcome
|
||||
in the documentation of your product. If for some reason you cannot
|
||||
@ -95,14 +99,8 @@ local block_state deflate_huff OF((deflate_state *s, int flush));
|
||||
local void lm_init OF((deflate_state *s));
|
||||
local void putShortMSB OF((deflate_state *s, uInt b));
|
||||
local void flush_pending OF((z_streamp strm));
|
||||
unsigned ZLIB_INTERNAL deflate_read_buf OF((z_streamp strm, Bytef *buf, unsigned size));
|
||||
#ifdef ASMV
|
||||
# pragma message("Assembler code may have bugs -- use at your own risk")
|
||||
void match_init OF((void)); /* asm code initialization */
|
||||
uInt longest_match OF((deflate_state *s, IPos cur_match));
|
||||
#else
|
||||
local unsigned read_buf OF((z_streamp strm, Bytef *buf, unsigned size));
|
||||
local uInt longest_match OF((deflate_state *s, IPos cur_match));
|
||||
#endif
|
||||
|
||||
#ifdef ZLIB_DEBUG
|
||||
local void check_match OF((deflate_state *s, IPos start, IPos match,
|
||||
@ -171,10 +169,15 @@ local const config configuration_table[10] = {
|
||||
/* ===========================================================================
|
||||
* Initialize the hash table (avoiding 64K overflow for 16 bit systems).
|
||||
* prev[] will be initialized on the fly.
|
||||
* TODO(cavalcantii): optimization opportunity, check comments on:
|
||||
* https://chromium-review.googlesource.com/c/chromium/src/+/3561506/
|
||||
*/
|
||||
#define CLEAR_HASH(s) \
|
||||
s->head[s->hash_size-1] = NIL; \
|
||||
zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
|
||||
do { \
|
||||
s->head[s->hash_size - 1] = NIL; \
|
||||
zmemzero((Bytef *)s->head, \
|
||||
(unsigned)(s->hash_size - 1)*sizeof(*s->head)); \
|
||||
} while (0)
|
||||
|
||||
/* ===========================================================================
|
||||
* Slide the hash table when sliding the window down (could be avoided with 32
|
||||
@ -184,10 +187,11 @@ local const config configuration_table[10] = {
|
||||
local void slide_hash(s)
|
||||
deflate_state *s;
|
||||
{
|
||||
#if (defined(__ARM_NEON__) || defined(__ARM_NEON))
|
||||
/* NEON based hash table rebase. */
|
||||
return neon_slide_hash(s->head, s->prev, s->w_size, s->hash_size);
|
||||
#if defined(DEFLATE_SLIDE_HASH_SSE2) || defined(DEFLATE_SLIDE_HASH_NEON)
|
||||
slide_hash_simd(s->head, s->prev, s->w_size, s->hash_size);
|
||||
return;
|
||||
#endif
|
||||
|
||||
unsigned n, m;
|
||||
Posf *p;
|
||||
uInt wsize = s->w_size;
|
||||
@ -244,10 +248,8 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
|
||||
// for all wrapper formats (e.g. RAW, ZLIB, GZIP).
|
||||
// Feature detection is not triggered while using RAW mode (i.e. we never
|
||||
// call crc32() with a NULL buffer).
|
||||
#if defined(CRC32_ARMV8_CRC32)
|
||||
arm_check_features();
|
||||
#elif defined(CRC32_SIMD_SSE42_PCLMUL)
|
||||
x86_check_features();
|
||||
#if defined(CRC32_ARMV8_CRC32) || defined(CRC32_SIMD_SSE42_PCLMUL)
|
||||
cpu_check_features();
|
||||
#endif
|
||||
|
||||
if (version == Z_NULL || version[0] != my_version[0] ||
|
||||
@ -280,6 +282,8 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
|
||||
|
||||
if (windowBits < 0) { /* suppress zlib wrapper */
|
||||
wrap = 0;
|
||||
if (windowBits < -15)
|
||||
return Z_STREAM_ERROR;
|
||||
windowBits = -windowBits;
|
||||
}
|
||||
#ifdef GZIP
|
||||
@ -306,20 +310,37 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
|
||||
s->w_size = 1 << s->w_bits;
|
||||
s->w_mask = s->w_size - 1;
|
||||
|
||||
if (x86_cpu_enable_simd) {
|
||||
s->chromium_zlib_hash = 0;
|
||||
#if !defined(USE_ZLIB_RABIN_KARP_ROLLING_HASH)
|
||||
#if defined(TARGET_CPU_WITH_CRC) && defined(CRC32_SIMD_SSE42_PCLMUL)
|
||||
if (x86_cpu_enable_simd)
|
||||
s->chromium_zlib_hash = 1;
|
||||
#elif defined(TARGET_CPU_WITH_CRC) && defined(CRC32_ARMV8_CRC32)
|
||||
if (arm_cpu_enable_crc32)
|
||||
s->chromium_zlib_hash = 1;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
s->hash_bits = memLevel + 7;
|
||||
if (s->chromium_zlib_hash && s->hash_bits < 15) {
|
||||
s->hash_bits = 15;
|
||||
} else {
|
||||
s->hash_bits = memLevel + 7;
|
||||
}
|
||||
|
||||
s->hash_size = 1 << s->hash_bits;
|
||||
s->hash_mask = s->hash_size - 1;
|
||||
s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
|
||||
s->hash_shift = ((s->hash_bits + MIN_MATCH-1) / MIN_MATCH);
|
||||
|
||||
s->window = (Bytef *) ZALLOC(strm,
|
||||
s->w_size + window_padding,
|
||||
2*sizeof(Byte));
|
||||
/* Avoid use of unitialized values in the window, see crbug.com/1137613 and
|
||||
* crbug.com/1144420 */
|
||||
zmemzero(s->window, (s->w_size + window_padding) * (2 * sizeof(Byte)));
|
||||
s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos));
|
||||
/* Avoid use of uninitialized value, see:
|
||||
* https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=11360
|
||||
*/
|
||||
zmemzero(s->prev, s->w_size * sizeof(Pos));
|
||||
s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos));
|
||||
|
||||
s->high_water = 0; /* nothing written to s->window yet */
|
||||
@ -342,11 +363,11 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
|
||||
* sym_buf value to read moves forward three bytes. From that symbol, up to
|
||||
* 31 bits are written to pending_buf. The closest the written pending_buf
|
||||
* bits gets to the next sym_buf symbol to read is just before the last
|
||||
* code is written. At that time, 31*(n-2) bits have been written, just
|
||||
* after 24*(n-2) bits have been consumed from sym_buf. sym_buf starts at
|
||||
* 8*n bits into pending_buf. (Note that the symbol buffer fills when n-1
|
||||
* code is written. At that time, 31*(n - 2) bits have been written, just
|
||||
* after 24*(n - 2) bits have been consumed from sym_buf. sym_buf starts at
|
||||
* 8*n bits into pending_buf. (Note that the symbol buffer fills when n - 1
|
||||
* symbols are written.) The closest the writing gets to what is unread is
|
||||
* then n+14 bits. Here n is lit_bufsize, which is 16384 by default, and
|
||||
* then n + 14 bits. Here n is lit_bufsize, which is 16384 by default, and
|
||||
* can range from 128 to 32768.
|
||||
*
|
||||
* Therefore, at a minimum, there are 142 bits of space between what is
|
||||
@ -391,7 +412,7 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
|
||||
/* =========================================================================
|
||||
* Check for a valid deflate stream state. Return 0 if ok, 1 if not.
|
||||
*/
|
||||
local int deflateStateCheck (strm)
|
||||
local int deflateStateCheck(strm)
|
||||
z_streamp strm;
|
||||
{
|
||||
deflate_state *s;
|
||||
@ -414,7 +435,7 @@ local int deflateStateCheck (strm)
|
||||
}
|
||||
|
||||
/* ========================================================================= */
|
||||
int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)
|
||||
int ZEXPORT deflateSetDictionary(strm, dictionary, dictLength)
|
||||
z_streamp strm;
|
||||
const Bytef *dictionary;
|
||||
uInt dictLength;
|
||||
@ -435,7 +456,7 @@ int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)
|
||||
/* when using zlib wrappers, compute Adler-32 for provided dictionary */
|
||||
if (wrap == 1)
|
||||
strm->adler = adler32(strm->adler, dictionary, dictLength);
|
||||
s->wrap = 0; /* avoid computing Adler-32 in deflate_read_buf */
|
||||
s->wrap = 0; /* avoid computing Adler-32 in read_buf */
|
||||
|
||||
/* if dictionary would fill window, just replace the history */
|
||||
if (dictLength >= s->w_size) {
|
||||
@ -479,7 +500,7 @@ int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)
|
||||
}
|
||||
|
||||
/* ========================================================================= */
|
||||
int ZEXPORT deflateGetDictionary (strm, dictionary, dictLength)
|
||||
int ZEXPORT deflateGetDictionary(strm, dictionary, dictLength)
|
||||
z_streamp strm;
|
||||
Bytef *dictionary;
|
||||
uInt *dictLength;
|
||||
@ -501,7 +522,7 @@ int ZEXPORT deflateGetDictionary (strm, dictionary, dictLength)
|
||||
}
|
||||
|
||||
/* ========================================================================= */
|
||||
int ZEXPORT deflateResetKeep (strm)
|
||||
int ZEXPORT deflateResetKeep(strm)
|
||||
z_streamp strm;
|
||||
{
|
||||
deflate_state *s;
|
||||
@ -525,13 +546,13 @@ int ZEXPORT deflateResetKeep (strm)
|
||||
#ifdef GZIP
|
||||
s->wrap == 2 ? GZIP_STATE :
|
||||
#endif
|
||||
s->wrap ? INIT_STATE : BUSY_STATE;
|
||||
INIT_STATE;
|
||||
strm->adler =
|
||||
#ifdef GZIP
|
||||
s->wrap == 2 ? crc32(0L, Z_NULL, 0) :
|
||||
#endif
|
||||
adler32(0L, Z_NULL, 0);
|
||||
s->last_flush = Z_NO_FLUSH;
|
||||
s->last_flush = -2;
|
||||
|
||||
_tr_init(s);
|
||||
|
||||
@ -539,7 +560,7 @@ int ZEXPORT deflateResetKeep (strm)
|
||||
}
|
||||
|
||||
/* ========================================================================= */
|
||||
int ZEXPORT deflateReset (strm)
|
||||
int ZEXPORT deflateReset(strm)
|
||||
z_streamp strm;
|
||||
{
|
||||
int ret;
|
||||
@ -551,7 +572,7 @@ int ZEXPORT deflateReset (strm)
|
||||
}
|
||||
|
||||
/* ========================================================================= */
|
||||
int ZEXPORT deflateSetHeader (strm, head)
|
||||
int ZEXPORT deflateSetHeader(strm, head)
|
||||
z_streamp strm;
|
||||
gz_headerp head;
|
||||
{
|
||||
@ -562,7 +583,7 @@ int ZEXPORT deflateSetHeader (strm, head)
|
||||
}
|
||||
|
||||
/* ========================================================================= */
|
||||
int ZEXPORT deflatePending (strm, pending, bits)
|
||||
int ZEXPORT deflatePending(strm, pending, bits)
|
||||
unsigned *pending;
|
||||
int *bits;
|
||||
z_streamp strm;
|
||||
@ -576,7 +597,7 @@ int ZEXPORT deflatePending (strm, pending, bits)
|
||||
}
|
||||
|
||||
/* ========================================================================= */
|
||||
int ZEXPORT deflatePrime (strm, bits, value)
|
||||
int ZEXPORT deflatePrime(strm, bits, value)
|
||||
z_streamp strm;
|
||||
int bits;
|
||||
int value;
|
||||
@ -586,7 +607,8 @@ int ZEXPORT deflatePrime (strm, bits, value)
|
||||
|
||||
if (deflateStateCheck(strm)) return Z_STREAM_ERROR;
|
||||
s = strm->state;
|
||||
if (s->sym_buf < s->pending_out + ((Buf_size + 7) >> 3))
|
||||
if (bits < 0 || bits > 16 ||
|
||||
s->sym_buf < s->pending_out + ((Buf_size + 7) >> 3))
|
||||
return Z_BUF_ERROR;
|
||||
do {
|
||||
put = Buf_size - s->bi_valid;
|
||||
@ -624,12 +646,12 @@ int ZEXPORT deflateParams(strm, level, strategy)
|
||||
func = configuration_table[s->level].func;
|
||||
|
||||
if ((strategy != s->strategy || func != configuration_table[level].func) &&
|
||||
s->high_water) {
|
||||
s->last_flush != -2) {
|
||||
/* Flush the last buffer: */
|
||||
int err = deflate(strm, Z_BLOCK);
|
||||
if (err == Z_STREAM_ERROR)
|
||||
return err;
|
||||
if (strm->avail_out == 0)
|
||||
if (strm->avail_in || (s->strstart - s->block_start) + s->lookahead)
|
||||
return Z_BUF_ERROR;
|
||||
}
|
||||
if (s->level != level) {
|
||||
@ -670,36 +692,50 @@ int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain)
|
||||
}
|
||||
|
||||
/* =========================================================================
|
||||
* For the default windowBits of 15 and memLevel of 8, this function returns
|
||||
* a close to exact, as well as small, upper bound on the compressed size.
|
||||
* They are coded as constants here for a reason--if the #define's are
|
||||
* changed, then this function needs to be changed as well. The return
|
||||
* value for 15 and 8 only works for those exact settings.
|
||||
* For the default windowBits of 15 and memLevel of 8, this function returns a
|
||||
* close to exact, as well as small, upper bound on the compressed size. This
|
||||
* is an expansion of ~0.03%, plus a small constant.
|
||||
*
|
||||
* For any setting other than those defaults for windowBits and memLevel,
|
||||
* the value returned is a conservative worst case for the maximum expansion
|
||||
* resulting from using fixed blocks instead of stored blocks, which deflate
|
||||
* can emit on compressed data for some combinations of the parameters.
|
||||
* For any setting other than those defaults for windowBits and memLevel, one
|
||||
* of two worst case bounds is returned. This is at most an expansion of ~4% or
|
||||
* ~13%, plus a small constant.
|
||||
*
|
||||
* This function could be more sophisticated to provide closer upper bounds for
|
||||
* every combination of windowBits and memLevel. But even the conservative
|
||||
* upper bound of about 14% expansion does not seem onerous for output buffer
|
||||
* allocation.
|
||||
* Both the 0.03% and 4% derive from the overhead of stored blocks. The first
|
||||
* one is for stored blocks of 16383 bytes (memLevel == 8), whereas the second
|
||||
* is for stored blocks of 127 bytes (the worst case memLevel == 1). The
|
||||
* expansion results from five bytes of header for each stored block.
|
||||
*
|
||||
* The larger expansion of 13% results from a window size less than or equal to
|
||||
* the symbols buffer size (windowBits <= memLevel + 7). In that case some of
|
||||
* the data being compressed may have slid out of the sliding window, impeding
|
||||
* a stored block from being emitted. Then the only choice is a fixed or
|
||||
* dynamic block, where a fixed block limits the maximum expansion to 9 bits
|
||||
* per 8-bit byte, plus 10 bits for every block. The smallest block size for
|
||||
* which this can occur is 255 (memLevel == 2).
|
||||
*
|
||||
* Shifts are used to approximate divisions, for speed.
|
||||
*/
|
||||
uLong ZEXPORT deflateBound(strm, sourceLen)
|
||||
z_streamp strm;
|
||||
uLong sourceLen;
|
||||
{
|
||||
deflate_state *s;
|
||||
uLong complen, wraplen;
|
||||
uLong fixedlen, storelen, wraplen;
|
||||
|
||||
/* conservative upper bound for compressed data */
|
||||
complen = sourceLen +
|
||||
((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5;
|
||||
/* upper bound for fixed blocks with 9-bit literals and length 255
|
||||
(memLevel == 2, which is the lowest that may not use stored blocks) --
|
||||
~13% overhead plus a small constant */
|
||||
fixedlen = sourceLen + (sourceLen >> 3) + (sourceLen >> 8) +
|
||||
(sourceLen >> 9) + 4;
|
||||
|
||||
/* if can't get parameters, return conservative bound plus zlib wrapper */
|
||||
/* upper bound for stored blocks with length 127 (memLevel == 1) --
|
||||
~4% overhead plus a small constant */
|
||||
storelen = sourceLen + (sourceLen >> 5) + (sourceLen >> 7) +
|
||||
(sourceLen >> 11) + 7;
|
||||
|
||||
/* if can't get parameters, return larger bound plus a zlib wrapper */
|
||||
if (deflateStateCheck(strm))
|
||||
return complen + 6;
|
||||
return (fixedlen > storelen ? fixedlen : storelen) + 6;
|
||||
|
||||
/* compute wrapper length */
|
||||
s = strm->state;
|
||||
@ -736,11 +772,12 @@ uLong ZEXPORT deflateBound(strm, sourceLen)
|
||||
wraplen = 6;
|
||||
}
|
||||
|
||||
/* if not default parameters, return conservative bound */
|
||||
/* if not default parameters, return one of the conservative bounds */
|
||||
if (s->w_bits != 15 || s->hash_bits != 8 + 7)
|
||||
return complen + wraplen;
|
||||
return (s->w_bits <= s->hash_bits ? fixedlen : storelen) + wraplen;
|
||||
|
||||
/* default settings: return tight bound for that case */
|
||||
/* default settings: return tight bound for that case -- ~0.03% overhead
|
||||
plus a small constant */
|
||||
return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
|
||||
(sourceLen >> 25) + 13 - 6 + wraplen;
|
||||
}
|
||||
@ -750,7 +787,7 @@ uLong ZEXPORT deflateBound(strm, sourceLen)
|
||||
* IN assertion: the stream state is correct and there is enough room in
|
||||
* pending_buf.
|
||||
*/
|
||||
local void putShortMSB (s, b)
|
||||
local void putShortMSB(s, b)
|
||||
deflate_state *s;
|
||||
uInt b;
|
||||
{
|
||||
@ -762,7 +799,7 @@ local void putShortMSB (s, b)
|
||||
* Flush as much pending output as possible. All deflate() output, except for
|
||||
* some deflate_stored() output, goes through this function so some
|
||||
* applications may wish to modify it to avoid allocating a large
|
||||
* strm->next_out buffer and copying into it. (See also deflate_read_buf()).
|
||||
* strm->next_out buffer and copying into it. (See also read_buf()).
|
||||
*/
|
||||
local void flush_pending(strm)
|
||||
z_streamp strm;
|
||||
@ -797,7 +834,7 @@ local void flush_pending(strm)
|
||||
} while (0)
|
||||
|
||||
/* ========================================================================= */
|
||||
int ZEXPORT deflate (strm, flush)
|
||||
int ZEXPORT deflate(strm, flush)
|
||||
z_streamp strm;
|
||||
int flush;
|
||||
{
|
||||
@ -848,9 +885,11 @@ int ZEXPORT deflate (strm, flush)
|
||||
}
|
||||
|
||||
/* Write the header */
|
||||
if (s->status == INIT_STATE && s->wrap == 0)
|
||||
s->status = BUSY_STATE;
|
||||
if (s->status == INIT_STATE) {
|
||||
/* zlib header */
|
||||
uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
|
||||
uInt header = (Z_DEFLATED + ((s->w_bits - 8) << 4)) << 8;
|
||||
uInt level_flags;
|
||||
|
||||
if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2)
|
||||
@ -1111,7 +1150,7 @@ int ZEXPORT deflate (strm, flush)
|
||||
}
|
||||
|
||||
/* ========================================================================= */
|
||||
int ZEXPORT deflateEnd (strm)
|
||||
int ZEXPORT deflateEnd(strm)
|
||||
z_streamp strm;
|
||||
{
|
||||
int status;
|
||||
@ -1137,7 +1176,7 @@ int ZEXPORT deflateEnd (strm)
|
||||
* To simplify the source, this is not supported for 16-bit MSDOS (which
|
||||
* doesn't have enough memory anyway to duplicate compression states).
|
||||
*/
|
||||
int ZEXPORT deflateCopy (dest, source)
|
||||
int ZEXPORT deflateCopy(dest, source)
|
||||
z_streamp dest;
|
||||
z_streamp source;
|
||||
{
|
||||
@ -1196,7 +1235,7 @@ int ZEXPORT deflateCopy (dest, source)
|
||||
* allocating a large strm->next_in buffer and copying from it.
|
||||
* (See also flush_pending()).
|
||||
*/
|
||||
ZLIB_INTERNAL unsigned deflate_read_buf(strm, buf, size)
|
||||
local unsigned read_buf(strm, buf, size)
|
||||
z_streamp strm;
|
||||
Bytef *buf;
|
||||
unsigned size;
|
||||
@ -1211,7 +1250,7 @@ ZLIB_INTERNAL unsigned deflate_read_buf(strm, buf, size)
|
||||
#ifdef GZIP
|
||||
if (strm->state->wrap == 2)
|
||||
copy_with_crc(strm, buf, len);
|
||||
else
|
||||
else
|
||||
#endif
|
||||
{
|
||||
zmemcpy(buf, strm->next_in, len);
|
||||
@ -1227,7 +1266,7 @@ ZLIB_INTERNAL unsigned deflate_read_buf(strm, buf, size)
|
||||
/* ===========================================================================
|
||||
* Initialize the "longest match" routines for a new zlib stream
|
||||
*/
|
||||
local void lm_init (s)
|
||||
local void lm_init(s)
|
||||
deflate_state *s;
|
||||
{
|
||||
s->window_size = (ulg)2L*s->w_size;
|
||||
@ -1248,11 +1287,6 @@ local void lm_init (s)
|
||||
s->match_length = s->prev_length = MIN_MATCH-1;
|
||||
s->match_available = 0;
|
||||
s->ins_h = 0;
|
||||
#ifndef FASTEST
|
||||
#ifdef ASMV
|
||||
match_init(); /* initialize the asm code */
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef FASTEST
|
||||
@ -1265,10 +1299,6 @@ local void lm_init (s)
|
||||
* string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
|
||||
* OUT assertion: the match length is not greater than s->lookahead.
|
||||
*/
|
||||
#ifndef ASMV
|
||||
/* 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)
|
||||
deflate_state *s;
|
||||
IPos cur_match; /* current match */
|
||||
@ -1293,10 +1323,10 @@ local uInt longest_match(s, cur_match)
|
||||
*/
|
||||
register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
|
||||
register ush scan_start = *(ushf*)scan;
|
||||
register ush scan_end = *(ushf*)(scan+best_len-1);
|
||||
register ush scan_end = *(ushf*)(scan + best_len - 1);
|
||||
#else
|
||||
register Bytef *strend = s->window + s->strstart + MAX_MATCH;
|
||||
register Byte scan_end1 = scan[best_len-1];
|
||||
register Byte scan_end1 = scan[best_len - 1];
|
||||
register Byte scan_end = scan[best_len];
|
||||
#endif
|
||||
|
||||
@ -1314,7 +1344,8 @@ local uInt longest_match(s, cur_match)
|
||||
*/
|
||||
if ((uInt)nice_match > s->lookahead) nice_match = (int)s->lookahead;
|
||||
|
||||
Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
|
||||
Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,
|
||||
"need lookahead");
|
||||
|
||||
do {
|
||||
Assert(cur_match < s->strstart, "no future");
|
||||
@ -1332,53 +1363,72 @@ local uInt longest_match(s, cur_match)
|
||||
/* This code assumes sizeof(unsigned short) == 2. Do not use
|
||||
* UNALIGNED_OK if your compiler uses a different size.
|
||||
*/
|
||||
if (*(ushf*)(match+best_len-1) != scan_end ||
|
||||
if (*(ushf*)(match + best_len - 1) != scan_end ||
|
||||
*(ushf*)match != scan_start) continue;
|
||||
|
||||
/* It is not necessary to compare scan[2] and match[2] since they are
|
||||
* always equal when the other bytes match, given that the hash keys
|
||||
* are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
|
||||
* strstart+3, +5, ... up to strstart+257. We check for insufficient
|
||||
* strstart + 3, + 5, up to strstart + 257. We check for insufficient
|
||||
* lookahead only every 4th comparison; the 128th check will be made
|
||||
* at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
|
||||
* at strstart + 257. If MAX_MATCH-2 is not a multiple of 8, it is
|
||||
* necessary to put more guard bytes at the end of the window, or
|
||||
* to check more often for insufficient lookahead.
|
||||
*/
|
||||
Assert(scan[2] == match[2], "scan[2]?");
|
||||
if (!s->chromium_zlib_hash) {
|
||||
Assert(scan[2] == match[2], "scan[2]?");
|
||||
} else {
|
||||
/* When using CRC hashing, scan[2] and match[2] may mismatch, but in
|
||||
* that case at least one of the other hashed bytes will mismatch
|
||||
* also. Bytes 0 and 1 were already checked above, and we know there
|
||||
* are at least four bytes to check otherwise the mismatch would have
|
||||
* been found by the scan_end comparison above, so: */
|
||||
Assert(scan[2] == match[2] || scan[3] != match[3], "scan[2]??");
|
||||
}
|
||||
scan++, match++;
|
||||
do {
|
||||
} while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
|
||||
*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
|
||||
*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
|
||||
*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
|
||||
} while (*(ushf*)(scan += 2) == *(ushf*)(match += 2) &&
|
||||
*(ushf*)(scan += 2) == *(ushf*)(match += 2) &&
|
||||
*(ushf*)(scan += 2) == *(ushf*)(match += 2) &&
|
||||
*(ushf*)(scan += 2) == *(ushf*)(match += 2) &&
|
||||
scan < strend);
|
||||
/* The funny "do {}" generates better code on most compilers */
|
||||
|
||||
/* Here, scan <= window+strstart+257 */
|
||||
Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
|
||||
/* Here, scan <= window + strstart + 257 */
|
||||
Assert(scan <= s->window+(unsigned)(s->window_size - 1),
|
||||
"wild scan");
|
||||
if (*scan == *match) scan++;
|
||||
|
||||
len = (MAX_MATCH - 1) - (int)(strend-scan);
|
||||
len = (MAX_MATCH - 1) - (int)(strend - scan);
|
||||
scan = strend - (MAX_MATCH-1);
|
||||
|
||||
#else /* UNALIGNED_OK */
|
||||
|
||||
if (match[best_len] != scan_end ||
|
||||
match[best_len-1] != scan_end1 ||
|
||||
match[best_len - 1] != scan_end1 ||
|
||||
*match != *scan ||
|
||||
*++match != scan[1]) continue;
|
||||
|
||||
/* The check at best_len-1 can be removed because it will be made
|
||||
/* The check at best_len - 1 can be removed because it will be made
|
||||
* again later. (This heuristic is not always a win.)
|
||||
* It is not necessary to compare scan[2] and match[2] since they
|
||||
* are always equal when the other bytes match, given that
|
||||
* the hash keys are equal and that HASH_BITS >= 8.
|
||||
*/
|
||||
scan += 2, match++;
|
||||
Assert(*scan == *match, "match[2]?");
|
||||
if (!s->chromium_zlib_hash) {
|
||||
Assert(*scan == *match, "match[2]?");
|
||||
} else {
|
||||
/* When using CRC hashing, scan[2] and match[2] may mismatch, but in
|
||||
* that case at least one of the other hashed bytes will mismatch
|
||||
* also. Bytes 0 and 1 were already checked above, and we know there
|
||||
* are at least four bytes to check otherwise the mismatch would have
|
||||
* been found by the scan_end comparison above, so: */
|
||||
Assert(*scan == *match || scan[1] != match[1], "match[2]??");
|
||||
}
|
||||
|
||||
/* We check for insufficient lookahead only every 8th comparison;
|
||||
* the 256th check will be made at strstart+258.
|
||||
* the 256th check will be made at strstart + 258.
|
||||
*/
|
||||
do {
|
||||
} while (*++scan == *++match && *++scan == *++match &&
|
||||
@ -1387,7 +1437,8 @@ local uInt longest_match(s, cur_match)
|
||||
*++scan == *++match && *++scan == *++match &&
|
||||
scan < strend);
|
||||
|
||||
Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
|
||||
Assert(scan <= s->window + (unsigned)(s->window_size - 1),
|
||||
"wild scan");
|
||||
|
||||
len = MAX_MATCH - (int)(strend - scan);
|
||||
scan = strend - MAX_MATCH;
|
||||
@ -1399,9 +1450,9 @@ local uInt longest_match(s, cur_match)
|
||||
best_len = len;
|
||||
if (len >= nice_match) break;
|
||||
#ifdef UNALIGNED_OK
|
||||
scan_end = *(ushf*)(scan+best_len-1);
|
||||
scan_end = *(ushf*)(scan + best_len - 1);
|
||||
#else
|
||||
scan_end1 = scan[best_len-1];
|
||||
scan_end1 = scan[best_len - 1];
|
||||
scan_end = scan[best_len];
|
||||
#endif
|
||||
}
|
||||
@ -1411,7 +1462,6 @@ local uInt longest_match(s, cur_match)
|
||||
if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
|
||||
return s->lookahead;
|
||||
}
|
||||
#endif /* ASMV */
|
||||
|
||||
#else /* FASTEST */
|
||||
|
||||
@ -1432,7 +1482,8 @@ local uInt longest_match(s, cur_match)
|
||||
*/
|
||||
Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
|
||||
|
||||
Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
|
||||
Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,
|
||||
"need lookahead");
|
||||
|
||||
Assert(cur_match < s->strstart, "no future");
|
||||
|
||||
@ -1442,7 +1493,7 @@ local uInt longest_match(s, cur_match)
|
||||
*/
|
||||
if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1;
|
||||
|
||||
/* The check at best_len-1 can be removed because it will be made
|
||||
/* The check at best_len - 1 can be removed because it will be made
|
||||
* again later. (This heuristic is not always a win.)
|
||||
* It is not necessary to compare scan[2] and match[2] since they
|
||||
* are always equal when the other bytes match, given that
|
||||
@ -1452,7 +1503,7 @@ local uInt longest_match(s, cur_match)
|
||||
Assert(*scan == *match, "match[2]?");
|
||||
|
||||
/* We check for insufficient lookahead only every 8th comparison;
|
||||
* the 256th check will be made at strstart+258.
|
||||
* the 256th check will be made at strstart + 258.
|
||||
*/
|
||||
do {
|
||||
} while (*++scan == *++match && *++scan == *++match &&
|
||||
@ -1461,7 +1512,7 @@ local uInt longest_match(s, cur_match)
|
||||
*++scan == *++match && *++scan == *++match &&
|
||||
scan < strend);
|
||||
|
||||
Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
|
||||
Assert(scan <= s->window + (unsigned)(s->window_size - 1), "wild scan");
|
||||
|
||||
len = MAX_MATCH - (int)(strend - scan);
|
||||
|
||||
@ -1497,7 +1548,7 @@ local void check_match(s, start, match, length)
|
||||
z_error("invalid match");
|
||||
}
|
||||
if (z_verbose > 1) {
|
||||
fprintf(stderr,"\\[%d,%d]", start-match, length);
|
||||
fprintf(stderr,"\\[%d,%d]", start - match, length);
|
||||
do { putc(s->window[start++], stderr); } while (--length != 0);
|
||||
}
|
||||
}
|
||||
@ -1515,19 +1566,7 @@ local void check_match(s, start, match, length)
|
||||
* performed for at least two bytes (required for the zip translate_eol
|
||||
* option -- not supported here).
|
||||
*/
|
||||
local void fill_window_c(deflate_state *s);
|
||||
|
||||
local void fill_window(deflate_state *s)
|
||||
{
|
||||
if (x86_cpu_enable_simd) {
|
||||
fill_window_sse(s);
|
||||
return;
|
||||
}
|
||||
|
||||
fill_window_c(s);
|
||||
}
|
||||
|
||||
local void fill_window_c(s)
|
||||
local void fill_window(s)
|
||||
deflate_state *s;
|
||||
{
|
||||
unsigned n;
|
||||
@ -1555,12 +1594,14 @@ local void fill_window_c(s)
|
||||
/* If the window is almost full and there is insufficient lookahead,
|
||||
* move the upper half to the lower one to make room in the upper half.
|
||||
*/
|
||||
if (s->strstart >= wsize+MAX_DIST(s)) {
|
||||
if (s->strstart >= wsize + MAX_DIST(s)) {
|
||||
|
||||
zmemcpy(s->window, s->window+wsize, (unsigned)wsize - more);
|
||||
zmemcpy(s->window, s->window + wsize, (unsigned)wsize - more);
|
||||
s->match_start -= wsize;
|
||||
s->strstart -= wsize; /* we now have strstart >= MAX_DIST */
|
||||
s->block_start -= (long) wsize;
|
||||
if (s->insert > s->strstart)
|
||||
s->insert = s->strstart;
|
||||
slide_hash(s);
|
||||
more += wsize;
|
||||
}
|
||||
@ -1579,9 +1620,23 @@ local void fill_window_c(s)
|
||||
*/
|
||||
Assert(more >= 2, "more < 2");
|
||||
|
||||
n = deflate_read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
|
||||
n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
|
||||
s->lookahead += n;
|
||||
|
||||
/* Initialize the hash value now that we have some input: */
|
||||
if (s->chromium_zlib_hash) {
|
||||
/* chromium hash reads 4 bytes */
|
||||
if (s->lookahead + s->insert > MIN_MATCH) {
|
||||
uInt str = s->strstart - s->insert;
|
||||
while (s->insert) {
|
||||
insert_string(s, str);
|
||||
str++;
|
||||
s->insert--;
|
||||
if (s->lookahead + s->insert <= MIN_MATCH)
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else
|
||||
/* Initialize the hash value now that we have some input: */
|
||||
if (s->lookahead + s->insert >= MIN_MATCH) {
|
||||
uInt str = s->strstart - s->insert;
|
||||
@ -1686,7 +1741,7 @@ local void fill_window_c(s)
|
||||
*
|
||||
* deflate_stored() is written to minimize the number of times an input byte is
|
||||
* copied. It is most efficient with large input and output buffers, which
|
||||
* maximizes the opportunites to have a single copy from next_in to next_out.
|
||||
* maximizes the opportunities to have a single copy from next_in to next_out.
|
||||
*/
|
||||
local block_state deflate_stored(s, flush)
|
||||
deflate_state *s;
|
||||
@ -1768,7 +1823,7 @@ local block_state deflate_stored(s, flush)
|
||||
* the check value.
|
||||
*/
|
||||
if (len) {
|
||||
deflate_read_buf(s->strm, s->strm->next_out, len);
|
||||
read_buf(s->strm, s->strm->next_out, len);
|
||||
s->strm->next_out += len;
|
||||
s->strm->avail_out -= len;
|
||||
s->strm->total_out += len;
|
||||
@ -1790,6 +1845,7 @@ local block_state deflate_stored(s, flush)
|
||||
s->matches = 2; /* clear hash */
|
||||
zmemcpy(s->window, s->strm->next_in - s->w_size, s->w_size);
|
||||
s->strstart = s->w_size;
|
||||
s->insert = s->strstart;
|
||||
}
|
||||
else {
|
||||
if (s->window_size - s->strstart <= used) {
|
||||
@ -1798,12 +1854,14 @@ local block_state deflate_stored(s, flush)
|
||||
zmemcpy(s->window, s->window + s->w_size, s->strstart);
|
||||
if (s->matches < 2)
|
||||
s->matches++; /* add a pending slide_hash() */
|
||||
if (s->insert > s->strstart)
|
||||
s->insert = s->strstart;
|
||||
}
|
||||
zmemcpy(s->window + s->strstart, s->strm->next_in - used, used);
|
||||
s->strstart += used;
|
||||
s->insert += MIN(used, s->w_size - s->insert);
|
||||
}
|
||||
s->block_start = s->strstart;
|
||||
s->insert += MIN(used, s->w_size - s->insert);
|
||||
}
|
||||
if (s->high_water < s->strstart)
|
||||
s->high_water = s->strstart;
|
||||
@ -1818,7 +1876,7 @@ local block_state deflate_stored(s, flush)
|
||||
return block_done;
|
||||
|
||||
/* Fill the window with any remaining input. */
|
||||
have = s->window_size - s->strstart - 1;
|
||||
have = s->window_size - s->strstart;
|
||||
if (s->strm->avail_in > have && s->block_start >= (long)s->w_size) {
|
||||
/* Slide the window down. */
|
||||
s->block_start -= s->w_size;
|
||||
@ -1827,12 +1885,15 @@ local block_state deflate_stored(s, flush)
|
||||
if (s->matches < 2)
|
||||
s->matches++; /* add a pending slide_hash() */
|
||||
have += s->w_size; /* more space now */
|
||||
if (s->insert > s->strstart)
|
||||
s->insert = s->strstart;
|
||||
}
|
||||
if (have > s->strm->avail_in)
|
||||
have = s->strm->avail_in;
|
||||
if (have) {
|
||||
deflate_read_buf(s->strm, s->window + s->strstart, have);
|
||||
read_buf(s->strm, s->window + s->strstart, have);
|
||||
s->strstart += have;
|
||||
s->insert += MIN(have, s->w_size - s->insert);
|
||||
}
|
||||
if (s->high_water < s->strstart)
|
||||
s->high_water = s->strstart;
|
||||
@ -1890,7 +1951,7 @@ local block_state deflate_fast(s, flush)
|
||||
if (s->lookahead == 0) break; /* flush the current block */
|
||||
}
|
||||
|
||||
/* Insert the string window[strstart .. strstart+2] in the
|
||||
/* Insert the string window[strstart .. strstart + 2] in the
|
||||
* dictionary, and set hash_head to the head of the hash chain:
|
||||
*/
|
||||
hash_head = NIL;
|
||||
@ -1937,19 +1998,22 @@ local block_state deflate_fast(s, flush)
|
||||
{
|
||||
s->strstart += s->match_length;
|
||||
s->match_length = 0;
|
||||
s->ins_h = s->window[s->strstart];
|
||||
UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
|
||||
|
||||
if (!s->chromium_zlib_hash) {
|
||||
s->ins_h = s->window[s->strstart];
|
||||
UPDATE_HASH(s, s->ins_h, s->window[s->strstart + 1]);
|
||||
#if MIN_MATCH != 3
|
||||
Call UPDATE_HASH() MIN_MATCH-3 more times
|
||||
Call UPDATE_HASH() MIN_MATCH-3 more times
|
||||
#endif
|
||||
/* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
|
||||
* matter since it will be recomputed at next deflate call.
|
||||
*/
|
||||
/* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
|
||||
* matter since it will be recomputed at next deflate call.
|
||||
*/
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* No match, output a literal byte */
|
||||
Tracevv((stderr,"%c", s->window[s->strstart]));
|
||||
_tr_tally_lit (s, s->window[s->strstart], bflush);
|
||||
_tr_tally_lit(s, s->window[s->strstart], bflush);
|
||||
s->lookahead--;
|
||||
s->strstart++;
|
||||
}
|
||||
@ -1993,7 +2057,7 @@ local block_state deflate_slow(s, flush)
|
||||
if (s->lookahead == 0) break; /* flush the current block */
|
||||
}
|
||||
|
||||
/* Insert the string window[strstart .. strstart+2] in the
|
||||
/* Insert the string window[strstart .. strstart + 2] in the
|
||||
* dictionary, and set hash_head to the head of the hash chain:
|
||||
*/
|
||||
hash_head = NIL;
|
||||
@ -2035,17 +2099,23 @@ local block_state deflate_slow(s, flush)
|
||||
uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
|
||||
/* Do not insert strings in hash table beyond this. */
|
||||
|
||||
check_match(s, s->strstart-1, s->prev_match, s->prev_length);
|
||||
if (s->prev_match == -1) {
|
||||
/* The window has slid one byte past the previous match,
|
||||
* so the first byte cannot be compared. */
|
||||
check_match(s, s->strstart, s->prev_match + 1, s->prev_length - 1);
|
||||
} else {
|
||||
check_match(s, s->strstart - 1, s->prev_match, s->prev_length);
|
||||
}
|
||||
|
||||
_tr_tally_dist(s, s->strstart -1 - s->prev_match,
|
||||
_tr_tally_dist(s, s->strstart - 1 - s->prev_match,
|
||||
s->prev_length - MIN_MATCH, bflush);
|
||||
|
||||
/* Insert in hash table all strings up to the end of the match.
|
||||
* strstart-1 and strstart are already inserted. If there is not
|
||||
* strstart - 1 and strstart are already inserted. If there is not
|
||||
* enough lookahead, the last two strings are not inserted in
|
||||
* the hash table.
|
||||
*/
|
||||
s->lookahead -= s->prev_length-1;
|
||||
s->lookahead -= s->prev_length - 1;
|
||||
s->prev_length -= 2;
|
||||
do {
|
||||
if (++s->strstart <= max_insert) {
|
||||
@ -2063,8 +2133,8 @@ local block_state deflate_slow(s, flush)
|
||||
* single literal. If there was a match but the current match
|
||||
* is longer, truncate the previous match to a single literal.
|
||||
*/
|
||||
Tracevv((stderr,"%c", s->window[s->strstart-1]));
|
||||
_tr_tally_lit(s, s->window[s->strstart-1], bflush);
|
||||
Tracevv((stderr,"%c", s->window[s->strstart - 1]));
|
||||
_tr_tally_lit(s, s->window[s->strstart - 1], bflush);
|
||||
if (bflush) {
|
||||
FLUSH_BLOCK_ONLY(s, 0);
|
||||
}
|
||||
@ -2082,8 +2152,8 @@ local block_state deflate_slow(s, flush)
|
||||
}
|
||||
Assert (flush != Z_NO_FLUSH, "no flush?");
|
||||
if (s->match_available) {
|
||||
Tracevv((stderr,"%c", s->window[s->strstart-1]));
|
||||
_tr_tally_lit(s, s->window[s->strstart-1], bflush);
|
||||
Tracevv((stderr,"%c", s->window[s->strstart - 1]));
|
||||
_tr_tally_lit(s, s->window[s->strstart - 1], bflush);
|
||||
s->match_available = 0;
|
||||
}
|
||||
s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1;
|
||||
@ -2140,7 +2210,8 @@ local block_state deflate_rle(s, flush)
|
||||
if (s->match_length > s->lookahead)
|
||||
s->match_length = s->lookahead;
|
||||
}
|
||||
Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan");
|
||||
Assert(scan <= s->window + (uInt)(s->window_size - 1),
|
||||
"wild scan");
|
||||
}
|
||||
|
||||
/* Emit match if have run of MIN_MATCH or longer, else emit literal */
|
||||
@ -2155,7 +2226,7 @@ local block_state deflate_rle(s, flush)
|
||||
} else {
|
||||
/* No match, output a literal byte */
|
||||
Tracevv((stderr,"%c", s->window[s->strstart]));
|
||||
_tr_tally_lit (s, s->window[s->strstart], bflush);
|
||||
_tr_tally_lit(s, s->window[s->strstart], bflush);
|
||||
s->lookahead--;
|
||||
s->strstart++;
|
||||
}
|
||||
@ -2195,7 +2266,7 @@ local block_state deflate_huff(s, flush)
|
||||
/* Output a literal byte */
|
||||
s->match_length = 0;
|
||||
Tracevv((stderr,"%c", s->window[s->strstart]));
|
||||
_tr_tally_lit (s, s->window[s->strstart], bflush);
|
||||
_tr_tally_lit(s, s->window[s->strstart], bflush);
|
||||
s->lookahead--;
|
||||
s->strstart++;
|
||||
if (bflush) FLUSH_BLOCK(s, 0);
|
||||
|
13
deps/zlib/deflate.h
vendored
13
deps/zlib/deflate.h
vendored
@ -1,5 +1,5 @@
|
||||
/* deflate.h -- internal compression state
|
||||
* Copyright (C) 1995-2016 Jean-loup Gailly
|
||||
* Copyright (C) 1995-2018 Jean-loup Gailly
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
@ -268,6 +268,11 @@ typedef struct internal_state {
|
||||
* updated to the new high water mark.
|
||||
*/
|
||||
|
||||
uInt chromium_zlib_hash;
|
||||
/* 0 if Rabin-Karp rolling hash is enabled, non-zero if chromium zlib
|
||||
* hash is enabled.
|
||||
*/
|
||||
|
||||
} FAR deflate_state;
|
||||
|
||||
/* Output a byte on the stream.
|
||||
@ -329,8 +334,8 @@ void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf,
|
||||
# define _tr_tally_dist(s, distance, length, flush) \
|
||||
{ uch len = (uch)(length); \
|
||||
ush dist = (ush)(distance); \
|
||||
s->sym_buf[s->sym_next++] = dist; \
|
||||
s->sym_buf[s->sym_next++] = dist >> 8; \
|
||||
s->sym_buf[s->sym_next++] = (uch)dist; \
|
||||
s->sym_buf[s->sym_next++] = (uch)(dist >> 8); \
|
||||
s->sym_buf[s->sym_next++] = len; \
|
||||
dist--; \
|
||||
s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
|
||||
@ -351,6 +356,4 @@ void ZLIB_INTERNAL crc_fold_copy(deflate_state* const s,
|
||||
long len);
|
||||
unsigned ZLIB_INTERNAL crc_fold_512to32(deflate_state* const s);
|
||||
|
||||
void ZLIB_INTERNAL fill_window_sse(deflate_state* s);
|
||||
|
||||
#endif /* DEFLATE_H */
|
||||
|
178
deps/zlib/fill_window_sse.c
vendored
178
deps/zlib/fill_window_sse.c
vendored
@ -1,178 +0,0 @@
|
||||
/*
|
||||
* Fill Window with SSE2-optimized hash shifting
|
||||
*
|
||||
* Copyright (C) 2013 Intel Corporation
|
||||
* Authors:
|
||||
* Arjan van de Ven <arjan@linux.intel.com>
|
||||
* Jim Kukunas <james.t.kukunas@linux.intel.com>
|
||||
*
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
#pragma GCC target ("sse2")
|
||||
#include <immintrin.h>
|
||||
#include "deflate.h"
|
||||
|
||||
#define UPDATE_HASH(s,h,i) \
|
||||
{\
|
||||
if (s->level < 6) { \
|
||||
h = (3483 * (s->window[i]) +\
|
||||
23081* (s->window[i+1]) +\
|
||||
6954 * (s->window[i+2]) +\
|
||||
20947* (s->window[i+3])) & s->hash_mask;\
|
||||
} else {\
|
||||
h = (25881* (s->window[i]) +\
|
||||
24674* (s->window[i+1]) +\
|
||||
25811* (s->window[i+2])) & s->hash_mask;\
|
||||
}\
|
||||
}\
|
||||
|
||||
extern int deflate_read_buf OF((z_streamp strm, Bytef *buf, unsigned size));
|
||||
|
||||
void fill_window_sse(deflate_state *s)
|
||||
{
|
||||
const __m128i xmm_wsize = _mm_set1_epi16(s->w_size);
|
||||
|
||||
register unsigned n;
|
||||
register Posf *p;
|
||||
unsigned more; /* Amount of free space at the end of the window. */
|
||||
uInt wsize = s->w_size;
|
||||
|
||||
Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead");
|
||||
|
||||
do {
|
||||
more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
|
||||
|
||||
/* Deal with !@#$% 64K limit: */
|
||||
if (sizeof(int) <= 2) {
|
||||
if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
|
||||
more = wsize;
|
||||
|
||||
} else if (more == (unsigned)(-1)) {
|
||||
/* Very unlikely, but possible on 16 bit machine if
|
||||
* strstart == 0 && lookahead == 1 (input done a byte at time)
|
||||
*/
|
||||
more--;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the window is almost full and there is insufficient lookahead,
|
||||
* move the upper half to the lower one to make room in the upper half.
|
||||
*/
|
||||
if (s->strstart >= wsize+MAX_DIST(s)) {
|
||||
|
||||
zmemcpy(s->window, s->window+wsize, (unsigned)wsize);
|
||||
s->match_start -= wsize;
|
||||
s->strstart -= wsize; /* we now have strstart >= MAX_DIST */
|
||||
s->block_start -= (long) wsize;
|
||||
|
||||
/* Slide the hash table (could be avoided with 32 bit values
|
||||
at the expense of memory usage). We slide even when level == 0
|
||||
to keep the hash table consistent if we switch back to level > 0
|
||||
later. (Using level 0 permanently is not an optimal usage of
|
||||
zlib, so we don't care about this pathological case.)
|
||||
*/
|
||||
n = s->hash_size;
|
||||
p = &s->head[n];
|
||||
p -= 8;
|
||||
do {
|
||||
__m128i value, result;
|
||||
|
||||
value = _mm_loadu_si128((__m128i *)p);
|
||||
result = _mm_subs_epu16(value, xmm_wsize);
|
||||
_mm_storeu_si128((__m128i *)p, result);
|
||||
|
||||
p -= 8;
|
||||
n -= 8;
|
||||
} while (n > 0);
|
||||
|
||||
n = wsize;
|
||||
#ifndef FASTEST
|
||||
p = &s->prev[n];
|
||||
p -= 8;
|
||||
do {
|
||||
__m128i value, result;
|
||||
|
||||
value = _mm_loadu_si128((__m128i *)p);
|
||||
result = _mm_subs_epu16(value, xmm_wsize);
|
||||
_mm_storeu_si128((__m128i *)p, result);
|
||||
|
||||
p -= 8;
|
||||
n -= 8;
|
||||
} while (n > 0);
|
||||
#endif
|
||||
more += wsize;
|
||||
}
|
||||
if (s->strm->avail_in == 0) break;
|
||||
|
||||
/* If there was no sliding:
|
||||
* strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
|
||||
* more == window_size - lookahead - strstart
|
||||
* => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
|
||||
* => more >= window_size - 2*WSIZE + 2
|
||||
* In the BIG_MEM or MMAP case (not yet supported),
|
||||
* window_size == input_size + MIN_LOOKAHEAD &&
|
||||
* strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
|
||||
* Otherwise, window_size == 2*WSIZE so more >= 2.
|
||||
* If there was sliding, more >= WSIZE. So in all cases, more >= 2.
|
||||
*/
|
||||
Assert(more >= 2, "more < 2");
|
||||
|
||||
n = deflate_read_buf(s->strm,
|
||||
s->window + s->strstart + s->lookahead,
|
||||
more);
|
||||
s->lookahead += n;
|
||||
|
||||
/* Initialize the hash value now that we have some input: */
|
||||
if (s->lookahead >= MIN_MATCH) {
|
||||
uInt str = s->strstart;
|
||||
s->ins_h = s->window[str];
|
||||
if (str >= 1)
|
||||
UPDATE_HASH(s, s->ins_h, str + 1 - (MIN_MATCH-1));
|
||||
#if MIN_MATCH != 3
|
||||
Call UPDATE_HASH() MIN_MATCH-3 more times
|
||||
#endif
|
||||
}
|
||||
/* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
|
||||
* but this is not important since only literal bytes will be emitted.
|
||||
*/
|
||||
|
||||
} while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
|
||||
|
||||
/* If the WIN_INIT bytes after the end of the current data have never been
|
||||
* written, then zero those bytes in order to avoid memory check reports of
|
||||
* the use of uninitialized (or uninitialised as Julian writes) bytes by
|
||||
* the longest match routines. Update the high water mark for the next
|
||||
* time through here. WIN_INIT is set to MAX_MATCH since the longest match
|
||||
* routines allow scanning to strstart + MAX_MATCH, ignoring lookahead.
|
||||
*/
|
||||
if (s->high_water < s->window_size) {
|
||||
ulg curr = s->strstart + (ulg)(s->lookahead);
|
||||
ulg init;
|
||||
|
||||
if (s->high_water < curr) {
|
||||
/* Previous high water mark below current data -- zero WIN_INIT
|
||||
* bytes or up to end of window, whichever is less.
|
||||
*/
|
||||
init = s->window_size - curr;
|
||||
if (init > WIN_INIT)
|
||||
init = WIN_INIT;
|
||||
zmemzero(s->window + curr, (unsigned)init);
|
||||
s->high_water = curr + init;
|
||||
}
|
||||
else if (s->high_water < (ulg)curr + WIN_INIT) {
|
||||
/* High water mark at or above current data, but below current data
|
||||
* plus WIN_INIT -- zero out to current data plus WIN_INIT, or up
|
||||
* to end of window, whichever is less.
|
||||
*/
|
||||
init = (ulg)curr + WIN_INIT - s->high_water;
|
||||
if (init > s->window_size - s->high_water)
|
||||
init = s->window_size - s->high_water;
|
||||
zmemzero(s->window + s->high_water, (unsigned)init);
|
||||
s->high_water += init;
|
||||
}
|
||||
}
|
||||
|
||||
Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,
|
||||
"not enough room for search");
|
||||
}
|
10
deps/zlib/google/BUILD.gn
vendored
10
deps/zlib/google/BUILD.gn
vendored
@ -1,4 +1,4 @@
|
||||
# Copyright 2017 The Chromium Authors. All rights reserved.
|
||||
# Copyright 2017 The Chromium Authors
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
@ -7,6 +7,7 @@ import("//build_overrides/build.gni")
|
||||
if (build_with_chromium) {
|
||||
static_library("zip") {
|
||||
sources = [
|
||||
"redact.h",
|
||||
"zip.cc",
|
||||
"zip.h",
|
||||
"zip_internal.cc",
|
||||
@ -18,6 +19,7 @@ if (build_with_chromium) {
|
||||
]
|
||||
deps = [
|
||||
"//base",
|
||||
"//base:i18n",
|
||||
"//third_party/zlib:minizip",
|
||||
]
|
||||
}
|
||||
@ -28,10 +30,10 @@ if (build_with_chromium) {
|
||||
"compression_utils.h",
|
||||
]
|
||||
deps = [
|
||||
":compression_utils_portable",
|
||||
"//base",
|
||||
"//third_party/zlib",
|
||||
]
|
||||
public_deps = [ ":compression_utils_portable" ]
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,7 +44,5 @@ static_library("compression_utils_portable") {
|
||||
"compression_utils_portable.cc",
|
||||
"compression_utils_portable.h",
|
||||
]
|
||||
deps = [
|
||||
"//third_party/zlib",
|
||||
]
|
||||
public_deps = [ "//third_party/zlib" ]
|
||||
}
|
||||
|
1
deps/zlib/google/DEPS
vendored
1
deps/zlib/google/DEPS
vendored
@ -2,4 +2,5 @@ include_rules = [
|
||||
'+base',
|
||||
'+build',
|
||||
'+testing',
|
||||
"+third_party/zlib/zlib.h",
|
||||
]
|
||||
|
3
deps/zlib/google/OWNERS
vendored
3
deps/zlib/google/OWNERS
vendored
@ -1,5 +1,8 @@
|
||||
fdegros@chromium.org
|
||||
noel@chromium.org
|
||||
satorux@chromium.org
|
||||
|
||||
# compression_utils*
|
||||
asvitkine@chromium.org
|
||||
isherman@chromium.org
|
||||
cavalcantii@chromium.org
|
||||
|
66
deps/zlib/google/compression_utils.cc
vendored
66
deps/zlib/google/compression_utils.cc
vendored
@ -1,20 +1,19 @@
|
||||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Copyright 2014 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "third_party/zlib/google/compression_utils.h"
|
||||
|
||||
#include "base/bit_cast.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/check_op.h"
|
||||
#include "base/process/memory.h"
|
||||
#include "base/strings/string_piece.h"
|
||||
#include "base/sys_byteorder.h"
|
||||
|
||||
#include "third_party/zlib/google/compression_utils_portable.h"
|
||||
|
||||
namespace compression {
|
||||
|
||||
bool GzipCompress(base::StringPiece input,
|
||||
bool GzipCompress(base::span<const char> input,
|
||||
char* output_buffer,
|
||||
size_t output_buffer_size,
|
||||
size_t* compressed_size,
|
||||
@ -25,8 +24,8 @@ bool GzipCompress(base::StringPiece input,
|
||||
// uLongf can be larger than size_t.
|
||||
uLongf compressed_size_long = static_cast<uLongf>(output_buffer_size);
|
||||
if (zlib_internal::GzipCompressHelper(
|
||||
bit_cast<Bytef*>(output_buffer), &compressed_size_long,
|
||||
bit_cast<const Bytef*>(input.data()),
|
||||
base::bit_cast<Bytef*>(output_buffer), &compressed_size_long,
|
||||
base::bit_cast<const Bytef*>(input.data()),
|
||||
static_cast<uLongf>(input.size()), malloc_fn, free_fn) != Z_OK) {
|
||||
return false;
|
||||
}
|
||||
@ -35,7 +34,11 @@ bool GzipCompress(base::StringPiece input,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GzipCompress(base::StringPiece input, std::string* output) {
|
||||
bool GzipCompress(base::span<const char> input, std::string* output) {
|
||||
return GzipCompress(base::as_bytes(input), output);
|
||||
}
|
||||
|
||||
bool GzipCompress(base::span<const uint8_t> input, std::string* output) {
|
||||
// Not using std::vector<> because allocation failures are recoverable,
|
||||
// which is hidden by std::vector<>.
|
||||
static_assert(sizeof(Bytef) == 1, "");
|
||||
@ -50,9 +53,10 @@ bool GzipCompress(base::StringPiece input, std::string* output) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (zlib_internal::GzipCompressHelper(compressed_data, &compressed_data_size,
|
||||
bit_cast<const Bytef*>(input.data()),
|
||||
input_size, nullptr, nullptr) != Z_OK) {
|
||||
if (zlib_internal::GzipCompressHelper(
|
||||
compressed_data, &compressed_data_size,
|
||||
base::bit_cast<const Bytef*>(input.data()), input_size, nullptr,
|
||||
nullptr) != Z_OK) {
|
||||
free(compressed_data);
|
||||
return false;
|
||||
}
|
||||
@ -73,13 +77,13 @@ bool GzipCompress(base::StringPiece input, std::string* output) {
|
||||
bool GzipUncompress(const std::string& input, std::string* output) {
|
||||
std::string uncompressed_output;
|
||||
uLongf uncompressed_size = static_cast<uLongf>(GetUncompressedSize(input));
|
||||
if (uncompressed_size > uncompressed_output.max_size())
|
||||
if (size_t{uncompressed_size} > uncompressed_output.max_size())
|
||||
return false;
|
||||
|
||||
uncompressed_output.resize(uncompressed_size);
|
||||
if (zlib_internal::GzipUncompressHelper(
|
||||
bit_cast<Bytef*>(uncompressed_output.data()), &uncompressed_size,
|
||||
bit_cast<const Bytef*>(input.data()),
|
||||
base::bit_cast<Bytef*>(uncompressed_output.data()),
|
||||
&uncompressed_size, base::bit_cast<const Bytef*>(input.data()),
|
||||
static_cast<uLongf>(input.length())) == Z_OK) {
|
||||
output->swap(uncompressed_output);
|
||||
return true;
|
||||
@ -87,30 +91,44 @@ bool GzipUncompress(const std::string& input, std::string* output) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GzipUncompress(base::StringPiece input, base::StringPiece output) {
|
||||
bool GzipUncompress(base::span<const char> input,
|
||||
base::span<const char> output) {
|
||||
return GzipUncompress(base::as_bytes(input), base::as_bytes(output));
|
||||
}
|
||||
|
||||
bool GzipUncompress(base::span<const uint8_t> input,
|
||||
base::span<const uint8_t> output) {
|
||||
uLongf uncompressed_size = GetUncompressedSize(input);
|
||||
if (uncompressed_size > output.size())
|
||||
return false;
|
||||
return zlib_internal::GzipUncompressHelper(
|
||||
bit_cast<Bytef*>(output.data()), &uncompressed_size,
|
||||
bit_cast<const Bytef*>(input.data()),
|
||||
static_cast<uLongf>(input.length())) == Z_OK;
|
||||
base::bit_cast<Bytef*>(output.data()), &uncompressed_size,
|
||||
base::bit_cast<const Bytef*>(input.data()),
|
||||
static_cast<uLongf>(input.size())) == Z_OK;
|
||||
}
|
||||
|
||||
bool GzipUncompress(base::StringPiece input, std::string* output) {
|
||||
bool GzipUncompress(base::span<const char> input, std::string* output) {
|
||||
return GzipUncompress(base::as_bytes(input), output);
|
||||
}
|
||||
|
||||
bool GzipUncompress(base::span<const uint8_t> input, std::string* output) {
|
||||
// Disallow in-place usage, i.e., |input| using |*output| as underlying data.
|
||||
DCHECK_NE(input.data(), output->data());
|
||||
DCHECK_NE(reinterpret_cast<const char*>(input.data()), output->data());
|
||||
uLongf uncompressed_size = GetUncompressedSize(input);
|
||||
output->resize(uncompressed_size);
|
||||
return zlib_internal::GzipUncompressHelper(
|
||||
bit_cast<Bytef*>(output->data()), &uncompressed_size,
|
||||
bit_cast<const Bytef*>(input.data()),
|
||||
static_cast<uLongf>(input.length())) == Z_OK;
|
||||
base::bit_cast<Bytef*>(output->data()), &uncompressed_size,
|
||||
base::bit_cast<const Bytef*>(input.data()),
|
||||
static_cast<uLongf>(input.size())) == Z_OK;
|
||||
}
|
||||
|
||||
uint32_t GetUncompressedSize(base::StringPiece compressed_data) {
|
||||
uint32_t GetUncompressedSize(base::span<const char> compressed_data) {
|
||||
return GetUncompressedSize(base::as_bytes(compressed_data));
|
||||
}
|
||||
|
||||
uint32_t GetUncompressedSize(base::span<const uint8_t> compressed_data) {
|
||||
return zlib_internal::GetGzipUncompressedSize(
|
||||
bit_cast<Bytef*>(compressed_data.data()), compressed_data.length());
|
||||
base::bit_cast<Bytef*>(compressed_data.data()), compressed_data.size());
|
||||
}
|
||||
|
||||
} // namespace compression
|
||||
|
30
deps/zlib/google/compression_utils.h
vendored
30
deps/zlib/google/compression_utils.h
vendored
@ -1,4 +1,4 @@
|
||||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Copyright 2014 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/strings/string_piece.h"
|
||||
#include "base/containers/span.h"
|
||||
|
||||
namespace compression {
|
||||
|
||||
@ -18,7 +18,7 @@ namespace compression {
|
||||
// |malloc_fn| and |free_fn| are pointers to malloc() and free()-like functions,
|
||||
// or nullptr to use the standard ones.
|
||||
// Returns true for success.
|
||||
bool GzipCompress(base::StringPiece input,
|
||||
bool GzipCompress(base::span<const char> input,
|
||||
char* output_buffer,
|
||||
size_t output_buffer_size,
|
||||
size_t* compressed_size,
|
||||
@ -29,27 +29,41 @@ bool GzipCompress(base::StringPiece input,
|
||||
// |input| and |output| are allowed to point to the same string (in-place
|
||||
// operation).
|
||||
// Returns true for success.
|
||||
bool GzipCompress(base::StringPiece input, std::string* output);
|
||||
bool GzipCompress(base::span<const char> input, std::string* output);
|
||||
|
||||
// Like the above method, but using uint8_t instead.
|
||||
bool GzipCompress(base::span<const uint8_t> input, std::string* output);
|
||||
|
||||
// Uncompresses the data in |input| using gzip, storing the result in |output|.
|
||||
// |input| and |output| are allowed to be the same string (in-place operation).
|
||||
// Returns true for success.
|
||||
bool GzipUncompress(const std::string& input, std::string* output);
|
||||
|
||||
// Like the above method, but uses base::StringPiece to avoid allocations if
|
||||
// Like the above method, but uses base::span to avoid allocations if
|
||||
// needed. |output|'s size must be at least as large as the return value from
|
||||
// GetUncompressedSize.
|
||||
// Returns true for success.
|
||||
bool GzipUncompress(base::StringPiece input, base::StringPiece output);
|
||||
bool GzipUncompress(base::span<const char> input,
|
||||
base::span<const char> output);
|
||||
|
||||
// Like the above method, but using uint8_t instead.
|
||||
bool GzipUncompress(base::span<const uint8_t> input,
|
||||
base::span<const uint8_t> output);
|
||||
|
||||
// Uncompresses the data in |input| using gzip, and writes the results to
|
||||
// |output|, which must NOT be the underlying string of |input|, and is resized
|
||||
// if necessary.
|
||||
// Returns true for success.
|
||||
bool GzipUncompress(base::StringPiece input, std::string* output);
|
||||
bool GzipUncompress(base::span<const char> input, std::string* output);
|
||||
|
||||
// Like the above method, but using uint8_t instead.
|
||||
bool GzipUncompress(base::span<const uint8_t> input, std::string* output);
|
||||
|
||||
// Returns the uncompressed size from GZIP-compressed |compressed_data|.
|
||||
uint32_t GetUncompressedSize(base::StringPiece compressed_data);
|
||||
uint32_t GetUncompressedSize(base::span<const char> compressed_data);
|
||||
|
||||
// Like the above method, but using uint8_t instead.
|
||||
uint32_t GetUncompressedSize(base::span<const uint8_t> compressed_data);
|
||||
|
||||
} // namespace compression
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
/* compression_utils_portable.cc
|
||||
*
|
||||
* Copyright 2019 The Chromium Authors. All rights reserved.
|
||||
* Copyright 2019 The Chromium Authors
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the Chromium source repository LICENSE file.
|
||||
*/
|
||||
|
||||
#include "third_party/zlib/google/compression_utils_portable.h"
|
||||
#include "compression_utils_portable.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
@ -84,7 +84,7 @@ int CompressHelper(WrapperType wrapper_type,
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* compression_utils_portable.h
|
||||
*
|
||||
* Copyright 2019 The Chromium Authors. All rights reserved.
|
||||
* Copyright 2019 The Chromium Authors
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the Chromium source repository LICENSE file.
|
||||
*/
|
||||
@ -9,10 +9,14 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* TODO(cavalcantii): remove support for Chromium ever building with a system
|
||||
* zlib.
|
||||
*/
|
||||
#if defined(USE_SYSTEM_ZLIB)
|
||||
#include <zlib.h>
|
||||
/* AOSP build requires relative paths. */
|
||||
#else
|
||||
#include "third_party/zlib/zlib.h"
|
||||
#include "zlib.h"
|
||||
#endif
|
||||
|
||||
namespace zlib_internal {
|
||||
|
27
deps/zlib/google/compression_utils_unittest.cc
vendored
27
deps/zlib/google/compression_utils_unittest.cc
vendored
@ -1,4 +1,4 @@
|
||||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Copyright 2014 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
@ -7,10 +7,9 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace compression {
|
||||
@ -34,37 +33,33 @@ const uint8_t kCompressedData[] = {
|
||||
} // namespace
|
||||
|
||||
TEST(CompressionUtilsTest, GzipCompression) {
|
||||
std::string data(reinterpret_cast<const char*>(kData), base::size(kData));
|
||||
std::string data(reinterpret_cast<const char*>(kData), std::size(kData));
|
||||
std::string compressed_data;
|
||||
EXPECT_TRUE(GzipCompress(data, &compressed_data));
|
||||
std::string golden_compressed_data(
|
||||
reinterpret_cast<const char*>(kCompressedData),
|
||||
base::size(kCompressedData));
|
||||
std::size(kCompressedData));
|
||||
EXPECT_EQ(golden_compressed_data, compressed_data);
|
||||
}
|
||||
|
||||
TEST(CompressionUtilsTest, GzipUncompression) {
|
||||
std::string compressed_data(reinterpret_cast<const char*>(kCompressedData),
|
||||
base::size(kCompressedData));
|
||||
std::size(kCompressedData));
|
||||
|
||||
std::string uncompressed_data;
|
||||
EXPECT_TRUE(GzipUncompress(compressed_data, &uncompressed_data));
|
||||
|
||||
std::string golden_data(reinterpret_cast<const char*>(kData),
|
||||
base::size(kData));
|
||||
std::size(kData));
|
||||
EXPECT_EQ(golden_data, uncompressed_data);
|
||||
}
|
||||
|
||||
TEST(CompressionUtilsTest, GzipUncompressionFromStringPieceToString) {
|
||||
base::StringPiece compressed_data(
|
||||
reinterpret_cast<const char*>(kCompressedData),
|
||||
base::size(kCompressedData));
|
||||
|
||||
TEST(CompressionUtilsTest, GzipUncompressionFromSpanToString) {
|
||||
std::string uncompressed_data;
|
||||
EXPECT_TRUE(GzipUncompress(compressed_data, &uncompressed_data));
|
||||
EXPECT_TRUE(GzipUncompress(kCompressedData, &uncompressed_data));
|
||||
|
||||
std::string golden_data(reinterpret_cast<const char*>(kData),
|
||||
base::size(kData));
|
||||
std::size(kData));
|
||||
EXPECT_EQ(golden_data, uncompressed_data);
|
||||
}
|
||||
|
||||
@ -89,10 +84,10 @@ TEST(CompressionUtilsTest, LargeInput) {
|
||||
|
||||
TEST(CompressionUtilsTest, InPlace) {
|
||||
const std::string original_data(reinterpret_cast<const char*>(kData),
|
||||
base::size(kData));
|
||||
std::size(kData));
|
||||
const std::string golden_compressed_data(
|
||||
reinterpret_cast<const char*>(kCompressedData),
|
||||
base::size(kCompressedData));
|
||||
std::size(kCompressedData));
|
||||
|
||||
std::string data(original_data);
|
||||
EXPECT_TRUE(GzipCompress(data, &data));
|
||||
|
31
deps/zlib/google/redact.h
vendored
Normal file
31
deps/zlib/google/redact.h
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright 2022 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
#ifndef THIRD_PARTY_ZLIB_GOOGLE_REDACT_H_
|
||||
#define THIRD_PARTY_ZLIB_GOOGLE_REDACT_H_
|
||||
|
||||
#include <ostream>
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/logging.h"
|
||||
|
||||
namespace zip {
|
||||
|
||||
// Redacts file paths in log messages.
|
||||
// Example:
|
||||
// LOG(ERROR) << "Cannot open " << Redact(path);
|
||||
class Redact {
|
||||
public:
|
||||
explicit Redact(const base::FilePath& path) : path_(path) {}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& out, const Redact&& r) {
|
||||
return LOG_IS_ON(INFO) ? out << "'" << r.path_ << "'" : out << "(redacted)";
|
||||
}
|
||||
|
||||
private:
|
||||
const base::FilePath& path_;
|
||||
};
|
||||
|
||||
} // namespace zip
|
||||
|
||||
#endif // THIRD_PARTY_ZLIB_GOOGLE_REDACT_H_
|
BIN
deps/zlib/google/test/data/Different Encryptions.zip
vendored
Normal file
BIN
deps/zlib/google/test/data/Different Encryptions.zip
vendored
Normal file
Binary file not shown.
BIN
deps/zlib/google/test/data/Empty Dir Same Name As File.zip
vendored
Normal file
BIN
deps/zlib/google/test/data/Empty Dir Same Name As File.zip
vendored
Normal file
Binary file not shown.
BIN
deps/zlib/google/test/data/Mixed Paths.zip
vendored
Normal file
BIN
deps/zlib/google/test/data/Mixed Paths.zip
vendored
Normal file
Binary file not shown.
BIN
deps/zlib/google/test/data/Parent Dir Same Name As File.zip
vendored
Normal file
BIN
deps/zlib/google/test/data/Parent Dir Same Name As File.zip
vendored
Normal file
Binary file not shown.
15
deps/zlib/google/test/data/README.md
vendored
Normal file
15
deps/zlib/google/test/data/README.md
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
## test\_posix\_permissions.zip
|
||||
Rebuild this zip by running:
|
||||
```
|
||||
rm test_posix_permissions.zip &&
|
||||
mkdir z &&
|
||||
cd z &&
|
||||
touch 0.txt 1.txt 2.txt 3.txt &&
|
||||
chmod a+x 0.txt &&
|
||||
chmod o+x 1.txt &&
|
||||
chmod u+x 2.txt &&
|
||||
zip test_posix_permissions.zip * &&
|
||||
mv test_posix_permissions.zip .. &&
|
||||
cd .. &&
|
||||
rm -r z
|
||||
```
|
BIN
deps/zlib/google/test/data/Repeated Dir Name.zip
vendored
Normal file
BIN
deps/zlib/google/test/data/Repeated Dir Name.zip
vendored
Normal file
Binary file not shown.
BIN
deps/zlib/google/test/data/Repeated File Name With Different Cases.zip
vendored
Normal file
BIN
deps/zlib/google/test/data/Repeated File Name With Different Cases.zip
vendored
Normal file
Binary file not shown.
BIN
deps/zlib/google/test/data/Repeated File Name.zip
vendored
Normal file
BIN
deps/zlib/google/test/data/Repeated File Name.zip
vendored
Normal file
Binary file not shown.
BIN
deps/zlib/google/test/data/SJIS Bug 846195.zip
vendored
Normal file
BIN
deps/zlib/google/test/data/SJIS Bug 846195.zip
vendored
Normal file
Binary file not shown.
BIN
deps/zlib/google/test/data/Windows Special Names.zip
vendored
Normal file
BIN
deps/zlib/google/test/data/Windows Special Names.zip
vendored
Normal file
Binary file not shown.
BIN
deps/zlib/google/test/data/Wrong CRC.zip
vendored
Normal file
BIN
deps/zlib/google/test/data/Wrong CRC.zip
vendored
Normal file
Binary file not shown.
@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
# Copyright 2011 The Chromium Authors
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
#
|
||||
|
BIN
deps/zlib/google/test/data/empty.zip
vendored
Normal file
BIN
deps/zlib/google/test/data/empty.zip
vendored
Normal file
Binary file not shown.
BIN
deps/zlib/google/test/data/test_posix_permissions.zip
vendored
Normal file
BIN
deps/zlib/google/test/data/test_posix_permissions.zip
vendored
Normal file
Binary file not shown.
333
deps/zlib/google/zip.cc
vendored
333
deps/zlib/google/zip.cc
vendored
@ -1,20 +1,21 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Copyright 2012 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "third_party/zlib/google/zip.h"
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/bind.h"
|
||||
#include "base/files/file.h"
|
||||
#include "base/files/file_enumerator.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/memory/ptr_util.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "build/build_config.h"
|
||||
#include "third_party/zlib/google/redact.h"
|
||||
#include "third_party/zlib/google/zip_internal.h"
|
||||
#include "third_party/zlib/google/zip_reader.h"
|
||||
#include "third_party/zlib/google/zip_writer.h"
|
||||
@ -26,18 +27,13 @@ bool IsHiddenFile(const base::FilePath& file_path) {
|
||||
return file_path.BaseName().value()[0] == '.';
|
||||
}
|
||||
|
||||
bool ExcludeNoFilesFilter(const base::FilePath& file_path) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ExcludeHiddenFilesFilter(const base::FilePath& file_path) {
|
||||
return !IsHiddenFile(file_path);
|
||||
}
|
||||
|
||||
// Creates a directory at |extract_dir|/|entry_path|, including any parents.
|
||||
bool CreateDirectory(const base::FilePath& extract_dir,
|
||||
const base::FilePath& entry_path) {
|
||||
return base::CreateDirectory(extract_dir.Append(entry_path));
|
||||
const base::FilePath dir = extract_dir.Append(entry_path);
|
||||
const bool ok = base::CreateDirectory(dir);
|
||||
PLOG_IF(ERROR, !ok) << "Cannot create directory " << Redact(dir);
|
||||
return ok;
|
||||
}
|
||||
|
||||
// Creates a WriterDelegate that can write a file at |extract_dir|/|entry_path|.
|
||||
@ -50,222 +46,229 @@ std::unique_ptr<WriterDelegate> CreateFilePathWriterDelegate(
|
||||
|
||||
class DirectFileAccessor : public FileAccessor {
|
||||
public:
|
||||
explicit DirectFileAccessor(base::FilePath src_dir) : src_dir_(src_dir) {}
|
||||
explicit DirectFileAccessor(base::FilePath src_dir)
|
||||
: src_dir_(std::move(src_dir)) {}
|
||||
|
||||
~DirectFileAccessor() override = default;
|
||||
|
||||
std::vector<base::File> OpenFilesForReading(
|
||||
const std::vector<base::FilePath>& paths) override {
|
||||
std::vector<base::File> files;
|
||||
for (const auto& path : paths) {
|
||||
base::File file;
|
||||
if (base::PathExists(path) && !base::DirectoryExists(path)) {
|
||||
file = base::File(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
|
||||
bool Open(const Paths paths, std::vector<base::File>* const files) override {
|
||||
DCHECK(files);
|
||||
files->reserve(files->size() + paths.size());
|
||||
|
||||
for (const base::FilePath& path : paths) {
|
||||
DCHECK(!path.IsAbsolute());
|
||||
const base::FilePath absolute_path = src_dir_.Append(path);
|
||||
if (base::DirectoryExists(absolute_path)) {
|
||||
files->emplace_back();
|
||||
LOG(ERROR) << "Cannot open " << Redact(path) << ": It is a directory";
|
||||
} else {
|
||||
const base::File& file = files->emplace_back(
|
||||
absolute_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
|
||||
LOG_IF(ERROR, !file.IsValid())
|
||||
<< "Cannot open " << Redact(path) << ": "
|
||||
<< base::File::ErrorToString(file.error_details());
|
||||
}
|
||||
files.push_back(std::move(file));
|
||||
}
|
||||
return files;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DirectoryExists(const base::FilePath& file) override {
|
||||
return base::DirectoryExists(file);
|
||||
}
|
||||
bool List(const base::FilePath& path,
|
||||
std::vector<base::FilePath>* const files,
|
||||
std::vector<base::FilePath>* const subdirs) override {
|
||||
DCHECK(!path.IsAbsolute());
|
||||
DCHECK(files);
|
||||
DCHECK(subdirs);
|
||||
|
||||
std::vector<DirectoryContentEntry> ListDirectoryContent(
|
||||
const base::FilePath& dir) override {
|
||||
std::vector<DirectoryContentEntry> files;
|
||||
base::FileEnumerator file_enumerator(
|
||||
dir, false /* recursive */,
|
||||
src_dir_.Append(path), false /* recursive */,
|
||||
base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
|
||||
for (base::FilePath path = file_enumerator.Next(); !path.value().empty();
|
||||
path = file_enumerator.Next()) {
|
||||
files.push_back(DirectoryContentEntry(path, base::DirectoryExists(path)));
|
||||
|
||||
while (!file_enumerator.Next().empty()) {
|
||||
const base::FileEnumerator::FileInfo info = file_enumerator.GetInfo();
|
||||
(info.IsDirectory() ? subdirs : files)
|
||||
->push_back(path.Append(info.GetName()));
|
||||
}
|
||||
return files;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
base::Time GetLastModifiedTime(const base::FilePath& path) override {
|
||||
bool GetInfo(const base::FilePath& path, Info* const info) override {
|
||||
DCHECK(!path.IsAbsolute());
|
||||
DCHECK(info);
|
||||
|
||||
base::File::Info file_info;
|
||||
if (!base::GetFileInfo(path, &file_info)) {
|
||||
LOG(ERROR) << "Failed to retrieve file modification time for "
|
||||
<< path.value();
|
||||
if (!base::GetFileInfo(src_dir_.Append(path), &file_info)) {
|
||||
PLOG(ERROR) << "Cannot get info of " << Redact(path);
|
||||
return false;
|
||||
}
|
||||
return file_info.last_modified;
|
||||
|
||||
info->is_directory = file_info.is_directory;
|
||||
info->last_modified = file_info.last_modified;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
base::FilePath src_dir_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(DirectFileAccessor);
|
||||
const base::FilePath src_dir_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
ZipParams::ZipParams(const base::FilePath& src_dir,
|
||||
const base::FilePath& dest_file)
|
||||
: src_dir_(src_dir),
|
||||
dest_file_(dest_file),
|
||||
file_accessor_(new DirectFileAccessor(src_dir)) {}
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
// Does not take ownership of |fd|.
|
||||
ZipParams::ZipParams(const base::FilePath& src_dir, int dest_fd)
|
||||
: src_dir_(src_dir),
|
||||
dest_fd_(dest_fd),
|
||||
file_accessor_(new DirectFileAccessor(src_dir)) {}
|
||||
#endif
|
||||
std::ostream& operator<<(std::ostream& out, const Progress& progress) {
|
||||
return out << progress.bytes << " bytes, " << progress.files << " files, "
|
||||
<< progress.directories << " dirs, " << progress.errors
|
||||
<< " errors";
|
||||
}
|
||||
|
||||
bool Zip(const ZipParams& params) {
|
||||
// Using a pointer to avoid copies of a potentially large array.
|
||||
const std::vector<base::FilePath>* files_to_add = ¶ms.files_to_zip();
|
||||
std::vector<base::FilePath> all_files;
|
||||
if (files_to_add->empty()) {
|
||||
// Include all files from the src_dir (modulo the src_dir itself and
|
||||
// filtered and hidden files).
|
||||
|
||||
files_to_add = &all_files;
|
||||
// Using a list so we can call push_back while iterating.
|
||||
std::list<FileAccessor::DirectoryContentEntry> entries;
|
||||
entries.push_back(FileAccessor::DirectoryContentEntry(
|
||||
params.src_dir(), true /* is directory*/));
|
||||
const FilterCallback& filter_callback = params.filter_callback();
|
||||
for (auto iter = entries.begin(); iter != entries.end(); ++iter) {
|
||||
const base::FilePath& entry_path = iter->path;
|
||||
if (iter != entries.begin() && // Don't filter the root dir.
|
||||
((!params.include_hidden_files() && IsHiddenFile(entry_path)) ||
|
||||
(filter_callback && !filter_callback.Run(entry_path)))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (iter != entries.begin()) { // Exclude the root dir from the ZIP file.
|
||||
// Make the path relative for AddEntryToZip.
|
||||
base::FilePath relative_path;
|
||||
bool success =
|
||||
params.src_dir().AppendRelativePath(entry_path, &relative_path);
|
||||
DCHECK(success);
|
||||
all_files.push_back(relative_path);
|
||||
}
|
||||
|
||||
if (iter->is_directory) {
|
||||
std::vector<FileAccessor::DirectoryContentEntry> subentries =
|
||||
params.file_accessor()->ListDirectoryContent(entry_path);
|
||||
entries.insert(entries.end(), subentries.begin(), subentries.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
DirectFileAccessor default_accessor(params.src_dir);
|
||||
FileAccessor* const file_accessor = params.file_accessor ?: &default_accessor;
|
||||
|
||||
std::unique_ptr<internal::ZipWriter> zip_writer;
|
||||
#if defined(OS_POSIX)
|
||||
if (params.dest_fd() != base::kInvalidPlatformFile) {
|
||||
DCHECK(params.dest_file().empty());
|
||||
zip_writer = internal::ZipWriter::CreateWithFd(
|
||||
params.dest_fd(), params.src_dir(), params.file_accessor());
|
||||
|
||||
#if defined(OS_POSIX) || defined(OS_FUCHSIA)
|
||||
if (params.dest_fd != base::kInvalidPlatformFile) {
|
||||
DCHECK(params.dest_file.empty());
|
||||
zip_writer =
|
||||
internal::ZipWriter::CreateWithFd(params.dest_fd, file_accessor);
|
||||
if (!zip_writer)
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!zip_writer) {
|
||||
zip_writer = internal::ZipWriter::Create(
|
||||
params.dest_file(), params.src_dir(), params.file_accessor());
|
||||
zip_writer = internal::ZipWriter::Create(params.dest_file, file_accessor);
|
||||
if (!zip_writer)
|
||||
return false;
|
||||
}
|
||||
return zip_writer->WriteEntries(*files_to_add);
|
||||
|
||||
zip_writer->SetProgressCallback(params.progress_callback,
|
||||
params.progress_period);
|
||||
zip_writer->SetRecursive(params.recursive);
|
||||
zip_writer->ContinueOnError(params.continue_on_error);
|
||||
|
||||
if (!params.include_hidden_files || params.filter_callback)
|
||||
zip_writer->SetFilterCallback(base::BindRepeating(
|
||||
[](const ZipParams* const params, const base::FilePath& path) -> bool {
|
||||
return (params->include_hidden_files || !IsHiddenFile(path)) &&
|
||||
(!params->filter_callback ||
|
||||
params->filter_callback.Run(params->src_dir.Append(path)));
|
||||
},
|
||||
¶ms));
|
||||
|
||||
if (params.src_files.empty()) {
|
||||
// No source items are specified. Zip the entire source directory.
|
||||
zip_writer->SetRecursive(true);
|
||||
if (!zip_writer->AddDirectoryContents(base::FilePath()))
|
||||
return false;
|
||||
} else {
|
||||
// Only zip the specified source items.
|
||||
if (!zip_writer->AddMixedEntries(params.src_files))
|
||||
return false;
|
||||
}
|
||||
|
||||
return zip_writer->Close();
|
||||
}
|
||||
|
||||
bool Unzip(const base::FilePath& src_file, const base::FilePath& dest_dir) {
|
||||
return UnzipWithFilterCallback(
|
||||
src_file, dest_dir, base::BindRepeating(&ExcludeNoFilesFilter), true);
|
||||
}
|
||||
|
||||
bool UnzipWithFilterCallback(const base::FilePath& src_file,
|
||||
const base::FilePath& dest_dir,
|
||||
const FilterCallback& filter_cb,
|
||||
bool log_skipped_files) {
|
||||
bool Unzip(const base::FilePath& src_file,
|
||||
const base::FilePath& dest_dir,
|
||||
UnzipOptions options) {
|
||||
base::File file(src_file, base::File::FLAG_OPEN | base::File::FLAG_READ);
|
||||
if (!file.IsValid()) {
|
||||
DLOG(WARNING) << "Failed to open " << src_file.value();
|
||||
PLOG(ERROR) << "Cannot open " << Redact(src_file) << ": "
|
||||
<< base::File::ErrorToString(file.error_details());
|
||||
return false;
|
||||
}
|
||||
return UnzipWithFilterAndWriters(
|
||||
file.GetPlatformFile(),
|
||||
base::BindRepeating(&CreateFilePathWriterDelegate, dest_dir),
|
||||
base::BindRepeating(&CreateDirectory, dest_dir), filter_cb,
|
||||
log_skipped_files);
|
||||
|
||||
DLOG_IF(WARNING, !base::IsDirectoryEmpty(dest_dir))
|
||||
<< "ZIP extraction directory is not empty: " << dest_dir;
|
||||
|
||||
return Unzip(file.GetPlatformFile(),
|
||||
base::BindRepeating(&CreateFilePathWriterDelegate, dest_dir),
|
||||
base::BindRepeating(&CreateDirectory, dest_dir),
|
||||
std::move(options));
|
||||
}
|
||||
|
||||
bool UnzipWithFilterAndWriters(const base::PlatformFile& src_file,
|
||||
const WriterFactory& writer_factory,
|
||||
const DirectoryCreator& directory_creator,
|
||||
const FilterCallback& filter_cb,
|
||||
bool log_skipped_files) {
|
||||
bool Unzip(const base::PlatformFile& src_file,
|
||||
WriterFactory writer_factory,
|
||||
DirectoryCreator directory_creator,
|
||||
UnzipOptions options) {
|
||||
ZipReader reader;
|
||||
reader.SetEncoding(std::move(options.encoding));
|
||||
reader.SetPassword(std::move(options.password));
|
||||
|
||||
if (!reader.OpenFromPlatformFile(src_file)) {
|
||||
DLOG(WARNING) << "Failed to open src_file " << src_file;
|
||||
LOG(ERROR) << "Cannot open ZIP from file handle " << src_file;
|
||||
return false;
|
||||
}
|
||||
while (reader.HasMore()) {
|
||||
if (!reader.OpenCurrentEntryInZip()) {
|
||||
DLOG(WARNING) << "Failed to open the current file in zip";
|
||||
return false;
|
||||
}
|
||||
const base::FilePath& entry_path = reader.current_entry_info()->file_path();
|
||||
if (reader.current_entry_info()->is_unsafe()) {
|
||||
DLOG(WARNING) << "Found an unsafe file in zip " << entry_path;
|
||||
return false;
|
||||
}
|
||||
if (filter_cb.Run(entry_path)) {
|
||||
if (reader.current_entry_info()->is_directory()) {
|
||||
if (!directory_creator.Run(entry_path))
|
||||
return false;
|
||||
} else {
|
||||
std::unique_ptr<WriterDelegate> writer = writer_factory.Run(entry_path);
|
||||
if (!reader.ExtractCurrentEntry(writer.get(),
|
||||
std::numeric_limits<uint64_t>::max())) {
|
||||
DLOG(WARNING) << "Failed to extract " << entry_path;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else if (log_skipped_files) {
|
||||
DLOG(WARNING) << "Skipped file " << entry_path;
|
||||
|
||||
while (const ZipReader::Entry* const entry = reader.Next()) {
|
||||
if (entry->is_unsafe) {
|
||||
LOG(ERROR) << "Found unsafe entry " << Redact(entry->path) << " in ZIP";
|
||||
if (!options.continue_on_error)
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!reader.AdvanceToNextEntry()) {
|
||||
DLOG(WARNING) << "Failed to advance to the next file";
|
||||
return false;
|
||||
if (options.filter && !options.filter.Run(entry->path)) {
|
||||
VLOG(1) << "Skipped ZIP entry " << Redact(entry->path);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry->is_directory) {
|
||||
// It's a directory.
|
||||
if (!directory_creator.Run(entry->path)) {
|
||||
LOG(ERROR) << "Cannot create directory " << Redact(entry->path);
|
||||
if (!options.continue_on_error)
|
||||
return false;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// It's a file.
|
||||
std::unique_ptr<WriterDelegate> writer = writer_factory.Run(entry->path);
|
||||
if (!writer ||
|
||||
(options.progress ? !reader.ExtractCurrentEntryWithListener(
|
||||
writer.get(), options.progress)
|
||||
: !reader.ExtractCurrentEntry(writer.get()))) {
|
||||
LOG(ERROR) << "Cannot extract file " << Redact(entry->path)
|
||||
<< " from ZIP";
|
||||
if (!options.continue_on_error)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
return reader.ok();
|
||||
}
|
||||
|
||||
bool ZipWithFilterCallback(const base::FilePath& src_dir,
|
||||
const base::FilePath& dest_file,
|
||||
const FilterCallback& filter_cb) {
|
||||
FilterCallback filter) {
|
||||
DCHECK(base::DirectoryExists(src_dir));
|
||||
ZipParams params(src_dir, dest_file);
|
||||
params.set_filter_callback(filter_cb);
|
||||
return Zip(params);
|
||||
return Zip({.src_dir = src_dir,
|
||||
.dest_file = dest_file,
|
||||
.filter_callback = std::move(filter)});
|
||||
}
|
||||
|
||||
bool Zip(const base::FilePath& src_dir, const base::FilePath& dest_file,
|
||||
bool Zip(const base::FilePath& src_dir,
|
||||
const base::FilePath& dest_file,
|
||||
bool include_hidden_files) {
|
||||
if (include_hidden_files) {
|
||||
return ZipWithFilterCallback(src_dir, dest_file,
|
||||
base::BindRepeating(&ExcludeNoFilesFilter));
|
||||
} else {
|
||||
return ZipWithFilterCallback(
|
||||
src_dir, dest_file, base::BindRepeating(&ExcludeHiddenFilesFilter));
|
||||
}
|
||||
return Zip({.src_dir = src_dir,
|
||||
.dest_file = dest_file,
|
||||
.include_hidden_files = include_hidden_files});
|
||||
}
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
#if defined(OS_POSIX) || defined(OS_FUCHSIA)
|
||||
bool ZipFiles(const base::FilePath& src_dir,
|
||||
const std::vector<base::FilePath>& src_relative_paths,
|
||||
Paths src_relative_paths,
|
||||
int dest_fd) {
|
||||
DCHECK(base::DirectoryExists(src_dir));
|
||||
ZipParams params(src_dir, dest_fd);
|
||||
params.set_files_to_zip(src_relative_paths);
|
||||
return Zip(params);
|
||||
return Zip({.src_dir = src_dir,
|
||||
.dest_fd = dest_fd,
|
||||
.src_files = src_relative_paths});
|
||||
}
|
||||
#endif // defined(OS_POSIX)
|
||||
#endif // defined(OS_POSIX) || defined(OS_FUCHSIA)
|
||||
|
||||
} // namespace zip
|
||||
|
236
deps/zlib/google/zip.h
vendored
236
deps/zlib/google/zip.h
vendored
@ -1,13 +1,17 @@
|
||||
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
// Copyright 2011 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef THIRD_PARTY_ZLIB_GOOGLE_ZIP_H_
|
||||
#define THIRD_PARTY_ZLIB_GOOGLE_ZIP_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <ostream>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/containers/span.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/files/platform_file.h"
|
||||
#include "base/time/time.h"
|
||||
@ -21,99 +25,118 @@ namespace zip {
|
||||
|
||||
class WriterDelegate;
|
||||
|
||||
// Paths passed as span to avoid copying them.
|
||||
using Paths = base::span<const base::FilePath>;
|
||||
|
||||
// Abstraction for file access operation required by Zip().
|
||||
//
|
||||
// Can be passed to the ZipParams for providing custom access to the files,
|
||||
// for example over IPC.
|
||||
// If none is provided, the files are accessed directly.
|
||||
// All parameters paths are expected to be absolute.
|
||||
//
|
||||
// All parameters paths are expected to be relative to the source directory.
|
||||
class FileAccessor {
|
||||
public:
|
||||
virtual ~FileAccessor() = default;
|
||||
|
||||
struct DirectoryContentEntry {
|
||||
DirectoryContentEntry(const base::FilePath& path, bool is_directory)
|
||||
: path(path), is_directory(is_directory) {}
|
||||
base::FilePath path;
|
||||
struct Info {
|
||||
bool is_directory = false;
|
||||
base::Time last_modified;
|
||||
};
|
||||
|
||||
// Opens files specified in |paths|.
|
||||
// Directories should be mapped to invalid files.
|
||||
virtual std::vector<base::File> OpenFilesForReading(
|
||||
const std::vector<base::FilePath>& paths) = 0;
|
||||
virtual bool Open(Paths paths, std::vector<base::File>* files) = 0;
|
||||
|
||||
virtual bool DirectoryExists(const base::FilePath& path) = 0;
|
||||
virtual std::vector<DirectoryContentEntry> ListDirectoryContent(
|
||||
const base::FilePath& dir_path) = 0;
|
||||
virtual base::Time GetLastModifiedTime(const base::FilePath& path) = 0;
|
||||
// Lists contents of a directory at |path|.
|
||||
virtual bool List(const base::FilePath& path,
|
||||
std::vector<base::FilePath>* files,
|
||||
std::vector<base::FilePath>* subdirs) = 0;
|
||||
|
||||
// Gets info about a file or directory.
|
||||
virtual bool GetInfo(const base::FilePath& path, Info* info) = 0;
|
||||
};
|
||||
|
||||
class ZipParams {
|
||||
public:
|
||||
ZipParams(const base::FilePath& src_dir, const base::FilePath& dest_file);
|
||||
#if defined(OS_POSIX)
|
||||
// Does not take ownership of |dest_fd|.
|
||||
ZipParams(const base::FilePath& src_dir, int dest_fd);
|
||||
// Progress of a ZIP creation operation.
|
||||
struct Progress {
|
||||
// Total number of bytes read from files getting zipped so far.
|
||||
std::int64_t bytes = 0;
|
||||
|
||||
int dest_fd() const { return dest_fd_; }
|
||||
// Number of file entries added to the ZIP so far.
|
||||
// A file entry is added after its bytes have been processed.
|
||||
int files = 0;
|
||||
|
||||
// Number of directory entries added to the ZIP so far.
|
||||
// A directory entry is added before items in it.
|
||||
int directories = 0;
|
||||
|
||||
// Number of errors encountered so far (files that cannot be opened,
|
||||
// directories that cannot be listed).
|
||||
int errors = 0;
|
||||
};
|
||||
|
||||
// Prints Progress to output stream.
|
||||
std::ostream& operator<<(std::ostream& out, const Progress& progress);
|
||||
|
||||
// Callback reporting the progress of a ZIP creation operation.
|
||||
//
|
||||
// This callback returns a boolean indicating whether the ZIP creation operation
|
||||
// should continue. If it returns false once, then the ZIP creation operation is
|
||||
// immediately cancelled and the callback won't be called again.
|
||||
using ProgressCallback = base::RepeatingCallback<bool(const Progress&)>;
|
||||
|
||||
using FilterCallback = base::RepeatingCallback<bool(const base::FilePath&)>;
|
||||
|
||||
// ZIP creation parameters and options.
|
||||
struct ZipParams {
|
||||
// Source directory. Ignored if |file_accessor| is set.
|
||||
base::FilePath src_dir;
|
||||
|
||||
// Abstraction around file system access used to read files.
|
||||
// If left null, an implementation that accesses files directly is used.
|
||||
FileAccessor* file_accessor = nullptr; // Not owned
|
||||
|
||||
// Destination file path.
|
||||
// Either dest_file or dest_fd should be set, but not both.
|
||||
base::FilePath dest_file;
|
||||
|
||||
#if defined(OS_POSIX) || defined(OS_FUCHSIA)
|
||||
// Destination file passed a file descriptor.
|
||||
// Either dest_file or dest_fd should be set, but not both.
|
||||
int dest_fd = base::kInvalidPlatformFile;
|
||||
#endif
|
||||
|
||||
const base::FilePath& src_dir() const { return src_dir_; }
|
||||
// The relative paths to the files and directories that should be included in
|
||||
// the ZIP file. If this is empty, the whole contents of |src_dir| are
|
||||
// included.
|
||||
//
|
||||
// These paths must be relative to |src_dir| and will be used as the file
|
||||
// names in the created ZIP file. All files must be under |src_dir| in the
|
||||
// file system hierarchy.
|
||||
//
|
||||
// All the paths in |src_files| are included in the created ZIP file,
|
||||
// irrespective of |include_hidden_files| and |filter_callback|.
|
||||
Paths src_files;
|
||||
|
||||
const base::FilePath& dest_file() const { return dest_file_; }
|
||||
// Filter used to exclude files from the ZIP file. This is only taken in
|
||||
// account when recursively adding subdirectory contents.
|
||||
FilterCallback filter_callback;
|
||||
|
||||
// Restricts the files actually zipped to the paths listed in
|
||||
// |src_relative_paths|. They must be relative to the |src_dir| passed in the
|
||||
// constructor and will be used as the file names in the created zip file. All
|
||||
// source paths must be under |src_dir| in the file system hierarchy.
|
||||
void set_files_to_zip(const std::vector<base::FilePath>& src_relative_paths) {
|
||||
src_files_ = src_relative_paths;
|
||||
}
|
||||
const std::vector<base::FilePath>& files_to_zip() const { return src_files_; }
|
||||
// Optional progress reporting callback.
|
||||
ProgressCallback progress_callback;
|
||||
|
||||
using FilterCallback = base::RepeatingCallback<bool(const base::FilePath&)>;
|
||||
void set_filter_callback(FilterCallback filter_callback) {
|
||||
filter_callback_ = filter_callback;
|
||||
}
|
||||
const FilterCallback& filter_callback() const { return filter_callback_; }
|
||||
// Progress reporting period. The final callback is always called when the ZIP
|
||||
// creation operation completes.
|
||||
base::TimeDelta progress_period;
|
||||
|
||||
void set_include_hidden_files(bool include_hidden_files) {
|
||||
include_hidden_files_ = include_hidden_files;
|
||||
}
|
||||
bool include_hidden_files() const { return include_hidden_files_; }
|
||||
// Should add hidden files? This is only taken in account when recursively
|
||||
// adding subdirectory contents.
|
||||
bool include_hidden_files = true;
|
||||
|
||||
// Sets a custom file accessor for file operations. Default is to directly
|
||||
// access the files (with fopen and the rest).
|
||||
// Useful in cases where running in a sandbox process and file access has to
|
||||
// go through IPC, for example.
|
||||
void set_file_accessor(std::unique_ptr<FileAccessor> file_accessor) {
|
||||
file_accessor_ = std::move(file_accessor);
|
||||
}
|
||||
FileAccessor* file_accessor() const { return file_accessor_.get(); }
|
||||
// Should recursively add subdirectory contents?
|
||||
bool recursive = false;
|
||||
|
||||
private:
|
||||
base::FilePath src_dir_;
|
||||
|
||||
base::FilePath dest_file_;
|
||||
#if defined(OS_POSIX)
|
||||
int dest_fd_ = base::kInvalidPlatformFile;
|
||||
#endif
|
||||
|
||||
// The relative paths to the files that should be included in the zip file. If
|
||||
// this is empty, all files in |src_dir_| are included.
|
||||
std::vector<base::FilePath> src_files_;
|
||||
|
||||
// Filter used to exclude files from the ZIP file. Only effective when
|
||||
// |src_files_| is empty.
|
||||
FilterCallback filter_callback_;
|
||||
|
||||
// Whether hidden files should be included in the ZIP file. Only effective
|
||||
// when |src_files_| is empty.
|
||||
bool include_hidden_files_ = true;
|
||||
|
||||
// Abstraction around file system access used to read files. An implementation
|
||||
// that accesses files directly is provided by default.
|
||||
std::unique_ptr<FileAccessor> file_accessor_;
|
||||
// Should ignore errors when discovering files and zipping them?
|
||||
bool continue_on_error = false;
|
||||
};
|
||||
|
||||
// Zip files specified into a ZIP archives. The source files and ZIP destination
|
||||
@ -125,56 +148,71 @@ bool Zip(const ZipParams& params);
|
||||
// of src_dir will be at the root level of the created zip. For each file in
|
||||
// src_dir, include it only if the callback |filter_cb| returns true. Otherwise
|
||||
// omit it.
|
||||
using FilterCallback = base::RepeatingCallback<bool(const base::FilePath&)>;
|
||||
bool ZipWithFilterCallback(const base::FilePath& src_dir,
|
||||
const base::FilePath& dest_file,
|
||||
const FilterCallback& filter_cb);
|
||||
FilterCallback filter_cb);
|
||||
|
||||
// Convenience method for callers who don't need to set up the filter callback.
|
||||
// If |include_hidden_files| is true, files starting with "." are included.
|
||||
// Otherwise they are omitted.
|
||||
bool Zip(const base::FilePath& src_dir, const base::FilePath& dest_file,
|
||||
bool Zip(const base::FilePath& src_dir,
|
||||
const base::FilePath& dest_file,
|
||||
bool include_hidden_files);
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
#if defined(OS_POSIX) || defined(OS_FUCHSIA)
|
||||
// Zips files listed in |src_relative_paths| to destination specified by file
|
||||
// descriptor |dest_fd|, without taking ownership of |dest_fd|. The paths listed
|
||||
// in |src_relative_paths| are relative to the |src_dir| and will be used as the
|
||||
// file names in the created zip file. All source paths must be under |src_dir|
|
||||
// in the file system hierarchy.
|
||||
bool ZipFiles(const base::FilePath& src_dir,
|
||||
const std::vector<base::FilePath>& src_relative_paths,
|
||||
Paths src_relative_paths,
|
||||
int dest_fd);
|
||||
#endif // defined(OS_POSIX)
|
||||
#endif // defined(OS_POSIX) || defined(OS_FUCHSIA)
|
||||
|
||||
// Unzip the contents of zip_file into dest_dir.
|
||||
// For each file in zip_file, include it only if the callback |filter_cb|
|
||||
// returns true. Otherwise omit it.
|
||||
// If |log_skipped_files| is true, files skipped during extraction are printed
|
||||
// to debug log.
|
||||
using FilterCallback = base::RepeatingCallback<bool(const base::FilePath&)>;
|
||||
bool UnzipWithFilterCallback(const base::FilePath& zip_file,
|
||||
const base::FilePath& dest_dir,
|
||||
const FilterCallback& filter_cb,
|
||||
bool log_skipped_files);
|
||||
// Callback reporting the number of bytes written during Unzip.
|
||||
using UnzipProgressCallback = base::RepeatingCallback<void(uint64_t bytes)>;
|
||||
|
||||
// Options of the Unzip function, with valid default values.
|
||||
struct UnzipOptions {
|
||||
// Encoding of entry paths in the ZIP archive. By default, paths are assumed
|
||||
// to be in UTF-8.
|
||||
std::string encoding;
|
||||
|
||||
// Only extract the entries for which |filter_cb| returns true. By default,
|
||||
// everything gets extracted.
|
||||
FilterCallback filter;
|
||||
|
||||
// Callback to report bytes extracted from the ZIP.
|
||||
UnzipProgressCallback progress;
|
||||
|
||||
// Password to decrypt the encrypted files.
|
||||
std::string password;
|
||||
|
||||
// Should ignore errors when extracting files?
|
||||
bool continue_on_error = false;
|
||||
};
|
||||
|
||||
// Unzip the contents of zip_file, using the writers provided by writer_factory.
|
||||
// For each file in zip_file, include it only if the callback |filter_cb|
|
||||
// returns true. Otherwise omit it.
|
||||
// If |log_skipped_files| is true, files skipped during extraction are printed
|
||||
// to debug log.
|
||||
typedef base::RepeatingCallback<std::unique_ptr<WriterDelegate>(
|
||||
const base::FilePath&)>
|
||||
WriterFactory;
|
||||
typedef base::RepeatingCallback<bool(const base::FilePath&)> DirectoryCreator;
|
||||
bool UnzipWithFilterAndWriters(const base::PlatformFile& zip_file,
|
||||
const WriterFactory& writer_factory,
|
||||
const DirectoryCreator& directory_creator,
|
||||
const FilterCallback& filter_cb,
|
||||
bool log_skipped_files);
|
||||
|
||||
// Unzip the contents of zip_file into dest_dir.
|
||||
bool Unzip(const base::FilePath& zip_file, const base::FilePath& dest_dir);
|
||||
typedef base::RepeatingCallback<bool(const base::FilePath&)> DirectoryCreator;
|
||||
|
||||
// Unzips the contents of |zip_file|, using the writers provided by
|
||||
// |writer_factory|.
|
||||
bool Unzip(const base::PlatformFile& zip_file,
|
||||
WriterFactory writer_factory,
|
||||
DirectoryCreator directory_creator,
|
||||
UnzipOptions options = {});
|
||||
|
||||
// Unzips the contents of |zip_file| into |dest_dir|.
|
||||
// This function does not overwrite any existing file.
|
||||
// A filename collision will result in an error.
|
||||
// Therefore, |dest_dir| should initially be an empty directory.
|
||||
bool Unzip(const base::FilePath& zip_file,
|
||||
const base::FilePath& dest_dir,
|
||||
UnzipOptions options = {});
|
||||
|
||||
} // namespace zip
|
||||
|
||||
|
244
deps/zlib/google/zip_internal.cc
vendored
244
deps/zlib/google/zip_internal.cc
vendored
@ -1,14 +1,20 @@
|
||||
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
// Copyright 2011 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "third_party/zlib/google/zip_internal.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/no_destructor.h"
|
||||
#include "base/notreached.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
|
||||
#if defined(USE_SYSTEM_MINIZIP)
|
||||
@ -34,9 +40,9 @@ typedef struct {
|
||||
} WIN32FILE_IOWIN;
|
||||
|
||||
// This function is derived from third_party/minizip/iowin32.c.
|
||||
// Its only difference is that it treats the char* as UTF8 and
|
||||
// Its only difference is that it treats the filename as UTF-8 and
|
||||
// uses the Unicode version of CreateFile.
|
||||
void* ZipOpenFunc(void *opaque, const char* filename, int mode) {
|
||||
void* ZipOpenFunc(void* opaque, const void* filename, int mode) {
|
||||
DWORD desired_access = 0, creation_disposition = 0;
|
||||
DWORD share_mode = 0, flags_and_attributes = 0;
|
||||
HANDLE file = 0;
|
||||
@ -54,10 +60,11 @@ void* ZipOpenFunc(void *opaque, const char* filename, int mode) {
|
||||
creation_disposition = CREATE_ALWAYS;
|
||||
}
|
||||
|
||||
base::string16 filename16 = base::UTF8ToUTF16(filename);
|
||||
if ((filename != NULL) && (desired_access != 0)) {
|
||||
file = CreateFile(filename16.c_str(), desired_access, share_mode,
|
||||
NULL, creation_disposition, flags_and_attributes, NULL);
|
||||
if (filename != nullptr && desired_access != 0) {
|
||||
file = CreateFileW(
|
||||
base::UTF8ToWide(static_cast<const char*>(filename)).c_str(),
|
||||
desired_access, share_mode, nullptr, creation_disposition,
|
||||
flags_and_attributes, nullptr);
|
||||
}
|
||||
|
||||
if (file == INVALID_HANDLE_VALUE)
|
||||
@ -77,11 +84,11 @@ void* ZipOpenFunc(void *opaque, const char* filename, int mode) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
#if defined(OS_POSIX) || defined(OS_FUCHSIA)
|
||||
// Callback function for zlib that opens a file stream from a file descriptor.
|
||||
// Since we do not own the file descriptor, dup it so that we can fdopen/fclose
|
||||
// a file stream.
|
||||
void* FdOpenFileFunc(void* opaque, const char* filename, int mode) {
|
||||
void* FdOpenFileFunc(void* opaque, const void* filename, int mode) {
|
||||
FILE* file = NULL;
|
||||
const char* mode_fopen = NULL;
|
||||
|
||||
@ -103,15 +110,15 @@ void* FdOpenFileFunc(void* opaque, const char* filename, int mode) {
|
||||
|
||||
int FdCloseFileFunc(void* opaque, void* stream) {
|
||||
fclose(static_cast<FILE*>(stream));
|
||||
free(opaque); // malloc'ed in FillFdOpenFileFunc()
|
||||
free(opaque); // malloc'ed in FillFdOpenFileFunc()
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Fills |pzlib_filecunc_def| appropriately to handle the zip file
|
||||
// referred to by |fd|.
|
||||
void FillFdOpenFileFunc(zlib_filefunc_def* pzlib_filefunc_def, int fd) {
|
||||
fill_fopen_filefunc(pzlib_filefunc_def);
|
||||
pzlib_filefunc_def->zopen_file = FdOpenFileFunc;
|
||||
void FillFdOpenFileFunc(zlib_filefunc64_def* pzlib_filefunc_def, int fd) {
|
||||
fill_fopen64_filefunc(pzlib_filefunc_def);
|
||||
pzlib_filefunc_def->zopen64_file = FdOpenFileFunc;
|
||||
pzlib_filefunc_def->zclose_file = FdCloseFileFunc;
|
||||
int* ptr_fd = static_cast<int*>(malloc(sizeof(fd)));
|
||||
*ptr_fd = fd;
|
||||
@ -122,7 +129,7 @@ void FillFdOpenFileFunc(zlib_filefunc_def* pzlib_filefunc_def, int fd) {
|
||||
#if defined(OS_WIN)
|
||||
// Callback function for zlib that opens a file stream from a Windows handle.
|
||||
// Does not take ownership of the handle.
|
||||
void* HandleOpenFileFunc(void* opaque, const char* filename, int mode) {
|
||||
void* HandleOpenFileFunc(void* opaque, const void* /*filename*/, int mode) {
|
||||
WIN32FILE_IOWIN file_ret;
|
||||
file_ret.hf = static_cast<HANDLE>(opaque);
|
||||
file_ret.error = 0;
|
||||
@ -136,7 +143,7 @@ void* HandleOpenFileFunc(void* opaque, const char* filename, int mode) {
|
||||
}
|
||||
|
||||
int HandleCloseFileFunc(void* opaque, void* stream) {
|
||||
free(stream); // malloc'ed in HandleOpenFileFunc()
|
||||
free(stream); // malloc'ed in HandleOpenFileFunc()
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@ -146,8 +153,8 @@ int HandleCloseFileFunc(void* opaque, void* stream) {
|
||||
// expect their opaque parameters refer to this struct.
|
||||
struct ZipBuffer {
|
||||
const char* data; // weak
|
||||
size_t length;
|
||||
size_t offset;
|
||||
ZPOS64_T length;
|
||||
ZPOS64_T offset;
|
||||
};
|
||||
|
||||
// Opens the specified file. When this function returns a non-NULL pointer, zlib
|
||||
@ -156,7 +163,7 @@ struct ZipBuffer {
|
||||
// given opaque parameter and returns it because this parameter stores all
|
||||
// information needed for uncompressing data. (This function does not support
|
||||
// writing compressed data and it returns NULL for this case.)
|
||||
void* OpenZipBuffer(void* opaque, const char* /*filename*/, int mode) {
|
||||
void* OpenZipBuffer(void* opaque, const void* /*filename*/, int mode) {
|
||||
if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) != ZLIB_FILEFUNC_MODE_READ) {
|
||||
NOTREACHED();
|
||||
return NULL;
|
||||
@ -173,10 +180,11 @@ void* OpenZipBuffer(void* opaque, const char* /*filename*/, int mode) {
|
||||
uLong ReadZipBuffer(void* opaque, void* /*stream*/, void* buf, uLong size) {
|
||||
ZipBuffer* buffer = static_cast<ZipBuffer*>(opaque);
|
||||
DCHECK_LE(buffer->offset, buffer->length);
|
||||
size_t remaining_bytes = buffer->length - buffer->offset;
|
||||
ZPOS64_T remaining_bytes = buffer->length - buffer->offset;
|
||||
if (!buffer || !buffer->data || !remaining_bytes)
|
||||
return 0;
|
||||
size = std::min(size, static_cast<uLong>(remaining_bytes));
|
||||
if (size > remaining_bytes)
|
||||
size = remaining_bytes;
|
||||
memcpy(buf, &buffer->data[buffer->offset], size);
|
||||
buffer->offset += size;
|
||||
return size;
|
||||
@ -193,21 +201,23 @@ uLong WriteZipBuffer(void* /*opaque*/,
|
||||
}
|
||||
|
||||
// Returns the offset from the beginning of the data.
|
||||
long GetOffsetOfZipBuffer(void* opaque, void* /*stream*/) {
|
||||
ZPOS64_T GetOffsetOfZipBuffer(void* opaque, void* /*stream*/) {
|
||||
ZipBuffer* buffer = static_cast<ZipBuffer*>(opaque);
|
||||
if (!buffer)
|
||||
return -1;
|
||||
return static_cast<long>(buffer->offset);
|
||||
return buffer->offset;
|
||||
}
|
||||
|
||||
// Moves the current offset to the specified position.
|
||||
long SeekZipBuffer(void* opaque, void* /*stream*/, uLong offset, int origin) {
|
||||
long SeekZipBuffer(void* opaque,
|
||||
void* /*stream*/,
|
||||
ZPOS64_T offset,
|
||||
int origin) {
|
||||
ZipBuffer* buffer = static_cast<ZipBuffer*>(opaque);
|
||||
if (!buffer)
|
||||
return -1;
|
||||
if (origin == ZLIB_FILEFUNC_SEEK_CUR) {
|
||||
buffer->offset = std::min(buffer->offset + static_cast<size_t>(offset),
|
||||
buffer->length);
|
||||
buffer->offset = std::min(buffer->offset + offset, buffer->length);
|
||||
return 0;
|
||||
}
|
||||
if (origin == ZLIB_FILEFUNC_SEEK_END) {
|
||||
@ -215,7 +225,7 @@ long SeekZipBuffer(void* opaque, void* /*stream*/, uLong offset, int origin) {
|
||||
return 0;
|
||||
}
|
||||
if (origin == ZLIB_FILEFUNC_SEEK_SET) {
|
||||
buffer->offset = std::min(buffer->length, static_cast<size_t>(offset));
|
||||
buffer->offset = std::min(buffer->length, offset);
|
||||
return 0;
|
||||
}
|
||||
NOTREACHED();
|
||||
@ -241,7 +251,7 @@ int GetErrorOfZipBuffer(void* /*opaque*/, void* /*stream*/) {
|
||||
// Returns a zip_fileinfo struct with the time represented by |file_time|.
|
||||
zip_fileinfo TimeToZipFileInfo(const base::Time& file_time) {
|
||||
base::Time::Exploded file_time_parts;
|
||||
file_time.LocalExplode(&file_time_parts);
|
||||
file_time.UTCExplode(&file_time_parts);
|
||||
|
||||
zip_fileinfo zip_info = {};
|
||||
if (file_time_parts.year >= 1980) {
|
||||
@ -266,33 +276,33 @@ namespace zip {
|
||||
namespace internal {
|
||||
|
||||
unzFile OpenForUnzipping(const std::string& file_name_utf8) {
|
||||
zlib_filefunc_def* zip_func_ptrs = NULL;
|
||||
zlib_filefunc64_def* zip_func_ptrs = nullptr;
|
||||
#if defined(OS_WIN)
|
||||
zlib_filefunc_def zip_funcs;
|
||||
fill_win32_filefunc(&zip_funcs);
|
||||
zip_funcs.zopen_file = ZipOpenFunc;
|
||||
zlib_filefunc64_def zip_funcs;
|
||||
fill_win32_filefunc64(&zip_funcs);
|
||||
zip_funcs.zopen64_file = ZipOpenFunc;
|
||||
zip_func_ptrs = &zip_funcs;
|
||||
#endif
|
||||
return unzOpen2(file_name_utf8.c_str(), zip_func_ptrs);
|
||||
return unzOpen2_64(file_name_utf8.c_str(), zip_func_ptrs);
|
||||
}
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
#if defined(OS_POSIX) || defined(OS_FUCHSIA)
|
||||
unzFile OpenFdForUnzipping(int zip_fd) {
|
||||
zlib_filefunc_def zip_funcs;
|
||||
zlib_filefunc64_def zip_funcs;
|
||||
FillFdOpenFileFunc(&zip_funcs, zip_fd);
|
||||
// Passing dummy "fd" filename to zlib.
|
||||
return unzOpen2("fd", &zip_funcs);
|
||||
return unzOpen2_64("fd", &zip_funcs);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(OS_WIN)
|
||||
unzFile OpenHandleForUnzipping(HANDLE zip_handle) {
|
||||
zlib_filefunc_def zip_funcs;
|
||||
fill_win32_filefunc(&zip_funcs);
|
||||
zip_funcs.zopen_file = HandleOpenFileFunc;
|
||||
zlib_filefunc64_def zip_funcs;
|
||||
fill_win32_filefunc64(&zip_funcs);
|
||||
zip_funcs.zopen64_file = HandleOpenFileFunc;
|
||||
zip_funcs.zclose_file = HandleCloseFileFunc;
|
||||
zip_funcs.opaque = zip_handle;
|
||||
return unzOpen2("fd", &zip_funcs);
|
||||
return unzOpen2_64("fd", &zip_funcs);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -308,72 +318,152 @@ unzFile PrepareMemoryForUnzipping(const std::string& data) {
|
||||
buffer->length = data.length();
|
||||
buffer->offset = 0;
|
||||
|
||||
zlib_filefunc_def zip_functions;
|
||||
zip_functions.zopen_file = OpenZipBuffer;
|
||||
zlib_filefunc64_def zip_functions;
|
||||
zip_functions.zopen64_file = OpenZipBuffer;
|
||||
zip_functions.zread_file = ReadZipBuffer;
|
||||
zip_functions.zwrite_file = WriteZipBuffer;
|
||||
zip_functions.ztell_file = GetOffsetOfZipBuffer;
|
||||
zip_functions.zseek_file = SeekZipBuffer;
|
||||
zip_functions.ztell64_file = GetOffsetOfZipBuffer;
|
||||
zip_functions.zseek64_file = SeekZipBuffer;
|
||||
zip_functions.zclose_file = CloseZipBuffer;
|
||||
zip_functions.zerror_file = GetErrorOfZipBuffer;
|
||||
zip_functions.opaque = static_cast<void*>(buffer);
|
||||
return unzOpen2(NULL, &zip_functions);
|
||||
zip_functions.opaque = buffer;
|
||||
return unzOpen2_64(nullptr, &zip_functions);
|
||||
}
|
||||
|
||||
zipFile OpenForZipping(const std::string& file_name_utf8, int append_flag) {
|
||||
zlib_filefunc_def* zip_func_ptrs = NULL;
|
||||
zlib_filefunc64_def* zip_func_ptrs = nullptr;
|
||||
#if defined(OS_WIN)
|
||||
zlib_filefunc_def zip_funcs;
|
||||
fill_win32_filefunc(&zip_funcs);
|
||||
zip_funcs.zopen_file = ZipOpenFunc;
|
||||
zlib_filefunc64_def zip_funcs;
|
||||
fill_win32_filefunc64(&zip_funcs);
|
||||
zip_funcs.zopen64_file = ZipOpenFunc;
|
||||
zip_func_ptrs = &zip_funcs;
|
||||
#endif
|
||||
return zipOpen2(file_name_utf8.c_str(),
|
||||
append_flag,
|
||||
NULL, // global comment
|
||||
zip_func_ptrs);
|
||||
return zipOpen2_64(file_name_utf8.c_str(), append_flag, nullptr,
|
||||
zip_func_ptrs);
|
||||
}
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
#if defined(OS_POSIX) || defined(OS_FUCHSIA)
|
||||
zipFile OpenFdForZipping(int zip_fd, int append_flag) {
|
||||
zlib_filefunc_def zip_funcs;
|
||||
zlib_filefunc64_def zip_funcs;
|
||||
FillFdOpenFileFunc(&zip_funcs, zip_fd);
|
||||
// Passing dummy "fd" filename to zlib.
|
||||
return zipOpen2("fd", append_flag, NULL, &zip_funcs);
|
||||
return zipOpen2_64("fd", append_flag, nullptr, &zip_funcs);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool ZipOpenNewFileInZip(zipFile zip_file,
|
||||
const std::string& str_path,
|
||||
base::Time last_modified_time) {
|
||||
base::Time last_modified_time,
|
||||
Compression compression) {
|
||||
// Section 4.4.4 http://www.pkware.com/documents/casestudies/APPNOTE.TXT
|
||||
// Setting the Language encoding flag so the file is told to be in utf-8.
|
||||
const uLong LANGUAGE_ENCODING_FLAG = 0x1 << 11;
|
||||
|
||||
zip_fileinfo file_info = TimeToZipFileInfo(last_modified_time);
|
||||
if (ZIP_OK != zipOpenNewFileInZip4(zip_file, // file
|
||||
str_path.c_str(), // filename
|
||||
&file_info, // zip_fileinfo
|
||||
NULL, // extrafield_local,
|
||||
0u, // size_extrafield_local
|
||||
NULL, // extrafield_global
|
||||
0u, // size_extrafield_global
|
||||
NULL, // comment
|
||||
Z_DEFLATED, // method
|
||||
Z_DEFAULT_COMPRESSION, // level
|
||||
0, // raw
|
||||
-MAX_WBITS, // windowBits
|
||||
DEF_MEM_LEVEL, // memLevel
|
||||
Z_DEFAULT_STRATEGY, // strategy
|
||||
NULL, // password
|
||||
0, // crcForCrypting
|
||||
0, // versionMadeBy
|
||||
LANGUAGE_ENCODING_FLAG)) { // flagBase
|
||||
DLOG(ERROR) << "Could not open zip file entry " << str_path;
|
||||
const zip_fileinfo file_info = TimeToZipFileInfo(last_modified_time);
|
||||
const int err = zipOpenNewFileInZip4_64(
|
||||
/*file=*/zip_file,
|
||||
/*filename=*/str_path.c_str(),
|
||||
/*zip_fileinfo=*/&file_info,
|
||||
/*extrafield_local=*/nullptr,
|
||||
/*size_extrafield_local=*/0u,
|
||||
/*extrafield_global=*/nullptr,
|
||||
/*size_extrafield_global=*/0u,
|
||||
/*comment=*/nullptr,
|
||||
/*method=*/compression,
|
||||
/*level=*/Z_DEFAULT_COMPRESSION,
|
||||
/*raw=*/0,
|
||||
/*windowBits=*/-MAX_WBITS,
|
||||
/*memLevel=*/DEF_MEM_LEVEL,
|
||||
/*strategy=*/Z_DEFAULT_STRATEGY,
|
||||
/*password=*/nullptr,
|
||||
/*crcForCrypting=*/0,
|
||||
/*versionMadeBy=*/0,
|
||||
/*flagBase=*/LANGUAGE_ENCODING_FLAG,
|
||||
/*zip64=*/1);
|
||||
|
||||
if (err != ZIP_OK) {
|
||||
DLOG(ERROR) << "Cannot open ZIP file entry '" << str_path
|
||||
<< "': zipOpenNewFileInZip4_64 returned " << err;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Compression GetCompressionMethod(const base::FilePath& path) {
|
||||
// Get the filename extension in lower case.
|
||||
const base::FilePath::StringType ext =
|
||||
base::ToLowerASCII(path.FinalExtension());
|
||||
|
||||
if (ext.empty())
|
||||
return kDeflated;
|
||||
|
||||
using StringPiece = base::FilePath::StringPieceType;
|
||||
|
||||
// Skip the leading dot.
|
||||
StringPiece ext_without_dot = ext;
|
||||
DCHECK_EQ(ext_without_dot.front(), FILE_PATH_LITERAL('.'));
|
||||
ext_without_dot.remove_prefix(1);
|
||||
|
||||
// Well known filename extensions of files that a likely to be already
|
||||
// compressed. The extensions are in lower case without the leading dot.
|
||||
static const base::NoDestructor<
|
||||
std::unordered_set<StringPiece, base::StringPieceHashImpl<StringPiece>>>
|
||||
exts(std::initializer_list<StringPiece>{
|
||||
FILE_PATH_LITERAL("3g2"), //
|
||||
FILE_PATH_LITERAL("3gp"), //
|
||||
FILE_PATH_LITERAL("7z"), //
|
||||
FILE_PATH_LITERAL("7zip"), //
|
||||
FILE_PATH_LITERAL("aac"), //
|
||||
FILE_PATH_LITERAL("avi"), //
|
||||
FILE_PATH_LITERAL("bz"), //
|
||||
FILE_PATH_LITERAL("bz2"), //
|
||||
FILE_PATH_LITERAL("crx"), //
|
||||
FILE_PATH_LITERAL("gif"), //
|
||||
FILE_PATH_LITERAL("gz"), //
|
||||
FILE_PATH_LITERAL("jar"), //
|
||||
FILE_PATH_LITERAL("jpeg"), //
|
||||
FILE_PATH_LITERAL("jpg"), //
|
||||
FILE_PATH_LITERAL("lz"), //
|
||||
FILE_PATH_LITERAL("m2v"), //
|
||||
FILE_PATH_LITERAL("m4p"), //
|
||||
FILE_PATH_LITERAL("m4v"), //
|
||||
FILE_PATH_LITERAL("mng"), //
|
||||
FILE_PATH_LITERAL("mov"), //
|
||||
FILE_PATH_LITERAL("mp2"), //
|
||||
FILE_PATH_LITERAL("mp3"), //
|
||||
FILE_PATH_LITERAL("mp4"), //
|
||||
FILE_PATH_LITERAL("mpe"), //
|
||||
FILE_PATH_LITERAL("mpeg"), //
|
||||
FILE_PATH_LITERAL("mpg"), //
|
||||
FILE_PATH_LITERAL("mpv"), //
|
||||
FILE_PATH_LITERAL("ogg"), //
|
||||
FILE_PATH_LITERAL("ogv"), //
|
||||
FILE_PATH_LITERAL("png"), //
|
||||
FILE_PATH_LITERAL("qt"), //
|
||||
FILE_PATH_LITERAL("rar"), //
|
||||
FILE_PATH_LITERAL("taz"), //
|
||||
FILE_PATH_LITERAL("tb2"), //
|
||||
FILE_PATH_LITERAL("tbz"), //
|
||||
FILE_PATH_LITERAL("tbz2"), //
|
||||
FILE_PATH_LITERAL("tgz"), //
|
||||
FILE_PATH_LITERAL("tlz"), //
|
||||
FILE_PATH_LITERAL("tz"), //
|
||||
FILE_PATH_LITERAL("tz2"), //
|
||||
FILE_PATH_LITERAL("vob"), //
|
||||
FILE_PATH_LITERAL("webm"), //
|
||||
FILE_PATH_LITERAL("wma"), //
|
||||
FILE_PATH_LITERAL("wmv"), //
|
||||
FILE_PATH_LITERAL("xz"), //
|
||||
FILE_PATH_LITERAL("z"), //
|
||||
FILE_PATH_LITERAL("zip"), //
|
||||
});
|
||||
|
||||
if (exts->count(ext_without_dot))
|
||||
return kStored;
|
||||
|
||||
return kDeflated;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace zip
|
||||
|
24
deps/zlib/google/zip_internal.h
vendored
24
deps/zlib/google/zip_internal.h
vendored
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
// Copyright 2011 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
@ -35,7 +35,7 @@ namespace internal {
|
||||
// Windows.
|
||||
unzFile OpenForUnzipping(const std::string& file_name_utf8);
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
#if defined(OS_POSIX) || defined(OS_FUCHSIA)
|
||||
// Opens the file referred to by |zip_fd| for unzipping.
|
||||
unzFile OpenFdForUnzipping(int zip_fd);
|
||||
#endif
|
||||
@ -54,16 +54,30 @@ unzFile PrepareMemoryForUnzipping(const std::string& data);
|
||||
// Windows. |append_flag| will be passed to zipOpen2().
|
||||
zipFile OpenForZipping(const std::string& file_name_utf8, int append_flag);
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
#if defined(OS_POSIX) || defined(OS_FUCHSIA)
|
||||
// Opens the file referred to by |zip_fd| for zipping. |append_flag| will be
|
||||
// passed to zipOpen2().
|
||||
zipFile OpenFdForZipping(int zip_fd, int append_flag);
|
||||
#endif
|
||||
|
||||
// Wrapper around zipOpenNewFileInZip4 which passes most common options.
|
||||
// Compression methods.
|
||||
enum Compression {
|
||||
kStored = 0, // Stored (no compression)
|
||||
kDeflated = Z_DEFLATED, // Deflated
|
||||
};
|
||||
|
||||
// Adds a file (or directory) entry to the ZIP archive.
|
||||
bool ZipOpenNewFileInZip(zipFile zip_file,
|
||||
const std::string& str_path,
|
||||
base::Time last_modified_time);
|
||||
base::Time last_modified_time,
|
||||
Compression compression);
|
||||
|
||||
// Selects the best compression method for the given file. The heuristic is
|
||||
// based on the filename extension. By default, the compression method is
|
||||
// kDeflated. But if the given path has an extension indicating a well known
|
||||
// file format which is likely to be already compressed (eg ZIP, RAR, JPG,
|
||||
// PNG...) then the compression method is simply kStored.
|
||||
Compression GetCompressionMethod(const base::FilePath& path);
|
||||
|
||||
const int kZipMaxPath = 256;
|
||||
const int kZipBufSize = 8192;
|
||||
|
766
deps/zlib/google/zip_reader.cc
vendored
766
deps/zlib/google/zip_reader.cc
vendored
@ -1,20 +1,26 @@
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Copyright 2012 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "third_party/zlib/google/zip_reader.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
#include "base/bind.h"
|
||||
#include "base/check.h"
|
||||
#include "base/files/file.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/i18n/icu_string_conversions.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/single_thread_task_runner.h"
|
||||
#include "base/numerics/safe_conversions.h"
|
||||
#include "base/strings/strcat.h"
|
||||
#include "base/strings/string_piece.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/threading/thread_task_runner_handle.h"
|
||||
#include "base/threading/sequenced_task_runner_handle.h"
|
||||
#include "build/build_config.h"
|
||||
#include "third_party/zlib/google/redact.h"
|
||||
#include "third_party/zlib/google/zip_internal.h"
|
||||
|
||||
#if defined(USE_SYSTEM_MINIZIP)
|
||||
@ -26,114 +32,93 @@
|
||||
#endif // defined(OS_WIN)
|
||||
#endif // defined(USE_SYSTEM_MINIZIP)
|
||||
|
||||
namespace zip {
|
||||
#if defined(OS_POSIX)
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
namespace zip {
|
||||
namespace {
|
||||
|
||||
// StringWriterDelegate --------------------------------------------------------
|
||||
enum UnzipError : int;
|
||||
|
||||
// A writer delegate that writes no more than |max_read_bytes| to a given
|
||||
// std::string.
|
||||
class StringWriterDelegate : public WriterDelegate {
|
||||
public:
|
||||
StringWriterDelegate(size_t max_read_bytes, std::string* output);
|
||||
~StringWriterDelegate() override;
|
||||
|
||||
// WriterDelegate methods:
|
||||
|
||||
// Returns true.
|
||||
bool PrepareOutput() override;
|
||||
|
||||
// Appends |num_bytes| bytes from |data| to the output string. Returns false
|
||||
// if |num_bytes| will cause the string to exceed |max_read_bytes|.
|
||||
bool WriteBytes(const char* data, int num_bytes) override;
|
||||
|
||||
void SetTimeModified(const base::Time& time) override;
|
||||
|
||||
private:
|
||||
size_t max_read_bytes_;
|
||||
std::string* output_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(StringWriterDelegate);
|
||||
};
|
||||
|
||||
StringWriterDelegate::StringWriterDelegate(size_t max_read_bytes,
|
||||
std::string* output)
|
||||
: max_read_bytes_(max_read_bytes),
|
||||
output_(output) {
|
||||
std::ostream& operator<<(std::ostream& out, UnzipError error) {
|
||||
#define SWITCH_ERR(X) \
|
||||
case X: \
|
||||
return out << #X;
|
||||
switch (error) {
|
||||
SWITCH_ERR(UNZ_OK);
|
||||
SWITCH_ERR(UNZ_END_OF_LIST_OF_FILE);
|
||||
SWITCH_ERR(UNZ_ERRNO);
|
||||
SWITCH_ERR(UNZ_PARAMERROR);
|
||||
SWITCH_ERR(UNZ_BADZIPFILE);
|
||||
SWITCH_ERR(UNZ_INTERNALERROR);
|
||||
SWITCH_ERR(UNZ_CRCERROR);
|
||||
default:
|
||||
return out << "UNZ" << static_cast<int>(error);
|
||||
}
|
||||
#undef SWITCH_ERR
|
||||
}
|
||||
|
||||
StringWriterDelegate::~StringWriterDelegate() {
|
||||
}
|
||||
|
||||
bool StringWriterDelegate::PrepareOutput() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StringWriterDelegate::WriteBytes(const char* data, int num_bytes) {
|
||||
if (output_->size() + num_bytes > max_read_bytes_)
|
||||
bool IsValidFileNameCharacterOnWindows(char16_t c) {
|
||||
if (c < 32)
|
||||
return false;
|
||||
output_->append(data, num_bytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
void StringWriterDelegate::SetTimeModified(const base::Time& time) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// TODO(satorux): The implementation assumes that file names in zip files
|
||||
// are encoded in UTF-8. This is true for zip files created by Zip()
|
||||
// function in zip.h, but not true for user-supplied random zip files.
|
||||
ZipReader::EntryInfo::EntryInfo(const std::string& file_name_in_zip,
|
||||
const unz_file_info& raw_file_info)
|
||||
: file_path_(base::FilePath::FromUTF8Unsafe(file_name_in_zip)),
|
||||
is_directory_(false),
|
||||
is_unsafe_(false),
|
||||
is_encrypted_(false) {
|
||||
original_size_ = raw_file_info.uncompressed_size;
|
||||
|
||||
// Directory entries in zip files end with "/".
|
||||
is_directory_ = base::EndsWith(file_name_in_zip, "/",
|
||||
base::CompareCase::INSENSITIVE_ASCII);
|
||||
|
||||
// Check the file name here for directory traversal issues.
|
||||
is_unsafe_ = file_path_.ReferencesParent();
|
||||
|
||||
// We also consider that the file name is unsafe, if it's invalid UTF-8.
|
||||
base::string16 file_name_utf16;
|
||||
if (!base::UTF8ToUTF16(file_name_in_zip.data(), file_name_in_zip.size(),
|
||||
&file_name_utf16)) {
|
||||
is_unsafe_ = true;
|
||||
switch (c) {
|
||||
case '<': // Less than
|
||||
case '>': // Greater than
|
||||
case ':': // Colon
|
||||
case '"': // Double quote
|
||||
case '|': // Vertical bar or pipe
|
||||
case '?': // Question mark
|
||||
case '*': // Asterisk
|
||||
case '/': // Forward slash
|
||||
case '\\': // Backslash
|
||||
return false;
|
||||
}
|
||||
|
||||
// We also consider that the file name is unsafe, if it's absolute.
|
||||
// On Windows, IsAbsolute() returns false for paths starting with "/".
|
||||
if (file_path_.IsAbsolute() ||
|
||||
base::StartsWith(file_name_in_zip, "/",
|
||||
base::CompareCase::INSENSITIVE_ASCII))
|
||||
is_unsafe_ = true;
|
||||
|
||||
// Whether the file is encrypted is bit 0 of the flag.
|
||||
is_encrypted_ = raw_file_info.flag & 1;
|
||||
|
||||
// Construct the last modified time. The timezone info is not present in
|
||||
// zip files, so we construct the time as local time.
|
||||
base::Time::Exploded exploded_time = {}; // Zero-clear.
|
||||
exploded_time.year = raw_file_info.tmu_date.tm_year;
|
||||
// The month in zip file is 0-based, whereas ours is 1-based.
|
||||
exploded_time.month = raw_file_info.tmu_date.tm_mon + 1;
|
||||
exploded_time.day_of_month = raw_file_info.tmu_date.tm_mday;
|
||||
exploded_time.hour = raw_file_info.tmu_date.tm_hour;
|
||||
exploded_time.minute = raw_file_info.tmu_date.tm_min;
|
||||
exploded_time.second = raw_file_info.tmu_date.tm_sec;
|
||||
exploded_time.millisecond = 0;
|
||||
|
||||
if (!base::Time::FromLocalExploded(exploded_time, &last_modified_))
|
||||
last_modified_ = base::Time::UnixEpoch();
|
||||
return true;
|
||||
}
|
||||
|
||||
// A writer delegate that writes to a given string.
|
||||
class StringWriterDelegate : public WriterDelegate {
|
||||
public:
|
||||
explicit StringWriterDelegate(std::string* output) : output_(output) {}
|
||||
|
||||
// WriterDelegate methods:
|
||||
bool WriteBytes(const char* data, int num_bytes) override {
|
||||
output_->append(data, num_bytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string* const output_;
|
||||
};
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
void SetPosixFilePermissions(int fd, int mode) {
|
||||
base::stat_wrapper_t sb;
|
||||
if (base::File::Fstat(fd, &sb)) {
|
||||
return;
|
||||
}
|
||||
mode_t new_mode = sb.st_mode;
|
||||
// Transfer the executable bit only if the file is readable.
|
||||
if ((sb.st_mode & S_IRUSR) == S_IRUSR && (mode & S_IXUSR) == S_IXUSR) {
|
||||
new_mode |= S_IXUSR;
|
||||
}
|
||||
if ((sb.st_mode & S_IRGRP) == S_IRGRP && (mode & S_IXGRP) == S_IXGRP) {
|
||||
new_mode |= S_IXGRP;
|
||||
}
|
||||
if ((sb.st_mode & S_IROTH) == S_IROTH && (mode & S_IXOTH) == S_IXOTH) {
|
||||
new_mode |= S_IXOTH;
|
||||
}
|
||||
if (new_mode != sb.st_mode) {
|
||||
fchmod(fd, new_mode);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
ZipReader::ZipReader() {
|
||||
Reset();
|
||||
}
|
||||
@ -142,13 +127,14 @@ ZipReader::~ZipReader() {
|
||||
Close();
|
||||
}
|
||||
|
||||
bool ZipReader::Open(const base::FilePath& zip_file_path) {
|
||||
bool ZipReader::Open(const base::FilePath& zip_path) {
|
||||
DCHECK(!zip_file_);
|
||||
|
||||
// Use of "Unsafe" function does not look good, but there is no way to do
|
||||
// this safely on Linux. See file_util.h for details.
|
||||
zip_file_ = internal::OpenForUnzipping(zip_file_path.AsUTF8Unsafe());
|
||||
zip_file_ = internal::OpenForUnzipping(zip_path.AsUTF8Unsafe());
|
||||
if (!zip_file_) {
|
||||
LOG(ERROR) << "Cannot open ZIP archive " << Redact(zip_path);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -158,12 +144,13 @@ bool ZipReader::Open(const base::FilePath& zip_file_path) {
|
||||
bool ZipReader::OpenFromPlatformFile(base::PlatformFile zip_fd) {
|
||||
DCHECK(!zip_file_);
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
#if defined(OS_POSIX) || defined(OS_FUCHSIA)
|
||||
zip_file_ = internal::OpenFdForUnzipping(zip_fd);
|
||||
#elif defined(OS_WIN)
|
||||
zip_file_ = internal::OpenHandleForUnzipping(zip_fd);
|
||||
#endif
|
||||
if (!zip_file_) {
|
||||
LOG(ERROR) << "Cannot open ZIP from file handle " << zip_fd;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -179,145 +166,329 @@ bool ZipReader::OpenFromString(const std::string& data) {
|
||||
|
||||
void ZipReader::Close() {
|
||||
if (zip_file_) {
|
||||
unzClose(zip_file_);
|
||||
if (const UnzipError err{unzClose(zip_file_)}; err != UNZ_OK) {
|
||||
LOG(ERROR) << "Error while closing ZIP archive: " << err;
|
||||
}
|
||||
}
|
||||
Reset();
|
||||
}
|
||||
|
||||
bool ZipReader::HasMore() {
|
||||
return !reached_end_;
|
||||
}
|
||||
|
||||
bool ZipReader::AdvanceToNextEntry() {
|
||||
const ZipReader::Entry* ZipReader::Next() {
|
||||
DCHECK(zip_file_);
|
||||
|
||||
// Should not go further if we already reached the end.
|
||||
if (reached_end_)
|
||||
return false;
|
||||
return nullptr;
|
||||
|
||||
unz_file_pos position = {};
|
||||
if (unzGetFilePos(zip_file_, &position) != UNZ_OK)
|
||||
return false;
|
||||
const int current_entry_index = position.num_of_file;
|
||||
// If we are currently at the last entry, then the next position is the
|
||||
// end of the zip file, so mark that we reached the end.
|
||||
if (current_entry_index + 1 == num_entries_) {
|
||||
reached_end_ = true;
|
||||
} else {
|
||||
DCHECK_LT(current_entry_index + 1, num_entries_);
|
||||
if (unzGoToNextFile(zip_file_) != UNZ_OK) {
|
||||
return false;
|
||||
DCHECK(ok_);
|
||||
|
||||
// Move to the next entry if we're not trying to open the first entry.
|
||||
if (next_index_ > 0) {
|
||||
if (const UnzipError err{unzGoToNextFile(zip_file_)}; err != UNZ_OK) {
|
||||
reached_end_ = true;
|
||||
if (err != UNZ_END_OF_LIST_OF_FILE) {
|
||||
LOG(ERROR) << "Cannot go to next entry in ZIP: " << err;
|
||||
ok_ = false;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
current_entry_info_.reset();
|
||||
|
||||
next_index_++;
|
||||
|
||||
if (!OpenEntry()) {
|
||||
reached_end_ = true;
|
||||
ok_ = false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &entry_;
|
||||
}
|
||||
|
||||
bool ZipReader::OpenEntry() {
|
||||
DCHECK(zip_file_);
|
||||
|
||||
// Get entry info.
|
||||
unz_file_info64 info = {};
|
||||
char path_in_zip[internal::kZipMaxPath] = {};
|
||||
if (const UnzipError err{unzGetCurrentFileInfo64(
|
||||
zip_file_, &info, path_in_zip, sizeof(path_in_zip) - 1, nullptr, 0,
|
||||
nullptr, 0)};
|
||||
err != UNZ_OK) {
|
||||
LOG(ERROR) << "Cannot get entry from ZIP: " << err;
|
||||
return false;
|
||||
}
|
||||
|
||||
entry_.path_in_original_encoding = path_in_zip;
|
||||
|
||||
// Convert path from original encoding to Unicode.
|
||||
std::u16string path_in_utf16;
|
||||
const char* const encoding = encoding_.empty() ? "UTF-8" : encoding_.c_str();
|
||||
if (!base::CodepageToUTF16(entry_.path_in_original_encoding, encoding,
|
||||
base::OnStringConversionError::SUBSTITUTE,
|
||||
&path_in_utf16)) {
|
||||
LOG(ERROR) << "Cannot convert path from encoding " << encoding;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Normalize path.
|
||||
Normalize(path_in_utf16);
|
||||
|
||||
entry_.original_size = info.uncompressed_size;
|
||||
|
||||
// The file content of this entry is encrypted if flag bit 0 is set.
|
||||
entry_.is_encrypted = info.flag & 1;
|
||||
if (entry_.is_encrypted) {
|
||||
// Is the entry AES encrypted.
|
||||
entry_.uses_aes_encryption = info.compression_method == 99;
|
||||
} else {
|
||||
entry_.uses_aes_encryption = false;
|
||||
}
|
||||
|
||||
// Construct the last modified time. The timezone info is not present in ZIP
|
||||
// archives, so we construct the time as UTC.
|
||||
base::Time::Exploded exploded_time = {};
|
||||
exploded_time.year = info.tmu_date.tm_year;
|
||||
exploded_time.month = info.tmu_date.tm_mon + 1; // 0-based vs 1-based
|
||||
exploded_time.day_of_month = info.tmu_date.tm_mday;
|
||||
exploded_time.hour = info.tmu_date.tm_hour;
|
||||
exploded_time.minute = info.tmu_date.tm_min;
|
||||
exploded_time.second = info.tmu_date.tm_sec;
|
||||
exploded_time.millisecond = 0;
|
||||
|
||||
if (!base::Time::FromUTCExploded(exploded_time, &entry_.last_modified))
|
||||
entry_.last_modified = base::Time::UnixEpoch();
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
entry_.posix_mode = (info.external_fa >> 16L) & (S_IRWXU | S_IRWXG | S_IRWXO);
|
||||
#else
|
||||
entry_.posix_mode = 0;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZipReader::OpenCurrentEntryInZip() {
|
||||
DCHECK(zip_file_);
|
||||
void ZipReader::Normalize(base::StringPiece16 in) {
|
||||
entry_.is_unsafe = true;
|
||||
|
||||
unz_file_info raw_file_info = {};
|
||||
char raw_file_name_in_zip[internal::kZipMaxPath] = {};
|
||||
const int result = unzGetCurrentFileInfo(zip_file_,
|
||||
&raw_file_info,
|
||||
raw_file_name_in_zip,
|
||||
sizeof(raw_file_name_in_zip) - 1,
|
||||
NULL, // extraField.
|
||||
0, // extraFieldBufferSize.
|
||||
NULL, // szComment.
|
||||
0); // commentBufferSize.
|
||||
if (result != UNZ_OK)
|
||||
return false;
|
||||
if (raw_file_name_in_zip[0] == '\0')
|
||||
return false;
|
||||
current_entry_info_.reset(
|
||||
new EntryInfo(raw_file_name_in_zip, raw_file_info));
|
||||
return true;
|
||||
// Directory entries in ZIP have a path ending with "/".
|
||||
entry_.is_directory = base::EndsWith(in, u"/");
|
||||
|
||||
std::u16string normalized_path;
|
||||
if (base::StartsWith(in, u"/")) {
|
||||
normalized_path = u"ROOT";
|
||||
entry_.is_unsafe = false;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
// Consume initial path separators.
|
||||
const base::StringPiece16::size_type i = in.find_first_not_of(u'/');
|
||||
if (i == base::StringPiece16::npos)
|
||||
break;
|
||||
|
||||
in.remove_prefix(i);
|
||||
DCHECK(!in.empty());
|
||||
|
||||
// Isolate next path component.
|
||||
const base::StringPiece16 part = in.substr(0, in.find_first_of(u'/'));
|
||||
DCHECK(!part.empty());
|
||||
|
||||
in.remove_prefix(part.size());
|
||||
|
||||
if (!normalized_path.empty())
|
||||
normalized_path += u'/';
|
||||
|
||||
if (part == u".") {
|
||||
normalized_path += u"DOT";
|
||||
entry_.is_unsafe = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (part == u"..") {
|
||||
normalized_path += u"UP";
|
||||
entry_.is_unsafe = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Windows has more restrictions than other systems when it comes to valid
|
||||
// file paths. Replace Windows-invalid characters on all systems for
|
||||
// consistency. In particular, this prevents a path component containing
|
||||
// colon and backslash from being misinterpreted as an absolute path on
|
||||
// Windows.
|
||||
for (const char16_t c : part) {
|
||||
normalized_path += IsValidFileNameCharacterOnWindows(c) ? c : 0xFFFD;
|
||||
}
|
||||
|
||||
entry_.is_unsafe = false;
|
||||
}
|
||||
|
||||
// If the entry is a directory, add the final path separator to the entry
|
||||
// path.
|
||||
if (entry_.is_directory && !normalized_path.empty()) {
|
||||
normalized_path += u'/';
|
||||
entry_.is_unsafe = false;
|
||||
}
|
||||
|
||||
entry_.path = base::FilePath::FromUTF16Unsafe(normalized_path);
|
||||
|
||||
// By construction, we should always get a relative path.
|
||||
DCHECK(!entry_.path.IsAbsolute()) << entry_.path;
|
||||
}
|
||||
|
||||
void ZipReader::ReportProgress(ListenerCallback listener_callback,
|
||||
uint64_t bytes) const {
|
||||
delta_bytes_read_ += bytes;
|
||||
|
||||
const base::TimeTicks now = base::TimeTicks::Now();
|
||||
if (next_progress_report_time_ > now)
|
||||
return;
|
||||
|
||||
next_progress_report_time_ = now + progress_period_;
|
||||
listener_callback.Run(delta_bytes_read_);
|
||||
delta_bytes_read_ = 0;
|
||||
}
|
||||
|
||||
bool ZipReader::ExtractCurrentEntry(WriterDelegate* delegate,
|
||||
ListenerCallback listener_callback,
|
||||
uint64_t num_bytes_to_extract) const {
|
||||
DCHECK(zip_file_);
|
||||
DCHECK_LT(0, next_index_);
|
||||
DCHECK(ok_);
|
||||
DCHECK(!reached_end_);
|
||||
|
||||
const int open_result = unzOpenCurrentFile(zip_file_);
|
||||
if (open_result != UNZ_OK)
|
||||
// Use password only for encrypted files. For non-encrypted files, no password
|
||||
// is needed, and must be nullptr.
|
||||
const char* const password =
|
||||
entry_.is_encrypted ? password_.c_str() : nullptr;
|
||||
if (const UnzipError err{unzOpenCurrentFilePassword(zip_file_, password)};
|
||||
err != UNZ_OK) {
|
||||
LOG(ERROR) << "Cannot open file " << Redact(entry_.path)
|
||||
<< " from ZIP: " << err;
|
||||
return false;
|
||||
}
|
||||
|
||||
DCHECK(delegate);
|
||||
if (!delegate->PrepareOutput())
|
||||
return false;
|
||||
std::unique_ptr<char[]> buf(new char[internal::kZipBufSize]);
|
||||
|
||||
uint64_t remaining_capacity = num_bytes_to_extract;
|
||||
bool entire_file_extracted = false;
|
||||
|
||||
while (remaining_capacity > 0) {
|
||||
char buf[internal::kZipBufSize];
|
||||
const int num_bytes_read =
|
||||
unzReadCurrentFile(zip_file_, buf.get(), internal::kZipBufSize);
|
||||
unzReadCurrentFile(zip_file_, buf, internal::kZipBufSize);
|
||||
|
||||
if (num_bytes_read == 0) {
|
||||
entire_file_extracted = true;
|
||||
break;
|
||||
} else if (num_bytes_read < 0) {
|
||||
// If num_bytes_read < 0, then it's a specific UNZ_* error code.
|
||||
break;
|
||||
} else if (num_bytes_read > 0) {
|
||||
uint64_t num_bytes_to_write = std::min<uint64_t>(
|
||||
remaining_capacity, base::checked_cast<uint64_t>(num_bytes_read));
|
||||
if (!delegate->WriteBytes(buf.get(), num_bytes_to_write))
|
||||
break;
|
||||
if (remaining_capacity == base::checked_cast<uint64_t>(num_bytes_read)) {
|
||||
// Ensures function returns true if the entire file has been read.
|
||||
entire_file_extracted =
|
||||
(unzReadCurrentFile(zip_file_, buf.get(), 1) == 0);
|
||||
}
|
||||
CHECK_GE(remaining_capacity, num_bytes_to_write);
|
||||
remaining_capacity -= num_bytes_to_write;
|
||||
}
|
||||
|
||||
if (num_bytes_read < 0) {
|
||||
LOG(ERROR) << "Cannot read file " << Redact(entry_.path)
|
||||
<< " from ZIP: " << UnzipError(num_bytes_read);
|
||||
break;
|
||||
}
|
||||
|
||||
if (listener_callback) {
|
||||
ReportProgress(listener_callback, num_bytes_read);
|
||||
}
|
||||
|
||||
DCHECK_LT(0, num_bytes_read);
|
||||
CHECK_LE(num_bytes_read, internal::kZipBufSize);
|
||||
|
||||
uint64_t num_bytes_to_write = std::min<uint64_t>(
|
||||
remaining_capacity, base::checked_cast<uint64_t>(num_bytes_read));
|
||||
if (!delegate->WriteBytes(buf, num_bytes_to_write))
|
||||
break;
|
||||
|
||||
if (remaining_capacity == base::checked_cast<uint64_t>(num_bytes_read)) {
|
||||
// Ensures function returns true if the entire file has been read.
|
||||
const int n = unzReadCurrentFile(zip_file_, buf, 1);
|
||||
entire_file_extracted = (n == 0);
|
||||
LOG_IF(ERROR, n < 0) << "Cannot read file " << Redact(entry_.path)
|
||||
<< " from ZIP: " << UnzipError(n);
|
||||
}
|
||||
|
||||
CHECK_GE(remaining_capacity, num_bytes_to_write);
|
||||
remaining_capacity -= num_bytes_to_write;
|
||||
}
|
||||
|
||||
unzCloseCurrentFile(zip_file_);
|
||||
if (const UnzipError err{unzCloseCurrentFile(zip_file_)}; err != UNZ_OK) {
|
||||
LOG(ERROR) << "Cannot extract file " << Redact(entry_.path)
|
||||
<< " from ZIP: " << err;
|
||||
entire_file_extracted = false;
|
||||
}
|
||||
|
||||
if (entire_file_extracted &&
|
||||
current_entry_info()->last_modified() != base::Time::UnixEpoch()) {
|
||||
delegate->SetTimeModified(current_entry_info()->last_modified());
|
||||
if (entire_file_extracted) {
|
||||
delegate->SetPosixFilePermissions(entry_.posix_mode);
|
||||
if (entry_.last_modified != base::Time::UnixEpoch()) {
|
||||
delegate->SetTimeModified(entry_.last_modified);
|
||||
}
|
||||
} else {
|
||||
delegate->OnError();
|
||||
}
|
||||
|
||||
if (listener_callback) {
|
||||
listener_callback.Run(delta_bytes_read_);
|
||||
delta_bytes_read_ = 0;
|
||||
}
|
||||
|
||||
return entire_file_extracted;
|
||||
}
|
||||
|
||||
bool ZipReader::ExtractCurrentEntry(WriterDelegate* delegate,
|
||||
uint64_t num_bytes_to_extract) const {
|
||||
return ExtractCurrentEntry(delegate, ListenerCallback(),
|
||||
num_bytes_to_extract);
|
||||
}
|
||||
|
||||
bool ZipReader::ExtractCurrentEntryWithListener(
|
||||
WriterDelegate* delegate,
|
||||
ListenerCallback listener_callback) const {
|
||||
return ExtractCurrentEntry(delegate, listener_callback);
|
||||
}
|
||||
|
||||
void ZipReader::ExtractCurrentEntryToFilePathAsync(
|
||||
const base::FilePath& output_file_path,
|
||||
SuccessCallback success_callback,
|
||||
FailureCallback failure_callback,
|
||||
const ProgressCallback& progress_callback) {
|
||||
ProgressCallback progress_callback) {
|
||||
DCHECK(zip_file_);
|
||||
DCHECK(current_entry_info_.get());
|
||||
DCHECK_LT(0, next_index_);
|
||||
DCHECK(ok_);
|
||||
DCHECK(!reached_end_);
|
||||
|
||||
// If this is a directory, just create it and return.
|
||||
if (current_entry_info()->is_directory()) {
|
||||
if (entry_.is_directory) {
|
||||
if (base::CreateDirectory(output_file_path)) {
|
||||
base::ThreadTaskRunnerHandle::Get()->PostTask(
|
||||
base::SequencedTaskRunnerHandle::Get()->PostTask(
|
||||
FROM_HERE, std::move(success_callback));
|
||||
} else {
|
||||
DVLOG(1) << "Unzip failed: unable to create directory.";
|
||||
base::ThreadTaskRunnerHandle::Get()->PostTask(
|
||||
LOG(ERROR) << "Cannot create directory " << Redact(output_file_path);
|
||||
base::SequencedTaskRunnerHandle::Get()->PostTask(
|
||||
FROM_HERE, std::move(failure_callback));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (unzOpenCurrentFile(zip_file_) != UNZ_OK) {
|
||||
DVLOG(1) << "Unzip failed: unable to open current zip entry.";
|
||||
base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
|
||||
std::move(failure_callback));
|
||||
// Use password only for encrypted files. For non-encrypted files, no password
|
||||
// is needed, and must be nullptr.
|
||||
const char* const password =
|
||||
entry_.is_encrypted ? password_.c_str() : nullptr;
|
||||
if (const UnzipError err{unzOpenCurrentFilePassword(zip_file_, password)};
|
||||
err != UNZ_OK) {
|
||||
LOG(ERROR) << "Cannot open file " << Redact(entry_.path)
|
||||
<< " from ZIP: " << err;
|
||||
base::SequencedTaskRunnerHandle::Get()->PostTask(
|
||||
FROM_HERE, std::move(failure_callback));
|
||||
return;
|
||||
}
|
||||
|
||||
base::FilePath output_dir_path = output_file_path.DirName();
|
||||
if (!base::CreateDirectory(output_dir_path)) {
|
||||
DVLOG(1) << "Unzip failed: unable to create containing directory.";
|
||||
base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
|
||||
std::move(failure_callback));
|
||||
LOG(ERROR) << "Cannot create directory " << Redact(output_dir_path);
|
||||
base::SequencedTaskRunnerHandle::Get()->PostTask(
|
||||
FROM_HERE, std::move(failure_callback));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -325,139 +496,155 @@ void ZipReader::ExtractCurrentEntryToFilePathAsync(
|
||||
base::File output_file(output_file_path, flags);
|
||||
|
||||
if (!output_file.IsValid()) {
|
||||
DVLOG(1) << "Unzip failed: unable to create platform file at "
|
||||
<< output_file_path.value();
|
||||
base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
|
||||
std::move(failure_callback));
|
||||
LOG(ERROR) << "Cannot create file " << Redact(output_file_path);
|
||||
base::SequencedTaskRunnerHandle::Get()->PostTask(
|
||||
FROM_HERE, std::move(failure_callback));
|
||||
return;
|
||||
}
|
||||
|
||||
base::ThreadTaskRunnerHandle::Get()->PostTask(
|
||||
base::SequencedTaskRunnerHandle::Get()->PostTask(
|
||||
FROM_HERE,
|
||||
base::BindOnce(&ZipReader::ExtractChunk, weak_ptr_factory_.GetWeakPtr(),
|
||||
Passed(std::move(output_file)),
|
||||
std::move(success_callback), std::move(failure_callback),
|
||||
progress_callback, 0 /* initial offset */));
|
||||
std::move(output_file), std::move(success_callback),
|
||||
std::move(failure_callback), std::move(progress_callback),
|
||||
0 /* initial offset */));
|
||||
}
|
||||
|
||||
bool ZipReader::ExtractCurrentEntryToString(uint64_t max_read_bytes,
|
||||
std::string* output) const {
|
||||
DCHECK(output);
|
||||
DCHECK(zip_file_);
|
||||
DCHECK_LT(0, next_index_);
|
||||
DCHECK(ok_);
|
||||
DCHECK(!reached_end_);
|
||||
|
||||
if (max_read_bytes == 0) {
|
||||
output->clear();
|
||||
output->clear();
|
||||
|
||||
if (max_read_bytes == 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (current_entry_info()->is_directory()) {
|
||||
output->clear();
|
||||
if (entry_.is_directory)
|
||||
return true;
|
||||
}
|
||||
|
||||
// The original_size() is the best hint for the real size, so it saves
|
||||
// doing reallocations for the common case when the uncompressed size is
|
||||
// correct. However, we need to assume that the uncompressed size could be
|
||||
// incorrect therefore this function needs to read as much data as possible.
|
||||
std::string contents;
|
||||
contents.reserve(
|
||||
static_cast<size_t>(std::min(base::checked_cast<int64_t>(max_read_bytes),
|
||||
current_entry_info()->original_size())));
|
||||
// The original_size is the best hint for the real size, so it saves doing
|
||||
// reallocations for the common case when the uncompressed size is correct.
|
||||
// However, we need to assume that the uncompressed size could be incorrect
|
||||
// therefore this function needs to read as much data as possible.
|
||||
output->reserve(base::checked_cast<size_t>(std::min<uint64_t>(
|
||||
max_read_bytes, base::checked_cast<uint64_t>(entry_.original_size))));
|
||||
|
||||
StringWriterDelegate writer(max_read_bytes, &contents);
|
||||
if (!ExtractCurrentEntry(&writer, max_read_bytes)) {
|
||||
if (contents.length() < max_read_bytes) {
|
||||
// There was an error in extracting entry. If ExtractCurrentEntry()
|
||||
// returns false, the entire file was not read - in which case
|
||||
// contents.length() should equal |max_read_bytes| unless an error
|
||||
// occurred which caused extraction to be aborted.
|
||||
output->clear();
|
||||
} else {
|
||||
// |num_bytes| is less than the length of current entry.
|
||||
output->swap(contents);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
output->swap(contents);
|
||||
return true;
|
||||
StringWriterDelegate writer(output);
|
||||
return ExtractCurrentEntry(&writer, max_read_bytes);
|
||||
}
|
||||
|
||||
bool ZipReader::OpenInternal() {
|
||||
DCHECK(zip_file_);
|
||||
|
||||
unz_global_info zip_info = {}; // Zero-clear.
|
||||
if (unzGetGlobalInfo(zip_file_, &zip_info) != UNZ_OK) {
|
||||
if (const UnzipError err{unzGetGlobalInfo(zip_file_, &zip_info)};
|
||||
err != UNZ_OK) {
|
||||
LOG(ERROR) << "Cannot get ZIP info: " << err;
|
||||
return false;
|
||||
}
|
||||
num_entries_ = zip_info.number_entry;
|
||||
if (num_entries_ < 0)
|
||||
return false;
|
||||
|
||||
// We are already at the end if the zip file is empty.
|
||||
reached_end_ = (num_entries_ == 0);
|
||||
num_entries_ = zip_info.number_entry;
|
||||
reached_end_ = (num_entries_ <= 0);
|
||||
ok_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ZipReader::Reset() {
|
||||
zip_file_ = NULL;
|
||||
zip_file_ = nullptr;
|
||||
num_entries_ = 0;
|
||||
reached_end_ = false;
|
||||
current_entry_info_.reset();
|
||||
next_index_ = 0;
|
||||
reached_end_ = true;
|
||||
ok_ = false;
|
||||
delta_bytes_read_ = 0;
|
||||
entry_ = {};
|
||||
}
|
||||
|
||||
void ZipReader::ExtractChunk(base::File output_file,
|
||||
SuccessCallback success_callback,
|
||||
FailureCallback failure_callback,
|
||||
const ProgressCallback& progress_callback,
|
||||
const int64_t offset) {
|
||||
ProgressCallback progress_callback,
|
||||
int64_t offset) {
|
||||
char buffer[internal::kZipBufSize];
|
||||
|
||||
const int num_bytes_read = unzReadCurrentFile(zip_file_,
|
||||
buffer,
|
||||
internal::kZipBufSize);
|
||||
const int num_bytes_read =
|
||||
unzReadCurrentFile(zip_file_, buffer, internal::kZipBufSize);
|
||||
|
||||
if (num_bytes_read == 0) {
|
||||
unzCloseCurrentFile(zip_file_);
|
||||
std::move(success_callback).Run();
|
||||
} else if (num_bytes_read < 0) {
|
||||
DVLOG(1) << "Unzip failed: error while reading zipfile "
|
||||
<< "(" << num_bytes_read << ")";
|
||||
std::move(failure_callback).Run();
|
||||
} else {
|
||||
if (num_bytes_read != output_file.Write(offset, buffer, num_bytes_read)) {
|
||||
DVLOG(1) << "Unzip failed: unable to write all bytes to target.";
|
||||
if (const UnzipError err{unzCloseCurrentFile(zip_file_)}; err != UNZ_OK) {
|
||||
LOG(ERROR) << "Cannot extract file " << Redact(entry_.path)
|
||||
<< " from ZIP: " << err;
|
||||
std::move(failure_callback).Run();
|
||||
return;
|
||||
}
|
||||
|
||||
int64_t current_progress = offset + num_bytes_read;
|
||||
|
||||
progress_callback.Run(current_progress);
|
||||
|
||||
base::ThreadTaskRunnerHandle::Get()->PostTask(
|
||||
FROM_HERE,
|
||||
base::BindOnce(&ZipReader::ExtractChunk, weak_ptr_factory_.GetWeakPtr(),
|
||||
Passed(std::move(output_file)),
|
||||
std::move(success_callback), std::move(failure_callback),
|
||||
progress_callback, current_progress));
|
||||
std::move(success_callback).Run();
|
||||
return;
|
||||
}
|
||||
|
||||
if (num_bytes_read < 0) {
|
||||
LOG(ERROR) << "Cannot read file " << Redact(entry_.path)
|
||||
<< " from ZIP: " << UnzipError(num_bytes_read);
|
||||
std::move(failure_callback).Run();
|
||||
return;
|
||||
}
|
||||
|
||||
if (num_bytes_read != output_file.Write(offset, buffer, num_bytes_read)) {
|
||||
LOG(ERROR) << "Cannot write " << num_bytes_read
|
||||
<< " bytes to file at offset " << offset;
|
||||
std::move(failure_callback).Run();
|
||||
return;
|
||||
}
|
||||
|
||||
offset += num_bytes_read;
|
||||
progress_callback.Run(offset);
|
||||
|
||||
base::SequencedTaskRunnerHandle::Get()->PostTask(
|
||||
FROM_HERE,
|
||||
base::BindOnce(&ZipReader::ExtractChunk, weak_ptr_factory_.GetWeakPtr(),
|
||||
std::move(output_file), std::move(success_callback),
|
||||
std::move(failure_callback), std::move(progress_callback),
|
||||
offset));
|
||||
}
|
||||
|
||||
// FileWriterDelegate ----------------------------------------------------------
|
||||
|
||||
FileWriterDelegate::FileWriterDelegate(base::File* file) : file_(file) {}
|
||||
|
||||
FileWriterDelegate::FileWriterDelegate(std::unique_ptr<base::File> file)
|
||||
: file_(file.get()), owned_file_(std::move(file)) {}
|
||||
|
||||
FileWriterDelegate::~FileWriterDelegate() {
|
||||
if (!file_->SetLength(file_length_)) {
|
||||
DVPLOG(1) << "Failed updating length of written file";
|
||||
}
|
||||
FileWriterDelegate::FileWriterDelegate(base::File* file) : file_(file) {
|
||||
DCHECK(file_);
|
||||
}
|
||||
|
||||
FileWriterDelegate::FileWriterDelegate(base::File owned_file)
|
||||
: owned_file_(std::move(owned_file)) {
|
||||
DCHECK_EQ(file_, &owned_file_);
|
||||
}
|
||||
|
||||
FileWriterDelegate::~FileWriterDelegate() {}
|
||||
|
||||
bool FileWriterDelegate::PrepareOutput() {
|
||||
return file_->Seek(base::File::FROM_BEGIN, 0) >= 0;
|
||||
DCHECK(file_);
|
||||
|
||||
if (!file_->IsValid()) {
|
||||
LOG(ERROR) << "File is not valid";
|
||||
return false;
|
||||
}
|
||||
|
||||
const int64_t length = file_->GetLength();
|
||||
if (length < 0) {
|
||||
PLOG(ERROR) << "Cannot get length of file handle "
|
||||
<< file_->GetPlatformFile();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Just log a warning if the file is not empty.
|
||||
// See crbug.com/1309879 and crbug.com/774762.
|
||||
LOG_IF(WARNING, length > 0)
|
||||
<< "File handle " << file_->GetPlatformFile()
|
||||
<< " is not empty: Its length is " << length << " bytes";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FileWriterDelegate::WriteBytes(const char* data, int num_bytes) {
|
||||
@ -471,32 +658,65 @@ void FileWriterDelegate::SetTimeModified(const base::Time& time) {
|
||||
file_->SetTimes(base::Time::Now(), time);
|
||||
}
|
||||
|
||||
void FileWriterDelegate::SetPosixFilePermissions(int mode) {
|
||||
#if defined(OS_POSIX)
|
||||
zip::SetPosixFilePermissions(file_->GetPlatformFile(), mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
void FileWriterDelegate::OnError() {
|
||||
file_length_ = 0;
|
||||
file_->SetLength(0);
|
||||
}
|
||||
|
||||
// FilePathWriterDelegate ------------------------------------------------------
|
||||
|
||||
FilePathWriterDelegate::FilePathWriterDelegate(
|
||||
const base::FilePath& output_file_path)
|
||||
: output_file_path_(output_file_path) {}
|
||||
FilePathWriterDelegate::FilePathWriterDelegate(base::FilePath output_file_path)
|
||||
: FileWriterDelegate(base::File()),
|
||||
output_file_path_(std::move(output_file_path)) {}
|
||||
|
||||
FilePathWriterDelegate::~FilePathWriterDelegate() {}
|
||||
|
||||
bool FilePathWriterDelegate::PrepareOutput() {
|
||||
// We can't rely on parent directory entries being specified in the
|
||||
// zip, so we make sure they are created.
|
||||
if (!base::CreateDirectory(output_file_path_.DirName()))
|
||||
if (const base::FilePath dir = output_file_path_.DirName();
|
||||
!base::CreateDirectory(dir)) {
|
||||
PLOG(ERROR) << "Cannot create directory " << Redact(dir);
|
||||
return false;
|
||||
}
|
||||
|
||||
file_.Initialize(output_file_path_,
|
||||
base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
|
||||
return file_.IsValid();
|
||||
owned_file_.Initialize(output_file_path_,
|
||||
base::File::FLAG_CREATE | base::File::FLAG_WRITE);
|
||||
if (!owned_file_.IsValid()) {
|
||||
PLOG(ERROR) << "Cannot create file " << Redact(output_file_path_) << ": "
|
||||
<< base::File::ErrorToString(owned_file_.error_details());
|
||||
return false;
|
||||
}
|
||||
|
||||
const int64_t length = owned_file_.GetLength();
|
||||
if (length < 0) {
|
||||
PLOG(ERROR) << "Cannot get length of file " << Redact(output_file_path_);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (length > 0) {
|
||||
LOG(ERROR) << "File " << Redact(output_file_path_)
|
||||
<< " is not empty: Its length is " << length << " bytes";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FilePathWriterDelegate::WriteBytes(const char* data, int num_bytes) {
|
||||
return num_bytes == file_.WriteAtCurrentPos(data, num_bytes);
|
||||
}
|
||||
void FilePathWriterDelegate::OnError() {
|
||||
FileWriterDelegate::OnError();
|
||||
owned_file_.Close();
|
||||
|
||||
void FilePathWriterDelegate::SetTimeModified(const base::Time& time) {
|
||||
file_.Close();
|
||||
base::TouchFile(output_file_path_, base::Time::Now(), time);
|
||||
if (!base::DeleteFile(output_file_path_)) {
|
||||
LOG(ERROR) << "Cannot delete partially extracted file "
|
||||
<< Redact(output_file_path_);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace zip
|
||||
|
375
deps/zlib/google/zip_reader.h
vendored
375
deps/zlib/google/zip_reader.h
vendored
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
// Copyright 2011 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
#ifndef THIRD_PARTY_ZLIB_GOOGLE_ZIP_READER_H_
|
||||
@ -7,15 +7,15 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/files/file.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/numerics/safe_conversions.h"
|
||||
#include "base/time/time.h"
|
||||
|
||||
#if defined(USE_SYSTEM_MINIZIP)
|
||||
@ -34,33 +34,47 @@ class WriterDelegate {
|
||||
|
||||
// Invoked once before any data is streamed out to pave the way (e.g., to open
|
||||
// the output file). Return false on failure to cancel extraction.
|
||||
virtual bool PrepareOutput() = 0;
|
||||
virtual bool PrepareOutput() { return true; }
|
||||
|
||||
// Invoked to write the next chunk of data. Return false on failure to cancel
|
||||
// extraction.
|
||||
virtual bool WriteBytes(const char* data, int num_bytes) = 0;
|
||||
virtual bool WriteBytes(const char* data, int num_bytes) { return true; }
|
||||
|
||||
// Sets the last-modified time of the data.
|
||||
virtual void SetTimeModified(const base::Time& time) = 0;
|
||||
virtual void SetTimeModified(const base::Time& time) {}
|
||||
|
||||
// Called with the POSIX file permissions of the data; POSIX implementations
|
||||
// may apply some of the permissions (for example, the executable bit) to the
|
||||
// output file.
|
||||
virtual void SetPosixFilePermissions(int mode) {}
|
||||
|
||||
// Called if an error occurred while extracting the file. The WriterDelegate
|
||||
// can then remove and clean up the partially extracted data.
|
||||
virtual void OnError() {}
|
||||
};
|
||||
|
||||
// This class is used for reading zip files. A typical use case of this
|
||||
// class is to scan entries in a zip file and extract them. The code will
|
||||
// look like:
|
||||
// This class is used for reading ZIP archives. A typical use case of this class
|
||||
// is to scan entries in a ZIP archive and extract them. The code will look
|
||||
// like:
|
||||
//
|
||||
// ZipReader reader;
|
||||
// reader.Open(zip_file_path);
|
||||
// while (reader.HasMore()) {
|
||||
// reader.OpenCurrentEntryInZip();
|
||||
// const base::FilePath& entry_path =
|
||||
// reader.current_entry_info()->file_path();
|
||||
// auto writer = CreateFilePathWriterDelegate(extract_dir, entry_path);
|
||||
// reader.ExtractCurrentEntry(writer, std::numeric_limits<uint64_t>::max());
|
||||
// reader.AdvanceToNextEntry();
|
||||
// if (!reader.Open(zip_path)) {
|
||||
// // Cannot open
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// For simplicity, error checking is omitted in the example code above. The
|
||||
// production code should check return values from all of these functions.
|
||||
// while (const ZipReader::entry* entry = reader.Next()) {
|
||||
// auto writer = CreateFilePathWriterDelegate(extract_dir, entry->path);
|
||||
// if (!reader.ExtractCurrentEntry(writer)) {
|
||||
// // Cannot extract
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (!reader.ok()) {
|
||||
// // Error while enumerating entries
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
class ZipReader {
|
||||
public:
|
||||
@ -71,63 +85,77 @@ class ZipReader {
|
||||
// A callback that is called periodically during the operation with the number
|
||||
// of bytes that have been processed so far.
|
||||
using ProgressCallback = base::RepeatingCallback<void(int64_t)>;
|
||||
// A callback that is called periodically during the operation with the number
|
||||
// of bytes that have been processed since the previous call (i.e. delta).
|
||||
using ListenerCallback = base::RepeatingCallback<void(uint64_t)>;
|
||||
|
||||
// This class represents information of an entry (file or directory) in
|
||||
// a zip file.
|
||||
class EntryInfo {
|
||||
public:
|
||||
EntryInfo(const std::string& filename_in_zip,
|
||||
const unz_file_info& raw_file_info);
|
||||
// Information of an entry (file or directory) in a ZIP archive.
|
||||
struct Entry {
|
||||
// Path of this entry, in its original encoding as it is stored in the ZIP
|
||||
// archive. The encoding is not specified here. It might or might not be
|
||||
// UTF-8, and the caller needs to use other means to determine the encoding
|
||||
// if it wants to interpret this path correctly.
|
||||
std::string path_in_original_encoding;
|
||||
|
||||
// Returns the file path. The path is usually relative like
|
||||
// "foo/bar.txt", but if it's absolute, is_unsafe() returns true.
|
||||
const base::FilePath& file_path() const { return file_path_; }
|
||||
// Path of the entry, converted to Unicode. This path is relative (eg
|
||||
// "foo/bar.txt"). Absolute paths (eg "/foo/bar.txt") or paths containing
|
||||
// ".." or "." components (eg "../foo/bar.txt") are converted to safe
|
||||
// relative paths. Eg:
|
||||
// (In ZIP) -> (Entry.path)
|
||||
// /foo/bar -> ROOT/foo/bar
|
||||
// ../a -> UP/a
|
||||
// ./a -> DOT/a
|
||||
base::FilePath path;
|
||||
|
||||
// Returns the size of the original file (i.e. after uncompressed).
|
||||
// Returns 0 if the entry is a directory.
|
||||
// Note: this value should not be trusted, because it is stored as metadata
|
||||
// in the zip archive and can be different from the real uncompressed size.
|
||||
int64_t original_size() const { return original_size_; }
|
||||
// Size of the original uncompressed file, or 0 if the entry is a directory.
|
||||
// This value should not be trusted, because it is stored as metadata in the
|
||||
// ZIP archive and can be different from the real uncompressed size.
|
||||
int64_t original_size;
|
||||
|
||||
// Returns the last modified time. If the time stored in the zip file was
|
||||
// not valid, the unix epoch will be returned.
|
||||
// Last modified time. If the timestamp stored in the ZIP archive is not
|
||||
// valid, the Unix epoch will be returned.
|
||||
//
|
||||
// The timestamp stored in the ZIP archive uses the MS-DOS date and time
|
||||
// format.
|
||||
//
|
||||
// The time stored in the zip archive uses the MS-DOS date and time format.
|
||||
// http://msdn.microsoft.com/en-us/library/ms724247(v=vs.85).aspx
|
||||
//
|
||||
// As such the following limitations apply:
|
||||
// * only years from 1980 to 2107 can be represented.
|
||||
// * the time stamp has a 2 second resolution.
|
||||
// * there's no timezone information, so the time is interpreted as local.
|
||||
base::Time last_modified() const { return last_modified_; }
|
||||
// * Only years from 1980 to 2107 can be represented.
|
||||
// * The timestamp has a 2-second resolution.
|
||||
// * There is no timezone information, so the time is interpreted as UTC.
|
||||
base::Time last_modified;
|
||||
|
||||
// Returns true if the entry is a directory.
|
||||
bool is_directory() const { return is_directory_; }
|
||||
// True if the entry is a directory.
|
||||
// False if the entry is a file.
|
||||
bool is_directory = false;
|
||||
|
||||
// Returns true if the entry is unsafe, like having ".." or invalid
|
||||
// UTF-8 characters in its file name, or the file path is absolute.
|
||||
bool is_unsafe() const { return is_unsafe_; }
|
||||
// True if the entry path cannot be converted to a safe relative path. This
|
||||
// happens if a file entry (not a directory) has a filename "." or "..".
|
||||
bool is_unsafe = false;
|
||||
|
||||
// Returns true if the entry is encrypted.
|
||||
bool is_encrypted() const { return is_encrypted_; }
|
||||
// True if the file content is encrypted.
|
||||
bool is_encrypted = false;
|
||||
|
||||
private:
|
||||
const base::FilePath file_path_;
|
||||
int64_t original_size_;
|
||||
base::Time last_modified_;
|
||||
bool is_directory_;
|
||||
bool is_unsafe_;
|
||||
bool is_encrypted_;
|
||||
DISALLOW_COPY_AND_ASSIGN(EntryInfo);
|
||||
// True if the encryption scheme is AES.
|
||||
bool uses_aes_encryption = false;
|
||||
|
||||
// Entry POSIX permissions (POSIX systems only).
|
||||
int posix_mode;
|
||||
};
|
||||
|
||||
ZipReader();
|
||||
|
||||
ZipReader(const ZipReader&) = delete;
|
||||
ZipReader& operator=(const ZipReader&) = delete;
|
||||
|
||||
~ZipReader();
|
||||
|
||||
// Opens the zip file specified by |zip_file_path|. Returns true on
|
||||
// Opens the ZIP archive specified by |zip_path|. Returns true on
|
||||
// success.
|
||||
bool Open(const base::FilePath& zip_file_path);
|
||||
bool Open(const base::FilePath& zip_path);
|
||||
|
||||
// Opens the zip file referred to by the platform file |zip_fd|, without
|
||||
// Opens the ZIP archive referred to by the platform file |zip_fd|, without
|
||||
// taking ownership of |zip_fd|. Returns true on success.
|
||||
bool OpenFromPlatformFile(base::PlatformFile zip_fd);
|
||||
|
||||
@ -136,72 +164,105 @@ class ZipReader {
|
||||
// string until it finishes extracting files.
|
||||
bool OpenFromString(const std::string& data);
|
||||
|
||||
// Closes the currently opened zip file. This function is called in the
|
||||
// Closes the currently opened ZIP archive. This function is called in the
|
||||
// destructor of the class, so you usually don't need to call this.
|
||||
void Close();
|
||||
|
||||
// Returns true if there is at least one entry to read. This function is
|
||||
// used to scan entries with AdvanceToNextEntry(), like:
|
||||
// Sets the encoding of entry paths in the ZIP archive.
|
||||
// By default, paths are assumed to be in UTF-8.
|
||||
void SetEncoding(std::string encoding) { encoding_ = std::move(encoding); }
|
||||
|
||||
// Sets the decryption password that will be used to decrypt encrypted file in
|
||||
// the ZIP archive.
|
||||
void SetPassword(std::string password) { password_ = std::move(password); }
|
||||
|
||||
// Gets the next entry. Returns null if there is no more entry, or if an error
|
||||
// occurred while scanning entries. The returned Entry is owned by this
|
||||
// ZipReader, and is valid until Next() is called again or until this
|
||||
// ZipReader is closed.
|
||||
//
|
||||
// while (reader.HasMore()) {
|
||||
// // Do something with the current file here.
|
||||
// reader.AdvanceToNextEntry();
|
||||
// This function should be called before operations over the current entry
|
||||
// like ExtractCurrentEntryToFile().
|
||||
//
|
||||
// while (const ZipReader::Entry* entry = reader.Next()) {
|
||||
// // Do something with the current entry here.
|
||||
// ...
|
||||
// }
|
||||
bool HasMore();
|
||||
|
||||
// Advances the next entry. Returns true on success.
|
||||
bool AdvanceToNextEntry();
|
||||
|
||||
// Opens the current entry in the zip file. On success, returns true and
|
||||
// updates the the current entry state (i.e. current_entry_info() is
|
||||
// updated). This function should be called before operations over the
|
||||
// current entry like ExtractCurrentEntryToFile().
|
||||
//
|
||||
// Note that there is no CloseCurrentEntryInZip(). The the current entry
|
||||
// state is reset automatically as needed.
|
||||
bool OpenCurrentEntryInZip();
|
||||
// // Finished scanning entries.
|
||||
// // Check if the scanning stopped because of an error.
|
||||
// if (!reader.ok()) {
|
||||
// // There was an error.
|
||||
// ...
|
||||
// }
|
||||
const Entry* Next();
|
||||
|
||||
// Returns true if the enumeration of entries was successful, or false if it
|
||||
// stopped because of an error.
|
||||
bool ok() const { return ok_; }
|
||||
|
||||
// Extracts |num_bytes_to_extract| bytes of the current entry to |delegate|,
|
||||
// starting from the beginning of the entry. Return value specifies whether
|
||||
// the entire file was extracted.
|
||||
// starting from the beginning of the entry.
|
||||
//
|
||||
// Returns true if the entire file was extracted without error.
|
||||
//
|
||||
// Precondition: Next() returned a non-null Entry.
|
||||
bool ExtractCurrentEntry(WriterDelegate* delegate,
|
||||
uint64_t num_bytes_to_extract) const;
|
||||
uint64_t num_bytes_to_extract =
|
||||
std::numeric_limits<uint64_t>::max()) const;
|
||||
|
||||
// Asynchronously extracts the current entry to the given output file path.
|
||||
// If the current entry is a directory it just creates the directory
|
||||
// synchronously instead. OpenCurrentEntryInZip() must be called beforehand.
|
||||
// success_callback will be called on success and failure_callback will be
|
||||
// called on failure. progress_callback will be called at least once.
|
||||
// Extracts the current entry to |delegate|, starting from the beginning
|
||||
// of the entry, calling |listener_callback| regularly with the number of
|
||||
// bytes extracted.
|
||||
//
|
||||
// Returns true if the entire file was extracted without error.
|
||||
//
|
||||
// Precondition: Next() returned a non-null Entry.
|
||||
bool ExtractCurrentEntryWithListener(
|
||||
WriterDelegate* delegate,
|
||||
ListenerCallback listener_callback) const;
|
||||
|
||||
// Asynchronously extracts the current entry to the given output file path. If
|
||||
// the current entry is a directory it just creates the directory
|
||||
// synchronously instead.
|
||||
//
|
||||
// |success_callback| will be called on success and |failure_callback| will be
|
||||
// called on failure. |progress_callback| will be called at least once.
|
||||
// Callbacks will be posted to the current MessageLoop in-order.
|
||||
//
|
||||
// Precondition: Next() returned a non-null Entry.
|
||||
void ExtractCurrentEntryToFilePathAsync(
|
||||
const base::FilePath& output_file_path,
|
||||
SuccessCallback success_callback,
|
||||
FailureCallback failure_callback,
|
||||
const ProgressCallback& progress_callback);
|
||||
ProgressCallback progress_callback);
|
||||
|
||||
// Extracts the current entry into memory. If the current entry is a
|
||||
// directory, the |output| parameter is set to the empty string. If the
|
||||
// current entry is a file, the |output| parameter is filled with its
|
||||
// contents. OpenCurrentEntryInZip() must be called beforehand. Note: the
|
||||
// |output| parameter can be filled with a big amount of data, avoid passing
|
||||
// it around by value, but by reference or pointer. Note: the value returned
|
||||
// by EntryInfo::original_size() cannot be trusted, so the real size of the
|
||||
// uncompressed contents can be different. |max_read_bytes| limits the ammount
|
||||
// of memory used to carry the entry. Returns true if the entire content is
|
||||
// read. If the entry is bigger than |max_read_bytes|, returns false and
|
||||
// |output| is filled with |max_read_bytes| of data. If an error occurs,
|
||||
// returns false, and |output| is set to the empty string.
|
||||
// directory, |*output| is set to the empty string. If the current entry is a
|
||||
// file, |*output| is filled with its contents.
|
||||
//
|
||||
// The value in |Entry::original_size| cannot be trusted, so the real size of
|
||||
// the uncompressed contents can be different. |max_read_bytes| limits the
|
||||
// amount of memory used to carry the entry.
|
||||
//
|
||||
// Returns true if the entire content is read without error. If the content is
|
||||
// bigger than |max_read_bytes|, this function returns false and |*output| is
|
||||
// filled with |max_read_bytes| of data. If an error occurs, this function
|
||||
// returns false and |*output| contains the content extracted so far, which
|
||||
// might be garbage data.
|
||||
//
|
||||
// Precondition: Next() returned a non-null Entry.
|
||||
bool ExtractCurrentEntryToString(uint64_t max_read_bytes,
|
||||
std::string* output) const;
|
||||
|
||||
// Returns the current entry info. Returns NULL if the current entry is
|
||||
// not yet opened. OpenCurrentEntryInZip() must be called beforehand.
|
||||
EntryInfo* current_entry_info() const {
|
||||
return current_entry_info_.get();
|
||||
bool ExtractCurrentEntryToString(std::string* output) const {
|
||||
return ExtractCurrentEntryToString(
|
||||
base::checked_cast<uint64_t>(output->max_size()), output);
|
||||
}
|
||||
|
||||
// Returns the number of entries in the zip file.
|
||||
// Open() must be called beforehand.
|
||||
// Returns the number of entries in the ZIP archive.
|
||||
//
|
||||
// Precondition: one of the Open() methods returned true.
|
||||
int num_entries() const { return num_entries_; }
|
||||
|
||||
private:
|
||||
@ -211,25 +272,64 @@ class ZipReader {
|
||||
// Resets the internal state.
|
||||
void Reset();
|
||||
|
||||
// Opens the current entry in the ZIP archive. On success, returns true and
|
||||
// updates the current entry state |entry_|.
|
||||
//
|
||||
// Note that there is no matching CloseEntry(). The current entry state is
|
||||
// reset automatically as needed.
|
||||
bool OpenEntry();
|
||||
|
||||
// Normalizes the given path passed as UTF-16 string piece. Sets entry_.path,
|
||||
// entry_.is_directory and entry_.is_unsafe.
|
||||
void Normalize(base::StringPiece16 in);
|
||||
|
||||
// Runs the ListenerCallback at a throttled rate.
|
||||
void ReportProgress(ListenerCallback listener_callback, uint64_t bytes) const;
|
||||
|
||||
// Extracts |num_bytes_to_extract| bytes of the current entry to |delegate|,
|
||||
// starting from the beginning of the entry calling |listener_callback| if
|
||||
// its supplied.
|
||||
//
|
||||
// Returns true if the entire file was extracted without error.
|
||||
//
|
||||
// Precondition: Next() returned a non-null Entry.
|
||||
bool ExtractCurrentEntry(WriterDelegate* delegate,
|
||||
ListenerCallback listener_callback,
|
||||
uint64_t num_bytes_to_extract =
|
||||
std::numeric_limits<uint64_t>::max()) const;
|
||||
|
||||
// Extracts a chunk of the file to the target. Will post a task for the next
|
||||
// chunk and success/failure/progress callbacks as necessary.
|
||||
void ExtractChunk(base::File target_file,
|
||||
SuccessCallback success_callback,
|
||||
FailureCallback failure_callback,
|
||||
const ProgressCallback& progress_callback,
|
||||
ProgressCallback progress_callback,
|
||||
const int64_t offset);
|
||||
|
||||
std::string encoding_;
|
||||
std::string password_;
|
||||
unzFile zip_file_;
|
||||
int num_entries_;
|
||||
int next_index_;
|
||||
bool reached_end_;
|
||||
std::unique_ptr<EntryInfo> current_entry_info_;
|
||||
bool ok_;
|
||||
Entry entry_;
|
||||
|
||||
// Next time to report progress.
|
||||
mutable base::TimeTicks next_progress_report_time_ = base::TimeTicks::Now();
|
||||
|
||||
// Progress time delta.
|
||||
// TODO(crbug.com/953256) Add this as parameter to the unzip options.
|
||||
base::TimeDelta progress_period_ = base::Milliseconds(1000);
|
||||
|
||||
// Number of bytes read since last progress report callback executed.
|
||||
mutable uint64_t delta_bytes_read_ = 0;
|
||||
|
||||
base::WeakPtrFactory<ZipReader> weak_ptr_factory_{this};
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ZipReader);
|
||||
};
|
||||
|
||||
// A writer delegate that writes to a given File.
|
||||
// A writer delegate that writes to a given File. It is recommended that this
|
||||
// file be initially empty.
|
||||
class FileWriterDelegate : public WriterDelegate {
|
||||
public:
|
||||
// Constructs a FileWriterDelegate that manipulates |file|. The delegate will
|
||||
@ -238,14 +338,14 @@ class FileWriterDelegate : public WriterDelegate {
|
||||
explicit FileWriterDelegate(base::File* file);
|
||||
|
||||
// Constructs a FileWriterDelegate that takes ownership of |file|.
|
||||
explicit FileWriterDelegate(std::unique_ptr<base::File> file);
|
||||
explicit FileWriterDelegate(base::File owned_file);
|
||||
|
||||
FileWriterDelegate(const FileWriterDelegate&) = delete;
|
||||
FileWriterDelegate& operator=(const FileWriterDelegate&) = delete;
|
||||
|
||||
// Truncates the file to the number of bytes written.
|
||||
~FileWriterDelegate() override;
|
||||
|
||||
// WriterDelegate methods:
|
||||
|
||||
// Seeks to the beginning of the file, returning false if the seek fails.
|
||||
// Returns true if the file handle passed to the constructor is valid.
|
||||
bool PrepareOutput() override;
|
||||
|
||||
// Writes |num_bytes| bytes of |data| to the file, returning false on error or
|
||||
@ -255,45 +355,48 @@ class FileWriterDelegate : public WriterDelegate {
|
||||
// Sets the last-modified time of the data.
|
||||
void SetTimeModified(const base::Time& time) override;
|
||||
|
||||
// Return the actual size of the file.
|
||||
// On POSIX systems, sets the file to be executable if the source file was
|
||||
// executable.
|
||||
void SetPosixFilePermissions(int mode) override;
|
||||
|
||||
// Empties the file to avoid leaving garbage data in it.
|
||||
void OnError() override;
|
||||
|
||||
// Gets the number of bytes written into the file.
|
||||
int64_t file_length() { return file_length_; }
|
||||
|
||||
private:
|
||||
// The file the delegate modifies.
|
||||
base::File* file_;
|
||||
|
||||
protected:
|
||||
// The delegate can optionally own the file it modifies, in which case
|
||||
// owned_file_ is set and file_ is an alias for owned_file_.
|
||||
std::unique_ptr<base::File> owned_file_;
|
||||
base::File owned_file_;
|
||||
|
||||
// The file the delegate modifies.
|
||||
base::File* const file_ = &owned_file_;
|
||||
|
||||
int64_t file_length_ = 0;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(FileWriterDelegate);
|
||||
};
|
||||
|
||||
// A writer delegate that writes a file at a given path.
|
||||
class FilePathWriterDelegate : public WriterDelegate {
|
||||
// A writer delegate that creates and writes a file at a given path. This does
|
||||
// not overwrite any existing file.
|
||||
class FilePathWriterDelegate : public FileWriterDelegate {
|
||||
public:
|
||||
explicit FilePathWriterDelegate(const base::FilePath& output_file_path);
|
||||
explicit FilePathWriterDelegate(base::FilePath output_file_path);
|
||||
|
||||
FilePathWriterDelegate(const FilePathWriterDelegate&) = delete;
|
||||
FilePathWriterDelegate& operator=(const FilePathWriterDelegate&) = delete;
|
||||
|
||||
~FilePathWriterDelegate() override;
|
||||
|
||||
// WriterDelegate methods:
|
||||
|
||||
// Creates the output file and any necessary intermediate directories.
|
||||
// Creates the output file and any necessary intermediate directories. Does
|
||||
// not overwrite any existing file, and returns false if the output file
|
||||
// cannot be created because another file conflicts with it.
|
||||
bool PrepareOutput() override;
|
||||
|
||||
// Writes |num_bytes| bytes of |data| to the file, returning false if not all
|
||||
// bytes could be written.
|
||||
bool WriteBytes(const char* data, int num_bytes) override;
|
||||
|
||||
// Sets the last-modified time of the data.
|
||||
void SetTimeModified(const base::Time& time) override;
|
||||
// Deletes the output file.
|
||||
void OnError() override;
|
||||
|
||||
private:
|
||||
base::FilePath output_file_path_;
|
||||
base::File file_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(FilePathWriterDelegate);
|
||||
const base::FilePath output_file_path_;
|
||||
};
|
||||
|
||||
} // namespace zip
|
||||
|
729
deps/zlib/google/zip_reader_unittest.cc
vendored
729
deps/zlib/google/zip_reader_unittest.cc
vendored
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
// Copyright 2011 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
@ -8,29 +8,36 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <set>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/bind.h"
|
||||
#include "base/check.h"
|
||||
#include "base/files/file.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/files/scoped_temp_dir.h"
|
||||
#include "base/hash/md5.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/path_service.h"
|
||||
#include "base/run_loop.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "base/strings/string_piece.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/test/bind.h"
|
||||
#include "base/test/task_environment.h"
|
||||
#include "base/time/time.h"
|
||||
#include "build/build_config.h"
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "testing/platform_test.h"
|
||||
#include "third_party/zlib/google/zip_internal.h"
|
||||
|
||||
using ::testing::Return;
|
||||
using ::testing::_;
|
||||
using ::testing::ElementsAre;
|
||||
using ::testing::ElementsAreArray;
|
||||
using ::testing::Return;
|
||||
using ::testing::SizeIs;
|
||||
|
||||
namespace {
|
||||
|
||||
@ -38,10 +45,7 @@ const static std::string kQuuxExpectedMD5 = "d1ae4ac8a17a0e09317113ab284b57a6";
|
||||
|
||||
class FileWrapper {
|
||||
public:
|
||||
typedef enum {
|
||||
READ_ONLY,
|
||||
READ_WRITE
|
||||
} AccessMode;
|
||||
typedef enum { READ_ONLY, READ_WRITE } AccessMode;
|
||||
|
||||
FileWrapper(const base::FilePath& path, AccessMode mode) {
|
||||
int flags = base::File::FLAG_READ;
|
||||
@ -72,18 +76,13 @@ class MockUnzipListener : public base::SupportsWeakPtr<MockUnzipListener> {
|
||||
: success_calls_(0),
|
||||
failure_calls_(0),
|
||||
progress_calls_(0),
|
||||
current_progress_(0) {
|
||||
}
|
||||
current_progress_(0) {}
|
||||
|
||||
// Success callback for async functions.
|
||||
void OnUnzipSuccess() {
|
||||
success_calls_++;
|
||||
}
|
||||
void OnUnzipSuccess() { success_calls_++; }
|
||||
|
||||
// Failure callback for async functions.
|
||||
void OnUnzipFailure() {
|
||||
failure_calls_++;
|
||||
}
|
||||
void OnUnzipFailure() { failure_calls_++; }
|
||||
|
||||
// Progress callback for async functions.
|
||||
void OnUnzipProgress(int64_t progress) {
|
||||
@ -110,184 +109,189 @@ class MockWriterDelegate : public zip::WriterDelegate {
|
||||
MOCK_METHOD0(PrepareOutput, bool());
|
||||
MOCK_METHOD2(WriteBytes, bool(const char*, int));
|
||||
MOCK_METHOD1(SetTimeModified, void(const base::Time&));
|
||||
MOCK_METHOD1(SetPosixFilePermissions, void(int));
|
||||
MOCK_METHOD0(OnError, void());
|
||||
};
|
||||
|
||||
bool ExtractCurrentEntryToFilePath(zip::ZipReader* reader,
|
||||
base::FilePath path) {
|
||||
zip::FilePathWriterDelegate writer(path);
|
||||
return reader->ExtractCurrentEntry(&writer,
|
||||
std::numeric_limits<uint64_t>::max());
|
||||
return reader->ExtractCurrentEntry(&writer);
|
||||
}
|
||||
|
||||
bool LocateAndOpenEntry(zip::ZipReader* reader,
|
||||
const base::FilePath& path_in_zip) {
|
||||
const zip::ZipReader::Entry* LocateAndOpenEntry(
|
||||
zip::ZipReader* const reader,
|
||||
const base::FilePath& path_in_zip) {
|
||||
DCHECK(reader);
|
||||
EXPECT_TRUE(reader->ok());
|
||||
|
||||
// The underlying library can do O(1) access, but ZipReader does not expose
|
||||
// that. O(N) access is acceptable for these tests.
|
||||
while (reader->HasMore()) {
|
||||
if (!reader->OpenCurrentEntryInZip())
|
||||
return false;
|
||||
if (reader->current_entry_info()->file_path() == path_in_zip)
|
||||
return true;
|
||||
reader->AdvanceToNextEntry();
|
||||
while (const zip::ZipReader::Entry* const entry = reader->Next()) {
|
||||
EXPECT_TRUE(reader->ok());
|
||||
if (entry->path == path_in_zip)
|
||||
return entry;
|
||||
}
|
||||
return false;
|
||||
|
||||
EXPECT_TRUE(reader->ok());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
using Paths = std::vector<base::FilePath>;
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace zip {
|
||||
|
||||
// Make the test a PlatformTest to setup autorelease pools properly on Mac.
|
||||
class ZipReaderTest : public PlatformTest {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
void SetUp() override {
|
||||
PlatformTest::SetUp();
|
||||
|
||||
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
|
||||
test_dir_ = temp_dir_.GetPath();
|
||||
|
||||
ASSERT_TRUE(GetTestDataDirectory(&test_data_dir_));
|
||||
|
||||
test_zip_file_ = test_data_dir_.AppendASCII("test.zip");
|
||||
encrypted_zip_file_ = test_data_dir_.AppendASCII("test_encrypted.zip");
|
||||
evil_zip_file_ = test_data_dir_.AppendASCII("evil.zip");
|
||||
evil_via_invalid_utf8_zip_file_ = test_data_dir_.AppendASCII(
|
||||
"evil_via_invalid_utf8.zip");
|
||||
evil_via_absolute_file_name_zip_file_ = test_data_dir_.AppendASCII(
|
||||
"evil_via_absolute_file_name.zip");
|
||||
|
||||
test_zip_contents_.insert(base::FilePath(FILE_PATH_LITERAL("foo/")));
|
||||
test_zip_contents_.insert(base::FilePath(FILE_PATH_LITERAL("foo/bar/")));
|
||||
test_zip_contents_.insert(
|
||||
base::FilePath(FILE_PATH_LITERAL("foo/bar/baz.txt")));
|
||||
test_zip_contents_.insert(
|
||||
base::FilePath(FILE_PATH_LITERAL("foo/bar/quux.txt")));
|
||||
test_zip_contents_.insert(
|
||||
base::FilePath(FILE_PATH_LITERAL("foo/bar.txt")));
|
||||
test_zip_contents_.insert(base::FilePath(FILE_PATH_LITERAL("foo.txt")));
|
||||
test_zip_contents_.insert(
|
||||
base::FilePath(FILE_PATH_LITERAL("foo/bar/.hidden")));
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
PlatformTest::TearDown();
|
||||
static base::FilePath GetTestDataDirectory() {
|
||||
base::FilePath path;
|
||||
CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &path));
|
||||
return path.AppendASCII("third_party")
|
||||
.AppendASCII("zlib")
|
||||
.AppendASCII("google")
|
||||
.AppendASCII("test")
|
||||
.AppendASCII("data");
|
||||
}
|
||||
|
||||
bool GetTestDataDirectory(base::FilePath* path) {
|
||||
bool success = base::PathService::Get(base::DIR_SOURCE_ROOT, path);
|
||||
EXPECT_TRUE(success);
|
||||
if (!success)
|
||||
return false;
|
||||
*path = path->AppendASCII("third_party");
|
||||
*path = path->AppendASCII("zlib");
|
||||
*path = path->AppendASCII("google");
|
||||
*path = path->AppendASCII("test");
|
||||
*path = path->AppendASCII("data");
|
||||
return true;
|
||||
}
|
||||
static Paths GetPaths(const base::FilePath& zip_path,
|
||||
base::StringPiece encoding = {}) {
|
||||
Paths paths;
|
||||
|
||||
bool CompareFileAndMD5(const base::FilePath& path,
|
||||
const std::string expected_md5) {
|
||||
// Read the output file and compute the MD5.
|
||||
std::string output;
|
||||
if (!base::ReadFileToString(path, &output))
|
||||
return false;
|
||||
const std::string md5 = base::MD5String(output);
|
||||
return expected_md5 == md5;
|
||||
if (ZipReader reader; reader.Open(zip_path)) {
|
||||
if (!encoding.empty())
|
||||
reader.SetEncoding(std::string(encoding));
|
||||
|
||||
while (const ZipReader::Entry* const entry = reader.Next()) {
|
||||
EXPECT_TRUE(reader.ok());
|
||||
paths.push_back(entry->path);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(reader.ok());
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
// The path to temporary directory used to contain the test operations.
|
||||
base::FilePath test_dir_;
|
||||
// The path to the test data directory where test.zip etc. are located.
|
||||
base::FilePath test_data_dir_;
|
||||
const base::FilePath data_dir_ = GetTestDataDirectory();
|
||||
// The path to test.zip in the test data directory.
|
||||
base::FilePath test_zip_file_;
|
||||
// The path to test_encrypted.zip in the test data directory.
|
||||
base::FilePath encrypted_zip_file_;
|
||||
// The path to evil.zip in the test data directory.
|
||||
base::FilePath evil_zip_file_;
|
||||
// The path to evil_via_invalid_utf8.zip in the test data directory.
|
||||
base::FilePath evil_via_invalid_utf8_zip_file_;
|
||||
// The path to evil_via_absolute_file_name.zip in the test data directory.
|
||||
base::FilePath evil_via_absolute_file_name_zip_file_;
|
||||
std::set<base::FilePath> test_zip_contents_;
|
||||
|
||||
const base::FilePath test_zip_file_ = data_dir_.AppendASCII("test.zip");
|
||||
const Paths test_zip_contents_ = {
|
||||
base::FilePath(FILE_PATH_LITERAL("foo/")),
|
||||
base::FilePath(FILE_PATH_LITERAL("foo/bar/")),
|
||||
base::FilePath(FILE_PATH_LITERAL("foo/bar/baz.txt")),
|
||||
base::FilePath(FILE_PATH_LITERAL("foo/bar/quux.txt")),
|
||||
base::FilePath(FILE_PATH_LITERAL("foo/bar.txt")),
|
||||
base::FilePath(FILE_PATH_LITERAL("foo.txt")),
|
||||
base::FilePath(FILE_PATH_LITERAL("foo/bar/.hidden")),
|
||||
};
|
||||
base::ScopedTempDir temp_dir_;
|
||||
|
||||
base::test::TaskEnvironment task_environment_;
|
||||
};
|
||||
|
||||
TEST_F(ZipReaderTest, Open_ValidZipFile) {
|
||||
ZipReader reader;
|
||||
ASSERT_TRUE(reader.Open(test_zip_file_));
|
||||
EXPECT_TRUE(reader.Open(test_zip_file_));
|
||||
EXPECT_TRUE(reader.ok());
|
||||
}
|
||||
|
||||
TEST_F(ZipReaderTest, Open_ValidZipPlatformFile) {
|
||||
ZipReader reader;
|
||||
EXPECT_FALSE(reader.ok());
|
||||
FileWrapper zip_fd_wrapper(test_zip_file_, FileWrapper::READ_ONLY);
|
||||
ASSERT_TRUE(reader.OpenFromPlatformFile(zip_fd_wrapper.platform_file()));
|
||||
EXPECT_TRUE(reader.OpenFromPlatformFile(zip_fd_wrapper.platform_file()));
|
||||
EXPECT_TRUE(reader.ok());
|
||||
}
|
||||
|
||||
TEST_F(ZipReaderTest, Open_NonExistentFile) {
|
||||
ZipReader reader;
|
||||
ASSERT_FALSE(reader.Open(test_data_dir_.AppendASCII("nonexistent.zip")));
|
||||
EXPECT_FALSE(reader.ok());
|
||||
EXPECT_FALSE(reader.Open(data_dir_.AppendASCII("nonexistent.zip")));
|
||||
EXPECT_FALSE(reader.ok());
|
||||
}
|
||||
|
||||
TEST_F(ZipReaderTest, Open_ExistentButNonZipFile) {
|
||||
ZipReader reader;
|
||||
ASSERT_FALSE(reader.Open(test_data_dir_.AppendASCII("create_test_zip.sh")));
|
||||
EXPECT_FALSE(reader.ok());
|
||||
EXPECT_FALSE(reader.Open(data_dir_.AppendASCII("create_test_zip.sh")));
|
||||
EXPECT_FALSE(reader.ok());
|
||||
}
|
||||
|
||||
// Iterate through the contents in the test zip file, and compare that the
|
||||
// contents collected from the zip reader matches the expected contents.
|
||||
TEST_F(ZipReaderTest, Iteration) {
|
||||
std::set<base::FilePath> actual_contents;
|
||||
TEST_F(ZipReaderTest, Open_EmptyFile) {
|
||||
ZipReader reader;
|
||||
ASSERT_TRUE(reader.Open(test_zip_file_));
|
||||
while (reader.HasMore()) {
|
||||
ASSERT_TRUE(reader.OpenCurrentEntryInZip());
|
||||
actual_contents.insert(reader.current_entry_info()->file_path());
|
||||
ASSERT_TRUE(reader.AdvanceToNextEntry());
|
||||
}
|
||||
EXPECT_FALSE(reader.AdvanceToNextEntry()); // Shouldn't go further.
|
||||
EXPECT_EQ(test_zip_contents_.size(),
|
||||
static_cast<size_t>(reader.num_entries()));
|
||||
EXPECT_EQ(test_zip_contents_.size(), actual_contents.size());
|
||||
EXPECT_EQ(test_zip_contents_, actual_contents);
|
||||
EXPECT_FALSE(reader.ok());
|
||||
EXPECT_FALSE(reader.Open(data_dir_.AppendASCII("empty.zip")));
|
||||
EXPECT_FALSE(reader.ok());
|
||||
}
|
||||
|
||||
// Open the test zip file from a file descriptor, iterate through its contents,
|
||||
// and compare that they match the expected contents.
|
||||
// Iterate through the contents in the test ZIP archive, and compare that the
|
||||
// contents collected from the ZipReader matches the expected contents.
|
||||
TEST_F(ZipReaderTest, Iteration) {
|
||||
Paths actual_contents;
|
||||
ZipReader reader;
|
||||
EXPECT_FALSE(reader.ok());
|
||||
EXPECT_TRUE(reader.Open(test_zip_file_));
|
||||
EXPECT_TRUE(reader.ok());
|
||||
while (const ZipReader::Entry* const entry = reader.Next()) {
|
||||
EXPECT_TRUE(reader.ok());
|
||||
actual_contents.push_back(entry->path);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(reader.ok());
|
||||
EXPECT_FALSE(reader.Next()); // Shouldn't go further.
|
||||
EXPECT_TRUE(reader.ok());
|
||||
|
||||
EXPECT_THAT(actual_contents, SizeIs(reader.num_entries()));
|
||||
EXPECT_THAT(actual_contents, ElementsAreArray(test_zip_contents_));
|
||||
}
|
||||
|
||||
// Open the test ZIP archive from a file descriptor, iterate through its
|
||||
// contents, and compare that they match the expected contents.
|
||||
TEST_F(ZipReaderTest, PlatformFileIteration) {
|
||||
std::set<base::FilePath> actual_contents;
|
||||
Paths actual_contents;
|
||||
ZipReader reader;
|
||||
FileWrapper zip_fd_wrapper(test_zip_file_, FileWrapper::READ_ONLY);
|
||||
ASSERT_TRUE(reader.OpenFromPlatformFile(zip_fd_wrapper.platform_file()));
|
||||
while (reader.HasMore()) {
|
||||
ASSERT_TRUE(reader.OpenCurrentEntryInZip());
|
||||
actual_contents.insert(reader.current_entry_info()->file_path());
|
||||
ASSERT_TRUE(reader.AdvanceToNextEntry());
|
||||
EXPECT_TRUE(reader.OpenFromPlatformFile(zip_fd_wrapper.platform_file()));
|
||||
EXPECT_TRUE(reader.ok());
|
||||
while (const ZipReader::Entry* const entry = reader.Next()) {
|
||||
EXPECT_TRUE(reader.ok());
|
||||
actual_contents.push_back(entry->path);
|
||||
}
|
||||
EXPECT_FALSE(reader.AdvanceToNextEntry()); // Shouldn't go further.
|
||||
EXPECT_EQ(test_zip_contents_.size(),
|
||||
static_cast<size_t>(reader.num_entries()));
|
||||
EXPECT_EQ(test_zip_contents_.size(), actual_contents.size());
|
||||
EXPECT_EQ(test_zip_contents_, actual_contents);
|
||||
|
||||
EXPECT_TRUE(reader.ok());
|
||||
EXPECT_FALSE(reader.Next()); // Shouldn't go further.
|
||||
EXPECT_TRUE(reader.ok());
|
||||
|
||||
EXPECT_THAT(actual_contents, SizeIs(reader.num_entries()));
|
||||
EXPECT_THAT(actual_contents, ElementsAreArray(test_zip_contents_));
|
||||
}
|
||||
|
||||
TEST_F(ZipReaderTest, current_entry_info_RegularFile) {
|
||||
TEST_F(ZipReaderTest, RegularFile) {
|
||||
ZipReader reader;
|
||||
ASSERT_TRUE(reader.Open(test_zip_file_));
|
||||
base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
|
||||
ASSERT_TRUE(LocateAndOpenEntry(&reader, target_path));
|
||||
ZipReader::EntryInfo* current_entry_info = reader.current_entry_info();
|
||||
|
||||
EXPECT_EQ(target_path, current_entry_info->file_path());
|
||||
EXPECT_EQ(13527, current_entry_info->original_size());
|
||||
const ZipReader::Entry* entry = LocateAndOpenEntry(&reader, target_path);
|
||||
ASSERT_TRUE(entry);
|
||||
|
||||
EXPECT_EQ(target_path, entry->path);
|
||||
EXPECT_EQ(13527, entry->original_size);
|
||||
|
||||
// The expected time stamp: 2009-05-29 06:22:20
|
||||
base::Time::Exploded exploded = {}; // Zero-clear.
|
||||
current_entry_info->last_modified().LocalExplode(&exploded);
|
||||
entry->last_modified.UTCExplode(&exploded);
|
||||
EXPECT_EQ(2009, exploded.year);
|
||||
EXPECT_EQ(5, exploded.month);
|
||||
EXPECT_EQ(29, exploded.day_of_month);
|
||||
@ -296,67 +300,106 @@ TEST_F(ZipReaderTest, current_entry_info_RegularFile) {
|
||||
EXPECT_EQ(20, exploded.second);
|
||||
EXPECT_EQ(0, exploded.millisecond);
|
||||
|
||||
EXPECT_FALSE(current_entry_info->is_unsafe());
|
||||
EXPECT_FALSE(current_entry_info->is_directory());
|
||||
EXPECT_FALSE(entry->is_unsafe);
|
||||
EXPECT_FALSE(entry->is_directory);
|
||||
}
|
||||
|
||||
TEST_F(ZipReaderTest, current_entry_info_DotDotFile) {
|
||||
TEST_F(ZipReaderTest, DotDotFile) {
|
||||
ZipReader reader;
|
||||
ASSERT_TRUE(reader.Open(evil_zip_file_));
|
||||
ASSERT_TRUE(reader.Open(data_dir_.AppendASCII("evil.zip")));
|
||||
base::FilePath target_path(FILE_PATH_LITERAL(
|
||||
"../levilevilevilevilevilevilevilevilevilevilevilevil"));
|
||||
ASSERT_TRUE(LocateAndOpenEntry(&reader, target_path));
|
||||
ZipReader::EntryInfo* current_entry_info = reader.current_entry_info();
|
||||
EXPECT_EQ(target_path, current_entry_info->file_path());
|
||||
|
||||
// This file is unsafe because of ".." in the file name.
|
||||
EXPECT_TRUE(current_entry_info->is_unsafe());
|
||||
EXPECT_FALSE(current_entry_info->is_directory());
|
||||
"UP/levilevilevilevilevilevilevilevilevilevilevilevil"));
|
||||
const ZipReader::Entry* entry = LocateAndOpenEntry(&reader, target_path);
|
||||
ASSERT_TRUE(entry);
|
||||
EXPECT_EQ(target_path, entry->path);
|
||||
EXPECT_FALSE(entry->is_unsafe);
|
||||
EXPECT_FALSE(entry->is_directory);
|
||||
}
|
||||
|
||||
TEST_F(ZipReaderTest, current_entry_info_InvalidUTF8File) {
|
||||
TEST_F(ZipReaderTest, InvalidUTF8File) {
|
||||
ZipReader reader;
|
||||
ASSERT_TRUE(reader.Open(evil_via_invalid_utf8_zip_file_));
|
||||
// The evil file is the 2nd file in the zip file.
|
||||
// We cannot locate by the file name ".\x80.\\evil.txt",
|
||||
// as FilePath may internally convert the string.
|
||||
ASSERT_TRUE(reader.AdvanceToNextEntry());
|
||||
ASSERT_TRUE(reader.OpenCurrentEntryInZip());
|
||||
ZipReader::EntryInfo* current_entry_info = reader.current_entry_info();
|
||||
|
||||
// This file is unsafe because of invalid UTF-8 in the file name.
|
||||
EXPECT_TRUE(current_entry_info->is_unsafe());
|
||||
EXPECT_FALSE(current_entry_info->is_directory());
|
||||
ASSERT_TRUE(reader.Open(data_dir_.AppendASCII("evil_via_invalid_utf8.zip")));
|
||||
base::FilePath target_path = base::FilePath::FromUTF8Unsafe(".<2E>.<2E>evil.txt");
|
||||
const ZipReader::Entry* entry = LocateAndOpenEntry(&reader, target_path);
|
||||
ASSERT_TRUE(entry);
|
||||
EXPECT_EQ(target_path, entry->path);
|
||||
EXPECT_FALSE(entry->is_unsafe);
|
||||
EXPECT_FALSE(entry->is_directory);
|
||||
}
|
||||
|
||||
TEST_F(ZipReaderTest, current_entry_info_AbsoluteFile) {
|
||||
// By default, file paths in ZIPs are interpreted as UTF-8. But in this test,
|
||||
// the ZIP archive contains file paths that are actually encoded in Shift JIS.
|
||||
// The SJIS-encoded paths are thus wrongly interpreted as UTF-8, resulting in
|
||||
// garbled paths. Invalid UTF-8 sequences are safely converted to the
|
||||
// replacement character <20>.
|
||||
TEST_F(ZipReaderTest, EncodingSjisAsUtf8) {
|
||||
EXPECT_THAT(
|
||||
GetPaths(data_dir_.AppendASCII("SJIS Bug 846195.zip")),
|
||||
ElementsAre(
|
||||
base::FilePath::FromUTF8Unsafe("<EFBFBD>V<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>t<EFBFBD>H<EFBFBD><EFBFBD><EFBFBD>_/SJIS_835C_<43><5F>.txt"),
|
||||
base::FilePath::FromUTF8Unsafe(
|
||||
"<EFBFBD>V<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>t<EFBFBD>H<EFBFBD><EFBFBD><EFBFBD>_/<2F>V<EFBFBD><56><EFBFBD><EFBFBD><EFBFBD>e<EFBFBD>L<EFBFBD>X<EFBFBD>g <20>h<EFBFBD>L<EFBFBD><4C><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>g.txt")));
|
||||
}
|
||||
|
||||
// In this test, SJIS-encoded paths are interpreted as Code Page 1252. This
|
||||
// results in garbled paths. Note the presence of C1 control codes U+0090 and
|
||||
// U+0081 in the garbled paths.
|
||||
TEST_F(ZipReaderTest, EncodingSjisAs1252) {
|
||||
EXPECT_THAT(
|
||||
GetPaths(data_dir_.AppendASCII("SJIS Bug 846195.zip"), "windows-1252"),
|
||||
ElementsAre(base::FilePath::FromUTF8Unsafe(
|
||||
"\u0090V‚µ‚¢ƒtƒHƒ‹ƒ_/SJIS_835C_ƒ<5F>.txt"),
|
||||
base::FilePath::FromUTF8Unsafe(
|
||||
"\u0090V‚µ‚¢ƒtƒHƒ‹ƒ_/\u0090V‚µ‚¢ƒeƒLƒXƒg "
|
||||
"ƒhƒLƒ…ƒ\u0081ƒ“ƒg.txt")));
|
||||
}
|
||||
|
||||
// In this test, SJIS-encoded paths are interpreted as Code Page 866. This
|
||||
// results in garbled paths.
|
||||
TEST_F(ZipReaderTest, EncodingSjisAsIbm866) {
|
||||
EXPECT_THAT(
|
||||
GetPaths(data_dir_.AppendASCII("SJIS Bug 846195.zip"), "IBM866"),
|
||||
ElementsAre(
|
||||
base::FilePath::FromUTF8Unsafe("РVВ╡ВвГtГHГЛГ_/SJIS_835C_Г<5F>.txt"),
|
||||
base::FilePath::FromUTF8Unsafe(
|
||||
"РVВ╡ВвГtГHГЛГ_/РVВ╡ВвГeГLГXГg ГhГLГЕГБГУГg.txt")));
|
||||
}
|
||||
|
||||
// Tests that SJIS-encoded paths are correctly converted to Unicode.
|
||||
TEST_F(ZipReaderTest, EncodingSjis) {
|
||||
EXPECT_THAT(
|
||||
GetPaths(data_dir_.AppendASCII("SJIS Bug 846195.zip"), "Shift_JIS"),
|
||||
ElementsAre(
|
||||
base::FilePath::FromUTF8Unsafe("新しいフォルダ/SJIS_835C_ソ.txt"),
|
||||
base::FilePath::FromUTF8Unsafe(
|
||||
"新しいフォルダ/新しいテキスト ドキュメント.txt")));
|
||||
}
|
||||
|
||||
TEST_F(ZipReaderTest, AbsoluteFile) {
|
||||
ZipReader reader;
|
||||
ASSERT_TRUE(reader.Open(evil_via_absolute_file_name_zip_file_));
|
||||
base::FilePath target_path(FILE_PATH_LITERAL("/evil.txt"));
|
||||
ASSERT_TRUE(LocateAndOpenEntry(&reader, target_path));
|
||||
ZipReader::EntryInfo* current_entry_info = reader.current_entry_info();
|
||||
EXPECT_EQ(target_path, current_entry_info->file_path());
|
||||
|
||||
// This file is unsafe because of the absolute file name.
|
||||
EXPECT_TRUE(current_entry_info->is_unsafe());
|
||||
EXPECT_FALSE(current_entry_info->is_directory());
|
||||
ASSERT_TRUE(
|
||||
reader.Open(data_dir_.AppendASCII("evil_via_absolute_file_name.zip")));
|
||||
base::FilePath target_path(FILE_PATH_LITERAL("ROOT/evil.txt"));
|
||||
const ZipReader::Entry* entry = LocateAndOpenEntry(&reader, target_path);
|
||||
ASSERT_TRUE(entry);
|
||||
EXPECT_EQ(target_path, entry->path);
|
||||
EXPECT_FALSE(entry->is_unsafe);
|
||||
EXPECT_FALSE(entry->is_directory);
|
||||
}
|
||||
|
||||
TEST_F(ZipReaderTest, current_entry_info_Directory) {
|
||||
TEST_F(ZipReaderTest, Directory) {
|
||||
ZipReader reader;
|
||||
ASSERT_TRUE(reader.Open(test_zip_file_));
|
||||
base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/"));
|
||||
ASSERT_TRUE(LocateAndOpenEntry(&reader, target_path));
|
||||
ZipReader::EntryInfo* current_entry_info = reader.current_entry_info();
|
||||
|
||||
EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("foo/bar/")),
|
||||
current_entry_info->file_path());
|
||||
const ZipReader::Entry* entry = LocateAndOpenEntry(&reader, target_path);
|
||||
ASSERT_TRUE(entry);
|
||||
EXPECT_EQ(target_path, entry->path);
|
||||
// The directory size should be zero.
|
||||
EXPECT_EQ(0, current_entry_info->original_size());
|
||||
EXPECT_EQ(0, entry->original_size);
|
||||
|
||||
// The expected time stamp: 2009-05-31 15:49:52
|
||||
base::Time::Exploded exploded = {}; // Zero-clear.
|
||||
current_entry_info->last_modified().LocalExplode(&exploded);
|
||||
entry->last_modified.UTCExplode(&exploded);
|
||||
EXPECT_EQ(2009, exploded.year);
|
||||
EXPECT_EQ(5, exploded.month);
|
||||
EXPECT_EQ(31, exploded.day_of_month);
|
||||
@ -365,22 +408,91 @@ TEST_F(ZipReaderTest, current_entry_info_Directory) {
|
||||
EXPECT_EQ(52, exploded.second);
|
||||
EXPECT_EQ(0, exploded.millisecond);
|
||||
|
||||
EXPECT_FALSE(current_entry_info->is_unsafe());
|
||||
EXPECT_TRUE(current_entry_info->is_directory());
|
||||
EXPECT_FALSE(entry->is_unsafe);
|
||||
EXPECT_TRUE(entry->is_directory);
|
||||
}
|
||||
|
||||
TEST_F(ZipReaderTest, current_entry_info_EncryptedFile) {
|
||||
TEST_F(ZipReaderTest, EncryptedFile_WrongPassword) {
|
||||
ZipReader reader;
|
||||
base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
|
||||
ASSERT_TRUE(reader.Open(data_dir_.AppendASCII("Different Encryptions.zip")));
|
||||
reader.SetPassword("wrong password");
|
||||
|
||||
ASSERT_TRUE(reader.Open(encrypted_zip_file_));
|
||||
ASSERT_TRUE(LocateAndOpenEntry(&reader, target_path));
|
||||
EXPECT_TRUE(reader.current_entry_info()->is_encrypted());
|
||||
reader.Close();
|
||||
{
|
||||
const ZipReader::Entry* entry = reader.Next();
|
||||
ASSERT_TRUE(entry);
|
||||
EXPECT_EQ(base::FilePath::FromASCII("ClearText.txt"), entry->path);
|
||||
EXPECT_FALSE(entry->is_directory);
|
||||
EXPECT_FALSE(entry->is_encrypted);
|
||||
std::string contents = "dummy";
|
||||
EXPECT_TRUE(reader.ExtractCurrentEntryToString(&contents));
|
||||
EXPECT_EQ("This is not encrypted.\n", contents);
|
||||
}
|
||||
|
||||
ASSERT_TRUE(reader.Open(test_zip_file_));
|
||||
ASSERT_TRUE(LocateAndOpenEntry(&reader, target_path));
|
||||
EXPECT_FALSE(reader.current_entry_info()->is_encrypted());
|
||||
for (const base::StringPiece path : {
|
||||
"Encrypted AES-128.txt",
|
||||
"Encrypted AES-192.txt",
|
||||
"Encrypted AES-256.txt",
|
||||
"Encrypted ZipCrypto.txt",
|
||||
}) {
|
||||
const ZipReader::Entry* entry = reader.Next();
|
||||
ASSERT_TRUE(entry);
|
||||
EXPECT_EQ(base::FilePath::FromASCII(path), entry->path);
|
||||
EXPECT_FALSE(entry->is_directory);
|
||||
EXPECT_TRUE(entry->is_encrypted);
|
||||
std::string contents = "dummy";
|
||||
EXPECT_FALSE(reader.ExtractCurrentEntryToString(&contents));
|
||||
}
|
||||
|
||||
EXPECT_FALSE(reader.Next());
|
||||
EXPECT_TRUE(reader.ok());
|
||||
}
|
||||
|
||||
TEST_F(ZipReaderTest, EncryptedFile_RightPassword) {
|
||||
ZipReader reader;
|
||||
ASSERT_TRUE(reader.Open(data_dir_.AppendASCII("Different Encryptions.zip")));
|
||||
reader.SetPassword("password");
|
||||
|
||||
{
|
||||
const ZipReader::Entry* entry = reader.Next();
|
||||
ASSERT_TRUE(entry);
|
||||
EXPECT_EQ(base::FilePath::FromASCII("ClearText.txt"), entry->path);
|
||||
EXPECT_FALSE(entry->is_directory);
|
||||
EXPECT_FALSE(entry->is_encrypted);
|
||||
std::string contents = "dummy";
|
||||
EXPECT_TRUE(reader.ExtractCurrentEntryToString(&contents));
|
||||
EXPECT_EQ("This is not encrypted.\n", contents);
|
||||
}
|
||||
|
||||
// TODO(crbug.com/1296838) Support AES encryption.
|
||||
for (const base::StringPiece path : {
|
||||
"Encrypted AES-128.txt",
|
||||
"Encrypted AES-192.txt",
|
||||
"Encrypted AES-256.txt",
|
||||
}) {
|
||||
const ZipReader::Entry* entry = reader.Next();
|
||||
ASSERT_TRUE(entry);
|
||||
EXPECT_EQ(base::FilePath::FromASCII(path), entry->path);
|
||||
EXPECT_FALSE(entry->is_directory);
|
||||
EXPECT_TRUE(entry->is_encrypted);
|
||||
std::string contents = "dummy";
|
||||
EXPECT_FALSE(reader.ExtractCurrentEntryToString(&contents));
|
||||
EXPECT_EQ("", contents);
|
||||
}
|
||||
|
||||
{
|
||||
const ZipReader::Entry* entry = reader.Next();
|
||||
ASSERT_TRUE(entry);
|
||||
EXPECT_EQ(base::FilePath::FromASCII("Encrypted ZipCrypto.txt"),
|
||||
entry->path);
|
||||
EXPECT_FALSE(entry->is_directory);
|
||||
EXPECT_TRUE(entry->is_encrypted);
|
||||
std::string contents = "dummy";
|
||||
EXPECT_TRUE(reader.ExtractCurrentEntryToString(&contents));
|
||||
EXPECT_EQ("This is encrypted with ZipCrypto.\n", contents);
|
||||
}
|
||||
|
||||
EXPECT_FALSE(reader.Next());
|
||||
EXPECT_TRUE(reader.ok());
|
||||
}
|
||||
|
||||
// Verifies that the ZipReader class can extract a file from a zip archive
|
||||
@ -403,7 +515,7 @@ TEST_F(ZipReaderTest, OpenFromString) {
|
||||
"\x50\x75\x78\x0b\x00\x01\x04\x8e\xf0\x00\x00\x04\x88\x13\x00\x00"
|
||||
"\x50\x4b\x05\x06\x00\x00\x00\x00\x01\x00\x01\x00\x4e\x00\x00\x00"
|
||||
"\x52\x00\x00\x00\x00\x00";
|
||||
std::string data(kTestData, base::size(kTestData));
|
||||
std::string data(kTestData, std::size(kTestData));
|
||||
ZipReader reader;
|
||||
ASSERT_TRUE(reader.OpenFromString(data));
|
||||
base::FilePath target_path(FILE_PATH_LITERAL("test.txt"));
|
||||
@ -412,8 +524,8 @@ TEST_F(ZipReaderTest, OpenFromString) {
|
||||
test_dir_.AppendASCII("test.txt")));
|
||||
|
||||
std::string actual;
|
||||
ASSERT_TRUE(base::ReadFileToString(
|
||||
test_dir_.AppendASCII("test.txt"), &actual));
|
||||
ASSERT_TRUE(
|
||||
base::ReadFileToString(test_dir_.AppendASCII("test.txt"), &actual));
|
||||
EXPECT_EQ(std::string("This is a test.\n"), actual);
|
||||
}
|
||||
|
||||
@ -444,8 +556,8 @@ TEST_F(ZipReaderTest, ExtractToFileAsync_RegularFile) {
|
||||
EXPECT_LE(1, listener.progress_calls());
|
||||
|
||||
std::string output;
|
||||
ASSERT_TRUE(base::ReadFileToString(test_dir_.AppendASCII("quux.txt"),
|
||||
&output));
|
||||
ASSERT_TRUE(
|
||||
base::ReadFileToString(test_dir_.AppendASCII("quux.txt"), &output));
|
||||
const std::string md5 = base::MD5String(output);
|
||||
EXPECT_EQ(kQuuxExpectedMD5, md5);
|
||||
|
||||
@ -455,6 +567,103 @@ TEST_F(ZipReaderTest, ExtractToFileAsync_RegularFile) {
|
||||
EXPECT_EQ(file_size, listener.current_progress());
|
||||
}
|
||||
|
||||
TEST_F(ZipReaderTest, ExtractToFileAsync_Encrypted_NoPassword) {
|
||||
MockUnzipListener listener;
|
||||
|
||||
ZipReader reader;
|
||||
ASSERT_TRUE(reader.Open(data_dir_.AppendASCII("Different Encryptions.zip")));
|
||||
ASSERT_TRUE(LocateAndOpenEntry(
|
||||
&reader, base::FilePath::FromASCII("Encrypted ZipCrypto.txt")));
|
||||
const base::FilePath target_path = test_dir_.AppendASCII("extracted");
|
||||
reader.ExtractCurrentEntryToFilePathAsync(
|
||||
target_path,
|
||||
base::BindOnce(&MockUnzipListener::OnUnzipSuccess, listener.AsWeakPtr()),
|
||||
base::BindOnce(&MockUnzipListener::OnUnzipFailure, listener.AsWeakPtr()),
|
||||
base::BindRepeating(&MockUnzipListener::OnUnzipProgress,
|
||||
listener.AsWeakPtr()));
|
||||
|
||||
EXPECT_EQ(0, listener.success_calls());
|
||||
EXPECT_EQ(0, listener.failure_calls());
|
||||
EXPECT_EQ(0, listener.progress_calls());
|
||||
|
||||
base::RunLoop().RunUntilIdle();
|
||||
|
||||
EXPECT_EQ(0, listener.success_calls());
|
||||
EXPECT_EQ(1, listener.failure_calls());
|
||||
EXPECT_LE(1, listener.progress_calls());
|
||||
|
||||
// The extracted file contains rubbish data.
|
||||
// We probably shouldn't even look at it.
|
||||
std::string contents;
|
||||
ASSERT_TRUE(base::ReadFileToString(target_path, &contents));
|
||||
EXPECT_NE("", contents);
|
||||
EXPECT_EQ(contents.size(), listener.current_progress());
|
||||
}
|
||||
|
||||
TEST_F(ZipReaderTest, ExtractToFileAsync_Encrypted_RightPassword) {
|
||||
MockUnzipListener listener;
|
||||
|
||||
ZipReader reader;
|
||||
reader.SetPassword("password");
|
||||
ASSERT_TRUE(reader.Open(data_dir_.AppendASCII("Different Encryptions.zip")));
|
||||
ASSERT_TRUE(LocateAndOpenEntry(
|
||||
&reader, base::FilePath::FromASCII("Encrypted ZipCrypto.txt")));
|
||||
const base::FilePath target_path = test_dir_.AppendASCII("extracted");
|
||||
reader.ExtractCurrentEntryToFilePathAsync(
|
||||
target_path,
|
||||
base::BindOnce(&MockUnzipListener::OnUnzipSuccess, listener.AsWeakPtr()),
|
||||
base::BindOnce(&MockUnzipListener::OnUnzipFailure, listener.AsWeakPtr()),
|
||||
base::BindRepeating(&MockUnzipListener::OnUnzipProgress,
|
||||
listener.AsWeakPtr()));
|
||||
|
||||
EXPECT_EQ(0, listener.success_calls());
|
||||
EXPECT_EQ(0, listener.failure_calls());
|
||||
EXPECT_EQ(0, listener.progress_calls());
|
||||
|
||||
base::RunLoop().RunUntilIdle();
|
||||
|
||||
EXPECT_EQ(1, listener.success_calls());
|
||||
EXPECT_EQ(0, listener.failure_calls());
|
||||
EXPECT_LE(1, listener.progress_calls());
|
||||
|
||||
std::string contents;
|
||||
ASSERT_TRUE(base::ReadFileToString(target_path, &contents));
|
||||
EXPECT_EQ("This is encrypted with ZipCrypto.\n", contents);
|
||||
EXPECT_EQ(contents.size(), listener.current_progress());
|
||||
}
|
||||
|
||||
TEST_F(ZipReaderTest, ExtractToFileAsync_WrongCrc) {
|
||||
MockUnzipListener listener;
|
||||
|
||||
ZipReader reader;
|
||||
ASSERT_TRUE(reader.Open(data_dir_.AppendASCII("Wrong CRC.zip")));
|
||||
ASSERT_TRUE(
|
||||
LocateAndOpenEntry(&reader, base::FilePath::FromASCII("Corrupted.txt")));
|
||||
const base::FilePath target_path = test_dir_.AppendASCII("extracted");
|
||||
reader.ExtractCurrentEntryToFilePathAsync(
|
||||
target_path,
|
||||
base::BindOnce(&MockUnzipListener::OnUnzipSuccess, listener.AsWeakPtr()),
|
||||
base::BindOnce(&MockUnzipListener::OnUnzipFailure, listener.AsWeakPtr()),
|
||||
base::BindRepeating(&MockUnzipListener::OnUnzipProgress,
|
||||
listener.AsWeakPtr()));
|
||||
|
||||
EXPECT_EQ(0, listener.success_calls());
|
||||
EXPECT_EQ(0, listener.failure_calls());
|
||||
EXPECT_EQ(0, listener.progress_calls());
|
||||
|
||||
base::RunLoop().RunUntilIdle();
|
||||
|
||||
EXPECT_EQ(0, listener.success_calls());
|
||||
EXPECT_EQ(1, listener.failure_calls());
|
||||
EXPECT_LE(1, listener.progress_calls());
|
||||
|
||||
std::string contents;
|
||||
ASSERT_TRUE(base::ReadFileToString(target_path, &contents));
|
||||
EXPECT_EQ("This file has been changed after its CRC was computed.\n",
|
||||
contents);
|
||||
EXPECT_EQ(contents.size(), listener.current_progress());
|
||||
}
|
||||
|
||||
// Verifies that the asynchronous extraction to a file works.
|
||||
TEST_F(ZipReaderTest, ExtractToFileAsync_Directory) {
|
||||
MockUnzipListener listener;
|
||||
@ -489,7 +698,7 @@ TEST_F(ZipReaderTest, ExtractCurrentEntryToString) {
|
||||
// sizes from 0 to 7 bytes respectively, being the contents of each file a
|
||||
// substring of "0123456" starting at '0'.
|
||||
base::FilePath test_zip_file =
|
||||
test_data_dir_.AppendASCII("test_mismatch_size.zip");
|
||||
data_dir_.AppendASCII("test_mismatch_size.zip");
|
||||
|
||||
ZipReader reader;
|
||||
std::string contents;
|
||||
@ -510,12 +719,12 @@ TEST_F(ZipReaderTest, ExtractCurrentEntryToString) {
|
||||
if (i > 0) {
|
||||
// Exact byte read limit: must pass.
|
||||
EXPECT_TRUE(reader.ExtractCurrentEntryToString(i, &contents));
|
||||
EXPECT_EQ(base::StringPiece("0123456", i).as_string(), contents);
|
||||
EXPECT_EQ(std::string(base::StringPiece("0123456", i)), contents);
|
||||
}
|
||||
|
||||
// More than necessary byte read limit: must pass.
|
||||
EXPECT_TRUE(reader.ExtractCurrentEntryToString(16, &contents));
|
||||
EXPECT_EQ(base::StringPiece("0123456", i).as_string(), contents);
|
||||
EXPECT_TRUE(reader.ExtractCurrentEntryToString(&contents));
|
||||
EXPECT_EQ(std::string(base::StringPiece("0123456", i)), contents);
|
||||
}
|
||||
reader.Close();
|
||||
}
|
||||
@ -525,7 +734,7 @@ TEST_F(ZipReaderTest, ExtractPartOfCurrentEntry) {
|
||||
// sizes from 0 to 7 bytes respectively, being the contents of each file a
|
||||
// substring of "0123456" starting at '0'.
|
||||
base::FilePath test_zip_file =
|
||||
test_data_dir_.AppendASCII("test_mismatch_size.zip");
|
||||
data_dir_.AppendASCII("test_mismatch_size.zip");
|
||||
|
||||
ZipReader reader;
|
||||
std::string contents;
|
||||
@ -563,6 +772,37 @@ TEST_F(ZipReaderTest, ExtractPartOfCurrentEntry) {
|
||||
reader.Close();
|
||||
}
|
||||
|
||||
TEST_F(ZipReaderTest, ExtractPosixPermissions) {
|
||||
base::ScopedTempDir temp_dir;
|
||||
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
|
||||
|
||||
ZipReader reader;
|
||||
ASSERT_TRUE(reader.Open(data_dir_.AppendASCII("test_posix_permissions.zip")));
|
||||
for (auto entry : {"0.txt", "1.txt", "2.txt", "3.txt"}) {
|
||||
ASSERT_TRUE(LocateAndOpenEntry(&reader, base::FilePath::FromASCII(entry)));
|
||||
FilePathWriterDelegate delegate(temp_dir.GetPath().AppendASCII(entry));
|
||||
ASSERT_TRUE(reader.ExtractCurrentEntry(&delegate));
|
||||
}
|
||||
reader.Close();
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
// This assumes a umask of at least 0400.
|
||||
int mode = 0;
|
||||
EXPECT_TRUE(base::GetPosixFilePermissions(
|
||||
temp_dir.GetPath().AppendASCII("0.txt"), &mode));
|
||||
EXPECT_EQ(mode & 0700, 0700);
|
||||
EXPECT_TRUE(base::GetPosixFilePermissions(
|
||||
temp_dir.GetPath().AppendASCII("1.txt"), &mode));
|
||||
EXPECT_EQ(mode & 0700, 0600);
|
||||
EXPECT_TRUE(base::GetPosixFilePermissions(
|
||||
temp_dir.GetPath().AppendASCII("2.txt"), &mode));
|
||||
EXPECT_EQ(mode & 0700, 0700);
|
||||
EXPECT_TRUE(base::GetPosixFilePermissions(
|
||||
temp_dir.GetPath().AppendASCII("3.txt"), &mode));
|
||||
EXPECT_EQ(mode & 0700, 0600);
|
||||
#endif
|
||||
}
|
||||
|
||||
// This test exposes http://crbug.com/430959, at least on OS X
|
||||
TEST_F(ZipReaderTest, DISABLED_LeakDetectionTest) {
|
||||
for (int i = 0; i < 100000; ++i) {
|
||||
@ -577,45 +817,40 @@ TEST_F(ZipReaderTest, DISABLED_LeakDetectionTest) {
|
||||
TEST_F(ZipReaderTest, ExtractCurrentEntryPrepareFailure) {
|
||||
testing::StrictMock<MockWriterDelegate> mock_writer;
|
||||
|
||||
EXPECT_CALL(mock_writer, PrepareOutput())
|
||||
.WillOnce(Return(false));
|
||||
EXPECT_CALL(mock_writer, PrepareOutput()).WillOnce(Return(false));
|
||||
|
||||
base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
|
||||
ZipReader reader;
|
||||
|
||||
ASSERT_TRUE(reader.Open(test_zip_file_));
|
||||
ASSERT_TRUE(LocateAndOpenEntry(&reader, target_path));
|
||||
ASSERT_FALSE(reader.ExtractCurrentEntry(
|
||||
&mock_writer, std::numeric_limits<uint64_t>::max()));
|
||||
ASSERT_FALSE(reader.ExtractCurrentEntry(&mock_writer));
|
||||
}
|
||||
|
||||
// Test that when WriterDelegate::WriteBytes returns false, no other methods on
|
||||
// the delegate are called and the extraction fails.
|
||||
// Test that when WriterDelegate::WriteBytes returns false, only the OnError
|
||||
// method on the delegate is called and the extraction fails.
|
||||
TEST_F(ZipReaderTest, ExtractCurrentEntryWriteBytesFailure) {
|
||||
testing::StrictMock<MockWriterDelegate> mock_writer;
|
||||
|
||||
EXPECT_CALL(mock_writer, PrepareOutput())
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_writer, WriteBytes(_, _))
|
||||
.WillOnce(Return(false));
|
||||
EXPECT_CALL(mock_writer, PrepareOutput()).WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_writer, WriteBytes(_, _)).WillOnce(Return(false));
|
||||
EXPECT_CALL(mock_writer, OnError());
|
||||
|
||||
base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
|
||||
ZipReader reader;
|
||||
|
||||
ASSERT_TRUE(reader.Open(test_zip_file_));
|
||||
ASSERT_TRUE(LocateAndOpenEntry(&reader, target_path));
|
||||
ASSERT_FALSE(reader.ExtractCurrentEntry(
|
||||
&mock_writer, std::numeric_limits<uint64_t>::max()));
|
||||
ASSERT_FALSE(reader.ExtractCurrentEntry(&mock_writer));
|
||||
}
|
||||
|
||||
// Test that extraction succeeds when the writer delegate reports all is well.
|
||||
TEST_F(ZipReaderTest, ExtractCurrentEntrySuccess) {
|
||||
testing::StrictMock<MockWriterDelegate> mock_writer;
|
||||
|
||||
EXPECT_CALL(mock_writer, PrepareOutput())
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_writer, WriteBytes(_, _))
|
||||
.WillRepeatedly(Return(true));
|
||||
EXPECT_CALL(mock_writer, PrepareOutput()).WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_writer, WriteBytes(_, _)).WillRepeatedly(Return(true));
|
||||
EXPECT_CALL(mock_writer, SetPosixFilePermissions(_));
|
||||
EXPECT_CALL(mock_writer, SetTimeModified(_));
|
||||
|
||||
base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
|
||||
@ -623,50 +858,84 @@ TEST_F(ZipReaderTest, ExtractCurrentEntrySuccess) {
|
||||
|
||||
ASSERT_TRUE(reader.Open(test_zip_file_));
|
||||
ASSERT_TRUE(LocateAndOpenEntry(&reader, target_path));
|
||||
ASSERT_TRUE(reader.ExtractCurrentEntry(&mock_writer,
|
||||
std::numeric_limits<uint64_t>::max()));
|
||||
ASSERT_TRUE(reader.ExtractCurrentEntry(&mock_writer));
|
||||
}
|
||||
|
||||
TEST_F(ZipReaderTest, WrongCrc) {
|
||||
ZipReader reader;
|
||||
ASSERT_TRUE(reader.Open(data_dir_.AppendASCII("Wrong CRC.zip")));
|
||||
|
||||
const ZipReader::Entry* const entry =
|
||||
LocateAndOpenEntry(&reader, base::FilePath::FromASCII("Corrupted.txt"));
|
||||
ASSERT_TRUE(entry);
|
||||
|
||||
std::string contents = "dummy";
|
||||
EXPECT_FALSE(reader.ExtractCurrentEntryToString(&contents));
|
||||
EXPECT_EQ("This file has been changed after its CRC was computed.\n",
|
||||
contents);
|
||||
|
||||
contents = "dummy";
|
||||
EXPECT_FALSE(
|
||||
reader.ExtractCurrentEntryToString(entry->original_size + 1, &contents));
|
||||
EXPECT_EQ("This file has been changed after its CRC was computed.\n",
|
||||
contents);
|
||||
|
||||
contents = "dummy";
|
||||
EXPECT_FALSE(
|
||||
reader.ExtractCurrentEntryToString(entry->original_size, &contents));
|
||||
EXPECT_EQ("This file has been changed after its CRC was computed.\n",
|
||||
contents);
|
||||
|
||||
contents = "dummy";
|
||||
EXPECT_FALSE(
|
||||
reader.ExtractCurrentEntryToString(entry->original_size - 1, &contents));
|
||||
EXPECT_EQ("This file has been changed after its CRC was computed.", contents);
|
||||
}
|
||||
|
||||
class FileWriterDelegateTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
ASSERT_TRUE(base::CreateTemporaryFile(&temp_file_path_));
|
||||
file_.Initialize(temp_file_path_, (base::File::FLAG_CREATE_ALWAYS |
|
||||
base::File::FLAG_READ |
|
||||
base::File::FLAG_WRITE |
|
||||
base::File::FLAG_TEMPORARY |
|
||||
base::File::FLAG_DELETE_ON_CLOSE));
|
||||
file_.Initialize(temp_file_path_,
|
||||
(base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_READ |
|
||||
base::File::FLAG_WRITE | base::File::FLAG_WIN_TEMPORARY |
|
||||
base::File::FLAG_DELETE_ON_CLOSE));
|
||||
ASSERT_TRUE(file_.IsValid());
|
||||
}
|
||||
|
||||
// Writes data to the file, leaving the current position at the end of the
|
||||
// write.
|
||||
void PopulateFile() {
|
||||
static const char kSomeData[] = "this sure is some data.";
|
||||
static const size_t kSomeDataLen = sizeof(kSomeData) - 1;
|
||||
ASSERT_NE(-1LL, file_.Write(0LL, kSomeData, kSomeDataLen));
|
||||
}
|
||||
|
||||
base::FilePath temp_file_path_;
|
||||
base::File file_;
|
||||
};
|
||||
|
||||
TEST_F(FileWriterDelegateTest, WriteToStartAndTruncate) {
|
||||
// Write stuff and advance.
|
||||
PopulateFile();
|
||||
TEST_F(FileWriterDelegateTest, WriteToEnd) {
|
||||
const std::string payload = "This is the actualy payload data.\n";
|
||||
|
||||
// This should rewind, write, then truncate.
|
||||
static const char kSomeData[] = "short";
|
||||
static const int kSomeDataLen = sizeof(kSomeData) - 1;
|
||||
{
|
||||
FileWriterDelegate writer(&file_);
|
||||
EXPECT_EQ(0, writer.file_length());
|
||||
ASSERT_TRUE(writer.PrepareOutput());
|
||||
ASSERT_TRUE(writer.WriteBytes(kSomeData, kSomeDataLen));
|
||||
ASSERT_TRUE(writer.WriteBytes(payload.data(), payload.size()));
|
||||
EXPECT_EQ(payload.size(), writer.file_length());
|
||||
}
|
||||
ASSERT_EQ(kSomeDataLen, file_.GetLength());
|
||||
char buf[kSomeDataLen] = {};
|
||||
ASSERT_EQ(kSomeDataLen, file_.Read(0LL, buf, kSomeDataLen));
|
||||
ASSERT_EQ(std::string(kSomeData), std::string(buf, kSomeDataLen));
|
||||
|
||||
EXPECT_EQ(payload.size(), file_.GetLength());
|
||||
}
|
||||
|
||||
TEST_F(FileWriterDelegateTest, EmptyOnError) {
|
||||
const std::string payload = "This is the actualy payload data.\n";
|
||||
|
||||
{
|
||||
FileWriterDelegate writer(&file_);
|
||||
EXPECT_EQ(0, writer.file_length());
|
||||
ASSERT_TRUE(writer.PrepareOutput());
|
||||
ASSERT_TRUE(writer.WriteBytes(payload.data(), payload.size()));
|
||||
EXPECT_EQ(payload.size(), writer.file_length());
|
||||
EXPECT_EQ(payload.size(), file_.GetLength());
|
||||
writer.OnError();
|
||||
EXPECT_EQ(0, writer.file_length());
|
||||
}
|
||||
|
||||
EXPECT_EQ(0, file_.GetLength());
|
||||
}
|
||||
|
||||
} // namespace zip
|
||||
|
1291
deps/zlib/google/zip_unittest.cc
vendored
1291
deps/zlib/google/zip_unittest.cc
vendored
File diff suppressed because it is too large
Load Diff
341
deps/zlib/google/zip_writer.cc
vendored
341
deps/zlib/google/zip_writer.cc
vendored
@ -1,203 +1,308 @@
|
||||
// Copyright 2017 The Chromium Authors. All rights reserved.
|
||||
// Copyright 2017 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "third_party/zlib/google/zip_writer.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "base/files/file.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/strcat.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "third_party/zlib/google/redact.h"
|
||||
#include "third_party/zlib/google/zip_internal.h"
|
||||
|
||||
namespace zip {
|
||||
namespace internal {
|
||||
|
||||
namespace {
|
||||
bool ZipWriter::ShouldContinue() {
|
||||
if (!progress_callback_)
|
||||
return true;
|
||||
|
||||
// Numbers of pending entries that trigger writting them to the ZIP file.
|
||||
constexpr size_t kMaxPendingEntriesCount = 50;
|
||||
const base::TimeTicks now = base::TimeTicks::Now();
|
||||
if (next_progress_report_time_ > now)
|
||||
return true;
|
||||
|
||||
bool AddFileContentToZip(zipFile zip_file,
|
||||
base::File file,
|
||||
const base::FilePath& file_path) {
|
||||
int num_bytes;
|
||||
char buf[zip::internal::kZipBufSize];
|
||||
do {
|
||||
num_bytes = file.ReadAtCurrentPos(buf, zip::internal::kZipBufSize);
|
||||
next_progress_report_time_ = now + progress_period_;
|
||||
if (progress_callback_.Run(progress_))
|
||||
return true;
|
||||
|
||||
if (num_bytes > 0) {
|
||||
if (zipWriteInFileInZip(zip_file, buf, num_bytes) != ZIP_OK) {
|
||||
DLOG(ERROR) << "Could not write data to zip for path "
|
||||
<< file_path.value();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} while (num_bytes > 0);
|
||||
|
||||
return true;
|
||||
LOG(ERROR) << "Cancelling ZIP creation";
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OpenNewFileEntry(zipFile zip_file,
|
||||
const base::FilePath& path,
|
||||
bool is_directory,
|
||||
base::Time last_modified) {
|
||||
bool ZipWriter::AddFileContent(const base::FilePath& path, base::File file) {
|
||||
char buf[zip::internal::kZipBufSize];
|
||||
|
||||
while (ShouldContinue()) {
|
||||
const int num_bytes =
|
||||
file.ReadAtCurrentPos(buf, zip::internal::kZipBufSize);
|
||||
|
||||
if (num_bytes < 0) {
|
||||
PLOG(ERROR) << "Cannot read file " << Redact(path);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (num_bytes == 0)
|
||||
return true;
|
||||
|
||||
if (zipWriteInFileInZip(zip_file_, buf, num_bytes) != ZIP_OK) {
|
||||
PLOG(ERROR) << "Cannot write data from file " << Redact(path)
|
||||
<< " to ZIP";
|
||||
return false;
|
||||
}
|
||||
|
||||
progress_.bytes += num_bytes;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ZipWriter::OpenNewFileEntry(const base::FilePath& path,
|
||||
bool is_directory,
|
||||
base::Time last_modified) {
|
||||
std::string str_path = path.AsUTF8Unsafe();
|
||||
|
||||
#if defined(OS_WIN)
|
||||
base::ReplaceSubstringsAfterOffset(&str_path, 0u, "\\", "/");
|
||||
#endif
|
||||
if (is_directory)
|
||||
|
||||
Compression compression = kDeflated;
|
||||
|
||||
if (is_directory) {
|
||||
str_path += "/";
|
||||
} else {
|
||||
compression = GetCompressionMethod(path);
|
||||
}
|
||||
|
||||
return zip::internal::ZipOpenNewFileInZip(zip_file, str_path, last_modified);
|
||||
return zip::internal::ZipOpenNewFileInZip(zip_file_, str_path, last_modified,
|
||||
compression);
|
||||
}
|
||||
|
||||
bool CloseNewFileEntry(zipFile zip_file) {
|
||||
return zipCloseFileInZip(zip_file) == ZIP_OK;
|
||||
bool ZipWriter::CloseNewFileEntry() {
|
||||
return zipCloseFileInZip(zip_file_) == ZIP_OK;
|
||||
}
|
||||
|
||||
bool AddFileEntryToZip(zipFile zip_file,
|
||||
const base::FilePath& path,
|
||||
base::File file) {
|
||||
base::File::Info file_info;
|
||||
if (!file.GetInfo(&file_info))
|
||||
bool ZipWriter::AddFileEntry(const base::FilePath& path, base::File file) {
|
||||
base::File::Info info;
|
||||
if (!file.GetInfo(&info))
|
||||
return false;
|
||||
|
||||
if (!OpenNewFileEntry(zip_file, path, /*is_directory=*/false,
|
||||
file_info.last_modified))
|
||||
if (!OpenNewFileEntry(path, /*is_directory=*/false, info.last_modified))
|
||||
return false;
|
||||
|
||||
bool success = AddFileContentToZip(zip_file, std::move(file), path);
|
||||
if (!CloseNewFileEntry(zip_file))
|
||||
if (!AddFileContent(path, std::move(file)))
|
||||
return false;
|
||||
|
||||
return success;
|
||||
progress_.files++;
|
||||
return CloseNewFileEntry();
|
||||
}
|
||||
|
||||
bool AddDirectoryEntryToZip(zipFile zip_file,
|
||||
const base::FilePath& path,
|
||||
base::Time last_modified) {
|
||||
return OpenNewFileEntry(zip_file, path, /*is_directory=*/true,
|
||||
last_modified) &&
|
||||
CloseNewFileEntry(zip_file);
|
||||
bool ZipWriter::AddDirectoryEntry(const base::FilePath& path) {
|
||||
FileAccessor::Info info;
|
||||
if (!file_accessor_->GetInfo(path, &info) || !info.is_directory) {
|
||||
LOG(ERROR) << "Not a directory: " << Redact(path);
|
||||
progress_.errors++;
|
||||
return continue_on_error_;
|
||||
}
|
||||
|
||||
if (!OpenNewFileEntry(path, /*is_directory=*/true, info.last_modified))
|
||||
return false;
|
||||
|
||||
if (!CloseNewFileEntry())
|
||||
return false;
|
||||
|
||||
progress_.directories++;
|
||||
if (!ShouldContinue())
|
||||
return false;
|
||||
|
||||
if (!recursive_)
|
||||
return true;
|
||||
|
||||
return AddDirectoryContents(path);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
#if defined(OS_POSIX) || defined(OS_FUCHSIA)
|
||||
// static
|
||||
std::unique_ptr<ZipWriter> ZipWriter::CreateWithFd(
|
||||
int zip_file_fd,
|
||||
const base::FilePath& root_dir,
|
||||
FileAccessor* file_accessor) {
|
||||
DCHECK(zip_file_fd != base::kInvalidPlatformFile);
|
||||
zipFile zip_file =
|
||||
internal::OpenFdForZipping(zip_file_fd, APPEND_STATUS_CREATE);
|
||||
|
||||
if (!zip_file) {
|
||||
DLOG(ERROR) << "Couldn't create ZIP file for FD " << zip_file_fd;
|
||||
DLOG(ERROR) << "Cannot create ZIP file for FD " << zip_file_fd;
|
||||
return nullptr;
|
||||
}
|
||||
return std::unique_ptr<ZipWriter>(
|
||||
new ZipWriter(zip_file, root_dir, file_accessor));
|
||||
|
||||
return std::unique_ptr<ZipWriter>(new ZipWriter(zip_file, file_accessor));
|
||||
}
|
||||
#endif
|
||||
|
||||
// static
|
||||
std::unique_ptr<ZipWriter> ZipWriter::Create(
|
||||
const base::FilePath& zip_file_path,
|
||||
const base::FilePath& root_dir,
|
||||
FileAccessor* file_accessor) {
|
||||
DCHECK(!zip_file_path.empty());
|
||||
zipFile zip_file = internal::OpenForZipping(zip_file_path.AsUTF8Unsafe(),
|
||||
APPEND_STATUS_CREATE);
|
||||
|
||||
if (!zip_file) {
|
||||
DLOG(ERROR) << "Couldn't create ZIP file at path " << zip_file_path;
|
||||
PLOG(ERROR) << "Cannot create ZIP file " << Redact(zip_file_path);
|
||||
return nullptr;
|
||||
}
|
||||
return std::unique_ptr<ZipWriter>(
|
||||
new ZipWriter(zip_file, root_dir, file_accessor));
|
||||
|
||||
return std::unique_ptr<ZipWriter>(new ZipWriter(zip_file, file_accessor));
|
||||
}
|
||||
|
||||
ZipWriter::ZipWriter(zipFile zip_file,
|
||||
const base::FilePath& root_dir,
|
||||
FileAccessor* file_accessor)
|
||||
: zip_file_(zip_file), root_dir_(root_dir), file_accessor_(file_accessor) {}
|
||||
ZipWriter::ZipWriter(zipFile zip_file, FileAccessor* file_accessor)
|
||||
: zip_file_(zip_file), file_accessor_(file_accessor) {}
|
||||
|
||||
ZipWriter::~ZipWriter() {
|
||||
DCHECK(pending_entries_.empty());
|
||||
}
|
||||
|
||||
bool ZipWriter::WriteEntries(const std::vector<base::FilePath>& paths) {
|
||||
return AddEntries(paths) && Close();
|
||||
}
|
||||
|
||||
bool ZipWriter::AddEntries(const std::vector<base::FilePath>& paths) {
|
||||
DCHECK(zip_file_);
|
||||
pending_entries_.insert(pending_entries_.end(), paths.begin(), paths.end());
|
||||
return FlushEntriesIfNeeded(/*force=*/false);
|
||||
if (zip_file_)
|
||||
zipClose(zip_file_, nullptr);
|
||||
}
|
||||
|
||||
bool ZipWriter::Close() {
|
||||
bool success = FlushEntriesIfNeeded(/*force=*/true) &&
|
||||
zipClose(zip_file_, nullptr) == ZIP_OK;
|
||||
const bool success = zipClose(zip_file_, nullptr) == ZIP_OK;
|
||||
zip_file_ = nullptr;
|
||||
|
||||
// Call the progress callback one last time with the final progress status.
|
||||
if (progress_callback_ && !progress_callback_.Run(progress_)) {
|
||||
LOG(ERROR) << "Cancelling ZIP creation at the end";
|
||||
return false;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool ZipWriter::FlushEntriesIfNeeded(bool force) {
|
||||
if (pending_entries_.size() < kMaxPendingEntriesCount && !force)
|
||||
return true;
|
||||
bool ZipWriter::AddMixedEntries(Paths paths) {
|
||||
// Pointers to directory paths in |paths|.
|
||||
std::vector<const base::FilePath*> directories;
|
||||
|
||||
while (pending_entries_.size() >= kMaxPendingEntriesCount ||
|
||||
(force && !pending_entries_.empty())) {
|
||||
size_t entry_count =
|
||||
std::min(pending_entries_.size(), kMaxPendingEntriesCount);
|
||||
std::vector<base::FilePath> relative_paths;
|
||||
std::vector<base::FilePath> absolute_paths;
|
||||
relative_paths.insert(relative_paths.begin(), pending_entries_.begin(),
|
||||
pending_entries_.begin() + entry_count);
|
||||
for (auto iter = pending_entries_.begin();
|
||||
iter != pending_entries_.begin() + entry_count; ++iter) {
|
||||
// The FileAccessor requires absolute paths.
|
||||
absolute_paths.push_back(root_dir_.Append(*iter));
|
||||
}
|
||||
pending_entries_.erase(pending_entries_.begin(),
|
||||
pending_entries_.begin() + entry_count);
|
||||
// Declared outside loop to reuse internal buffer.
|
||||
std::vector<base::File> files;
|
||||
|
||||
// We don't know which paths are files and which ones are directories, and
|
||||
// we want to avoid making a call to file_accessor_ for each entry. Open the
|
||||
// files instead, invalid files are returned for directories.
|
||||
std::vector<base::File> files =
|
||||
file_accessor_->OpenFilesForReading(absolute_paths);
|
||||
DCHECK_EQ(files.size(), relative_paths.size());
|
||||
for (size_t i = 0; i < files.size(); i++) {
|
||||
// First pass. We don't know which paths are files and which ones are
|
||||
// directories, and we want to avoid making a call to file_accessor_ for each
|
||||
// path. Try to open all of the paths as files. We'll get invalid file
|
||||
// descriptors for directories, and we'll process these directories in the
|
||||
// second pass.
|
||||
while (!paths.empty()) {
|
||||
// Work with chunks of 50 paths at most.
|
||||
const size_t n = std::min<size_t>(paths.size(), 50);
|
||||
const Paths relative_paths = paths.subspan(0, n);
|
||||
paths = paths.subspan(n, paths.size() - n);
|
||||
|
||||
files.clear();
|
||||
if (!file_accessor_->Open(relative_paths, &files) || files.size() != n)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
const base::FilePath& relative_path = relative_paths[i];
|
||||
const base::FilePath& absolute_path = absolute_paths[i];
|
||||
base::File file = std::move(files[i]);
|
||||
DCHECK(!relative_path.empty());
|
||||
base::File& file = files[i];
|
||||
|
||||
if (file.IsValid()) {
|
||||
if (!AddFileEntryToZip(zip_file_, relative_path, std::move(file))) {
|
||||
LOG(ERROR) << "Failed to write file " << relative_path.value()
|
||||
<< " to ZIP file.";
|
||||
// It's a file.
|
||||
if (!AddFileEntry(relative_path, std::move(file)))
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Missing file or directory case.
|
||||
base::Time last_modified =
|
||||
file_accessor_->GetLastModifiedTime(absolute_path);
|
||||
if (last_modified.is_null()) {
|
||||
LOG(ERROR) << "Failed to write entry " << relative_path.value()
|
||||
<< " to ZIP file.";
|
||||
return false;
|
||||
}
|
||||
DCHECK(file_accessor_->DirectoryExists(absolute_path));
|
||||
if (!AddDirectoryEntryToZip(zip_file_, relative_path, last_modified)) {
|
||||
LOG(ERROR) << "Failed to write directory " << relative_path.value()
|
||||
<< " to ZIP file.";
|
||||
return false;
|
||||
}
|
||||
// It's probably a directory. Remember its path for the second pass.
|
||||
directories.push_back(&relative_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Second pass for directories discovered during the first pass.
|
||||
for (const base::FilePath* const path : directories) {
|
||||
DCHECK(path);
|
||||
if (!AddDirectoryEntry(*path))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZipWriter::AddFileEntries(Paths paths) {
|
||||
// Declared outside loop to reuse internal buffer.
|
||||
std::vector<base::File> files;
|
||||
|
||||
while (!paths.empty()) {
|
||||
// Work with chunks of 50 paths at most.
|
||||
const size_t n = std::min<size_t>(paths.size(), 50);
|
||||
const Paths relative_paths = paths.subspan(0, n);
|
||||
paths = paths.subspan(n, paths.size() - n);
|
||||
|
||||
DCHECK_EQ(relative_paths.size(), n);
|
||||
|
||||
files.clear();
|
||||
if (!file_accessor_->Open(relative_paths, &files) || files.size() != n)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
const base::FilePath& relative_path = relative_paths[i];
|
||||
DCHECK(!relative_path.empty());
|
||||
base::File& file = files[i];
|
||||
|
||||
if (!file.IsValid()) {
|
||||
LOG(ERROR) << "Cannot open " << Redact(relative_path);
|
||||
progress_.errors++;
|
||||
|
||||
if (continue_on_error_)
|
||||
continue;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!AddFileEntry(relative_path, std::move(file)))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZipWriter::AddDirectoryEntries(Paths paths) {
|
||||
for (const base::FilePath& path : paths) {
|
||||
if (!AddDirectoryEntry(path))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZipWriter::AddDirectoryContents(const base::FilePath& path) {
|
||||
std::vector<base::FilePath> files, subdirs;
|
||||
|
||||
if (!file_accessor_->List(path, &files, &subdirs)) {
|
||||
progress_.errors++;
|
||||
return continue_on_error_;
|
||||
}
|
||||
|
||||
Filter(&files);
|
||||
Filter(&subdirs);
|
||||
|
||||
if (!AddFileEntries(files))
|
||||
return false;
|
||||
|
||||
return AddDirectoryEntries(subdirs);
|
||||
}
|
||||
|
||||
void ZipWriter::Filter(std::vector<base::FilePath>* const paths) {
|
||||
DCHECK(paths);
|
||||
|
||||
if (!filter_callback_)
|
||||
return;
|
||||
|
||||
const auto end = std::remove_if(paths->begin(), paths->end(),
|
||||
[this](const base::FilePath& path) {
|
||||
return !filter_callback_.Run(path);
|
||||
});
|
||||
paths->erase(end, paths->end());
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace zip
|
||||
|
131
deps/zlib/google/zip_writer.h
vendored
131
deps/zlib/google/zip_writer.h
vendored
@ -1,4 +1,4 @@
|
||||
// Copyright 2017 The Chromium Authors. All rights reserved.
|
||||
// Copyright 2017 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/time/time.h"
|
||||
#include "build/build_config.h"
|
||||
#include "third_party/zlib/google/zip.h"
|
||||
|
||||
@ -28,64 +29,126 @@ namespace internal {
|
||||
// performance reasons as these calls may be expensive when IPC based).
|
||||
// This class is so far internal and only used by zip.cc, but could be made
|
||||
// public if needed.
|
||||
//
|
||||
// All methods returning a bool return true on success and false on error.
|
||||
class ZipWriter {
|
||||
public:
|
||||
// Creates a writer that will write a ZIP file to |zip_file_fd|/|zip_file|
|
||||
// and which entries (specifies with AddEntries) are relative to |root_dir|.
|
||||
// Creates a writer that will write a ZIP file to |zip_file_fd| or |zip_file|
|
||||
// and which entries are relative to |file_accessor|'s source directory.
|
||||
// All file reads are performed using |file_accessor|.
|
||||
#if defined(OS_POSIX)
|
||||
#if defined(OS_POSIX) || defined(OS_FUCHSIA)
|
||||
static std::unique_ptr<ZipWriter> CreateWithFd(int zip_file_fd,
|
||||
const base::FilePath& root_dir,
|
||||
FileAccessor* file_accessor);
|
||||
#endif
|
||||
|
||||
static std::unique_ptr<ZipWriter> Create(const base::FilePath& zip_file,
|
||||
const base::FilePath& root_dir,
|
||||
FileAccessor* file_accessor);
|
||||
|
||||
ZipWriter(const ZipWriter&) = delete;
|
||||
ZipWriter& operator=(const ZipWriter&) = delete;
|
||||
|
||||
~ZipWriter();
|
||||
|
||||
// Writes the files at |paths| to the ZIP file and closes this Zip file.
|
||||
// Note that the the FilePaths must be relative to |root_dir| specified in the
|
||||
// Create method.
|
||||
// Returns true if all entries were written successfuly.
|
||||
bool WriteEntries(const std::vector<base::FilePath>& paths);
|
||||
// Sets the optional progress callback. The callback is called once for each
|
||||
// time |period|. The final callback is always called when the ZIP operation
|
||||
// completes.
|
||||
void SetProgressCallback(ProgressCallback callback, base::TimeDelta period) {
|
||||
progress_callback_ = std::move(callback);
|
||||
progress_period_ = std::move(period);
|
||||
}
|
||||
|
||||
private:
|
||||
ZipWriter(zipFile zip_file,
|
||||
const base::FilePath& root_dir,
|
||||
FileAccessor* file_accessor);
|
||||
// Should ignore missing files and directories?
|
||||
void ContinueOnError(bool continue_on_error) {
|
||||
continue_on_error_ = continue_on_error;
|
||||
}
|
||||
|
||||
// Writes the pending entries to the ZIP file if there are at least
|
||||
// |kMaxPendingEntriesCount| of them. If |force| is true, all pending entries
|
||||
// are written regardless of how many there are.
|
||||
// Returns false if writing an entry fails, true if no entry was written or
|
||||
// there was no error writing entries.
|
||||
bool FlushEntriesIfNeeded(bool force);
|
||||
// Sets the recursive flag, indicating whether the contents of subdirectories
|
||||
// should be included.
|
||||
void SetRecursive(bool b) { recursive_ = b; }
|
||||
|
||||
// Adds the files at |paths| to the ZIP file. These FilePaths must be relative
|
||||
// to |root_dir| specified in the Create method.
|
||||
bool AddEntries(const std::vector<base::FilePath>& paths);
|
||||
// Sets the filter callback.
|
||||
void SetFilterCallback(FilterCallback callback) {
|
||||
filter_callback_ = std::move(callback);
|
||||
}
|
||||
|
||||
// Adds the contents of a directory. If the recursive flag is set, the
|
||||
// contents of subdirectories are also added.
|
||||
bool AddDirectoryContents(const base::FilePath& path);
|
||||
|
||||
// Adds the entries at |paths| to the ZIP file. These can be a mixed bag of
|
||||
// files and directories. If the recursive flag is set, the contents of
|
||||
// subdirectories is also added.
|
||||
bool AddMixedEntries(Paths paths);
|
||||
|
||||
// Closes the ZIP file.
|
||||
// Returns true if successful, false otherwise (typically if an entry failed
|
||||
// to be written).
|
||||
bool Close();
|
||||
|
||||
// The entries that have been added but not yet written to the ZIP file.
|
||||
std::vector<base::FilePath> pending_entries_;
|
||||
private:
|
||||
// Takes ownership of |zip_file|.
|
||||
ZipWriter(zipFile zip_file, FileAccessor* file_accessor);
|
||||
|
||||
// Regularly called during processing to check whether zipping should continue
|
||||
// or should be cancelled.
|
||||
bool ShouldContinue();
|
||||
|
||||
// Adds file content to currently open file entry.
|
||||
bool AddFileContent(const base::FilePath& path, base::File file);
|
||||
|
||||
// Adds a file entry (including file contents).
|
||||
bool AddFileEntry(const base::FilePath& path, base::File file);
|
||||
|
||||
// Adds file entries. All the paths should be existing files.
|
||||
bool AddFileEntries(Paths paths);
|
||||
|
||||
// Adds a directory entry. If the recursive flag is set, the contents of this
|
||||
// directory are also added.
|
||||
bool AddDirectoryEntry(const base::FilePath& path);
|
||||
|
||||
// Adds directory entries. All the paths should be existing directories. If
|
||||
// the recursive flag is set, the contents of these directories are also
|
||||
// added.
|
||||
bool AddDirectoryEntries(Paths paths);
|
||||
|
||||
// Opens a file or directory entry.
|
||||
bool OpenNewFileEntry(const base::FilePath& path,
|
||||
bool is_directory,
|
||||
base::Time last_modified);
|
||||
|
||||
// Closes the currently open entry.
|
||||
bool CloseNewFileEntry();
|
||||
|
||||
// Filters entries.
|
||||
void Filter(std::vector<base::FilePath>* paths);
|
||||
|
||||
// The actual zip file.
|
||||
zipFile zip_file_;
|
||||
|
||||
// Path to the directory entry paths are relative to.
|
||||
base::FilePath root_dir_;
|
||||
|
||||
// Abstraction over file access methods used to read files.
|
||||
FileAccessor* file_accessor_;
|
||||
FileAccessor* const file_accessor_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ZipWriter);
|
||||
// Progress stats.
|
||||
Progress progress_;
|
||||
|
||||
// Optional progress callback.
|
||||
ProgressCallback progress_callback_;
|
||||
|
||||
// Optional progress reporting period.
|
||||
base::TimeDelta progress_period_;
|
||||
|
||||
// Next time to report progress.
|
||||
base::TimeTicks next_progress_report_time_ = base::TimeTicks::Now();
|
||||
|
||||
// Filter used to exclude files from the ZIP file.
|
||||
FilterCallback filter_callback_;
|
||||
|
||||
// Should recursively add directories?
|
||||
bool recursive_ = false;
|
||||
|
||||
// Should ignore missing files and directories?
|
||||
bool continue_on_error_ = false;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace zip
|
||||
|
||||
#endif // THIRD_PARTY_ZLIB_GOOGLE_ZIP_WRITER_H_
|
||||
#endif // THIRD_PARTY_ZLIB_GOOGLE_ZIP_WRITER_H_
|
||||
|
5
deps/zlib/gzguts.h
vendored
5
deps/zlib/gzguts.h
vendored
@ -1,5 +1,5 @@
|
||||
/* gzguts.h -- zlib internal header definitions for gz* operations
|
||||
* Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler
|
||||
* Copyright (C) 2004-2019 Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
@ -39,7 +39,7 @@
|
||||
# include <io.h>
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
#if defined(_WIN32)
|
||||
# define WIDECHAR
|
||||
#endif
|
||||
|
||||
@ -190,6 +190,7 @@ typedef struct {
|
||||
/* just for writing */
|
||||
int level; /* compression level */
|
||||
int strategy; /* compression strategy */
|
||||
int reset; /* true if a reset is pending after a Z_FINISH */
|
||||
/* seek request */
|
||||
z_off64_t skip; /* amount to skip (already rewound if backwards) */
|
||||
int seek; /* true if seek request pending */
|
||||
|
10
deps/zlib/gzlib.c
vendored
10
deps/zlib/gzlib.c
vendored
@ -1,11 +1,11 @@
|
||||
/* gzlib.c -- zlib functions common to reading and writing gzip files
|
||||
* Copyright (C) 2004-2017 Mark Adler
|
||||
* Copyright (C) 2004-2019 Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
#include "gzguts.h"
|
||||
|
||||
#if defined(_WIN32) && !defined(__BORLANDC__) && !defined(__MINGW32__)
|
||||
#if defined(_WIN32) && !defined(__BORLANDC__)
|
||||
# define LSEEK _lseeki64
|
||||
#else
|
||||
#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
|
||||
@ -30,7 +30,7 @@ local gzFile gz_open OF((const void *, int, const char *));
|
||||
|
||||
The gz_strwinerror function does not change the current setting of
|
||||
GetLastError. */
|
||||
char ZLIB_INTERNAL *gz_strwinerror (error)
|
||||
char ZLIB_INTERNAL *gz_strwinerror(error)
|
||||
DWORD error;
|
||||
{
|
||||
static char buf[1024];
|
||||
@ -81,6 +81,8 @@ local void gz_reset(state)
|
||||
state->past = 0; /* have not read past end yet */
|
||||
state->how = LOOK; /* look for gzip header */
|
||||
}
|
||||
else /* for writing ... */
|
||||
state->reset = 0; /* no deflateReset pending */
|
||||
state->seek = 0; /* no seek request pending */
|
||||
gz_error(state, Z_OK, NULL); /* clear error */
|
||||
state->x.pos = 0; /* no uncompressed data yet */
|
||||
@ -397,7 +399,7 @@ z_off64_t ZEXPORT gzseek64(file, offset, whence)
|
||||
/* if within raw area while reading, just go there */
|
||||
if (state->mode == GZ_READ && state->how == COPY &&
|
||||
state->x.pos + offset >= 0) {
|
||||
ret = LSEEK(state->fd, offset - state->x.have, SEEK_CUR);
|
||||
ret = LSEEK(state->fd, offset - (z_off64_t)state->x.have, SEEK_CUR);
|
||||
if (ret == -1)
|
||||
return -1;
|
||||
state->x.have = 0;
|
||||
|
20
deps/zlib/gzread.c
vendored
20
deps/zlib/gzread.c
vendored
@ -1,5 +1,5 @@
|
||||
/* gzread.c -- zlib functions for reading gzip files
|
||||
* Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler
|
||||
* Copyright (C) 2004-2017 Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
@ -157,11 +157,9 @@ local int gz_look(state)
|
||||
the output buffer is larger than the input buffer, which also assures
|
||||
space for gzungetc() */
|
||||
state->x.next = state->out;
|
||||
if (strm->avail_in) {
|
||||
memcpy(state->x.next, strm->next_in, strm->avail_in);
|
||||
state->x.have = strm->avail_in;
|
||||
strm->avail_in = 0;
|
||||
}
|
||||
memcpy(state->x.next, strm->next_in, strm->avail_in);
|
||||
state->x.have = strm->avail_in;
|
||||
strm->avail_in = 0;
|
||||
state->how = COPY;
|
||||
state->direct = 1;
|
||||
return 0;
|
||||
@ -314,9 +312,9 @@ local z_size_t gz_read(state, buf, len)
|
||||
got = 0;
|
||||
do {
|
||||
/* set n to the maximum amount of len that fits in an unsigned int */
|
||||
n = -1;
|
||||
n = (unsigned)-1;
|
||||
if (n > len)
|
||||
n = len;
|
||||
n = (unsigned)len;
|
||||
|
||||
/* first just try copying data from the output buffer */
|
||||
if (state->x.have) {
|
||||
@ -397,7 +395,7 @@ int ZEXPORT gzread(file, buf, len)
|
||||
}
|
||||
|
||||
/* read len or fewer bytes to buf */
|
||||
len = gz_read(state, buf, len);
|
||||
len = (unsigned)gz_read(state, buf, len);
|
||||
|
||||
/* check for an error */
|
||||
if (len == 0 && state->err != Z_OK && state->err != Z_BUF_ERROR)
|
||||
@ -451,7 +449,6 @@ z_size_t ZEXPORT gzfread(buf, size, nitems, file)
|
||||
int ZEXPORT gzgetc(file)
|
||||
gzFile file;
|
||||
{
|
||||
int ret;
|
||||
unsigned char buf[1];
|
||||
gz_statep state;
|
||||
|
||||
@ -473,8 +470,7 @@ int ZEXPORT gzgetc(file)
|
||||
}
|
||||
|
||||
/* nothing there -- try gz_read() */
|
||||
ret = gz_read(state, buf, 1);
|
||||
return ret < 1 ? -1 : buf[0];
|
||||
return gz_read(state, buf, 1) < 1 ? -1 : buf[0];
|
||||
}
|
||||
|
||||
int ZEXPORT gzgetc_(file)
|
||||
|
40
deps/zlib/gzwrite.c
vendored
40
deps/zlib/gzwrite.c
vendored
@ -1,5 +1,5 @@
|
||||
/* gzwrite.c -- zlib functions for writing gzip files
|
||||
* Copyright (C) 2004-2017 Mark Adler
|
||||
* Copyright (C) 2004-2019 Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
@ -97,6 +97,15 @@ local int gz_comp(state, flush)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check for a pending reset */
|
||||
if (state->reset) {
|
||||
/* don't start a new gzip member unless there is data to write */
|
||||
if (strm->avail_in == 0)
|
||||
return 0;
|
||||
deflateReset(strm);
|
||||
state->reset = 0;
|
||||
}
|
||||
|
||||
/* run deflate() on provided input until it produces no more output */
|
||||
ret = Z_OK;
|
||||
do {
|
||||
@ -134,7 +143,7 @@ local int gz_comp(state, flush)
|
||||
|
||||
/* if that completed a deflate stream, allow another to start */
|
||||
if (flush == Z_FINISH)
|
||||
deflateReset(strm);
|
||||
state->reset = 1;
|
||||
|
||||
/* all done, no errors */
|
||||
return 0;
|
||||
@ -209,7 +218,7 @@ local z_size_t gz_write(state, buf, len)
|
||||
state->in);
|
||||
copy = state->size - have;
|
||||
if (copy > len)
|
||||
copy = len;
|
||||
copy = (unsigned)len;
|
||||
memcpy(state->in + have, buf, copy);
|
||||
state->strm.avail_in += copy;
|
||||
state->x.pos += copy;
|
||||
@ -229,7 +238,7 @@ local z_size_t gz_write(state, buf, len)
|
||||
do {
|
||||
unsigned n = (unsigned)-1;
|
||||
if (n > len)
|
||||
n = len;
|
||||
n = (unsigned)len;
|
||||
state->strm.avail_in = n;
|
||||
state->x.pos += n;
|
||||
if (gz_comp(state, Z_NO_FLUSH) == -1)
|
||||
@ -349,12 +358,11 @@ int ZEXPORT gzputc(file, c)
|
||||
}
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
int ZEXPORT gzputs(file, str)
|
||||
int ZEXPORT gzputs(file, s)
|
||||
gzFile file;
|
||||
const char *str;
|
||||
const char *s;
|
||||
{
|
||||
int ret;
|
||||
z_size_t len;
|
||||
z_size_t len, put;
|
||||
gz_statep state;
|
||||
|
||||
/* get internal structure */
|
||||
@ -367,9 +375,13 @@ int ZEXPORT gzputs(file, str)
|
||||
return -1;
|
||||
|
||||
/* write string */
|
||||
len = strlen(str);
|
||||
ret = gz_write(state, str, len);
|
||||
return ret == 0 && len != 0 ? -1 : ret;
|
||||
len = strlen(s);
|
||||
if ((int)len < 0 || (unsigned)len != len) {
|
||||
gz_error(state, Z_STREAM_ERROR, "string length does not fit in int");
|
||||
return -1;
|
||||
}
|
||||
put = gz_write(state, s, len);
|
||||
return put < len ? -1 : (int)len;
|
||||
}
|
||||
|
||||
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
|
||||
@ -441,7 +453,7 @@ int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va)
|
||||
strm->avail_in = state->size;
|
||||
if (gz_comp(state, Z_NO_FLUSH) == -1)
|
||||
return state->err;
|
||||
memcpy(state->in, state->in + state->size, left);
|
||||
memmove(state->in, state->in + state->size, left);
|
||||
strm->next_in = state->in;
|
||||
strm->avail_in = left;
|
||||
}
|
||||
@ -462,7 +474,7 @@ int ZEXPORTVA gzprintf(gzFile file, const char *format, ...)
|
||||
#else /* !STDC && !Z_HAVE_STDARG_H */
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
|
||||
int ZEXPORTVA gzprintf(file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
|
||||
a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
gzFile file;
|
||||
const char *format;
|
||||
@ -540,7 +552,7 @@ int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
|
||||
strm->avail_in = state->size;
|
||||
if (gz_comp(state, Z_NO_FLUSH) == -1)
|
||||
return state->err;
|
||||
memcpy(state->in, state->in + state->size, left);
|
||||
memmove(state->in, state->in + state->size, left);
|
||||
strm->next_in = state->in;
|
||||
strm->avail_in = left;
|
||||
}
|
||||
|
26
deps/zlib/infback.c
vendored
26
deps/zlib/infback.c
vendored
@ -1,5 +1,5 @@
|
||||
/* infback.c -- inflate using a call-back interface
|
||||
* Copyright (C) 1995-2016 Mark Adler
|
||||
* Copyright (C) 1995-2022 Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
@ -66,6 +66,7 @@ int stream_size;
|
||||
state->window = window;
|
||||
state->wnext = 0;
|
||||
state->whave = 0;
|
||||
state->sane = 1;
|
||||
return Z_OK;
|
||||
}
|
||||
|
||||
@ -454,11 +455,11 @@ void FAR *out_desc;
|
||||
}
|
||||
|
||||
/* build code tables -- note: do not change the lenbits or distbits
|
||||
values here (9 and 6) without reading the comments in inftrees.h
|
||||
values here (10 and 9) without reading the comments in inftrees.h
|
||||
concerning the ENOUGH constants, which depend on those values */
|
||||
state->next = state->codes;
|
||||
state->lencode = (code const FAR *)(state->next);
|
||||
state->lenbits = 9;
|
||||
state->lenbits = 10;
|
||||
ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
|
||||
&(state->lenbits), state->work);
|
||||
if (ret) {
|
||||
@ -467,7 +468,7 @@ void FAR *out_desc;
|
||||
break;
|
||||
}
|
||||
state->distcode = (code const FAR *)(state->next);
|
||||
state->distbits = 6;
|
||||
state->distbits = 9;
|
||||
ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
|
||||
&(state->next), &(state->distbits), state->work);
|
||||
if (ret) {
|
||||
@ -477,6 +478,7 @@ void FAR *out_desc;
|
||||
}
|
||||
Tracev((stderr, "inflate: codes ok\n"));
|
||||
state->mode = LEN;
|
||||
/* fallthrough */
|
||||
|
||||
case LEN:
|
||||
/* use inflate_fast() if we have enough input and output */
|
||||
@ -605,25 +607,27 @@ void FAR *out_desc;
|
||||
break;
|
||||
|
||||
case DONE:
|
||||
/* inflate stream terminated properly -- write leftover output */
|
||||
/* inflate stream terminated properly */
|
||||
ret = Z_STREAM_END;
|
||||
if (left < state->wsize) {
|
||||
if (out(out_desc, state->window, state->wsize - left))
|
||||
ret = Z_BUF_ERROR;
|
||||
}
|
||||
goto inf_leave;
|
||||
|
||||
case BAD:
|
||||
ret = Z_DATA_ERROR;
|
||||
goto inf_leave;
|
||||
|
||||
default: /* can't happen, but makes compilers happy */
|
||||
default:
|
||||
/* can't happen, but makes compilers happy */
|
||||
ret = Z_STREAM_ERROR;
|
||||
goto inf_leave;
|
||||
}
|
||||
|
||||
/* Return unused input */
|
||||
/* Write leftover output and return unused input */
|
||||
inf_leave:
|
||||
if (left < state->wsize) {
|
||||
if (out(out_desc, state->window, state->wsize - left) &&
|
||||
ret == Z_STREAM_END)
|
||||
ret = Z_BUF_ERROR;
|
||||
}
|
||||
strm->next_in = next;
|
||||
strm->avail_in = have;
|
||||
return ret;
|
||||
|
28
deps/zlib/inffast.c
vendored
28
deps/zlib/inffast.c
vendored
@ -74,7 +74,7 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
|
||||
code const FAR *dcode; /* local strm->distcode */
|
||||
unsigned lmask; /* mask for first level of length codes */
|
||||
unsigned dmask; /* mask for first level of distance codes */
|
||||
code here; /* retrieved table entry */
|
||||
code const *here; /* retrieved table entry */
|
||||
unsigned op; /* code bits, operation, extra bits, or */
|
||||
/* window position, window bytes to copy */
|
||||
unsigned len; /* match length, unused bytes */
|
||||
@ -111,20 +111,20 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
|
||||
hold += (unsigned long)(*in++) << bits;
|
||||
bits += 8;
|
||||
}
|
||||
here = lcode[hold & lmask];
|
||||
here = lcode + (hold & lmask);
|
||||
dolen:
|
||||
op = (unsigned)(here.bits);
|
||||
op = (unsigned)(here->bits);
|
||||
hold >>= op;
|
||||
bits -= op;
|
||||
op = (unsigned)(here.op);
|
||||
op = (unsigned)(here->op);
|
||||
if (op == 0) { /* literal */
|
||||
Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
|
||||
Tracevv((stderr, here->val >= 0x20 && here->val < 0x7f ?
|
||||
"inflate: literal '%c'\n" :
|
||||
"inflate: literal 0x%02x\n", here.val));
|
||||
*out++ = (unsigned char)(here.val);
|
||||
"inflate: literal 0x%02x\n", here->val));
|
||||
*out++ = (unsigned char)(here->val);
|
||||
}
|
||||
else if (op & 16) { /* length base */
|
||||
len = (unsigned)(here.val);
|
||||
len = (unsigned)(here->val);
|
||||
op &= 15; /* number of extra bits */
|
||||
if (op) {
|
||||
if (bits < op) {
|
||||
@ -142,14 +142,14 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
|
||||
hold += (unsigned long)(*in++) << bits;
|
||||
bits += 8;
|
||||
}
|
||||
here = dcode[hold & dmask];
|
||||
here = dcode + (hold & dmask);
|
||||
dodist:
|
||||
op = (unsigned)(here.bits);
|
||||
op = (unsigned)(here->bits);
|
||||
hold >>= op;
|
||||
bits -= op;
|
||||
op = (unsigned)(here.op);
|
||||
op = (unsigned)(here->op);
|
||||
if (op & 16) { /* distance base */
|
||||
dist = (unsigned)(here.val);
|
||||
dist = (unsigned)(here->val);
|
||||
op &= 15; /* number of extra bits */
|
||||
if (bits < op) {
|
||||
hold += (unsigned long)(*in++) << bits;
|
||||
@ -268,7 +268,7 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
|
||||
}
|
||||
}
|
||||
else if ((op & 64) == 0) { /* 2nd level distance code */
|
||||
here = dcode[here.val + (hold & ((1U << op) - 1))];
|
||||
here = dcode + here->val + (hold & ((1U << op) - 1));
|
||||
goto dodist;
|
||||
}
|
||||
else {
|
||||
@ -278,7 +278,7 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
|
||||
}
|
||||
}
|
||||
else if ((op & 64) == 0) { /* 2nd level length code */
|
||||
here = lcode[here.val + (hold & ((1U << op) - 1))];
|
||||
here = lcode + here->val + (hold & ((1U << op) - 1));
|
||||
goto dolen;
|
||||
}
|
||||
else if (op & 32) { /* end-of-block */
|
||||
|
60
deps/zlib/inflate.c
vendored
60
deps/zlib/inflate.c
vendored
@ -1,5 +1,5 @@
|
||||
/* inflate.c -- zlib decompression
|
||||
* Copyright (C) 1995-2016 Mark Adler
|
||||
* Copyright (C) 1995-2022 Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
@ -130,6 +130,7 @@ z_streamp strm;
|
||||
state->mode = HEAD;
|
||||
state->last = 0;
|
||||
state->havedict = 0;
|
||||
state->flags = -1;
|
||||
state->dmax = 32768U;
|
||||
state->head = Z_NULL;
|
||||
state->hold = 0;
|
||||
@ -167,6 +168,8 @@ int windowBits;
|
||||
|
||||
/* extract wrap request from windowBits parameter */
|
||||
if (windowBits < 0) {
|
||||
if (windowBits < -15)
|
||||
return Z_STREAM_ERROR;
|
||||
wrap = 0;
|
||||
windowBits = -windowBits;
|
||||
}
|
||||
@ -448,10 +451,10 @@ unsigned copy;
|
||||
|
||||
/* check function to use adler32() for zlib or crc32() for gzip */
|
||||
#ifdef GUNZIP
|
||||
# define UPDATE(check, buf, len) \
|
||||
# define UPDATE_CHECK(check, buf, len) \
|
||||
(state->flags ? crc32(check, buf, len) : adler32(check, buf, len))
|
||||
#else
|
||||
# define UPDATE(check, buf, len) adler32(check, buf, len)
|
||||
# define UPDATE_CHECK(check, buf, len) adler32(check, buf, len)
|
||||
#endif
|
||||
|
||||
/* check macros for header crc */
|
||||
@ -671,7 +674,6 @@ int flush;
|
||||
state->mode = FLAGS;
|
||||
break;
|
||||
}
|
||||
state->flags = 0; /* expect zlib header */
|
||||
if (state->head != Z_NULL)
|
||||
state->head->done = -1;
|
||||
if (!(state->wrap & 1) || /* check if zlib header allowed */
|
||||
@ -698,6 +700,7 @@ int flush;
|
||||
break;
|
||||
}
|
||||
state->dmax = 1U << len;
|
||||
state->flags = 0; /* indicate zlib header */
|
||||
Tracev((stderr, "inflate: zlib header ok\n"));
|
||||
strm->adler = state->check = adler32(0L, Z_NULL, 0);
|
||||
state->mode = hold & 0x200 ? DICTID : TYPE;
|
||||
@ -723,6 +726,7 @@ int flush;
|
||||
CRC2(state->check, hold);
|
||||
INITBITS();
|
||||
state->mode = TIME;
|
||||
/* fallthrough */
|
||||
case TIME:
|
||||
NEEDBITS(32);
|
||||
if (state->head != Z_NULL)
|
||||
@ -731,6 +735,7 @@ int flush;
|
||||
CRC4(state->check, hold);
|
||||
INITBITS();
|
||||
state->mode = OS;
|
||||
/* fallthrough */
|
||||
case OS:
|
||||
NEEDBITS(16);
|
||||
if (state->head != Z_NULL) {
|
||||
@ -741,6 +746,7 @@ int flush;
|
||||
CRC2(state->check, hold);
|
||||
INITBITS();
|
||||
state->mode = EXLEN;
|
||||
/* fallthrough */
|
||||
case EXLEN:
|
||||
if (state->flags & 0x0400) {
|
||||
NEEDBITS(16);
|
||||
@ -754,14 +760,16 @@ int flush;
|
||||
else if (state->head != Z_NULL)
|
||||
state->head->extra = Z_NULL;
|
||||
state->mode = EXTRA;
|
||||
/* fallthrough */
|
||||
case EXTRA:
|
||||
if (state->flags & 0x0400) {
|
||||
copy = state->length;
|
||||
if (copy > have) copy = have;
|
||||
if (copy) {
|
||||
if (state->head != Z_NULL &&
|
||||
state->head->extra != Z_NULL) {
|
||||
len = state->head->extra_len - state->length;
|
||||
state->head->extra != Z_NULL &&
|
||||
(len = state->head->extra_len - state->length) <
|
||||
state->head->extra_max) {
|
||||
zmemcpy(state->head->extra + len, next,
|
||||
len + copy > state->head->extra_max ?
|
||||
state->head->extra_max - len : copy);
|
||||
@ -776,6 +784,7 @@ int flush;
|
||||
}
|
||||
state->length = 0;
|
||||
state->mode = NAME;
|
||||
/* fallthrough */
|
||||
case NAME:
|
||||
if (state->flags & 0x0800) {
|
||||
if (have == 0) goto inf_leave;
|
||||
@ -797,6 +806,7 @@ int flush;
|
||||
state->head->name = Z_NULL;
|
||||
state->length = 0;
|
||||
state->mode = COMMENT;
|
||||
/* fallthrough */
|
||||
case COMMENT:
|
||||
if (state->flags & 0x1000) {
|
||||
if (have == 0) goto inf_leave;
|
||||
@ -817,6 +827,7 @@ int flush;
|
||||
else if (state->head != Z_NULL)
|
||||
state->head->comment = Z_NULL;
|
||||
state->mode = HCRC;
|
||||
/* fallthrough */
|
||||
case HCRC:
|
||||
if (state->flags & 0x0200) {
|
||||
NEEDBITS(16);
|
||||
@ -840,6 +851,7 @@ int flush;
|
||||
strm->adler = state->check = ZSWAP32(hold);
|
||||
INITBITS();
|
||||
state->mode = DICT;
|
||||
/* fallthrough */
|
||||
case DICT:
|
||||
if (state->havedict == 0) {
|
||||
RESTORE();
|
||||
@ -847,8 +859,10 @@ int flush;
|
||||
}
|
||||
strm->adler = state->check = adler32(0L, Z_NULL, 0);
|
||||
state->mode = TYPE;
|
||||
/* fallthrough */
|
||||
case TYPE:
|
||||
if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave;
|
||||
/* fallthrough */
|
||||
case TYPEDO:
|
||||
if (state->last) {
|
||||
BYTEBITS();
|
||||
@ -899,8 +913,10 @@ int flush;
|
||||
INITBITS();
|
||||
state->mode = COPY_;
|
||||
if (flush == Z_TREES) goto inf_leave;
|
||||
/* fallthrough */
|
||||
case COPY_:
|
||||
state->mode = COPY;
|
||||
/* fallthrough */
|
||||
case COPY:
|
||||
copy = state->length;
|
||||
if (copy) {
|
||||
@ -936,6 +952,7 @@ int flush;
|
||||
Tracev((stderr, "inflate: table sizes ok\n"));
|
||||
state->have = 0;
|
||||
state->mode = LENLENS;
|
||||
/* fallthrough */
|
||||
case LENLENS:
|
||||
while (state->have < state->ncode) {
|
||||
NEEDBITS(3);
|
||||
@ -957,6 +974,7 @@ int flush;
|
||||
Tracev((stderr, "inflate: code lengths ok\n"));
|
||||
state->have = 0;
|
||||
state->mode = CODELENS;
|
||||
/* fallthrough */
|
||||
case CODELENS:
|
||||
while (state->have < state->nlen + state->ndist) {
|
||||
for (;;) {
|
||||
@ -1016,11 +1034,11 @@ int flush;
|
||||
}
|
||||
|
||||
/* build code tables -- note: do not change the lenbits or distbits
|
||||
values here (9 and 6) without reading the comments in inftrees.h
|
||||
values here (10 and 9) without reading the comments in inftrees.h
|
||||
concerning the ENOUGH constants, which depend on those values */
|
||||
state->next = state->codes;
|
||||
state->lencode = (const code FAR *)(state->next);
|
||||
state->lenbits = 9;
|
||||
state->lenbits = 10;
|
||||
ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
|
||||
&(state->lenbits), state->work);
|
||||
if (ret) {
|
||||
@ -1029,7 +1047,7 @@ int flush;
|
||||
break;
|
||||
}
|
||||
state->distcode = (const code FAR *)(state->next);
|
||||
state->distbits = 6;
|
||||
state->distbits = 9;
|
||||
ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
|
||||
&(state->next), &(state->distbits), state->work);
|
||||
if (ret) {
|
||||
@ -1040,8 +1058,10 @@ int flush;
|
||||
Tracev((stderr, "inflate: codes ok\n"));
|
||||
state->mode = LEN_;
|
||||
if (flush == Z_TREES) goto inf_leave;
|
||||
/* fallthrough */
|
||||
case LEN_:
|
||||
state->mode = LEN;
|
||||
/* fallthrough */
|
||||
case LEN:
|
||||
if (have >= INFLATE_FAST_MIN_INPUT &&
|
||||
left >= INFLATE_FAST_MIN_OUTPUT) {
|
||||
@ -1092,6 +1112,7 @@ int flush;
|
||||
}
|
||||
state->extra = (unsigned)(here.op) & 15;
|
||||
state->mode = LENEXT;
|
||||
/* fallthrough */
|
||||
case LENEXT:
|
||||
if (state->extra) {
|
||||
NEEDBITS(state->extra);
|
||||
@ -1102,6 +1123,7 @@ int flush;
|
||||
Tracevv((stderr, "inflate: length %u\n", state->length));
|
||||
state->was = state->length;
|
||||
state->mode = DIST;
|
||||
/* fallthrough */
|
||||
case DIST:
|
||||
for (;;) {
|
||||
here = state->distcode[BITS(state->distbits)];
|
||||
@ -1129,6 +1151,7 @@ int flush;
|
||||
state->offset = (unsigned)here.val;
|
||||
state->extra = (unsigned)(here.op) & 15;
|
||||
state->mode = DISTEXT;
|
||||
/* fallthrough */
|
||||
case DISTEXT:
|
||||
if (state->extra) {
|
||||
NEEDBITS(state->extra);
|
||||
@ -1145,6 +1168,7 @@ int flush;
|
||||
#endif
|
||||
Tracevv((stderr, "inflate: distance %u\n", state->offset));
|
||||
state->mode = MATCH;
|
||||
/* fallthrough */
|
||||
case MATCH:
|
||||
if (left == 0) goto inf_leave;
|
||||
copy = out - left;
|
||||
@ -1204,7 +1228,7 @@ int flush;
|
||||
state->total += out;
|
||||
if ((state->wrap & 4) && out)
|
||||
strm->adler = state->check =
|
||||
UPDATE(state->check, put - out, out);
|
||||
UPDATE_CHECK(state->check, put - out, out);
|
||||
out = left;
|
||||
if ((state->wrap & 4) && (
|
||||
#ifdef GUNZIP
|
||||
@ -1220,10 +1244,11 @@ int flush;
|
||||
}
|
||||
#ifdef GUNZIP
|
||||
state->mode = LENGTH;
|
||||
/* fallthrough */
|
||||
case LENGTH:
|
||||
if (state->wrap && state->flags) {
|
||||
NEEDBITS(32);
|
||||
if (hold != (state->total & 0xffffffffUL)) {
|
||||
if ((state->wrap & 4) && hold != (state->total & 0xffffffff)) {
|
||||
strm->msg = (char *)"incorrect length check";
|
||||
state->mode = BAD;
|
||||
break;
|
||||
@ -1233,6 +1258,7 @@ int flush;
|
||||
}
|
||||
#endif
|
||||
state->mode = DONE;
|
||||
/* fallthrough */
|
||||
case DONE:
|
||||
ret = Z_STREAM_END;
|
||||
goto inf_leave;
|
||||
@ -1242,6 +1268,7 @@ int flush;
|
||||
case MEM:
|
||||
return Z_MEM_ERROR;
|
||||
case SYNC:
|
||||
/* fallthrough */
|
||||
default:
|
||||
return Z_STREAM_ERROR;
|
||||
}
|
||||
@ -1267,7 +1294,7 @@ int flush;
|
||||
state->total += out;
|
||||
if ((state->wrap & 4) && out)
|
||||
strm->adler = state->check =
|
||||
UPDATE(state->check, strm->next_out - out, out);
|
||||
UPDATE_CHECK(state->check, strm->next_out - out, out);
|
||||
strm->data_type = (int)state->bits + (state->last ? 64 : 0) +
|
||||
(state->mode == TYPE ? 128 : 0) +
|
||||
(state->mode == LEN_ || state->mode == COPY_ ? 256 : 0);
|
||||
@ -1403,6 +1430,7 @@ int ZEXPORT inflateSync(strm)
|
||||
z_streamp strm;
|
||||
{
|
||||
unsigned len; /* number of bytes to look at or looked at */
|
||||
int flags; /* temporary to save header status */
|
||||
unsigned long in, out; /* temporary to save total_in and total_out */
|
||||
unsigned char buf[4]; /* to restore bit buffer to byte string */
|
||||
struct inflate_state FAR *state;
|
||||
@ -1435,9 +1463,15 @@ z_streamp strm;
|
||||
|
||||
/* return no joy or set up to restart inflate() on a new block */
|
||||
if (state->have != 4) return Z_DATA_ERROR;
|
||||
if (state->flags == -1)
|
||||
state->wrap = 0; /* if no header yet, treat as raw */
|
||||
else
|
||||
state->wrap &= ~4; /* no point in computing a check value now */
|
||||
flags = state->flags;
|
||||
in = strm->total_in; out = strm->total_out;
|
||||
inflateReset(strm);
|
||||
strm->total_in = in; strm->total_out = out;
|
||||
state->flags = flags;
|
||||
state->mode = TYPE;
|
||||
return Z_OK;
|
||||
}
|
||||
@ -1533,7 +1567,7 @@ int check;
|
||||
|
||||
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
|
||||
state = (struct inflate_state FAR *)strm->state;
|
||||
if (check)
|
||||
if (check && state->wrap)
|
||||
state->wrap |= 4;
|
||||
else
|
||||
state->wrap &= ~4;
|
||||
|
5
deps/zlib/inflate.h
vendored
5
deps/zlib/inflate.h
vendored
@ -1,5 +1,5 @@
|
||||
/* inflate.h -- internal inflate state definition
|
||||
* Copyright (C) 1995-2016 Mark Adler
|
||||
* Copyright (C) 1995-2019 Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
@ -86,7 +86,8 @@ struct inflate_state {
|
||||
int wrap; /* bit 0 true for zlib, bit 1 true for gzip,
|
||||
bit 2 true to validate check value */
|
||||
int havedict; /* true if dictionary provided */
|
||||
int flags; /* gzip header method and flags (0 if zlib) */
|
||||
int flags; /* gzip header method and flags, 0 if zlib, or
|
||||
-1 if raw or no header yet */
|
||||
unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */
|
||||
unsigned long check; /* protected copy of check value */
|
||||
unsigned long total; /* protected copy of output count */
|
||||
|
6
deps/zlib/inftrees.c
vendored
6
deps/zlib/inftrees.c
vendored
@ -1,5 +1,5 @@
|
||||
/* inftrees.c -- generate Huffman trees for efficient decoding
|
||||
* Copyright (C) 1995-2017 Mark Adler
|
||||
* Copyright (C) 1995-2022 Mark Adler
|
||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||
*/
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
#define MAXBITS 15
|
||||
|
||||
const char inflate_copyright[] =
|
||||
" inflate 1.2.11 Copyright 1995-2017 Mark Adler ";
|
||||
" inflate 1.2.13 Copyright 1995-2022 Mark Adler ";
|
||||
/*
|
||||
If you use the zlib library in a product, an acknowledgment is welcome
|
||||
in the documentation of your product. If for some reason you cannot
|
||||
@ -62,7 +62,7 @@ unsigned short FAR *work;
|
||||
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
|
||||
static const unsigned short lext[31] = { /* Length codes 257..285 extra */
|
||||
16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
|
||||
19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 77, 202};
|
||||
19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 194, 65};
|
||||
static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
|
||||
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
|
||||
257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
|
||||
|
12
deps/zlib/inftrees.h
vendored
12
deps/zlib/inftrees.h
vendored
@ -36,17 +36,17 @@ typedef struct {
|
||||
*/
|
||||
|
||||
/* Maximum size of the dynamic table. The maximum number of code structures is
|
||||
1444, which is the sum of 852 for literal/length codes and 592 for distance
|
||||
1924, which is the sum of 1332 for literal/length codes and 592 for distance
|
||||
codes. These values were found by exhaustive searches using the program
|
||||
examples/enough.c found in the zlib distribtution. The arguments to that
|
||||
examples/enough.c found in the zlib distribution. The arguments to that
|
||||
program are the number of symbols, the initial root table size, and the
|
||||
maximum bit length of a code. "enough 286 9 15" for literal/length codes
|
||||
returns returns 852, and "enough 30 6 15" for distance codes returns 592.
|
||||
The initial root table size (9 or 6) is found in the fifth argument of the
|
||||
maximum bit length of a code. "enough 286 10 15" for literal/length codes
|
||||
returns returns 1332, and "enough 30 9 15" for distance codes returns 592.
|
||||
The initial root table size (10 or 9) is found in the fifth argument of the
|
||||
inflate_table() calls in inflate.c and infback.c. If the root table size is
|
||||
changed, then these maximum sizes would be need to be recalculated and
|
||||
updated. */
|
||||
#define ENOUGH_LENS 852
|
||||
#define ENOUGH_LENS 1332
|
||||
#define ENOUGH_DISTS 592
|
||||
#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS)
|
||||
|
||||
|
15
deps/zlib/patches/0003-uninitializedjump.patch
vendored
Normal file
15
deps/zlib/patches/0003-uninitializedjump.patch
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
diff --git a/third_party/zlib/deflate.c b/third_party/zlib/deflate.c
|
||||
index a39e62787862..c6053fd1c7ea 100644
|
||||
--- a/third_party/zlib/deflate.c
|
||||
+++ b/third_party/zlib/deflate.c
|
||||
@@ -318,6 +318,10 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
|
||||
s->w_size + window_padding,
|
||||
2*sizeof(Byte));
|
||||
s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos));
|
||||
+ /* Avoid use of uninitialized value, see:
|
||||
+ * https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=11360
|
||||
+ */
|
||||
+ zmemzero(s->prev, s->w_size * sizeof(Pos));
|
||||
s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos));
|
||||
|
||||
s->high_water = 0; /* nothing written to s->window yet */
|
22
deps/zlib/patches/0004-fix-uwp.patch
vendored
Normal file
22
deps/zlib/patches/0004-fix-uwp.patch
vendored
Normal file
@ -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));
|
405
deps/zlib/patches/0005-infcover-gtest.patch
vendored
Normal file
405
deps/zlib/patches/0005-infcover-gtest.patch
vendored
Normal file
@ -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 "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(©, &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)
|
||||
|
42
deps/zlib/patches/0006-fix-check_match.patch
vendored
Normal file
42
deps/zlib/patches/0006-fix-check_match.patch
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
From 8304bdda5293ffd5b3efce8e4f54904b387029d6 Mon Sep 17 00:00:00 2001
|
||||
From: Hans Wennborg <hans@chromium.org>
|
||||
Date: Wed, 23 Sep 2020 16:36:38 +0200
|
||||
Subject: [PATCH] Avoid crashing in check_match when prev_match == -1
|
||||
|
||||
prev_match can be set to -1 after sliding the window. In that case, the
|
||||
window has slid past the first byte of the last match, which means it
|
||||
cannot be compared in check_match.
|
||||
|
||||
This would cause zlib to crash on some inputs to deflate when built
|
||||
with ZLIB_DEBUG enabled.
|
||||
|
||||
Check for this situation and avoid crashing by not trying to compare
|
||||
the first byte.
|
||||
|
||||
Bug: 1113142
|
||||
---
|
||||
third_party/zlib/deflate.c | 8 +++++++-
|
||||
1 file changed, 7 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/third_party/zlib/deflate.c b/third_party/zlib/deflate.c
|
||||
index cfdd2f46b230..d70732ec6fc2 100644
|
||||
--- a/third_party/zlib/deflate.c
|
||||
+++ b/third_party/zlib/deflate.c
|
||||
@@ -2060,7 +2060,13 @@ local block_state deflate_slow(s, flush)
|
||||
uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
|
||||
/* Do not insert strings in hash table beyond this. */
|
||||
|
||||
- check_match(s, s->strstart-1, s->prev_match, s->prev_length);
|
||||
+ if (s->prev_match == -1) {
|
||||
+ /* The window has slid one byte past the previous match,
|
||||
+ * so the first byte cannot be compared. */
|
||||
+ check_match(s, s->strstart, s->prev_match+1, s->prev_length-1);
|
||||
+ } else {
|
||||
+ check_match(s, s->strstart-1, s->prev_match, s->prev_length);
|
||||
+ }
|
||||
|
||||
_tr_tally_dist(s, s->strstart -1 - s->prev_match,
|
||||
s->prev_length - MIN_MATCH, bflush);
|
||||
--
|
||||
2.28.0.681.g6f77f65b4e-goog
|
||||
|
40
deps/zlib/patches/0007-zero-init-deflate-window.patch
vendored
Normal file
40
deps/zlib/patches/0007-zero-init-deflate-window.patch
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
From 92537ee19784e0e545f06d89b7d89ab532a18cff Mon Sep 17 00:00:00 2001
|
||||
From: Hans Wennborg <hans@chromium.org>
|
||||
Date: Tue, 3 Nov 2020 15:54:09 +0100
|
||||
Subject: [PATCH] [zlib] Zero-initialize the window used for deflation
|
||||
|
||||
Otherwise MSan complains about use-of-uninitialized values in the
|
||||
window.
|
||||
This happens in both regular deflate's longest_match and deflate_rle.
|
||||
|
||||
Before crrev.com/822755 we used to suppress those reports, but it seems
|
||||
better to fix it properly. That will also allow us to catch other
|
||||
potential issues with MSan in these functions.
|
||||
|
||||
The instances of this that we've seen only reproduce with
|
||||
fill_window_sse(), not with the regular fill_window() function. Since
|
||||
the former doesn't exist in upstream zlib, I'm not planning to send this
|
||||
patch upstream.
|
||||
|
||||
Bug: 1137613, 1144420
|
||||
---
|
||||
third_party/zlib/deflate.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/third_party/zlib/deflate.c b/third_party/zlib/deflate.c
|
||||
index 8bf93e524875..fc7ae45905ff 100644
|
||||
--- a/third_party/zlib/deflate.c
|
||||
+++ b/third_party/zlib/deflate.c
|
||||
@@ -321,6 +321,9 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
|
||||
s->window = (Bytef *) ZALLOC(strm,
|
||||
s->w_size + window_padding,
|
||||
2*sizeof(Byte));
|
||||
+ /* Avoid use of unitialized values in the window, see crbug.com/1137613 and
|
||||
+ * crbug.com/1144420 */
|
||||
+ zmemzero(s->window, (s->w_size + window_padding) * (2 * sizeof(Byte)));
|
||||
s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos));
|
||||
/* Avoid use of uninitialized value, see:
|
||||
* https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=11360
|
||||
--
|
||||
2.29.1.341.ge80a0c044ae-goog
|
||||
|
98
deps/zlib/patches/0008-minizip-zip-unzip-tools.patch
vendored
Normal file
98
deps/zlib/patches/0008-minizip-zip-unzip-tools.patch
vendored
Normal file
@ -0,0 +1,98 @@
|
||||
From 0c7de17000659f4f79de878296892c46be0aff77 Mon Sep 17 00:00:00 2001
|
||||
From: Noel Gordon <noel@chromium.org>
|
||||
Date: Wed, 26 May 2021 21:57:43 +1000
|
||||
Subject: [PATCH] Build minizip zip and unzip tools
|
||||
|
||||
---
|
||||
third_party/zlib/contrib/minizip/miniunz.c | 13 ++++++-------
|
||||
third_party/zlib/contrib/minizip/minizip.c | 7 +++----
|
||||
2 files changed, 9 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/third_party/zlib/contrib/minizip/miniunz.c b/third_party/zlib/contrib/minizip/miniunz.c
|
||||
index 3d65401be5cd..08737f689a96 100644
|
||||
--- a/third_party/zlib/contrib/minizip/miniunz.c
|
||||
+++ b/third_party/zlib/contrib/minizip/miniunz.c
|
||||
@@ -12,7 +12,7 @@
|
||||
Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
|
||||
*/
|
||||
|
||||
-#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__))
|
||||
+#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__)) && (!defined(__ANDROID_API__))
|
||||
#ifndef __USE_FILE_OFFSET64
|
||||
#define __USE_FILE_OFFSET64
|
||||
#endif
|
||||
@@ -27,7 +27,7 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
-#ifdef __APPLE__
|
||||
+#if defined(__APPLE__) || defined(__Fuchsia__) || defined(__ANDROID_API__)
|
||||
// In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions
|
||||
#define FOPEN_FUNC(filename, mode) fopen(filename, mode)
|
||||
#define FTELLO_FUNC(stream) ftello(stream)
|
||||
@@ -45,6 +45,7 @@
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
+#include <sys/stat.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <direct.h>
|
||||
@@ -97,7 +98,7 @@ void change_file_date(filename,dosdate,tmu_date)
|
||||
SetFileTime(hFile,&ftm,&ftLastAcc,&ftm);
|
||||
CloseHandle(hFile);
|
||||
#else
|
||||
-#ifdef unix || __APPLE__
|
||||
+#if defined(unix) || defined(__APPLE__) || defined(__Fuchsia__) || defined(__ANDROID_API__)
|
||||
struct utimbuf ut;
|
||||
struct tm newdate;
|
||||
newdate.tm_sec = tmu_date.tm_sec;
|
||||
@@ -125,11 +126,9 @@ int mymkdir(dirname)
|
||||
const char* dirname;
|
||||
{
|
||||
int ret=0;
|
||||
-#ifdef _WIN32
|
||||
+#if defined(_WIN32)
|
||||
ret = _mkdir(dirname);
|
||||
-#elif unix
|
||||
- ret = mkdir (dirname,0775);
|
||||
-#elif __APPLE__
|
||||
+#elif defined(unix) || defined(__APPLE__) || defined(__Fuchsia__) || defined(__ANDROID_API__)
|
||||
ret = mkdir (dirname,0775);
|
||||
#endif
|
||||
return ret;
|
||||
diff --git a/third_party/zlib/contrib/minizip/minizip.c b/third_party/zlib/contrib/minizip/minizip.c
|
||||
index 4288962ecef0..b794953c5c23 100644
|
||||
--- a/third_party/zlib/contrib/minizip/minizip.c
|
||||
+++ b/third_party/zlib/contrib/minizip/minizip.c
|
||||
@@ -12,8 +12,7 @@
|
||||
Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
|
||||
*/
|
||||
|
||||
-
|
||||
-#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__))
|
||||
+#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__)) && (!defined(__ANDROID_API__))
|
||||
#ifndef __USE_FILE_OFFSET64
|
||||
#define __USE_FILE_OFFSET64
|
||||
#endif
|
||||
@@ -28,7 +27,7 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
-#ifdef __APPLE__
|
||||
+#if defined(__APPLE__) || defined(__Fuchsia__) || defined(__ANDROID_API__)
|
||||
// In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions
|
||||
#define FOPEN_FUNC(filename, mode) fopen(filename, mode)
|
||||
#define FTELLO_FUNC(stream) ftello(stream)
|
||||
@@ -94,7 +93,7 @@ uLong filetime(f, tmzip, dt)
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
-#ifdef unix || __APPLE__
|
||||
+#if defined(unix) || defined(__APPLE__) || defined(__Fuchsia__) || defined(__ANDROID_API__)
|
||||
uLong filetime(f, tmzip, dt)
|
||||
char *f; /* name of file to get info on */
|
||||
tm_zip *tmzip; /* return value: access, modific. and creation times */
|
||||
--
|
||||
2.31.1.818.g46aad6cb9e-goog
|
||||
|
24
deps/zlib/patches/0009-infcover-oob.patch
vendored
Normal file
24
deps/zlib/patches/0009-infcover-oob.patch
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
From 75690b2683667be5535ac6243438115dc9c40f6a Mon Sep 17 00:00:00 2001
|
||||
From: Florian Mayer <fmayer@google.com>
|
||||
Date: Wed, 16 Mar 2022 16:38:36 -0700
|
||||
Subject: [PATCH] Fix out of bounds in infcover.c.
|
||||
|
||||
---
|
||||
test/infcover.c | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/test/infcover.c b/test/infcover.c
|
||||
index 2be01646c..a6d83693c 100644
|
||||
--- a/test/infcover.c
|
||||
+++ b/test/infcover.c
|
||||
@@ -373,7 +373,9 @@ local void cover_support(void)
|
||||
mem_setup(&strm);
|
||||
strm.avail_in = 0;
|
||||
strm.next_in = Z_NULL;
|
||||
- ret = inflateInit_(&strm, ZLIB_VERSION - 1, (int)sizeof(z_stream));
|
||||
+ char versioncpy[] = ZLIB_VERSION;
|
||||
+ versioncpy[0] -= 1;
|
||||
+ ret = inflateInit_(&strm, versioncpy, (int)sizeof(z_stream));
|
||||
assert(ret == Z_VERSION_ERROR);
|
||||
mem_done(&strm, "wrong version");
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user