Coverage Report

Created: 2026-09-14 07:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libheif/libheif/file.h
Line
Count
Source
1
/*
2
 * HEIF codec.
3
 * Copyright (c) 2017 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
#ifndef LIBHEIF_FILE_H
22
#define LIBHEIF_FILE_H
23
24
#include "box.h"
25
#include "id_creator.h"
26
#include "nclx.h"
27
#include "image-items/avif.h"
28
#include "image-items/hevc.h"
29
#include "image-items/vvc.h"
30
//#include "codecs/uncompressed/unc_boxes.h"
31
#include "file_layout.h"
32
33
#include <map>
34
#include <memory>
35
#include <string>
36
#include <map>
37
#include <vector>
38
#include <unordered_set>
39
#include <limits>
40
#include <utility>
41
#include "mdat_data.h"
42
43
#if ENABLE_PARALLEL_TILE_DECODING
44
45
#include <mutex>
46
47
#endif
48
49
50
class HeifPixelImage;
51
52
class Box_j2kH;
53
54
class Box_moov;
55
56
class Box_mvhd;
57
58
59
60
class HeifFile
61
{
62
public:
63
  HeifFile();
64
65
  ~HeifFile();
66
67
  // The limits will be shared from the HeifContext limits.
68
  // You have to make sure that the pointer points to a valid object as long as the HeifFile is used.
69
222k
  void set_security_limits(const heif_security_limits* limits) { m_limits = limits; }
70
71
74.2k
  const heif_security_limits* get_security_limits() const { return m_limits; }
72
73
  Error read(const std::shared_ptr<StreamReader>& reader);
74
75
  Error read_from_file(const char* input_filename);
76
77
  Error read_from_memory(const void* data, size_t size, bool copy);
78
79
  bool has_images() const;
80
81
68.9k
  bool has_sequences() const { return m_moov_box != nullptr; }
82
83
0
  std::shared_ptr<StreamReader> get_reader() { return m_input_stream; }
84
85
  void new_empty_file();
86
87
  void init_for_meta_item();
88
89
  void init_for_image();
90
91
  // Create the 'iprp'/'ipco'/'ipma' boxes if they do not exist yet. Unlike init_for_image(),
92
  // this does not turn the file into an image file (no 'pict' handler, no 'pitm').
93
  void init_for_item_properties();
94
95
  void init_for_sequence();
96
97
3.28k
  void set_hdlr_box(std::shared_ptr<Box_hdlr> box) { m_hdlr_box = std::move(box); }
98
99
  size_t append_mdat_data(const std::vector<uint8_t>& data);
100
101
  void derive_box_versions();
102
103
  void write(StreamWriter& writer);
104
105
0
  void set_write_mini_format(bool enable) { m_write_mini_format = enable; }
106
0
  bool get_write_mini_format() const { return m_write_mini_format; }
107
108
0
  int get_num_images() const { return static_cast<int>(m_infe_boxes.size()); }
109
110
86.9k
  heif_item_id get_primary_image_ID() const { return m_pitm_box ? m_pitm_box->get_item_ID() : 0; }
111
112
0
  size_t get_number_of_items() const { return m_infe_boxes.size(); }
113
114
  std::vector<heif_item_id> get_item_IDs() const;
115
116
  bool item_exists(heif_item_id ID) const;
117
118
  bool has_item_with_id(heif_item_id ID) const;
119
120
  uint32_t get_item_type_4cc(heif_item_id ID) const;
121
122
  std::string get_content_type(heif_item_id ID) const;
123
124
  std::string get_item_uri_type(heif_item_id ID) const;
125
126
  Result<std::vector<uint8_t>> get_uncompressed_item_data(heif_item_id ID) const;
127
128
  Error append_data_from_file_range(std::vector<uint8_t>& out_data, uint64_t offset, uint32_t size) const;
129
130
  Error append_data_from_iloc(heif_item_id ID, std::vector<uint8_t>& out_data, uint64_t offset, uint64_t size) const;
131
132
75.4k
  Error append_data_from_iloc(heif_item_id ID, std::vector<uint8_t>& out_data) const {
133
75.4k
    return append_data_from_iloc(ID, out_data, 0, std::numeric_limits<uint64_t>::max());
134
75.4k
  }
135
136
  // If `out_compression` is not NULL, the compression method is returned there and the compressed data is returned.
137
  // If `out_compression` is NULL, the data is returned decompressed.
138
  Result<std::vector<uint8_t>> get_item_data(heif_item_id ID, heif_metadata_compression* out_compression) const;
139
140
70.9k
  std::shared_ptr<Box_ftyp> get_ftyp_box() { return m_ftyp_box; }
141
142
3.28k
  void init_meta_box() { m_meta_box = std::make_shared<Box_meta>(); }
143
144
  std::shared_ptr<const Box_infe> get_infe_box(heif_item_id imageID) const;
145
146
  std::shared_ptr<Box_infe> get_infe_box(heif_item_id imageID);
147
148
  void set_iref_box(const std::shared_ptr<Box_iref>&);
149
150
163k
  std::shared_ptr<Box_iref> get_iref_box() { return m_iref_box; }
151
152
0
  std::shared_ptr<const Box_iref> get_iref_box() const { return m_iref_box; }
153
154
149k
  std::shared_ptr<Box_ipco> get_ipco_box() { return m_ipco_box; }
155
156
  void set_ipco_box(const std::shared_ptr<Box_ipco>&);
157
158
0
  std::shared_ptr<Box_ipco> get_ipco_box() const { return m_ipco_box; }
159
160
  void set_ipma_box(const std::shared_ptr<Box_ipma>&);
161
162
149k
  std::shared_ptr<Box_ipma> get_ipma_box() { return m_ipma_box; }
163
164
0
  std::shared_ptr<Box_ipma> get_ipma_box() const { return m_ipma_box; }
165
166
0
  std::shared_ptr<Box_grpl> get_grpl_box() const { return m_grpl_box; }
167
168
0
  std::shared_ptr<Box_meta> get_meta_box() const { return m_meta_box; }
169
170
  std::shared_ptr<Box_EntityToGroup> get_entity_group(heif_entity_group_id id);
171
172
  Error get_properties(heif_item_id imageID,
173
                       std::vector<std::shared_ptr<Box>>& properties) const;
174
175
  template<class BoxType>
176
  std::shared_ptr<BoxType> get_property_for_item(heif_item_id imageID) const
177
89.7k
  {
178
89.7k
    std::vector<std::shared_ptr<Box>> properties;
179
89.7k
    Error err = get_properties(imageID, properties);
180
89.7k
    if (err) {
181
0
      return nullptr;
182
0
    }
183
184
314k
    for (auto& property : properties) {
185
314k
      if (auto box = std::dynamic_pointer_cast<BoxType>(property)) {
186
4
        return box;
187
4
      }
188
314k
    }
189
190
89.7k
    return nullptr;
191
89.7k
  }
Unexecuted instantiation: std::__1::shared_ptr<Box_taic> HeifFile::get_property_for_item<Box_taic>(unsigned int) const
Unexecuted instantiation: std::__1::shared_ptr<Box_itai> HeifFile::get_property_for_item<Box_itai>(unsigned int) const
Unexecuted instantiation: std::__1::shared_ptr<Box_pixi> HeifFile::get_property_for_item<Box_pixi>(unsigned int) const
std::__1::shared_ptr<Box_rref> HeifFile::get_property_for_item<Box_rref>(unsigned int) const
Line
Count
Source
177
89.7k
  {
178
89.7k
    std::vector<std::shared_ptr<Box>> properties;
179
89.7k
    Error err = get_properties(imageID, properties);
180
89.7k
    if (err) {
181
0
      return nullptr;
182
0
    }
183
184
314k
    for (auto& property : properties) {
185
314k
      if (auto box = std::dynamic_pointer_cast<BoxType>(property)) {
186
4
        return box;
187
4
      }
188
314k
    }
189
190
89.7k
    return nullptr;
191
89.7k
  }
Unexecuted instantiation: std::__1::shared_ptr<Box_elng> HeifFile::get_property_for_item<Box_elng>(unsigned int) const
Unexecuted instantiation: std::__1::shared_ptr<Box_udes> HeifFile::get_property_for_item<Box_udes>(unsigned int) const
Unexecuted instantiation: std::__1::shared_ptr<Box_imir> HeifFile::get_property_for_item<Box_imir>(unsigned int) const
Unexecuted instantiation: std::__1::shared_ptr<Box_irot> HeifFile::get_property_for_item<Box_irot>(unsigned int) const
Unexecuted instantiation: std::__1::shared_ptr<Box_clap> HeifFile::get_property_for_item<Box_clap>(unsigned int) const
Unexecuted instantiation: std::__1::shared_ptr<Box_other> HeifFile::get_property_for_item<Box_other>(unsigned int) const
192
193
  std::string debug_dump_boxes() const;
194
195
  std::string debug_dump_item_data() const;
196
197
198
  // --- writing ---
199
200
0
  IDCreator& get_id_creator() { return m_id_creator; }
201
202
0
  const IDCreator& get_id_creator() const { return m_id_creator; }
203
204
  Result<heif_item_id> get_unused_item_id();
205
206
  Result<heif_item_id> add_new_image(uint32_t item_type);
207
208
  Result<std::shared_ptr<Box_infe>> add_new_infe_box(uint32_t item_type);
209
210
  Result<std::shared_ptr<Box_infe>> add_new_meta_infe_box(uint32_t item_type);
211
212
  Error add_ispe_property(heif_item_id id, uint32_t width, uint32_t height, bool essential);
213
214
  // set irot/imir according to heif_orientation
215
  Error add_orientation_properties(heif_item_id id, heif_orientation);
216
217
  // TODO: can we remove the 'essential' parameter and take this from the box? Or is that depending on the context?
218
  heif_property_id add_property(heif_item_id id, const std::shared_ptr<Box>& property, bool essential);
219
220
  heif_property_id add_property_without_deduplication(heif_item_id id, const std::shared_ptr<Box>& property, bool essential);
221
222
  Result<heif_item_id> add_infe(uint32_t item_type, const uint8_t* data, size_t size);
223
224
  void add_infe_box(heif_item_id, std::shared_ptr<Box_infe> infe);
225
226
  Result<heif_item_id> add_infe_mime(const char* content_type, heif_metadata_compression content_encoding, const uint8_t* data, size_t size);
227
228
  Result<heif_item_id> add_precompressed_infe_mime(const char* content_type, const std::string& content_encoding, const uint8_t* data, size_t size);
229
230
  Result<heif_item_id> add_infe_uri(const char* item_uri_type, const uint8_t* data, size_t size);
231
232
  Error set_item_data(const std::shared_ptr<Box_infe>& item, const uint8_t* data, size_t size, heif_metadata_compression compression);
233
234
  Error set_precompressed_item_data(const std::shared_ptr<Box_infe>& item, const uint8_t* data, size_t size, const std::string& content_encoding);
235
236
  void append_iloc_data(heif_item_id id, const std::vector<uint8_t>& nal_packets, uint8_t construction_method);
237
238
  void replace_iloc_data(heif_item_id id, uint64_t offset, const std::vector<uint8_t>& data, uint8_t construction_method = 0);
239
240
  void set_iloc_box(const std::shared_ptr<Box_iloc>&);
241
242
0
  std::shared_ptr<Box_iloc> get_iloc_box() { return m_iloc_box; }
243
244
  void set_primary_item_id(heif_item_id id);
245
246
  void add_iref_reference(heif_item_id from, uint32_t type,
247
                          const std::vector<heif_item_id>& to);
248
249
  void set_iref_reference(heif_item_id from, uint32_t type, int reference_idx, heif_item_id to_item);
250
251
  void add_entity_group_box(const std::shared_ptr<Box>& entity_group_box);
252
253
  Error set_auxC_property(heif_item_id id, const std::string& type);
254
255
#if defined(__MINGW32__) || defined(__MINGW64__) || defined(_MSC_VER)
256
  static std::wstring convert_utf8_path_to_utf16(std::string pathutf8);
257
#endif
258
259
260
  // --- sequences
261
262
516
  std::shared_ptr<Box_moov> get_moov_box() { return m_moov_box; }
263
264
75
  std::shared_ptr<Box_mvhd> get_mvhd_box() { return m_mvhd_box; }
265
266
private:
267
#if ENABLE_PARALLEL_TILE_DECODING
268
  mutable std::mutex m_read_mutex;
269
#endif
270
271
  std::shared_ptr<FileLayout> m_file_layout;
272
273
  std::shared_ptr<StreamReader> m_input_stream;
274
275
  std::vector<std::shared_ptr<Box> > m_top_level_boxes;
276
277
  std::shared_ptr<Box_ftyp> m_ftyp_box;
278
  std::shared_ptr<Box_hdlr> m_hdlr_box;
279
  std::shared_ptr<Box_meta> m_meta_box;
280
  std::shared_ptr<Box_mini> m_mini_box; // meta alternative
281
  bool m_write_mini_format = false;
282
283
  std::shared_ptr<Box_iloc> m_iloc_box;
284
  std::shared_ptr<Box_idat> m_idat_box;
285
  std::shared_ptr<Box_iref> m_iref_box;
286
  std::shared_ptr<Box_iinf> m_iinf_box;
287
  std::shared_ptr<Box_grpl> m_grpl_box;
288
  std::shared_ptr<Box_pitm> m_pitm_box; // only non-null if has_images()==true
289
  std::shared_ptr<Box_iprp> m_iprp_box; // only non-null if has_images()==true
290
  std::shared_ptr<Box_ipco> m_ipco_box; // only non-null if has_images()==true
291
  std::shared_ptr<Box_ipma> m_ipma_box; // only non-null if has_images()==true
292
293
294
  std::map<heif_item_id, std::shared_ptr<Box_infe> > m_infe_boxes;
295
296
  std::unique_ptr<MdatData> m_mdat_data;
297
298
  // returns the position of the first data byte in the file
299
  Result<size_t> write_mdat(StreamWriter& writer);
300
301
  // --- sequences
302
303
  std::shared_ptr<Box_moov> m_moov_box;
304
  std::shared_ptr<Box_mvhd> m_mvhd_box;
305
306
  const heif_security_limits* m_limits = nullptr;
307
  IDCreator m_id_creator;
308
309
  Error parse_heif_file();
310
311
  // Advance the ID creator past all item, track and entity-group IDs found in the parsed
312
  // file, so that IDs allocated for new items cannot collide with existing ones.
313
  void seed_id_creator();
314
315
  // Undo add_new_infe_box() / add_new_meta_infe_box() when the item could not be completed.
316
  void remove_infe_box(const std::shared_ptr<Box_infe>& infe);
317
318
  Error parse_heif_images();
319
320
  Error parse_heif_sequences();
321
};
322
323
#endif