diff options
author | Adenilson Cavalcanti <adenilson.cavalcanti@arm.com> | 2019-08-09 19:12:20 +0000 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2019-08-09 19:12:20 +0000 |
commit | ddd7b06cf8c34e638643f7ce888bfc7c56e96933 (patch) | |
tree | 12f054245af4fe0c957d5f1272a9692c8fbd51dd | |
parent | 0f820c1d7165ba79e0429eab8b55c76f2be7d440 (diff) | |
download | zlib-ddd7b06cf8c34e638643f7ce888bfc7c56e96933.tar.gz |
Insulate portable GZipHelpers code
The helpers are portable code and don't depend on 'base' code,
this fixes a layer violation.
Another advantage is to make it easier to deploy Chromium's zlib i.e.
no need to write your own helpers.
Change-Id: I10a5452dd8835f1e1ec592d7c1c1cc3bb67f9e70
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1742295
Commit-Queue: Adenilson Cavalcanti <cavalcantii@chromium.org>
Reviewed-by: Chris Blume <cblume@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#685673}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: 3b866f5cefa5e4d12af1d565ea779e727e4feca6
-rw-r--r-- | google/BUILD.gn | 2 | ||||
-rw-r--r-- | google/compression_utils.cc | 177 | ||||
-rw-r--r-- | google/compression_utils_portable.cc | 146 | ||||
-rw-r--r-- | google/compression_utils_portable.h | 33 |
4 files changed, 203 insertions, 155 deletions
diff --git a/google/BUILD.gn b/google/BUILD.gn index efdcfe5..0dee214 100644 --- a/google/BUILD.gn +++ b/google/BUILD.gn @@ -26,6 +26,8 @@ if (build_with_chromium) { sources = [ "compression_utils.cc", "compression_utils.h", + "compression_utils_portable.cc", + "compression_utils_portable.h", ] deps = [ "//base", diff --git a/google/compression_utils.cc b/google/compression_utils.cc index a375054..6af42f3 100644 --- a/google/compression_utils.cc +++ b/google/compression_utils.cc @@ -4,147 +4,13 @@ #include "third_party/zlib/google/compression_utils.h" -#include <stddef.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> - #include "base/bit_cast.h" #include "base/logging.h" #include "base/process/memory.h" #include "base/strings/string_piece.h" #include "base/sys_byteorder.h" -#if defined(USE_SYSTEM_ZLIB) -#include <zlib.h> -#else -#include "third_party/zlib/zlib.h" -#endif - -namespace { - -// The difference in bytes between a zlib header and a gzip header. -const size_t kGzipZlibHeaderDifferenceBytes = 16; - -// Pass an integer greater than the following get a gzip header instead of a -// zlib header when calling deflateInit2() and inflateInit2(). -const int kWindowBitsToGetGzipHeader = 16; - -// This describes the amount of memory zlib uses to compress data. It can go -// from 1 to 9, with 8 being the default. For details, see: -// http://www.zlib.net/manual.html (search for memLevel). -const int kZlibMemoryLevel = 8; - -// This code is taken almost verbatim from third_party/zlib/compress.c. The only -// difference is deflateInit2() is called which sets the window bits to be > 16. -// That causes a gzip header to be emitted rather than a zlib header. -int GzipCompressHelper(Bytef* dest, - uLongf* dest_length, - const Bytef* source, - uLong source_length, - void* (*malloc_fn)(size_t), - void (*free_fn)(void*)) { - z_stream stream; - - stream.next_in = bit_cast<Bytef*>(source); - stream.avail_in = static_cast<uInt>(source_length); - stream.next_out = dest; - stream.avail_out = static_cast<uInt>(*dest_length); - if (static_cast<uLong>(stream.avail_out) != *dest_length) - return Z_BUF_ERROR; - - // Cannot convert capturing lambdas to function pointers directly, hence the - // structure. - struct MallocFreeFunctions { - void* (*malloc_fn)(size_t); - void (*free_fn)(void*); - } malloc_free = {malloc_fn, free_fn}; - - if (malloc_fn) { - DCHECK(free_fn); - auto zalloc = [](void* opaque, uInt items, uInt size) { - return reinterpret_cast<MallocFreeFunctions*>(opaque)->malloc_fn(items * - size); - }; - auto zfree = [](void* opaque, void* address) { - return reinterpret_cast<MallocFreeFunctions*>(opaque)->free_fn(address); - }; - - stream.zalloc = static_cast<alloc_func>(zalloc); - stream.zfree = static_cast<free_func>(zfree); - stream.opaque = static_cast<voidpf>(&malloc_free); - } else { - stream.zalloc = static_cast<alloc_func>(0); - stream.zfree = static_cast<free_func>(0); - stream.opaque = static_cast<voidpf>(0); - } - - gz_header gzip_header; - memset(&gzip_header, 0, sizeof(gzip_header)); - int err = deflateInit2(&stream, - Z_DEFAULT_COMPRESSION, - Z_DEFLATED, - MAX_WBITS + kWindowBitsToGetGzipHeader, - kZlibMemoryLevel, - Z_DEFAULT_STRATEGY); - if (err != Z_OK) - return err; - - err = deflateSetHeader(&stream, &gzip_header); - if (err != Z_OK) - return err; - - err = deflate(&stream, Z_FINISH); - if (err != Z_STREAM_END) { - deflateEnd(&stream); - return err == Z_OK ? Z_BUF_ERROR : err; - } - *dest_length = stream.total_out; - - err = deflateEnd(&stream); - return err; -} - -// This code is taken almost verbatim from third_party/zlib/uncompr.c. The only -// difference is inflateInit2() is called which sets the window bits to be > 16. -// That causes a gzip header to be parsed rather than a zlib header. -int GzipUncompressHelper(Bytef* dest, - uLongf* dest_length, - const Bytef* source, - uLong source_length) { - z_stream stream; - - stream.next_in = bit_cast<Bytef*>(source); - stream.avail_in = static_cast<uInt>(source_length); - if (static_cast<uLong>(stream.avail_in) != source_length) - return Z_BUF_ERROR; - - stream.next_out = dest; - stream.avail_out = static_cast<uInt>(*dest_length); - if (static_cast<uLong>(stream.avail_out) != *dest_length) - return Z_BUF_ERROR; - - stream.zalloc = static_cast<alloc_func>(0); - stream.zfree = static_cast<free_func>(0); - - int err = inflateInit2(&stream, MAX_WBITS + kWindowBitsToGetGzipHeader); - if (err != Z_OK) - return err; - - err = inflate(&stream, Z_FINISH); - if (err != Z_STREAM_END) { - inflateEnd(&stream); - if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) - return Z_DATA_ERROR; - return err; - } - *dest_length = stream.total_out; - - err = inflateEnd(&stream); - return err; -} - -} // namespace +#include "third_party/zlib/google/compression_utils_portable.h" namespace compression { @@ -158,10 +24,10 @@ bool GzipCompress(base::StringPiece input, // uLongf can be larger than size_t. uLongf compressed_size_long = static_cast<uLongf>(output_buffer_size); - if (GzipCompressHelper(bit_cast<Bytef*>(output_buffer), &compressed_size_long, - bit_cast<const Bytef*>(input.data()), - static_cast<uLongf>(input.size()), malloc_fn, - free_fn) != Z_OK) { + if (zlib_internal::GzipCompressHelper( + bit_cast<Bytef*>(output_buffer), &compressed_size_long, + bit_cast<const Bytef*>(input.data()), + static_cast<uLongf>(input.size()), malloc_fn, free_fn) != Z_OK) { return false; } // No overflow, as compressed_size_long <= output.size() which is a size_t. @@ -176,16 +42,17 @@ bool GzipCompress(base::StringPiece input, std::string* output) { const uLongf input_size = static_cast<uLongf>(input.size()); uLongf compressed_data_size = - kGzipZlibHeaderDifferenceBytes + compressBound(input_size); + zlib_internal::GZipExpectedCompressedSize(input_size); + Bytef* compressed_data; if (!base::UncheckedMalloc(compressed_data_size, reinterpret_cast<void**>(&compressed_data))) { return false; } - if (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, + bit_cast<const Bytef*>(input.data()), + input_size, nullptr, nullptr) != Z_OK) { free(compressed_data); return false; } @@ -210,10 +77,10 @@ bool GzipUncompress(const std::string& input, std::string* output) { return false; uncompressed_output.resize(uncompressed_size); - if (GzipUncompressHelper(bit_cast<Bytef*>(uncompressed_output.data()), - &uncompressed_size, - bit_cast<const Bytef*>(input.data()), - static_cast<uLongf>(input.length())) == Z_OK) { + if (zlib_internal::GzipUncompressHelper( + bit_cast<Bytef*>(uncompressed_output.data()), &uncompressed_size, + bit_cast<const Bytef*>(input.data()), + static_cast<uLongf>(input.length())) == Z_OK) { output->swap(uncompressed_output); return true; } @@ -224,10 +91,10 @@ bool GzipUncompress(base::StringPiece input, base::StringPiece output) { uLongf uncompressed_size = GetUncompressedSize(input); if (uncompressed_size > output.size()) return false; - return GzipUncompressHelper(bit_cast<Bytef*>(output.data()), - &uncompressed_size, - bit_cast<const Bytef*>(input.data()), - static_cast<uLongf>(input.length())) == Z_OK; + return zlib_internal::GzipUncompressHelper( + bit_cast<Bytef*>(output.data()), &uncompressed_size, + bit_cast<const Bytef*>(input.data()), + static_cast<uLongf>(input.length())) == Z_OK; } bool GzipUncompress(base::StringPiece input, std::string* output) { @@ -235,10 +102,10 @@ bool GzipUncompress(base::StringPiece input, std::string* output) { DCHECK_NE(input.data(), output->data()); uLongf uncompressed_size = GetUncompressedSize(input); output->resize(uncompressed_size); - return GzipUncompressHelper(bit_cast<Bytef*>(output->data()), - &uncompressed_size, - bit_cast<const Bytef*>(input.data()), - static_cast<uLongf>(input.length())) == Z_OK; + return zlib_internal::GzipUncompressHelper( + bit_cast<Bytef*>(output->data()), &uncompressed_size, + bit_cast<const Bytef*>(input.data()), + static_cast<uLongf>(input.length())) == Z_OK; } uint32_t GetUncompressedSize(base::StringPiece compressed_data) { diff --git a/google/compression_utils_portable.cc b/google/compression_utils_portable.cc new file mode 100644 index 0000000..686b657 --- /dev/null +++ b/google/compression_utils_portable.cc @@ -0,0 +1,146 @@ +/* compression_utils_portable.cc + * + * Copyright 2019 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 "third_party/zlib/google/compression_utils_portable.h" + +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +namespace zlib_internal { + +// The difference in bytes between a zlib header and a gzip header. +const size_t kGzipZlibHeaderDifferenceBytes = 16; + +// Pass an integer greater than the following get a gzip header instead of a +// zlib header when calling deflateInit2() and inflateInit2(). +const int kWindowBitsToGetGzipHeader = 16; + +// This describes the amount of memory zlib uses to compress data. It can go +// from 1 to 9, with 8 being the default. For details, see: +// http://www.zlib.net/manual.html (search for memLevel). +const int kZlibMemoryLevel = 8; + +// The expected compressed size is based on the input size factored by +// internal Zlib constants (e.g. window size, etc) plus the wrapper +// header size. +uLongf GZipExpectedCompressedSize(uLongf input_size) { + return kGzipZlibHeaderDifferenceBytes + compressBound(input_size); +} + +// This code is taken almost verbatim from third_party/zlib/compress.c. The only +// difference is deflateInit2() is called which sets the window bits to be > 16. +// That causes a gzip header to be emitted rather than a zlib header. +int GzipCompressHelper(Bytef* dest, + uLongf* dest_length, + const Bytef* source, + uLong source_length, + void* (*malloc_fn)(size_t), + void (*free_fn)(void*)) { + z_stream stream; + + // FIXME(cavalcantii): z_const is not defined as 'const'. + stream.next_in = static_cast<z_const Bytef*>(const_cast<Bytef*>(source)); + stream.avail_in = static_cast<uInt>(source_length); + stream.next_out = dest; + stream.avail_out = static_cast<uInt>(*dest_length); + if (static_cast<uLong>(stream.avail_out) != *dest_length) + return Z_BUF_ERROR; + + // Cannot convert capturing lambdas to function pointers directly, hence the + // structure. + struct MallocFreeFunctions { + void* (*malloc_fn)(size_t); + void (*free_fn)(void*); + } malloc_free = {malloc_fn, free_fn}; + + if (malloc_fn) { + if (!free_fn) + return Z_BUF_ERROR; + + auto zalloc = [](void* opaque, uInt items, uInt size) { + return reinterpret_cast<MallocFreeFunctions*>(opaque)->malloc_fn(items * + size); + }; + auto zfree = [](void* opaque, void* address) { + return reinterpret_cast<MallocFreeFunctions*>(opaque)->free_fn(address); + }; + + stream.zalloc = static_cast<alloc_func>(zalloc); + stream.zfree = static_cast<free_func>(zfree); + stream.opaque = static_cast<voidpf>(&malloc_free); + } else { + stream.zalloc = static_cast<alloc_func>(0); + stream.zfree = static_cast<free_func>(0); + stream.opaque = static_cast<voidpf>(0); + } + + gz_header gzip_header; + memset(&gzip_header, 0, sizeof(gzip_header)); + int err = deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, + MAX_WBITS + kWindowBitsToGetGzipHeader, + kZlibMemoryLevel, Z_DEFAULT_STRATEGY); + if (err != Z_OK) + return err; + + err = deflateSetHeader(&stream, &gzip_header); + if (err != Z_OK) + return err; + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *dest_length = stream.total_out; + + err = deflateEnd(&stream); + return err; +} + +// This code is taken almost verbatim from third_party/zlib/uncompr.c. The only +// difference is inflateInit2() is called which sets the window bits to be > 16. +// That causes a gzip header to be parsed rather than a zlib header. +int GzipUncompressHelper(Bytef* dest, + uLongf* dest_length, + const Bytef* source, + uLong source_length) { + z_stream stream; + + // FIXME(cavalcantii): z_const is not defined as 'const'. + stream.next_in = static_cast<z_const Bytef*>(const_cast<Bytef*>(source)); + stream.avail_in = static_cast<uInt>(source_length); + if (static_cast<uLong>(stream.avail_in) != source_length) + return Z_BUF_ERROR; + + stream.next_out = dest; + stream.avail_out = static_cast<uInt>(*dest_length); + if (static_cast<uLong>(stream.avail_out) != *dest_length) + return Z_BUF_ERROR; + + stream.zalloc = static_cast<alloc_func>(0); + stream.zfree = static_cast<free_func>(0); + + int err = inflateInit2(&stream, MAX_WBITS + kWindowBitsToGetGzipHeader); + if (err != Z_OK) + return err; + + err = inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + inflateEnd(&stream); + if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) + return Z_DATA_ERROR; + return err; + } + *dest_length = stream.total_out; + + err = inflateEnd(&stream); + return err; +} + +} // namespace zlib_internal diff --git a/google/compression_utils_portable.h b/google/compression_utils_portable.h new file mode 100644 index 0000000..5c07521 --- /dev/null +++ b/google/compression_utils_portable.h @@ -0,0 +1,33 @@ +/* compression_utils_portable.h + * + * Copyright 2019 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 THIRD_PARTY_ZLIB_GOOGLE_COMPRESSION_UTILS_PORTABLE_H_ +#define THIRD_PARTY_ZLIB_GOOGLE_COMPRESSION_UTILS_PORTABLE_H_ + +#if defined(USE_SYSTEM_ZLIB) +#include <zlib.h> +#else +#include "third_party/zlib/zlib.h" +#endif + +namespace zlib_internal { + +uLongf GZipExpectedCompressedSize(uLongf input_size); + +int GzipCompressHelper(Bytef* dest, + uLongf* dest_length, + const Bytef* source, + uLong source_length, + void* (*malloc_fn)(size_t), + void (*free_fn)(void*)); + +int GzipUncompressHelper(Bytef* dest, + uLongf* dest_length, + const Bytef* source, + uLong source_length); +} // namespace zlib_internal + +#endif // THIRD_PARTY_ZLIB_GOOGLE_COMPRESSION_UTILS_PORTABLE_H_ |