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