11cb0ef41Sopenharmony_ci/* compression_utils_portable.cc 21cb0ef41Sopenharmony_ci * 31cb0ef41Sopenharmony_ci * Copyright 2019 The Chromium Authors 41cb0ef41Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 51cb0ef41Sopenharmony_ci * found in the Chromium source repository LICENSE file. 61cb0ef41Sopenharmony_ci */ 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_ci#include "compression_utils_portable.h" 91cb0ef41Sopenharmony_ci 101cb0ef41Sopenharmony_ci#include <stddef.h> 111cb0ef41Sopenharmony_ci#include <stdlib.h> 121cb0ef41Sopenharmony_ci#include <string.h> 131cb0ef41Sopenharmony_ci 141cb0ef41Sopenharmony_cinamespace zlib_internal { 151cb0ef41Sopenharmony_ci 161cb0ef41Sopenharmony_ci// The difference in bytes between a zlib header and a gzip header. 171cb0ef41Sopenharmony_ciconst size_t kGzipZlibHeaderDifferenceBytes = 16; 181cb0ef41Sopenharmony_ci 191cb0ef41Sopenharmony_ci// Pass an integer greater than the following get a gzip header instead of a 201cb0ef41Sopenharmony_ci// zlib header when calling deflateInit2() and inflateInit2(). 211cb0ef41Sopenharmony_ciconst int kWindowBitsToGetGzipHeader = 16; 221cb0ef41Sopenharmony_ci 231cb0ef41Sopenharmony_ci// This describes the amount of memory zlib uses to compress data. It can go 241cb0ef41Sopenharmony_ci// from 1 to 9, with 8 being the default. For details, see: 251cb0ef41Sopenharmony_ci// http://www.zlib.net/manual.html (search for memLevel). 261cb0ef41Sopenharmony_ciconst int kZlibMemoryLevel = 8; 271cb0ef41Sopenharmony_ci 281cb0ef41Sopenharmony_ci// The expected compressed size is based on the input size factored by 291cb0ef41Sopenharmony_ci// internal Zlib constants (e.g. window size, etc) plus the wrapper 301cb0ef41Sopenharmony_ci// header size. 311cb0ef41Sopenharmony_ciuLongf GzipExpectedCompressedSize(uLongf input_size) { 321cb0ef41Sopenharmony_ci return kGzipZlibHeaderDifferenceBytes + compressBound(input_size); 331cb0ef41Sopenharmony_ci} 341cb0ef41Sopenharmony_ci 351cb0ef41Sopenharmony_ci// The expected decompressed size is stored in the last 361cb0ef41Sopenharmony_ci// 4 bytes of |input| in LE. See https://tools.ietf.org/html/rfc1952#page-5 371cb0ef41Sopenharmony_ciuint32_t GetGzipUncompressedSize(const Bytef* compressed_data, size_t length) { 381cb0ef41Sopenharmony_ci uint32_t size; 391cb0ef41Sopenharmony_ci if (length < sizeof(size)) 401cb0ef41Sopenharmony_ci return 0; 411cb0ef41Sopenharmony_ci 421cb0ef41Sopenharmony_ci memcpy(&size, &compressed_data[length - sizeof(size)], sizeof(size)); 431cb0ef41Sopenharmony_ci#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 441cb0ef41Sopenharmony_ci return size; 451cb0ef41Sopenharmony_ci#else 461cb0ef41Sopenharmony_ci return __builtin_bswap32(size); 471cb0ef41Sopenharmony_ci#endif 481cb0ef41Sopenharmony_ci} 491cb0ef41Sopenharmony_ci 501cb0ef41Sopenharmony_ci// The number of window bits determines the type of wrapper to use - see 511cb0ef41Sopenharmony_ci// https://cs.chromium.org/chromium/src/third_party/zlib/zlib.h?l=566 521cb0ef41Sopenharmony_ciinline int ZlibStreamWrapperType(WrapperType type) { 531cb0ef41Sopenharmony_ci if (type == ZLIB) // zlib DEFLATE stream wrapper 541cb0ef41Sopenharmony_ci return MAX_WBITS; 551cb0ef41Sopenharmony_ci if (type == GZIP) // gzip DEFLATE stream wrapper 561cb0ef41Sopenharmony_ci return MAX_WBITS + kWindowBitsToGetGzipHeader; 571cb0ef41Sopenharmony_ci if (type == ZRAW) // no wrapper, use raw DEFLATE 581cb0ef41Sopenharmony_ci return -MAX_WBITS; 591cb0ef41Sopenharmony_ci return 0; 601cb0ef41Sopenharmony_ci} 611cb0ef41Sopenharmony_ci 621cb0ef41Sopenharmony_ciint GzipCompressHelper(Bytef* dest, 631cb0ef41Sopenharmony_ci uLongf* dest_length, 641cb0ef41Sopenharmony_ci const Bytef* source, 651cb0ef41Sopenharmony_ci uLong source_length, 661cb0ef41Sopenharmony_ci void* (*malloc_fn)(size_t), 671cb0ef41Sopenharmony_ci void (*free_fn)(void*)) { 681cb0ef41Sopenharmony_ci return CompressHelper(GZIP, dest, dest_length, source, source_length, 691cb0ef41Sopenharmony_ci Z_DEFAULT_COMPRESSION, malloc_fn, free_fn); 701cb0ef41Sopenharmony_ci} 711cb0ef41Sopenharmony_ci 721cb0ef41Sopenharmony_ci// This code is taken almost verbatim from third_party/zlib/compress.c. The only 731cb0ef41Sopenharmony_ci// difference is deflateInit2() is called which allows different window bits to 741cb0ef41Sopenharmony_ci// be set. > 16 causes a gzip header to be emitted rather than a zlib header, 751cb0ef41Sopenharmony_ci// and negative causes no header to emitted. 761cb0ef41Sopenharmony_ci// 771cb0ef41Sopenharmony_ci// Compression level can be a number from 1-9, with 1 being the fastest, 9 being 781cb0ef41Sopenharmony_ci// the best compression. The default, which the GZIP helper uses, is 6. 791cb0ef41Sopenharmony_ciint CompressHelper(WrapperType wrapper_type, 801cb0ef41Sopenharmony_ci Bytef* dest, 811cb0ef41Sopenharmony_ci uLongf* dest_length, 821cb0ef41Sopenharmony_ci const Bytef* source, 831cb0ef41Sopenharmony_ci uLong source_length, 841cb0ef41Sopenharmony_ci int compression_level, 851cb0ef41Sopenharmony_ci void* (*malloc_fn)(size_t), 861cb0ef41Sopenharmony_ci void (*free_fn)(void*)) { 871cb0ef41Sopenharmony_ci if (compression_level < 0 || compression_level > 9) { 881cb0ef41Sopenharmony_ci compression_level = Z_DEFAULT_COMPRESSION; 891cb0ef41Sopenharmony_ci } 901cb0ef41Sopenharmony_ci 911cb0ef41Sopenharmony_ci z_stream stream; 921cb0ef41Sopenharmony_ci 931cb0ef41Sopenharmony_ci // FIXME(cavalcantii): z_const is not defined as 'const'. 941cb0ef41Sopenharmony_ci stream.next_in = static_cast<z_const Bytef*>(const_cast<Bytef*>(source)); 951cb0ef41Sopenharmony_ci stream.avail_in = static_cast<uInt>(source_length); 961cb0ef41Sopenharmony_ci stream.next_out = dest; 971cb0ef41Sopenharmony_ci stream.avail_out = static_cast<uInt>(*dest_length); 981cb0ef41Sopenharmony_ci if (static_cast<uLong>(stream.avail_out) != *dest_length) 991cb0ef41Sopenharmony_ci return Z_BUF_ERROR; 1001cb0ef41Sopenharmony_ci 1011cb0ef41Sopenharmony_ci // Cannot convert capturing lambdas to function pointers directly, hence the 1021cb0ef41Sopenharmony_ci // structure. 1031cb0ef41Sopenharmony_ci struct MallocFreeFunctions { 1041cb0ef41Sopenharmony_ci void* (*malloc_fn)(size_t); 1051cb0ef41Sopenharmony_ci void (*free_fn)(void*); 1061cb0ef41Sopenharmony_ci } malloc_free = {malloc_fn, free_fn}; 1071cb0ef41Sopenharmony_ci 1081cb0ef41Sopenharmony_ci if (malloc_fn) { 1091cb0ef41Sopenharmony_ci if (!free_fn) 1101cb0ef41Sopenharmony_ci return Z_BUF_ERROR; 1111cb0ef41Sopenharmony_ci 1121cb0ef41Sopenharmony_ci auto zalloc = [](void* opaque, uInt items, uInt size) { 1131cb0ef41Sopenharmony_ci return reinterpret_cast<MallocFreeFunctions*>(opaque)->malloc_fn(items * 1141cb0ef41Sopenharmony_ci size); 1151cb0ef41Sopenharmony_ci }; 1161cb0ef41Sopenharmony_ci auto zfree = [](void* opaque, void* address) { 1171cb0ef41Sopenharmony_ci return reinterpret_cast<MallocFreeFunctions*>(opaque)->free_fn(address); 1181cb0ef41Sopenharmony_ci }; 1191cb0ef41Sopenharmony_ci 1201cb0ef41Sopenharmony_ci stream.zalloc = static_cast<alloc_func>(zalloc); 1211cb0ef41Sopenharmony_ci stream.zfree = static_cast<free_func>(zfree); 1221cb0ef41Sopenharmony_ci stream.opaque = static_cast<voidpf>(&malloc_free); 1231cb0ef41Sopenharmony_ci } else { 1241cb0ef41Sopenharmony_ci stream.zalloc = static_cast<alloc_func>(0); 1251cb0ef41Sopenharmony_ci stream.zfree = static_cast<free_func>(0); 1261cb0ef41Sopenharmony_ci stream.opaque = static_cast<voidpf>(0); 1271cb0ef41Sopenharmony_ci } 1281cb0ef41Sopenharmony_ci 1291cb0ef41Sopenharmony_ci int err = deflateInit2(&stream, compression_level, Z_DEFLATED, 1301cb0ef41Sopenharmony_ci ZlibStreamWrapperType(wrapper_type), kZlibMemoryLevel, 1311cb0ef41Sopenharmony_ci Z_DEFAULT_STRATEGY); 1321cb0ef41Sopenharmony_ci if (err != Z_OK) 1331cb0ef41Sopenharmony_ci return err; 1341cb0ef41Sopenharmony_ci 1351cb0ef41Sopenharmony_ci // This has to exist outside of the if statement to prevent it going off the 1361cb0ef41Sopenharmony_ci // stack before deflate(), which will use this object. 1371cb0ef41Sopenharmony_ci gz_header gzip_header; 1381cb0ef41Sopenharmony_ci if (wrapper_type == GZIP) { 1391cb0ef41Sopenharmony_ci memset(&gzip_header, 0, sizeof(gzip_header)); 1401cb0ef41Sopenharmony_ci err = deflateSetHeader(&stream, &gzip_header); 1411cb0ef41Sopenharmony_ci if (err != Z_OK) 1421cb0ef41Sopenharmony_ci return err; 1431cb0ef41Sopenharmony_ci } 1441cb0ef41Sopenharmony_ci 1451cb0ef41Sopenharmony_ci err = deflate(&stream, Z_FINISH); 1461cb0ef41Sopenharmony_ci if (err != Z_STREAM_END) { 1471cb0ef41Sopenharmony_ci deflateEnd(&stream); 1481cb0ef41Sopenharmony_ci return err == Z_OK ? Z_BUF_ERROR : err; 1491cb0ef41Sopenharmony_ci } 1501cb0ef41Sopenharmony_ci *dest_length = stream.total_out; 1511cb0ef41Sopenharmony_ci 1521cb0ef41Sopenharmony_ci err = deflateEnd(&stream); 1531cb0ef41Sopenharmony_ci return err; 1541cb0ef41Sopenharmony_ci} 1551cb0ef41Sopenharmony_ci 1561cb0ef41Sopenharmony_ciint GzipUncompressHelper(Bytef* dest, 1571cb0ef41Sopenharmony_ci uLongf* dest_length, 1581cb0ef41Sopenharmony_ci const Bytef* source, 1591cb0ef41Sopenharmony_ci uLong source_length) { 1601cb0ef41Sopenharmony_ci return UncompressHelper(GZIP, dest, dest_length, source, source_length); 1611cb0ef41Sopenharmony_ci} 1621cb0ef41Sopenharmony_ci 1631cb0ef41Sopenharmony_ci// This code is taken almost verbatim from third_party/zlib/uncompr.c. The only 1641cb0ef41Sopenharmony_ci// difference is inflateInit2() is called which allows different window bits to 1651cb0ef41Sopenharmony_ci// be set. > 16 causes a gzip header to be emitted rather than a zlib header, 1661cb0ef41Sopenharmony_ci// and negative causes no header to emitted. 1671cb0ef41Sopenharmony_ciint UncompressHelper(WrapperType wrapper_type, 1681cb0ef41Sopenharmony_ci Bytef* dest, 1691cb0ef41Sopenharmony_ci uLongf* dest_length, 1701cb0ef41Sopenharmony_ci const Bytef* source, 1711cb0ef41Sopenharmony_ci uLong source_length) { 1721cb0ef41Sopenharmony_ci z_stream stream; 1731cb0ef41Sopenharmony_ci 1741cb0ef41Sopenharmony_ci // FIXME(cavalcantii): z_const is not defined as 'const'. 1751cb0ef41Sopenharmony_ci stream.next_in = static_cast<z_const Bytef*>(const_cast<Bytef*>(source)); 1761cb0ef41Sopenharmony_ci stream.avail_in = static_cast<uInt>(source_length); 1771cb0ef41Sopenharmony_ci if (static_cast<uLong>(stream.avail_in) != source_length) 1781cb0ef41Sopenharmony_ci return Z_BUF_ERROR; 1791cb0ef41Sopenharmony_ci 1801cb0ef41Sopenharmony_ci stream.next_out = dest; 1811cb0ef41Sopenharmony_ci stream.avail_out = static_cast<uInt>(*dest_length); 1821cb0ef41Sopenharmony_ci if (static_cast<uLong>(stream.avail_out) != *dest_length) 1831cb0ef41Sopenharmony_ci return Z_BUF_ERROR; 1841cb0ef41Sopenharmony_ci 1851cb0ef41Sopenharmony_ci stream.zalloc = static_cast<alloc_func>(0); 1861cb0ef41Sopenharmony_ci stream.zfree = static_cast<free_func>(0); 1871cb0ef41Sopenharmony_ci 1881cb0ef41Sopenharmony_ci int err = inflateInit2(&stream, ZlibStreamWrapperType(wrapper_type)); 1891cb0ef41Sopenharmony_ci if (err != Z_OK) 1901cb0ef41Sopenharmony_ci return err; 1911cb0ef41Sopenharmony_ci 1921cb0ef41Sopenharmony_ci err = inflate(&stream, Z_FINISH); 1931cb0ef41Sopenharmony_ci if (err != Z_STREAM_END) { 1941cb0ef41Sopenharmony_ci inflateEnd(&stream); 1951cb0ef41Sopenharmony_ci if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) 1961cb0ef41Sopenharmony_ci return Z_DATA_ERROR; 1971cb0ef41Sopenharmony_ci return err; 1981cb0ef41Sopenharmony_ci } 1991cb0ef41Sopenharmony_ci *dest_length = stream.total_out; 2001cb0ef41Sopenharmony_ci 2011cb0ef41Sopenharmony_ci err = inflateEnd(&stream); 2021cb0ef41Sopenharmony_ci return err; 2031cb0ef41Sopenharmony_ci} 2041cb0ef41Sopenharmony_ci 2051cb0ef41Sopenharmony_ci} // namespace zlib_internal 206