Coverage Report

Created: 2026-06-30 07:12

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
32.7k
  void set_security_limits(const heif_security_limits* limits) { m_limits = limits; }
70
71
7.02k
  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
9.50k
  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
  void init_for_sequence();
92
93
249
  void set_hdlr_box(std::shared_ptr<Box_hdlr> box) { m_hdlr_box = std::move(box); }
94
95
  size_t append_mdat_data(const std::vector<uint8_t>& data);
96
97
  void derive_box_versions();
98
99
  void write(StreamWriter& writer);
100
101
0
  void set_write_mini_format(bool enable) { m_write_mini_format = enable; }
102
0
  bool get_write_mini_format() const { return m_write_mini_format; }
103
104
0
  int get_num_images() const { return static_cast<int>(m_infe_boxes.size()); }
105
106
15.9k
  heif_item_id get_primary_image_ID() const { return m_pitm_box ? m_pitm_box->get_item_ID() : 0; }
107
108
0
  size_t get_number_of_items() const { return m_infe_boxes.size(); }
109
110
  std::vector<heif_item_id> get_item_IDs() const;
111
112
  bool item_exists(heif_item_id ID) const;
113
114
  bool has_item_with_id(heif_item_id ID) const;
115
116
  uint32_t get_item_type_4cc(heif_item_id ID) const;
117
118
  std::string get_content_type(heif_item_id ID) const;
119
120
  std::string get_item_uri_type(heif_item_id ID) const;
121
122
  Result<std::vector<uint8_t>> get_uncompressed_item_data(heif_item_id ID) const;
123
124
  Error append_data_from_file_range(std::vector<uint8_t>& out_data, uint64_t offset, uint32_t size) const;
125
126
  Error append_data_from_iloc(heif_item_id ID, std::vector<uint8_t>& out_data, uint64_t offset, uint64_t size) const;
127
128
9.74k
  Error append_data_from_iloc(heif_item_id ID, std::vector<uint8_t>& out_data) const {
129
9.74k
    return append_data_from_iloc(ID, out_data, 0, std::numeric_limits<uint64_t>::max());
130
9.74k
  }
131
132
  // If `out_compression` is not NULL, the compression method is returned there and the compressed data is returned.
133
  // If `out_compression` is NULL, the data is returned decompressed.
134
  Result<std::vector<uint8_t>> get_item_data(heif_item_id ID, heif_metadata_compression* out_compression) const;
135
136
249
  std::shared_ptr<Box_ftyp> get_ftyp_box() { return m_ftyp_box; }
137
138
249
  void init_meta_box() { m_meta_box = std::make_shared<Box_meta>(); }
139
140
  std::shared_ptr<const Box_infe> get_infe_box(heif_item_id imageID) const;
141
142
  std::shared_ptr<Box_infe> get_infe_box(heif_item_id imageID);
143
144
  void set_iref_box(std::shared_ptr<Box_iref>);
145
146
17.1k
  std::shared_ptr<Box_iref> get_iref_box() { return m_iref_box; }
147
148
0
  std::shared_ptr<const Box_iref> get_iref_box() const { return m_iref_box; }
149
150
15.5k
  std::shared_ptr<Box_ipco> get_ipco_box() { return m_ipco_box; }
151
152
  void set_ipco_box(std::shared_ptr<Box_ipco>);
153
154
0
  std::shared_ptr<Box_ipco> get_ipco_box() const { return m_ipco_box; }
155
156
  void set_ipma_box(std::shared_ptr<Box_ipma>);
157
158
15.5k
  std::shared_ptr<Box_ipma> get_ipma_box() { return m_ipma_box; }
159
160
0
  std::shared_ptr<Box_ipma> get_ipma_box() const { return m_ipma_box; }
161
162
0
  std::shared_ptr<Box_grpl> get_grpl_box() const { return m_grpl_box; }
163
164
0
  std::shared_ptr<Box_meta> get_meta_box() const { return m_meta_box; }
165
166
  std::shared_ptr<Box_EntityToGroup> get_entity_group(heif_entity_group_id id);
167
168
  Error get_properties(heif_item_id imageID,
169
                       std::vector<std::shared_ptr<Box>>& properties) const;
170
171
  template<class BoxType>
172
  std::shared_ptr<BoxType> get_property_for_item(heif_item_id imageID) const
173
14.1k
  {
174
14.1k
    std::vector<std::shared_ptr<Box>> properties;
175
14.1k
    Error err = get_properties(imageID, properties);
176
14.1k
    if (err) {
177
0
      return nullptr;
178
0
    }
179
180
35.6k
    for (auto& property : properties) {
181
35.6k
      if (auto box = std::dynamic_pointer_cast<BoxType>(property)) {
182
0
        return box;
183
0
      }
184
35.6k
    }
185
186
14.1k
    return nullptr;
187
14.1k
  }
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
std::__1::shared_ptr<Box_rref> HeifFile::get_property_for_item<Box_rref>(unsigned int) const
Line
Count
Source
173
14.1k
  {
174
14.1k
    std::vector<std::shared_ptr<Box>> properties;
175
14.1k
    Error err = get_properties(imageID, properties);
176
14.1k
    if (err) {
177
0
      return nullptr;
178
0
    }
179
180
35.6k
    for (auto& property : properties) {
181
35.6k
      if (auto box = std::dynamic_pointer_cast<BoxType>(property)) {
182
0
        return box;
183
0
      }
184
35.6k
    }
185
186
14.1k
    return nullptr;
187
14.1k
  }
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_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
188
189
  std::string debug_dump_boxes() const;
190
191
  std::string debug_dump_item_data() const;
192
193
194
  // --- writing ---
195
196
0
  IDCreator& get_id_creator() { return m_id_creator; }
197
198
0
  const IDCreator& get_id_creator() const { return m_id_creator; }
199
200
  Result<heif_item_id> get_unused_item_id();
201
202
  Result<heif_item_id> add_new_image(uint32_t item_type);
203
204
  Result<std::shared_ptr<Box_infe>> add_new_infe_box(uint32_t item_type);
205
206
  Result<std::shared_ptr<Box_infe>> add_new_meta_infe_box(uint32_t item_type);
207
208
  void add_ispe_property(heif_item_id id, uint32_t width, uint32_t height, bool essential);
209
210
  // set irot/imir according to heif_orientation
211
  void add_orientation_properties(heif_item_id id, heif_orientation);
212
213
  // TODO: can we remove the 'essential' parameter and take this from the box? Or is that depending on the context?
214
  heif_property_id add_property(heif_item_id id, const std::shared_ptr<Box>& property, bool essential);
215
216
  heif_property_id add_property_without_deduplication(heif_item_id id, const std::shared_ptr<Box>& property, bool essential);
217
218
  Result<heif_item_id> add_infe(uint32_t item_type, const uint8_t* data, size_t size);
219
220
  void add_infe_box(heif_item_id, std::shared_ptr<Box_infe> infe);
221
222
  Result<heif_item_id> add_infe_mime(const char* content_type, heif_metadata_compression content_encoding, const uint8_t* data, size_t size);
223
224
  Result<heif_item_id> add_precompressed_infe_mime(const char* content_type, std::string content_encoding, const uint8_t* data, size_t size);
225
226
  Result<heif_item_id> add_infe_uri(const char* item_uri_type, const uint8_t* data, size_t size);
227
228
  Error set_item_data(const std::shared_ptr<Box_infe>& item, const uint8_t* data, size_t size, heif_metadata_compression compression);
229
230
  Error set_precompressed_item_data(const std::shared_ptr<Box_infe>& item, const uint8_t* data, size_t size, std::string content_encoding);
231
232
  void append_iloc_data(heif_item_id id, const std::vector<uint8_t>& nal_packets, uint8_t construction_method);
233
234
  void replace_iloc_data(heif_item_id id, uint64_t offset, const std::vector<uint8_t>& data, uint8_t construction_method = 0);
235
236
  void set_iloc_box(std::shared_ptr<Box_iloc>);
237
238
0
  std::shared_ptr<Box_iloc> get_iloc_box() { return m_iloc_box; }
239
240
  void set_primary_item_id(heif_item_id id);
241
242
  void add_iref_reference(heif_item_id from, uint32_t type,
243
                          const std::vector<heif_item_id>& to);
244
245
  void set_iref_reference(heif_item_id from, uint32_t type, int reference_idx, heif_item_id to_item);
246
247
  void add_entity_group_box(const std::shared_ptr<Box>& entity_group_box);
248
249
  void set_auxC_property(heif_item_id id, const std::string& type);
250
251
#if defined(__MINGW32__) || defined(__MINGW64__) || defined(_MSC_VER)
252
  static std::wstring convert_utf8_path_to_utf16(std::string pathutf8);
253
#endif
254
255
256
  // --- sequences
257
258
48
  std::shared_ptr<Box_moov> get_moov_box() { return m_moov_box; }
259
260
0
  std::shared_ptr<Box_mvhd> get_mvhd_box() { return m_mvhd_box; }
261
262
private:
263
#if ENABLE_PARALLEL_TILE_DECODING
264
  mutable std::mutex m_read_mutex;
265
#endif
266
267
  std::shared_ptr<FileLayout> m_file_layout;
268
269
  std::shared_ptr<StreamReader> m_input_stream;
270
271
  std::vector<std::shared_ptr<Box> > m_top_level_boxes;
272
273
  std::shared_ptr<Box_ftyp> m_ftyp_box;
274
  std::shared_ptr<Box_hdlr> m_hdlr_box;
275
  std::shared_ptr<Box_meta> m_meta_box;
276
  std::shared_ptr<Box_mini> m_mini_box; // meta alternative
277
  bool m_write_mini_format = false;
278
279
  std::shared_ptr<Box_iloc> m_iloc_box;
280
  std::shared_ptr<Box_idat> m_idat_box;
281
  std::shared_ptr<Box_iref> m_iref_box;
282
  std::shared_ptr<Box_iinf> m_iinf_box;
283
  std::shared_ptr<Box_grpl> m_grpl_box;
284
  std::shared_ptr<Box_pitm> m_pitm_box; // only non-null if has_images()==true
285
  std::shared_ptr<Box_iprp> m_iprp_box; // only non-null if has_images()==true
286
  std::shared_ptr<Box_ipco> m_ipco_box; // only non-null if has_images()==true
287
  std::shared_ptr<Box_ipma> m_ipma_box; // only non-null if has_images()==true
288
289
290
  std::map<heif_item_id, std::shared_ptr<Box_infe> > m_infe_boxes;
291
292
  std::unique_ptr<MdatData> m_mdat_data;
293
294
  // returns the position of the first data byte in the file
295
  Result<size_t> write_mdat(StreamWriter& writer);
296
297
  // --- sequences
298
299
  std::shared_ptr<Box_moov> m_moov_box;
300
  std::shared_ptr<Box_mvhd> m_mvhd_box;
301
302
  const heif_security_limits* m_limits = nullptr;
303
  IDCreator m_id_creator;
304
305
  Error parse_heif_file();
306
307
  Error parse_heif_images();
308
309
  Error parse_heif_sequences();
310
311
  Error check_for_ref_cycle(heif_item_id ID,
312
                            const std::shared_ptr<Box_iref>& iref_box) const;
313
314
  Error check_for_ref_cycle_recursion(heif_item_id ID,
315
                                      const std::shared_ptr<Box_iref>& iref_box,
316
                                      std::unordered_set<heif_item_id>& parent_items) const;
317
};
318
319
#endif