Coverage Report

Created: 2025-07-23 08:18

/src/libheif/libheif/compression_zlib.cc
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * HEIF codec.
3
 * Copyright (c) 2022 Dirk Farin <dirk.farin@gmail.com>
4
 *
5
 * This file is part of libheif.
6
 *
7
 * libheif is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU Lesser General Public License as
9
 * published by the Free Software Foundation, either version 3 of
10
 * the License, or (at your option) any later version.
11
 *
12
 * libheif is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public License
18
 * along with libheif.  If not, see <http://www.gnu.org/licenses/>.
19
 */
20
21
22
#include "compression.h"
23
24
25
#if HAVE_ZLIB
26
27
#include <zlib.h>
28
#include <cstring>
29
#include <iostream>
30
31
std::vector<uint8_t> compress(const uint8_t* input, size_t size, int windowSize)
32
0
{
33
0
  std::vector<uint8_t> output;
34
35
  // initialize compressor
36
37
0
  const int outBufferSize = 8192;
38
0
  uint8_t dst[outBufferSize];
39
40
0
  z_stream strm;
41
0
  memset(&strm, 0, sizeof(z_stream));
42
43
0
  strm.avail_in = (uInt)size;
44
0
  strm.next_in = (Bytef*)input;
45
46
0
  strm.avail_out = outBufferSize;
47
0
  strm.next_out = (Bytef*) dst;
48
49
0
  strm.zalloc = Z_NULL;
50
0
  strm.zfree = Z_NULL;
51
0
  strm.opaque = Z_NULL;
52
53
0
  int err = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, windowSize, 8, Z_DEFAULT_STRATEGY);
54
0
  if (err != Z_OK) {
55
0
    return {}; // TODO: return error
56
0
  }
57
58
0
  do {
59
0
    strm.next_out = dst;
60
0
    strm.avail_out = outBufferSize;
61
62
0
    err = deflate(&strm, Z_FINISH);
63
0
    if (err == Z_BUF_ERROR || err == Z_OK) {
64
      // this is the usual case when we run out of buffer space
65
      // -> do nothing
66
0
    }
67
0
    else if (err == Z_STREAM_ERROR) {
68
0
      return {}; // TODO: return error
69
0
    }
70
71
72
    // append decoded data to output
73
74
0
    output.insert(output.end(), dst, dst + outBufferSize - strm.avail_out);
75
0
  } while (err != Z_STREAM_END);
76
77
0
  deflateEnd(&strm);
78
79
0
  return output;
80
0
}
81
82
83
Result<std::vector<uint8_t>> do_inflate(const std::vector<uint8_t>& compressed_input, int windowSize)
84
0
{
85
0
  std::vector<uint8_t> output;
86
87
  // decompress data with zlib
88
89
0
  const int outBufferSize = 8192;
90
0
  uint8_t dst[outBufferSize];
91
92
0
  z_stream strm;
93
0
  memset(&strm, 0, sizeof(z_stream));
94
95
0
  strm.avail_in = (int)compressed_input.size();
96
0
  strm.next_in = (Bytef*) compressed_input.data();
97
98
0
  strm.avail_out = outBufferSize;
99
0
  strm.next_out = (Bytef*) dst;
100
101
0
  strm.zalloc = Z_NULL;
102
0
  strm.zfree = Z_NULL;
103
0
  strm.opaque = Z_NULL;
104
105
0
  int err = -1;
106
107
0
  err = inflateInit2(&strm, windowSize);
108
0
  if (err != Z_OK) {
109
0
    std::stringstream sstr;
110
0
    sstr << "Error initialising zlib inflate: " << (strm.msg ? strm.msg : "NULL") << " (" << err << ")\n";
111
0
    return Error(heif_error_Memory_allocation_error, heif_suberror_Compression_initialisation_error, sstr.str());
112
0
  }
113
114
0
  do {
115
0
    strm.next_out = dst;
116
0
    strm.avail_out = outBufferSize;
117
118
0
    err = inflate(&strm, Z_FINISH);
119
0
    if (err == Z_BUF_ERROR || err == Z_OK) {
120
      // this is the usual case when we run out of buffer space
121
      // -> do nothing
122
0
    }
123
0
    else if (err == Z_NEED_DICT || err == Z_DATA_ERROR || err == Z_STREAM_ERROR) {
124
0
      inflateEnd(&strm);
125
0
      std::stringstream sstr;
126
0
      sstr << "Error performing zlib inflate: " << (strm.msg ? strm.msg : "NULL") << " (" << err << ")\n";
127
0
      return Error(heif_error_Invalid_input, heif_suberror_Decompression_invalid_data, sstr.str());
128
0
    }
129
130
    // append decoded data to output
131
0
    output.insert(output.end(), dst, dst + outBufferSize - strm.avail_out);
132
0
  } while (err != Z_STREAM_END);
133
134
135
0
  inflateEnd(&strm);
136
137
0
  return output;
138
0
}
139
140
std::vector<uint8_t> compress_zlib(const uint8_t* input, size_t size)
141
0
{
142
0
  return compress(input, size, 15);
143
0
}
144
145
std::vector<uint8_t> compress_deflate(const uint8_t* input, size_t size)
146
0
{
147
0
  return compress(input, size, -15);
148
0
}
149
150
151
Result<std::vector<uint8_t>> decompress_zlib(const std::vector<uint8_t>& compressed_input)
152
0
{
153
0
  return do_inflate(compressed_input, 15);
154
0
}
155
156
Result<std::vector<uint8_t>> decompress_deflate(const std::vector<uint8_t>& compressed_input)
157
0
{
158
0
  return do_inflate(compressed_input, -15);
159
0
}
160
#endif