Coverage Report

Created: 2026-07-25 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libheif/libheif/box.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_BOX_H
22
#define LIBHEIF_BOX_H
23
24
#include <cstdint>
25
#include "common_utils.h"
26
#include "libheif/heif.h"
27
#include "libheif/heif_experimental.h"
28
#include "libheif/heif_properties.h"
29
#include "libheif/heif_tai_timestamps.h"
30
#include <cinttypes>
31
#include <cstddef>
32
33
#include <utility>
34
#include <vector>
35
#include <string>
36
#include <memory>
37
#include <limits>
38
#include <istream>
39
#include <bitset>
40
#include <utility>
41
#include <optional>
42
43
#include "error.h"
44
#include "logging.h"
45
#include "bitstream.h"
46
47
#if !defined(__EMSCRIPTEN__) && !defined(_MSC_VER)
48
// std::array<bool> is not supported on some older compilers.
49
#define HAS_BOOL_ARRAY 1
50
#endif
51
52
/*
53
  constexpr uint32_t fourcc(const char* string)
54
  {
55
  return ((string[0]<<24) |
56
  (string[1]<<16) |
57
  (string[2]<< 8) |
58
  (string[3]));
59
  }
60
*/
61
62
63
class Fraction
64
{
65
public:
66
520
  Fraction() = default;
67
68
  Fraction(int32_t num, int32_t den);
69
70
  // may only use values up to int32_t maximum
71
  Fraction(uint32_t num, uint32_t den);
72
73
  // Values will be reduced until they fit into int32_t.
74
  Fraction(int64_t num, int64_t den);
75
76
  Fraction operator+(const Fraction&) const;
77
78
  Fraction operator-(const Fraction&) const;
79
80
  Fraction operator+(int) const;
81
82
  Fraction operator-(int) const;
83
84
  Fraction operator/(int) const;
85
86
  int32_t round_down() const;
87
88
  int32_t round_up() const;
89
90
  int32_t round() const;
91
92
  bool is_valid() const;
93
94
0
  double to_double() const {
95
0
    return numerator / (double)denominator;
96
0
  }
97
98
  int32_t numerator = 0;
99
  int32_t denominator = 1;
100
};
101
102
103
inline std::ostream& operator<<(std::ostream& str, const Fraction& f)
104
0
{
105
0
  str << f.numerator << "/" << f.denominator;
106
0
  return str;
107
0
}
108
109
110
class BoxHeader
111
{
112
public:
113
  BoxHeader();
114
115
150k
  virtual ~BoxHeader() = default;
116
117
  constexpr static uint64_t size_until_end_of_file = 0;
118
119
271k
  uint64_t get_box_size() const { return m_size; }
120
121
127k
  bool has_fixed_box_size() const { return m_size != 0; }
122
123
188k
  uint32_t get_header_size() const { return m_header_size; }
124
125
175k
  uint32_t get_short_type() const { return m_type; }
126
127
  std::vector<uint8_t> get_type() const;
128
129
  std::string get_type_string() const;
130
131
0
  virtual const char* debug_box_name() const { return nullptr; }
132
133
71.7k
  void set_short_type(uint32_t type) { m_type = type; }
134
135
136
  // should only be called if get_short_type == fourcc("uuid")
137
  std::vector<uint8_t> get_uuid_type() const;
138
139
  void set_uuid_type(const std::vector<uint8_t>&);
140
141
142
  Error parse_header(BitstreamRange& range);
143
144
  virtual std::string dump(Indent&) const;
145
146
147
0
  virtual bool is_full_box_header() const { return false; }
148
149
150
private:
151
  uint64_t m_size = 0;
152
153
  uint32_t m_type = 0;
154
  std::vector<uint8_t> m_uuid_type;
155
156
protected:
157
  uint32_t m_header_size = 0;
158
};
159
160
161
enum class BoxStorageMode {
162
  Undefined,
163
  Memory,
164
  Parsed,
165
  File
166
};
167
168
169
// Consequence of a box parse error
170
enum class parse_error_fatality {
171
  fatal,     // failure to parse this box leads to the associated item being unreable
172
  ignorable, // ignoring this box will lead to unexpected output, but may be better than nothing
173
  optional   // the box contains extra information that is not essential for viewing
174
};
175
176
177
class Box : public BoxHeader
178
{
179
public:
180
72.9k
  Box() = default;
181
182
  void set_short_header(const BoxHeader& hdr)
183
58.4k
  {
184
58.4k
    *(BoxHeader*) this = hdr;
185
58.4k
  }
186
187
  // header size without the FullBox fields (if applicable)
188
  int calculate_header_size(bool data64bit) const;
189
190
  static Error read(BitstreamRange& range, std::shared_ptr<Box>* box, const heif_security_limits*);
191
192
  virtual Error write(StreamWriter& writer) const;
193
194
  // check, which box version is required and set this in the (full) box header
195
0
  virtual void derive_box_version() {}
196
197
  void derive_box_version_recursive();
198
199
0
  virtual void patch_file_pointers(StreamWriter&, size_t offset) {}
200
201
  void patch_file_pointers_recursively(StreamWriter&, size_t offset);
202
203
  std::string dump(Indent&) const override;
204
205
  template<typename T> [[nodiscard]] std::shared_ptr<T> get_child_box() const
206
16.1k
  {
207
    // TODO: we could remove the dynamic_cast<> by adding the fourcc type of each Box
208
    //       as a "constexpr uint32_t Box::short_type", compare to that and use static_cast<>
209
60.8k
    for (auto& box : m_children) {
210
60.8k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
11.6k
        return typed_box;
212
11.6k
      }
213
60.8k
    }
214
215
4.49k
    return nullptr;
216
16.1k
  }
std::__1::shared_ptr<Box_mvhd> Box::get_child_box<Box_mvhd>() const
Line
Count
Source
206
26
  {
207
    // TODO: we could remove the dynamic_cast<> by adding the fourcc type of each Box
208
    //       as a "constexpr uint32_t Box::short_type", compare to that and use static_cast<>
209
34
    for (auto& box : m_children) {
210
34
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
24
        return typed_box;
212
24
      }
213
34
    }
214
215
2
    return nullptr;
216
26
  }
std::__1::shared_ptr<Box_hdlr> Box::get_child_box<Box_hdlr>() const
Line
Count
Source
206
1.84k
  {
207
    // TODO: we could remove the dynamic_cast<> by adding the fourcc type of each Box
208
    //       as a "constexpr uint32_t Box::short_type", compare to that and use static_cast<>
209
2.21k
    for (auto& box : m_children) {
210
2.21k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
1.78k
        return typed_box;
212
1.78k
      }
213
2.21k
    }
214
215
57
    return nullptr;
216
1.84k
  }
std::__1::shared_ptr<Box_iinf> Box::get_child_box<Box_iinf>() const
Line
Count
Source
206
1.84k
  {
207
    // TODO: we could remove the dynamic_cast<> by adding the fourcc type of each Box
208
    //       as a "constexpr uint32_t Box::short_type", compare to that and use static_cast<>
209
7.46k
    for (auto& box : m_children) {
210
7.46k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
1.81k
        return typed_box;
212
1.81k
      }
213
7.46k
    }
214
215
26
    return nullptr;
216
1.84k
  }
std::__1::shared_ptr<Box_pitm> Box::get_child_box<Box_pitm>() const
Line
Count
Source
206
1.77k
  {
207
    // TODO: we could remove the dynamic_cast<> by adding the fourcc type of each Box
208
    //       as a "constexpr uint32_t Box::short_type", compare to that and use static_cast<>
209
3.76k
    for (auto& box : m_children) {
210
3.76k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
1.76k
        return typed_box;
212
1.76k
      }
213
3.76k
    }
214
215
4
    return nullptr;
216
1.77k
  }
std::__1::shared_ptr<Box_iprp> Box::get_child_box<Box_iprp>() const
Line
Count
Source
206
1.76k
  {
207
    // TODO: we could remove the dynamic_cast<> by adding the fourcc type of each Box
208
    //       as a "constexpr uint32_t Box::short_type", compare to that and use static_cast<>
209
9.47k
    for (auto& box : m_children) {
210
9.47k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
1.76k
        return typed_box;
212
1.76k
      }
213
9.47k
    }
214
215
9
    return nullptr;
216
1.76k
  }
std::__1::shared_ptr<Box_ipco> Box::get_child_box<Box_ipco>() const
Line
Count
Source
206
1.76k
  {
207
    // TODO: we could remove the dynamic_cast<> by adding the fourcc type of each Box
208
    //       as a "constexpr uint32_t Box::short_type", compare to that and use static_cast<>
209
1.79k
    for (auto& box : m_children) {
210
1.79k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
1.75k
        return typed_box;
212
1.75k
      }
213
1.79k
    }
214
215
6
    return nullptr;
216
1.76k
  }
std::__1::shared_ptr<Box_iloc> Box::get_child_box<Box_iloc>() const
Line
Count
Source
206
1.79k
  {
207
    // TODO: we could remove the dynamic_cast<> by adding the fourcc type of each Box
208
    //       as a "constexpr uint32_t Box::short_type", compare to that and use static_cast<>
209
6.13k
    for (auto& box : m_children) {
210
6.13k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
1.78k
        return typed_box;
212
1.78k
      }
213
6.13k
    }
214
215
4
    return nullptr;
216
1.79k
  }
std::__1::shared_ptr<Box_idat> Box::get_child_box<Box_idat>() const
Line
Count
Source
206
1.78k
  {
207
    // TODO: we could remove the dynamic_cast<> by adding the fourcc type of each Box
208
    //       as a "constexpr uint32_t Box::short_type", compare to that and use static_cast<>
209
10.0k
    for (auto& box : m_children) {
210
10.0k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
232
        return typed_box;
212
232
      }
213
10.0k
    }
214
215
1.55k
    return nullptr;
216
1.78k
  }
std::__1::shared_ptr<Box_iref> Box::get_child_box<Box_iref>() const
Line
Count
Source
206
1.78k
  {
207
    // TODO: we could remove the dynamic_cast<> by adding the fourcc type of each Box
208
    //       as a "constexpr uint32_t Box::short_type", compare to that and use static_cast<>
209
9.55k
    for (auto& box : m_children) {
210
9.55k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
620
        return typed_box;
212
620
      }
213
9.55k
    }
214
215
1.16k
    return nullptr;
216
1.78k
  }
std::__1::shared_ptr<Box_grpl> Box::get_child_box<Box_grpl>() const
Line
Count
Source
206
1.77k
  {
207
    // TODO: we could remove the dynamic_cast<> by adding the fourcc type of each Box
208
    //       as a "constexpr uint32_t Box::short_type", compare to that and use static_cast<>
209
10.3k
    for (auto& box : m_children) {
210
10.3k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
114
        return typed_box;
212
114
      }
213
10.3k
    }
214
215
1.65k
    return nullptr;
216
1.77k
  }
Unexecuted instantiation: std::__1::shared_ptr<Box_infe> Box::get_child_box<Box_infe>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_hvcC> Box::get_child_box<Box_hvcC>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_av1C> Box::get_child_box<Box_av1C>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_vvcC> Box::get_child_box<Box_vvcC>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_avcC> Box::get_child_box<Box_avcC>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_uncC> Box::get_child_box<Box_uncC>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_cmpd> Box::get_child_box<Box_cmpd>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_cpat> Box::get_child_box<Box_cpat>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_cmpC> Box::get_child_box<Box_cmpC>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_icef> Box::get_child_box<Box_icef>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_cloc> Box::get_child_box<Box_cloc>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_j2kH> Box::get_child_box<Box_j2kH>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_jpgC> Box::get_child_box<Box_jpgC>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_tkhd> Box::get_child_box<Box_tkhd>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_edts> Box::get_child_box<Box_edts>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_elst> Box::get_child_box<Box_elst>() const
std::__1::shared_ptr<Box_mdia> Box::get_child_box<Box_mdia>() const
Line
Count
Source
206
6
  {
207
    // TODO: we could remove the dynamic_cast<> by adding the fourcc type of each Box
208
    //       as a "constexpr uint32_t Box::short_type", compare to that and use static_cast<>
209
15
    for (auto& box : m_children) {
210
15
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
0
        return typed_box;
212
0
      }
213
15
    }
214
215
6
    return nullptr;
216
6
  }
Unexecuted instantiation: std::__1::shared_ptr<Box_tref> Box::get_child_box<Box_tref>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_minf> Box::get_child_box<Box_minf>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_mdhd> Box::get_child_box<Box_mdhd>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_stbl> Box::get_child_box<Box_stbl>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_stsd> Box::get_child_box<Box_stsd>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_stsc> Box::get_child_box<Box_stsc>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_stco> Box::get_child_box<Box_stco>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_stsz> Box::get_child_box<Box_stsz>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_stts> Box::get_child_box<Box_stts>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_ctts> Box::get_child_box<Box_ctts>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_auxi> Box::get_child_box<Box_auxi>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_taic> Box::get_child_box<Box_taic>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_meta> Box::get_child_box<Box_meta>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_uri const> Box::get_child_box<Box_uri const>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_cmpd const> Box::get_child_box<Box_cmpd const>() const
217
218
  template<typename T> bool replace_child_box(const std::shared_ptr<T>& box)
219
230
  {
220
443
    for (auto & b : m_children) {
221
443
      if (std::dynamic_pointer_cast<T>(b) != nullptr) {
222
0
        b = box;
223
0
        return true;
224
0
      }
225
443
    }
226
227
230
    append_child_box(box);
228
230
    return false;
229
230
  }
bool Box::replace_child_box<Box_pitm>(std::__1::shared_ptr<Box_pitm> const&)
Line
Count
Source
219
51
  {
220
51
    for (auto & b : m_children) {
221
0
      if (std::dynamic_pointer_cast<T>(b) != nullptr) {
222
0
        b = box;
223
0
        return true;
224
0
      }
225
0
    }
226
227
51
    append_child_box(box);
228
51
    return false;
229
51
  }
bool Box::replace_child_box<Box_ipco>(std::__1::shared_ptr<Box_ipco> const&)
Line
Count
Source
219
47
  {
220
47
    for (auto & b : m_children) {
221
47
      if (std::dynamic_pointer_cast<T>(b) != nullptr) {
222
0
        b = box;
223
0
        return true;
224
0
      }
225
47
    }
226
227
47
    append_child_box(box);
228
47
    return false;
229
47
  }
bool Box::replace_child_box<Box_ipma>(std::__1::shared_ptr<Box_ipma> const&)
Line
Count
Source
219
44
  {
220
88
    for (auto & b : m_children) {
221
88
      if (std::dynamic_pointer_cast<T>(b) != nullptr) {
222
0
        b = box;
223
0
        return true;
224
0
      }
225
88
    }
226
227
44
    append_child_box(box);
228
44
    return false;
229
44
  }
bool Box::replace_child_box<Box_iloc>(std::__1::shared_ptr<Box_iloc> const&)
Line
Count
Source
219
44
  {
220
132
    for (auto & b : m_children) {
221
132
      if (std::dynamic_pointer_cast<T>(b) != nullptr) {
222
0
        b = box;
223
0
        return true;
224
0
      }
225
132
    }
226
227
44
    append_child_box(box);
228
44
    return false;
229
44
  }
bool Box::replace_child_box<Box_iref>(std::__1::shared_ptr<Box_iref> const&)
Line
Count
Source
219
44
  {
220
176
    for (auto & b : m_children) {
221
176
      if (std::dynamic_pointer_cast<T>(b) != nullptr) {
222
0
        b = box;
223
0
        return true;
224
0
      }
225
176
    }
226
227
44
    append_child_box(box);
228
44
    return false;
229
44
  }
230
231
  template<typename T>
232
  std::vector<std::shared_ptr<T>> get_child_boxes() const
233
3.58k
  {
234
3.58k
    std::vector<std::shared_ptr<T>> result;
235
16.1k
    for (auto& box : m_children) {
236
16.1k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
237
11.7k
        result.push_back(typed_box);
238
11.7k
      }
239
16.1k
    }
240
241
3.58k
    return result;
242
3.58k
  }
std::__1::vector<std::__1::shared_ptr<Box_trak>, std::__1::allocator<std::__1::shared_ptr<Box_trak> > > Box::get_child_boxes<Box_trak>() const
Line
Count
Source
233
12
  {
234
12
    std::vector<std::shared_ptr<T>> result;
235
45
    for (auto& box : m_children) {
236
45
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
237
6
        result.push_back(typed_box);
238
6
      }
239
45
    }
240
241
12
    return result;
242
12
  }
std::__1::vector<std::__1::shared_ptr<Box_infe>, std::__1::allocator<std::__1::shared_ptr<Box_infe> > > Box::get_child_boxes<Box_infe>() const
Line
Count
Source
233
1.81k
  {
234
1.81k
    std::vector<std::shared_ptr<T>> result;
235
12.5k
    for (auto& box : m_children) {
236
12.5k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
237
9.99k
        result.push_back(typed_box);
238
9.99k
      }
239
12.5k
    }
240
241
1.81k
    return result;
242
1.81k
  }
std::__1::vector<std::__1::shared_ptr<Box_ipma>, std::__1::allocator<std::__1::shared_ptr<Box_ipma> > > Box::get_child_boxes<Box_ipma>() const
Line
Count
Source
233
1.75k
  {
234
1.75k
    std::vector<std::shared_ptr<T>> result;
235
3.52k
    for (auto& box : m_children) {
236
3.52k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
237
1.75k
        result.push_back(typed_box);
238
1.75k
      }
239
3.52k
    }
240
241
1.75k
    return result;
242
1.75k
  }
Unexecuted instantiation: std::__1::vector<std::__1::shared_ptr<Box_splz>, std::__1::allocator<std::__1::shared_ptr<Box_splz> > > Box::get_child_boxes<Box_splz>() const
Unexecuted instantiation: std::__1::vector<std::__1::shared_ptr<Box_sbpm>, std::__1::allocator<std::__1::shared_ptr<Box_sbpm> > > Box::get_child_boxes<Box_sbpm>() const
Unexecuted instantiation: std::__1::vector<std::__1::shared_ptr<Box_snuc>, std::__1::allocator<std::__1::shared_ptr<Box_snuc> > > Box::get_child_boxes<Box_snuc>() const
Unexecuted instantiation: std::__1::vector<std::__1::shared_ptr<Box_saiz>, std::__1::allocator<std::__1::shared_ptr<Box_saiz> > > Box::get_child_boxes<Box_saiz>() const
Unexecuted instantiation: std::__1::vector<std::__1::shared_ptr<Box_saio>, std::__1::allocator<std::__1::shared_ptr<Box_saio> > > Box::get_child_boxes<Box_saio>() const
243
244
18.6k
  const std::vector<std::shared_ptr<Box>>& get_all_child_boxes() const { return m_children; }
245
246
  uint32_t append_child_box(const std::shared_ptr<Box>& box)
247
733
  {
248
733
    m_children.push_back(box);
249
733
    return (int) m_children.size() - 1;
250
733
  }
251
252
8.26k
  bool has_child_boxes() const { return !m_children.empty(); }
253
254
  bool remove_child_box(const std::shared_ptr<const Box>& box);
255
256
  virtual bool operator==(const Box& other) const;
257
258
  static bool equal(const std::shared_ptr<Box>& box1, const std::shared_ptr<Box>& box2);
259
260
0
  BoxStorageMode get_box_storage_mode() const { return m_storage_mode; }
261
262
4.81k
  void set_output_position(uint64_t pos) { m_output_position = pos; }
263
264
844
  virtual parse_error_fatality get_parse_error_fatality() const { return parse_error_fatality::fatal; }
265
266
  // Note: this function may never be called for `ispe` items since it depends
267
  //       on the image item type whether the `ispe` is essential.
268
0
  virtual bool is_essential() const { return m_is_essential; } // only used for properties
269
270
0
  void set_is_essential(bool flag) { m_is_essential = flag; }
271
272
0
  virtual bool is_transformative_property() const { return false; } // only used for properties
273
274
protected:
275
  virtual Error parse(BitstreamRange& range, const heif_security_limits* limits);
276
277
  std::vector<std::shared_ptr<Box>> m_children;
278
279
  BoxStorageMode m_storage_mode = BoxStorageMode::Undefined;
280
281
  const static uint64_t INVALID_POSITION = 0xFFFFFFFFFFFFFFFF;
282
283
  uint64_t m_input_position = INVALID_POSITION;
284
  uint64_t m_output_position = INVALID_POSITION;
285
  std::vector<uint8_t> m_box_data; // including header
286
287
  std::string m_debug_box_type;
288
289
  bool m_is_essential = false;
290
291
  const static uint32_t READ_CHILDREN_ALL = 0xFFFFFFFF;
292
293
  Error read_children(BitstreamRange& range, uint32_t number /* READ_CHILDREN_ALL */, const heif_security_limits* limits);
294
295
  Error write_children(StreamWriter& writer) const;
296
297
  std::string dump_children(Indent&, bool with_index = false) const;
298
299
300
  // --- writing
301
302
  virtual size_t reserve_box_header_space(StreamWriter& writer, bool data64bit = false) const;
303
304
  Error prepend_header(StreamWriter&, size_t box_start, bool data64bit = false) const;
305
306
  virtual Error write_header(StreamWriter&, size_t total_box_size, bool data64bit = false) const;
307
};
308
309
310
class FullBox : public Box
311
{
312
public:
313
0
  bool is_full_box_header() const override { return true; }
314
315
  std::string dump(Indent& indent) const override;
316
317
0
  void derive_box_version() override { set_version(0); }
318
319
320
  Error parse_full_box_header(BitstreamRange& range);
321
322
85.4k
  uint8_t get_version() const { return m_version; }
323
324
144
  void set_version(uint8_t version) { m_version = version; }
325
326
58.9k
  uint32_t get_flags() const { return m_flags; }
327
328
116
  void set_flags(uint32_t flags) { m_flags = flags; }
329
330
protected:
331
332
  // --- writing
333
334
  size_t reserve_box_header_space(StreamWriter& writer, bool data64bit = false) const override;
335
336
  Error write_header(StreamWriter&, size_t total_size, bool data64bit = false) const override;
337
338
  Error unsupported_version_error(const char* box) const;
339
340
private:
341
  uint8_t m_version = 0;
342
  uint32_t m_flags = 0;
343
};
344
345
346
class Box_other : public Box
347
{
348
public:
349
  Box_other(uint32_t short_type)
350
9.58k
  {
351
9.58k
    set_short_type(short_type);
352
9.58k
  }
353
354
0
  const std::vector<uint8_t>& get_raw_data() const { return m_data; }
355
356
0
  void set_raw_data(const std::vector<uint8_t>& data) { m_data = data; }
357
358
  Error write(StreamWriter& writer) const override;
359
360
  std::string dump(Indent&) const override;
361
362
protected:
363
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
364
365
  std::vector<uint8_t> m_data;
366
};
367
368
369
370
class Box_Error : public Box
371
{
372
public:
373
  Box_Error(uint32_t box4cc, Error err, parse_error_fatality fatality)
374
1.47k
  {
375
1.47k
    set_short_type(fourcc("ERR "));
376
377
1.47k
    m_box_type_with_parse_error = box4cc;
378
1.47k
    m_error = std::move(err);
379
1.47k
    m_fatality = fatality;
380
1.47k
  }
381
382
0
  Error write(StreamWriter& writer) const override { return {heif_error_Usage_error, heif_suberror_Unspecified, "Cannot write dummy error box."}; }
383
384
  std::string dump(Indent&) const override;
385
386
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override;
387
388
136
  [[nodiscard]] Error get_error() const { return m_error; }
389
390
protected:
391
0
  Error parse(BitstreamRange& range, const heif_security_limits*) override { assert(false); return Error::Ok; }
392
393
  uint32_t m_box_type_with_parse_error;
394
  Error m_error;
395
  parse_error_fatality m_fatality;
396
};
397
398
399
400
401
class Box_ftyp : public Box
402
{
403
public:
404
  Box_ftyp()
405
9.99k
  {
406
9.99k
    set_short_type(fourcc("ftyp"));
407
9.99k
  }
408
409
  std::string dump(Indent&) const override;
410
411
0
  const char* debug_box_name() const override { return "File Type"; }
412
413
  bool has_compatible_brand(uint32_t brand) const;
414
415
0
  std::vector<uint32_t> list_brands() const { return m_compatible_brands; }
416
417
62
  uint32_t get_major_brand() const { return m_major_brand; }
418
419
0
  void set_major_brand(heif_brand2 major_brand) { m_major_brand = major_brand; }
420
421
51
  uint32_t get_minor_version() const { return m_minor_version; }
422
423
0
  void set_minor_version(uint32_t minor_version) { m_minor_version = minor_version; }
424
425
0
  void clear_compatible_brands() { m_compatible_brands.clear(); }
426
427
  void add_compatible_brand(heif_brand2 brand);
428
429
  Error write(StreamWriter& writer) const override;
430
431
protected:
432
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
433
434
private:
435
  uint32_t m_major_brand = 0;
436
  uint32_t m_minor_version = 0;
437
  std::vector<heif_brand2> m_compatible_brands;
438
};
439
440
441
class Box_free : public Box
442
{
443
public:
444
  Box_free()
445
183
  {
446
183
    set_short_type(fourcc("free"));
447
183
  }
448
449
  std::string dump(Indent&) const override;
450
451
0
  const char* debug_box_name() const override { return "Free Space"; }
452
453
  Error write(StreamWriter& writer) const override;
454
455
protected:
456
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
457
};
458
459
460
class Box_meta : public FullBox
461
{
462
public:
463
  Box_meta()
464
3.66k
  {
465
3.66k
    set_short_type(fourcc("meta"));
466
3.66k
  }
467
468
  std::string dump(Indent&) const override;
469
470
0
  const char* debug_box_name() const override { return "Metadata"; }
471
472
protected:
473
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
474
};
475
476
477
class Box_hdlr : public FullBox
478
{
479
public:
480
  Box_hdlr()
481
2.04k
  {
482
2.04k
    set_short_type(fourcc("hdlr"));
483
2.04k
  }
484
485
  std::string dump(Indent&) const override;
486
487
0
  const char* debug_box_name() const override { return "Handler Reference"; }
488
489
3.56k
  uint32_t get_handler_type() const { return m_handler_type; }
490
491
51
  void set_handler_type(uint32_t handler) { m_handler_type = handler; }
492
493
  Error write(StreamWriter& writer) const override;
494
495
0
  void set_name(std::string name) { m_name = std::move(name); }
496
497
protected:
498
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
499
500
private:
501
  uint32_t m_pre_defined = 0;
502
  uint32_t m_handler_type = fourcc("pict");
503
  uint32_t m_reserved[3] = {0,};
504
  std::string m_name;
505
};
506
507
508
class Box_pitm : public FullBox
509
{
510
public:
511
  Box_pitm()
512
2.31k
  {
513
2.31k
    set_short_type(fourcc("pitm"));
514
2.31k
  }
515
516
  std::string dump(Indent&) const override;
517
518
0
  const char* debug_box_name() const override { return "Primary Item"; }
519
520
3.84k
  heif_item_id get_item_ID() const { return m_item_ID; }
521
522
51
  void set_item_ID(heif_item_id id) { m_item_ID = id; }
523
524
  void derive_box_version() override;
525
526
  Error write(StreamWriter& writer) const override;
527
528
protected:
529
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
530
531
private:
532
  heif_item_id m_item_ID = 0;
533
};
534
535
536
class Box_iloc : public FullBox
537
{
538
public:
539
  Box_iloc();
540
541
  ~Box_iloc() override;
542
543
  void set_use_tmp_file(bool flag);
544
545
  std::string dump(Indent&) const override;
546
547
0
  const char* debug_box_name() const override { return "Item Location"; }
548
549
  struct Extent
550
  {
551
    uint64_t index = 0;
552
    uint64_t offset = 0;
553
    uint64_t length = 0;
554
555
    std::vector<uint8_t> data; // only used when writing data
556
  };
557
558
  struct Item
559
  {
560
    heif_item_id item_ID = 0;
561
    uint8_t construction_method = 0; // >= version 1
562
    uint16_t data_reference_index = 0;
563
    uint64_t base_offset = 0;
564
565
    std::vector<Extent> extents;
566
  };
567
568
1.25k
  const std::vector<Item>& get_items() const { return m_items; }
569
570
  Error read_data(heif_item_id item,
571
                  const std::shared_ptr<StreamReader>& istr,
572
                  const std::shared_ptr<class Box_idat>&,
573
                  std::vector<uint8_t>* dest,
574
                  const heif_security_limits* limits) const;
575
576
  // Note: size==std::numeric_limits<uint64_t>::max() reads the data until the end
577
  Error read_data(heif_item_id item,
578
                  const std::shared_ptr<StreamReader>& istr,
579
                  const std::shared_ptr<class Box_idat>&,
580
                  std::vector<uint8_t>* dest,
581
                  uint64_t offset, uint64_t size,
582
                  const heif_security_limits* limits) const;
583
584
0
  void set_min_version(uint8_t min_version) { m_user_defined_min_version = min_version; }
585
586
  // append bitstream data that will be written later (after iloc box)
587
  // TODO: use an enum for the construction method
588
  Error append_data(heif_item_id item_ID,
589
                    const std::vector<uint8_t>& data,
590
                    uint8_t construction_method = 0);
591
592
  Error replace_data(heif_item_id item_ID,
593
                     uint64_t output_offset,
594
                     const std::vector<uint8_t>& data,
595
                     uint8_t construction_method);
596
597
  // append bitstream data that already has been written (before iloc box)
598
  // Error write_mdat_before_iloc(heif_image_id item_ID,
599
  //                              std::vector<uint8_t>& data)
600
601
  // reserve data entry that will be written later
602
  // Error reserve_mdat_item(heif_image_id item_ID,
603
  //                         uint8_t construction_method,
604
  //                         uint32_t* slot_ID);
605
  // void patch_mdat_slot(uint32_t slot_ID, size_t start, size_t length);
606
607
  void derive_box_version() override;
608
609
  Error write(StreamWriter& writer) const override;
610
611
  Error write_mdat_after_iloc(StreamWriter& writer);
612
613
91
  void append_item(Item &item) { m_items.push_back(item); }
614
615
protected:
616
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
617
618
private:
619
  std::vector<Item> m_items;
620
621
  mutable size_t m_iloc_box_start = 0;
622
  uint8_t m_user_defined_min_version = 0;
623
  uint8_t m_offset_size = 0;
624
  uint8_t m_length_size = 0;
625
  uint8_t m_base_offset_size = 0;
626
  uint8_t m_index_size = 0;
627
628
  void patch_iloc_header(StreamWriter& writer) const;
629
630
  int m_idat_offset = 0; // only for writing: offset of next data array
631
632
  bool m_use_tmpfile = false;
633
  int m_tmpfile_fd = 0;
634
  char m_tmp_filename[20];
635
};
636
637
638
class Box_infe : public FullBox
639
{
640
public:
641
  Box_infe()
642
11.3k
  {
643
11.3k
    set_short_type(fourcc("infe"));
644
11.3k
  }
645
646
  std::string dump(Indent&) const override;
647
648
0
  const char* debug_box_name() const override { return "Item Info Entry"; }
649
650
6.01k
  bool is_hidden_item() const { return m_hidden_item; }
651
652
  void set_hidden_item(bool hidden);
653
654
28.8k
  heif_item_id get_item_ID() const { return m_item_ID; }
655
656
100
  void set_item_ID(heif_item_id id) { m_item_ID = id; }
657
658
47.4k
  uint32_t get_item_type_4cc() const { return m_item_type_4cc; }
659
660
96
  void set_item_type_4cc(uint32_t type) { m_item_type_4cc = type; }
661
662
0
  void set_item_name(const std::string& name) { m_item_name = name; }
663
664
0
  const std::string& get_item_name() const { return m_item_name; }
665
666
12.0k
  const std::string& get_content_type() const { return m_content_type; }
667
668
74
  const std::string& get_content_encoding() const { return m_content_encoding; }
669
670
9
  void set_content_type(const std::string& content_type) { m_content_type = content_type; }
671
672
2
  void set_content_encoding(const std::string& content_encoding) { m_content_encoding = content_encoding; }
673
674
  void derive_box_version() override;
675
676
  Error write(StreamWriter& writer) const override;
677
678
2.86k
  const std::string& get_item_uri_type() const { return m_item_uri_type; }
679
680
0
  void set_item_uri_type(const std::string& uritype) { m_item_uri_type = uritype; }
681
682
protected:
683
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
684
685
private:
686
  heif_item_id m_item_ID = 0;
687
  uint16_t m_item_protection_index = 0;
688
689
  uint32_t m_item_type_4cc = 0;
690
  std::string m_item_name;
691
  std::string m_content_type;
692
  std::string m_content_encoding;
693
  std::string m_item_uri_type;
694
695
  // if set, this item should not be part of the presentation (i.e. hidden)
696
  bool m_hidden_item = false;
697
};
698
699
700
class Box_iinf : public FullBox
701
{
702
public:
703
  Box_iinf()
704
2.20k
  {
705
2.20k
    set_short_type(fourcc("iinf"));
706
2.20k
  }
707
708
  std::string dump(Indent&) const override;
709
710
0
  const char* debug_box_name() const override { return "Item Information"; }
711
712
  void derive_box_version() override;
713
714
  Error write(StreamWriter& writer) const override;
715
716
protected:
717
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
718
719
private:
720
  //std::vector< std::shared_ptr<Box_infe> > m_iteminfos;
721
};
722
723
724
class Box_iprp : public Box
725
{
726
public:
727
  Box_iprp()
728
2.14k
  {
729
2.14k
    set_short_type(fourcc("iprp"));
730
2.14k
  }
731
732
  std::string dump(Indent&) const override;
733
734
0
  const char* debug_box_name() const override { return "Item Properties"; }
735
736
protected:
737
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
738
};
739
740
741
class Box_ipco : public Box
742
{
743
public:
744
  Box_ipco()
745
2.12k
  {
746
2.12k
    set_short_type(fourcc("ipco"));
747
2.12k
  }
748
749
  uint32_t find_or_append_child_box(const std::shared_ptr<Box>& box);
750
751
  Error get_properties_for_item_ID(heif_item_id itemID,
752
                                   const std::shared_ptr<class Box_ipma>&,
753
                                   std::vector<std::shared_ptr<Box>>& out_properties) const;
754
755
  std::shared_ptr<Box> get_property_for_item_ID(heif_item_id itemID,
756
                                                const std::shared_ptr<class Box_ipma>&,
757
                                                uint32_t property_box_type) const;
758
759
  bool is_property_essential_for_item(heif_item_id itemId,
760
                                      const std::shared_ptr<const class Box>& property,
761
                                      const std::shared_ptr<class Box_ipma>&) const;
762
763
  std::string dump(Indent&) const override;
764
765
0
  const char* debug_box_name() const override { return "Item Property Container"; }
766
767
protected:
768
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
769
};
770
771
772
class Box_ispe : public FullBox
773
{
774
public:
775
  Box_ispe()
776
3.05k
  {
777
3.05k
    set_short_type(fourcc("ispe"));
778
3.05k
  }
779
780
8.75k
  uint32_t get_width() const { return m_image_width; }
781
782
8.75k
  uint32_t get_height() const { return m_image_height; }
783
784
  void set_size(uint32_t width, uint32_t height)
785
44
  {
786
44
    m_image_width = width;
787
44
    m_image_height = height;
788
44
  }
789
790
  std::string dump(Indent&) const override;
791
792
0
  const char* debug_box_name() const override { return "Image Spatial Extents"; }
793
794
  Error write(StreamWriter& writer) const override;
795
796
  bool operator==(const Box& other) const override;
797
798
  // Note: this depends on the image item type. Never call this for an `ispe` property.
799
0
  bool is_essential() const override { assert(false); return false; }
800
801
protected:
802
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
803
804
private:
805
  uint32_t m_image_width = 0;
806
  uint32_t m_image_height = 0;
807
};
808
809
810
class Box_ipma : public FullBox
811
{
812
public:
813
  Box_ipma()
814
2.01k
  {
815
2.01k
    set_short_type(fourcc("ipma"));
816
2.01k
  }
817
818
  std::string dump(Indent&) const override;
819
820
0
  const char* debug_box_name() const override { return "Item Property Association"; }
821
822
  struct PropertyAssociation
823
  {
824
    bool essential;
825
    uint16_t property_index;
826
  };
827
828
  const std::vector<PropertyAssociation>* get_properties_for_item_ID(heif_item_id itemID) const;
829
830
  bool is_property_essential_for_item(heif_item_id itemId, int propertyIndex) const;
831
832
  void add_property_for_item_ID(heif_item_id itemID,
833
                                PropertyAssociation assoc);
834
835
  void derive_box_version() override;
836
837
  Error write(StreamWriter& writer) const override;
838
839
  void insert_entries_from_other_ipma_box(const Box_ipma& b);
840
841
  // sorts properties such that descriptive properties precede the transformative properties
842
  void sort_properties(const std::shared_ptr<Box_ipco>&);
843
844
protected:
845
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
846
847
  struct Entry
848
  {
849
    heif_item_id item_ID;
850
    std::vector<PropertyAssociation> associations;
851
  };
852
853
  std::vector<Entry> m_entries;
854
};
855
856
857
class Box_auxC : public FullBox
858
{
859
public:
860
  Box_auxC()
861
505
  {
862
505
    set_short_type(fourcc("auxC"));
863
505
  }
864
865
374
  const std::string& get_aux_type() const { return m_aux_type; }
866
867
8
  void set_aux_type(const std::string& type) { m_aux_type = type; }
868
869
2
  const std::vector<uint8_t>& get_subtypes() const { return m_aux_subtypes; }
870
871
0
  bool is_essential() const override { return true; }
872
873
  std::string dump(Indent&) const override;
874
875
0
  const char* debug_box_name() const override { return "Image Properties for Auxiliary Images"; }
876
877
protected:
878
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
879
880
  Error write(StreamWriter& writer) const override;
881
882
private:
883
  std::string m_aux_type;
884
  std::vector<uint8_t> m_aux_subtypes;
885
};
886
887
888
class Box_irot : public Box
889
{
890
public:
891
  Box_irot()
892
191
  {
893
191
    set_short_type(fourcc("irot"));
894
191
  }
895
896
0
  bool is_essential() const override { return true; }
897
898
0
  bool is_transformative_property() const override { return true; }
899
900
  std::string dump(Indent&) const override;
901
902
0
  const char* debug_box_name() const override { return "Image Rotation"; }
903
904
298
  int get_rotation_ccw() const { return m_rotation; }
905
906
  // Only these multiples of 90 are allowed: 0, 90, 180, 270.
907
45
  void set_rotation_ccw(int rot) { m_rotation = rot; }
908
909
0
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::ignorable; }
910
911
protected:
912
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
913
914
  Error write(StreamWriter& writer) const override;
915
916
private:
917
  int m_rotation = 0; // in degrees (CCW)
918
};
919
920
921
class Box_imir : public Box
922
{
923
public:
924
  Box_imir()
925
85
  {
926
85
    set_short_type(fourcc("imir"));
927
85
  }
928
929
0
  bool is_essential() const override { return true; }
930
931
0
  bool is_transformative_property() const override { return true; }
932
933
147
  heif_transform_mirror_direction get_mirror_direction() const { return m_axis; }
934
935
11
  void set_mirror_direction(heif_transform_mirror_direction dir) { m_axis = dir; }
936
937
  std::string dump(Indent&) const override;
938
939
0
  const char* debug_box_name() const override { return "Image Mirroring"; }
940
941
0
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::ignorable; }
942
943
protected:
944
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
945
946
  Error write(StreamWriter& writer) const override;
947
948
private:
949
  heif_transform_mirror_direction m_axis = heif_transform_mirror_direction_vertical;
950
};
951
952
953
class Box_iscl : public FullBox
954
{
955
public:
956
  Box_iscl()
957
5
  {
958
5
    set_short_type(fourcc("iscl"));
959
5
  }
960
961
0
  bool is_essential() const override { return true; }
962
963
0
  bool is_transformative_property() const override { return true; }
964
965
0
  uint16_t get_target_width_numerator() const { return m_target_width_numerator; }
966
0
  uint16_t get_target_width_denominator() const { return m_target_width_denominator; }
967
0
  uint16_t get_target_height_numerator() const { return m_target_height_numerator; }
968
0
  uint16_t get_target_height_denominator() const { return m_target_height_denominator; }
969
970
  void set_scale(uint16_t w_num, uint16_t w_den, uint16_t h_num, uint16_t h_den)
971
0
  {
972
0
    m_target_width_numerator = w_num;
973
0
    m_target_width_denominator = w_den;
974
0
    m_target_height_numerator = h_num;
975
0
    m_target_height_denominator = h_den;
976
0
  }
977
978
  std::string dump(Indent&) const override;
979
980
0
  const char* debug_box_name() const override { return "Image Scaling"; }
981
982
4
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::ignorable; }
983
984
protected:
985
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
986
987
  Error write(StreamWriter& writer) const override;
988
989
private:
990
  uint16_t m_target_width_numerator = 1;
991
  uint16_t m_target_width_denominator = 1;
992
  uint16_t m_target_height_numerator = 1;
993
  uint16_t m_target_height_denominator = 1;
994
};
995
996
997
class Box_clap : public Box
998
{
999
public:
1000
  Box_clap()
1001
130
  {
1002
130
    set_short_type(fourcc("clap"));
1003
130
  }
1004
1005
0
  bool is_essential() const override { return true; }
1006
1007
0
  bool is_transformative_property() const override { return true; }
1008
1009
  std::string dump(Indent&) const override;
1010
1011
0
  const char* debug_box_name() const override { return "Clean Aperture"; }
1012
1013
  int left_rounded(uint32_t image_width) const;  // first column
1014
  int right_rounded(uint32_t image_width) const; // last column that is part of the cropped image
1015
  int top_rounded(uint32_t image_height) const;   // first row
1016
  int bottom_rounded(uint32_t image_height) const; // last row included in the cropped image
1017
1018
  double left(int image_width) const;
1019
  double top(int image_height) const;
1020
1021
  int get_width_rounded() const;
1022
1023
  int get_height_rounded() const;
1024
1025
  void set(uint32_t clap_width, uint32_t clap_height,
1026
           uint32_t image_width, uint32_t image_height);
1027
1028
102
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::ignorable; }
1029
1030
protected:
1031
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1032
1033
  Error write(StreamWriter& writer) const override;
1034
1035
private:
1036
  Fraction m_clean_aperture_width;
1037
  Fraction m_clean_aperture_height;
1038
  Fraction m_horizontal_offset;
1039
  Fraction m_vertical_offset;
1040
};
1041
1042
1043
class Box_iref : public FullBox
1044
{
1045
public:
1046
  Box_iref()
1047
1.22k
  {
1048
1.22k
    set_short_type(fourcc("iref"));
1049
1.22k
  }
1050
1051
  struct Reference
1052
  {
1053
    BoxHeader header;
1054
1055
    heif_item_id from_item_ID;
1056
    std::vector<heif_item_id> to_item_ID;
1057
  };
1058
1059
1060
  std::string dump(Indent&) const override;
1061
1062
0
  const char* debug_box_name() const override { return "Item Reference"; }
1063
1064
  bool has_references(heif_item_id itemID) const;
1065
1066
  std::vector<heif_item_id> get_references(heif_item_id itemID, uint32_t ref_type) const;
1067
1068
  std::vector<Reference> get_references_from(heif_item_id itemID) const;
1069
1070
  void add_references(heif_item_id from_id, uint32_t type, const std::vector<heif_item_id>& to_ids);
1071
1072
  void overwrite_reference(heif_item_id from_id, uint32_t type, uint32_t reference_idx, heif_item_id to_item);
1073
1074
protected:
1075
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1076
1077
  Error write(StreamWriter& writer) const override;
1078
1079
  void derive_box_version() override;
1080
1081
  Error check_for_double_references() const;
1082
1083
private:
1084
  std::vector<Reference> m_references;
1085
};
1086
1087
1088
class Box_rref : public FullBox
1089
{
1090
public:
1091
  Box_rref()
1092
7
  {
1093
7
    set_short_type(fourcc("rref"));
1094
7
  }
1095
1096
0
  bool is_essential() const override { return true; }
1097
1098
  std::string dump(Indent&) const override;
1099
1100
0
  const char* debug_box_name() const override { return "Required Reference Types"; }
1101
1102
0
  const std::vector<uint32_t>& get_reference_types() const { return m_reference_types; }
1103
1104
  bool all_reference_types_supported() const;
1105
1106
  Error reference_types_supported_error() const;
1107
1108
0
  void add_reference_type(uint32_t type) { m_reference_types.push_back(type); }
1109
1110
protected:
1111
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1112
1113
  Error write(StreamWriter& writer) const override;
1114
1115
private:
1116
  std::vector<uint32_t> m_reference_types;
1117
};
1118
1119
1120
class Box_idat : public Box
1121
{
1122
public:
1123
  std::string dump(Indent&) const override;
1124
1125
0
  const char* debug_box_name() const override { return "Item Data"; }
1126
1127
  Error read_data(const std::shared_ptr<StreamReader>& istr,
1128
                  uint64_t start, uint64_t length,
1129
                  std::vector<uint8_t>& out_data,
1130
                  const heif_security_limits* limits) const;
1131
1132
  int append_data(const std::vector<uint8_t>& data)
1133
0
  {
1134
0
    auto pos = m_data_for_writing.size();
1135
0
1136
0
    m_data_for_writing.insert(m_data_for_writing.end(),
1137
0
                              data.begin(),
1138
0
                              data.end());
1139
0
1140
0
    return (int) pos;
1141
0
  }
1142
1143
  Error write(StreamWriter& writer) const override;
1144
1145
protected:
1146
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1147
1148
  std::streampos m_data_start_pos;
1149
1150
  std::vector<uint8_t> m_data_for_writing;
1151
};
1152
1153
1154
class Box_grpl : public Box
1155
{
1156
public:
1157
  Box_grpl()
1158
135
  {
1159
135
    set_short_type(fourcc("grpl"));
1160
135
  }
1161
1162
  std::string dump(Indent&) const override;
1163
1164
0
  const char* debug_box_name() const override { return "Groups List"; }
1165
1166
protected:
1167
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1168
};
1169
1170
1171
class Box_EntityToGroup : public FullBox
1172
{
1173
public:
1174
  std::string dump(Indent&) const override;
1175
1176
  Error write(StreamWriter& writer) const override;
1177
1178
0
  void set_group_id(heif_entity_group_id id) { group_id = id; }
1179
1180
0
  heif_entity_group_id get_group_id() const { return group_id; }
1181
1182
0
  void set_item_ids(const std::vector<heif_item_id>& ids) { entity_ids = ids; }
1183
1184
0
  const std::vector<heif_item_id>& get_item_ids() const { return entity_ids; }
1185
1186
protected:
1187
  heif_entity_group_id group_id = 0;
1188
  std::vector<heif_item_id> entity_ids;
1189
1190
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1191
1192
  void write_entity_group_ids(StreamWriter& writer) const;
1193
};
1194
1195
1196
class Box_ster : public Box_EntityToGroup
1197
{
1198
public:
1199
  Box_ster()
1200
0
  {
1201
0
    set_short_type(fourcc("ster"));
1202
0
  }
1203
1204
  std::string dump(Indent&) const override;
1205
1206
0
  const char* debug_box_name() const override { return "Stereo pair"; }
1207
1208
0
  heif_item_id get_left_image() const { return entity_ids[0]; }
1209
0
  heif_item_id get_right_image() const { return entity_ids[1]; }
1210
1211
protected:
1212
1213
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1214
};
1215
1216
1217
class Box_pymd : public Box_EntityToGroup
1218
{
1219
public:
1220
  Box_pymd()
1221
101
  {
1222
101
    set_short_type(fourcc("pymd"));
1223
101
  }
1224
1225
  std::string dump(Indent&) const override;
1226
1227
0
  const char* debug_box_name() const override { return "Image pyramid group"; }
1228
1229
  Error write(StreamWriter& writer) const override;
1230
1231
  struct LayerInfo {
1232
    uint16_t layer_binning;
1233
    uint16_t tiles_in_layer_row_minus1;
1234
    uint16_t tiles_in_layer_column_minus1;
1235
  };
1236
1237
  void set_layers(uint16_t _tile_size_x,
1238
                  uint16_t _tile_size_y,
1239
                  const std::vector<LayerInfo>& layers,
1240
                  const std::vector<heif_item_id>& layer_item_ids) // low to high resolution
1241
0
  {
1242
0
    set_item_ids(layer_item_ids);
1243
0
    m_layer_infos = layers;
1244
0
    tile_size_x = _tile_size_x;
1245
0
    tile_size_y = _tile_size_y;
1246
0
  }
1247
1248
0
  const std::vector<LayerInfo>& get_layers() const { return m_layer_infos; }
1249
1250
31
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::ignorable; }
1251
1252
protected:
1253
  uint16_t tile_size_x = 0;
1254
  uint16_t tile_size_y = 0;
1255
1256
  std::vector<LayerInfo> m_layer_infos;
1257
1258
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1259
};
1260
1261
1262
1263
1264
class Box_dinf : public Box
1265
{
1266
public:
1267
  Box_dinf()
1268
91
  {
1269
91
    set_short_type(fourcc("dinf"));
1270
91
  }
1271
1272
  std::string dump(Indent&) const override;
1273
1274
0
  const char* debug_box_name() const override { return "Data Information"; }
1275
1276
protected:
1277
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1278
};
1279
1280
1281
class Box_dref : public FullBox
1282
{
1283
public:
1284
  Box_dref()
1285
4
  {
1286
4
    set_short_type(fourcc("dref"));
1287
4
  }
1288
1289
  std::string dump(Indent&) const override;
1290
1291
0
  const char* debug_box_name() const override { return "Data Reference"; }
1292
1293
  Error write(StreamWriter& writer) const override;
1294
1295
protected:
1296
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1297
};
1298
1299
1300
class Box_url : public FullBox
1301
{
1302
public:
1303
  Box_url()
1304
31
  {
1305
31
    set_short_type(fourcc("url "));
1306
31
    set_flags(1);
1307
31
  }
1308
1309
  std::string dump(Indent&) const override;
1310
1311
0
  const char* debug_box_name() const override { return "Data Entry URL"; }
1312
1313
0
  bool is_same_file() const { return m_location.empty(); }
1314
1315
0
  void set_location(const std::string& loc) { m_location = loc; set_flags(m_location.empty() ? 1 : 0); }
1316
1317
0
  void set_location_same_file() { m_location.clear(); set_flags(1); }
1318
1319
  Error write(StreamWriter& writer) const override;
1320
1321
protected:
1322
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1323
1324
  std::string m_location;
1325
};
1326
1327
class Box_pixi : public FullBox
1328
{
1329
public:
1330
  Box_pixi()
1331
1.35k
  {
1332
1.35k
    set_short_type(fourcc("pixi"));
1333
1.35k
  }
1334
1335
0
  int get_num_channels() const { return (int) m_bits_per_channel.size(); }
1336
1337
0
  int get_bits_per_channel(int channel) const { return m_bits_per_channel[channel]; }
1338
1339
  bool add_channel_bits(uint16_t c)
1340
132
  {
1341
132
    if (c <= 255) {
1342
132
      m_bits_per_channel.push_back(static_cast<uint8_t>(c));
1343
132
      return true;
1344
132
    }
1345
0
    else {
1346
0
      return false;
1347
0
    }
1348
132
  }
1349
1350
  std::string dump(Indent&) const override;
1351
1352
0
  const char* debug_box_name() const override { return "Pixel Information"; }
1353
1354
  Error write(StreamWriter& writer) const override;
1355
1356
416
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::optional; }
1357
1358
protected:
1359
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1360
1361
private:
1362
  std::vector<uint8_t> m_bits_per_channel;
1363
};
1364
1365
1366
class Box_pasp : public Box
1367
{
1368
public:
1369
  Box_pasp()
1370
12
  {
1371
12
    set_short_type(fourcc("pasp"));
1372
12
  }
1373
1374
  uint32_t hSpacing = 1;
1375
  uint32_t vSpacing = 1;
1376
1377
  std::string dump(Indent&) const override;
1378
1379
0
  const char* debug_box_name() const override { return "Pixel Aspect Ratio"; }
1380
1381
  Error write(StreamWriter& writer) const override;
1382
1383
0
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::optional; }
1384
1385
protected:
1386
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1387
};
1388
1389
1390
class Box_lsel : public Box
1391
{
1392
public:
1393
  Box_lsel()
1394
8
  {
1395
8
    set_short_type(fourcc("lsel"));
1396
8
  }
1397
1398
  uint16_t layer_id = 0;
1399
1400
  std::string dump(Indent&) const override;
1401
1402
0
  const char* debug_box_name() const override { return "Layer Selection"; }
1403
1404
  Error write(StreamWriter& writer) const override;
1405
1406
6
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::optional; }
1407
1408
protected:
1409
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1410
};
1411
1412
1413
class Box_clli : public Box
1414
{
1415
public:
1416
  Box_clli()
1417
667
  {
1418
667
    set_short_type(fourcc("clli"));
1419
1420
667
    clli.max_content_light_level = 0;
1421
667
    clli.max_pic_average_light_level = 0;
1422
667
  }
1423
1424
  heif_content_light_level clli;
1425
1426
  std::string dump(Indent&) const override;
1427
1428
0
  const char* debug_box_name() const override { return "Content Light Level Information"; }
1429
1430
  Error write(StreamWriter& writer) const override;
1431
1432
0
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::optional; }
1433
1434
protected:
1435
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1436
};
1437
1438
1439
class Box_mdcv : public Box
1440
{
1441
public:
1442
  Box_mdcv();
1443
1444
  heif_mastering_display_colour_volume mdcv;
1445
1446
  std::string dump(Indent&) const override;
1447
1448
0
  const char* debug_box_name() const override { return "Master Display Colour Volume"; }
1449
1450
  Error write(StreamWriter& writer) const override;
1451
1452
1
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::optional; }
1453
1454
protected:
1455
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1456
};
1457
1458
1459
class Box_amve : public Box
1460
{
1461
public:
1462
  Box_amve();
1463
1464
  heif_ambient_viewing_environment amve;
1465
1466
  std::string dump(Indent&) const override;
1467
1468
0
  const char* debug_box_name() const override { return "Ambient Viewing Environment"; }
1469
1470
  Error write(StreamWriter& writer) const override;
1471
1472
0
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::optional; }
1473
1474
protected:
1475
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1476
};
1477
1478
1479
class Box_ndwt : public FullBox
1480
{
1481
public:
1482
  Box_ndwt()
1483
573
  {
1484
573
    set_short_type(fourcc("ndwt"));
1485
573
  }
1486
1487
  // Nominal diffuse white luminance in units of 0.0001 cd/m^2.
1488
  // A value of 0 means the default definition of ISO/TS 22028-5 should be used.
1489
0
  uint32_t get_diffuse_white_luminance() const { return m_diffuse_white_luminance; }
1490
1491
573
  void set_diffuse_white_luminance(uint32_t luminance) { m_diffuse_white_luminance = luminance; }
1492
1493
  std::string dump(Indent&) const override;
1494
1495
0
  const char* debug_box_name() const override { return "Nominal Diffuse White"; }
1496
1497
  Error write(StreamWriter& writer) const override;
1498
1499
0
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::optional; }
1500
1501
protected:
1502
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1503
1504
private:
1505
  uint32_t m_diffuse_white_luminance = 0;
1506
};
1507
1508
1509
class Box_cclv : public Box
1510
{
1511
public:
1512
  Box_cclv();
1513
1514
0
  bool ccv_primaries_are_valid() const { return m_ccv_primaries_valid; }
1515
0
  int32_t get_ccv_primary_x0() const { return m_ccv_primaries_x[0]; }
1516
0
  int32_t get_ccv_primary_y0() const { return m_ccv_primaries_y[0]; }
1517
0
  int32_t get_ccv_primary_x1() const { return m_ccv_primaries_x[1]; }
1518
0
  int32_t get_ccv_primary_y1() const { return m_ccv_primaries_y[1]; }
1519
0
  int32_t get_ccv_primary_x2() const { return m_ccv_primaries_x[2]; }
1520
0
  int32_t get_ccv_primary_y2() const { return m_ccv_primaries_y[2]; }
1521
  void set_primaries(int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t x2, int32_t y2);
1522
1523
0
  bool min_luminance_is_valid() const { return m_ccv_min_luminance_value.has_value(); }
1524
0
  uint32_t get_min_luminance() const { return *m_ccv_min_luminance_value; }
1525
67
  void set_min_luminance(uint32_t luminance) { m_ccv_min_luminance_value = luminance; }
1526
1527
0
  bool max_luminance_is_valid() const { return m_ccv_max_luminance_value.has_value(); }
1528
0
  uint32_t get_max_luminance() const { return *m_ccv_max_luminance_value; }
1529
219
  void set_max_luminance(uint32_t luminance) { m_ccv_max_luminance_value = luminance; }
1530
1531
0
  bool avg_luminance_is_valid() const { return m_ccv_avg_luminance_value.has_value(); }
1532
0
  uint32_t get_avg_luminance() const { return *m_ccv_avg_luminance_value; }
1533
69
  void set_avg_luminance(uint32_t luminance) { m_ccv_avg_luminance_value = luminance; }
1534
1535
  std::string dump(Indent&) const override;
1536
1537
  // TODO const char* debug_box_name() const override { return ""; }
1538
1539
  Error write(StreamWriter& writer) const override;
1540
1541
0
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::optional; }
1542
1543
protected:
1544
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1545
1546
private:
1547
  bool m_ccv_primaries_valid = false;
1548
  int32_t m_ccv_primaries_x[3] {};
1549
  int32_t m_ccv_primaries_y[3] {};
1550
1551
  std::optional<uint32_t> m_ccv_min_luminance_value;
1552
  std::optional<uint32_t> m_ccv_max_luminance_value;
1553
  std::optional<uint32_t> m_ccv_avg_luminance_value;
1554
};
1555
1556
1557
class Box_cmin : public FullBox
1558
{
1559
public:
1560
  Box_cmin()
1561
110
  {
1562
110
    set_short_type(fourcc("cmin"));
1563
110
  }
1564
1565
  struct AbsoluteIntrinsicMatrix;
1566
1567
  struct RelativeIntrinsicMatrix
1568
  {
1569
    double focal_length_x = 0;
1570
    double principal_point_x = 0;
1571
    double principal_point_y = 0;
1572
1573
    bool is_anisotropic = false;
1574
    double focal_length_y = 0;
1575
    double skew = 0;
1576
1577
    void compute_focal_length(int image_width, int image_height,
1578
                              double& out_focal_length_x, double& out_focal_length_y) const;
1579
1580
    void compute_principal_point(int image_width, int image_height,
1581
                                 double& out_principal_point_x, double& out_principal_point_y) const;
1582
1583
    struct AbsoluteIntrinsicMatrix to_absolute(int image_width, int image_height) const;
1584
  };
1585
1586
  struct AbsoluteIntrinsicMatrix
1587
  {
1588
    double focal_length_x;
1589
    double focal_length_y;
1590
    double principal_point_x;
1591
    double principal_point_y;
1592
    double skew = 0;
1593
1594
0
    void apply_clap(const Box_clap* clap, int image_width, int image_height) {
1595
0
      principal_point_x -= clap->left(image_width);
1596
0
      principal_point_y -= clap->top(image_height);
1597
0
    }
1598
1599
119
    void apply_imir(const Box_imir* imir, uint32_t image_width, uint32_t image_height) {
1600
119
      switch (imir->get_mirror_direction()) {
1601
63
        case heif_transform_mirror_direction_horizontal:
1602
63
          focal_length_x *= -1;
1603
63
          skew *= -1;
1604
63
          principal_point_x = image_width - 1 - principal_point_x;
1605
63
          break;
1606
56
        case heif_transform_mirror_direction_vertical:
1607
56
          focal_length_y *= -1;
1608
56
          principal_point_y = image_height - 1 - principal_point_y;
1609
56
          break;
1610
0
        case heif_transform_mirror_direction_invalid:
1611
0
          break;
1612
119
      }
1613
119
    }
1614
  };
1615
1616
  std::string dump(Indent&) const override;
1617
1618
0
  const char* debug_box_name() const override { return "Camera Intrinsic Matrix"; }
1619
1620
48
  RelativeIntrinsicMatrix get_intrinsic_matrix() const { return m_matrix; }
1621
1622
  void set_intrinsic_matrix(RelativeIntrinsicMatrix matrix);
1623
1624
72
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::optional; }
1625
1626
protected:
1627
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1628
1629
  Error write(StreamWriter& writer) const override;
1630
1631
private:
1632
  RelativeIntrinsicMatrix m_matrix;
1633
1634
  uint32_t m_denominatorShift = 0;
1635
  uint32_t m_skewDenominatorShift = 0;
1636
};
1637
1638
1639
class Box_cmex : public FullBox
1640
{
1641
public:
1642
  Box_cmex()
1643
9
  {
1644
9
    set_short_type(fourcc("cmex"));
1645
9
  }
1646
1647
  struct ExtrinsicMatrix
1648
  {
1649
    // in micrometers (um)
1650
    int32_t pos_x = 0;
1651
    int32_t pos_y = 0;
1652
    int32_t pos_z = 0;
1653
1654
    bool rotation_as_quaternions = true;
1655
    bool orientation_is_32bit = false;
1656
1657
    double quaternion_x = 0;
1658
    double quaternion_y = 0;
1659
    double quaternion_z = 0;
1660
    double quaternion_w = 1.0;
1661
1662
    // rotation angle in degrees
1663
    double rotation_yaw = 0;   //  [-180 ; 180)
1664
    double rotation_pitch = 0; //  [-90 ; 90]
1665
    double rotation_roll = 0;  //  [-180 ; 180)
1666
1667
    uint32_t world_coordinate_system_id = 0;
1668
1669
    // Returns rotation matrix in row-major order.
1670
    std::array<double,9> calculate_rotation_matrix() const;
1671
  };
1672
1673
  std::string dump(Indent&) const override;
1674
1675
0
  const char* debug_box_name() const override { return "Camera Extrinsic Matrix"; }
1676
1677
0
  ExtrinsicMatrix get_extrinsic_matrix() const { return m_matrix; }
1678
1679
  Error set_extrinsic_matrix(ExtrinsicMatrix matrix);
1680
1681
0
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::optional; }
1682
1683
protected:
1684
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1685
1686
  Error write(StreamWriter& writer) const override;
1687
1688
private:
1689
  ExtrinsicMatrix m_matrix;
1690
1691
  bool m_has_pos_x = false;
1692
  bool m_has_pos_y = false;
1693
  bool m_has_pos_z = false;
1694
  bool m_has_orientation = false;
1695
  bool m_has_world_coordinate_system_id = false;
1696
1697
  enum Flags
1698
  {
1699
    pos_x_present = 0x01,
1700
    pos_y_present = 0x02,
1701
    pos_z_present = 0x04,
1702
    orientation_present = 0x08,
1703
    rot_large_field_size = 0x10,
1704
    id_present = 0x20
1705
  };
1706
};
1707
1708
1709
1710
1711
/**
1712
 * User Description property.
1713
 *
1714
 * Permits the association of items or entity groups with a user-defined name, description and tags;
1715
 * there may be multiple udes properties, each with a different language code.
1716
 *
1717
 * See ISO/IEC 23008-12:2022(E) Section 6.5.20.
1718
 */
1719
class Box_udes : public FullBox
1720
{
1721
public:
1722
  Box_udes()
1723
5
  {
1724
5
    set_short_type(fourcc("udes"));
1725
5
  }
1726
1727
  std::string dump(Indent&) const override;
1728
1729
0
  const char* debug_box_name() const override { return "User Description"; }
1730
1731
  Error write(StreamWriter& writer) const override;
1732
1733
  /**
1734
   * Language tag.
1735
   *
1736
   * An RFC 5646 compliant language identifier for the language of the text contained in the other properties.
1737
   * Examples: "en-AU", "de-DE", or "zh-CN“.
1738
   * When is empty, the language is unknown or not undefined.
1739
   */
1740
0
  std::string get_lang() const { return m_lang; }
1741
1742
  /**
1743
   * Set the language tag.
1744
   *
1745
   * An RFC 5646 compliant language identifier for the language of the text contained in the other properties.
1746
   * Examples: "en-AU", "de-DE", or "zh-CN“.
1747
   */
1748
0
  void set_lang(const std::string lang) { m_lang = lang; }
1749
1750
  /**
1751
   * Name.
1752
   *
1753
   * Human readable name for the item or group being described.
1754
   * May be empty, indicating no name is applicable.
1755
   */
1756
0
  std::string get_name() const { return m_name; }
1757
1758
  /**
1759
  * Set the name.
1760
  *
1761
  * Human readable name for the item or group being described.
1762
  */
1763
0
  void set_name(const std::string name) { m_name = name; }
1764
1765
  /**
1766
   * Description.
1767
   *
1768
   * Human readable description for the item or group.
1769
   * May be empty, indicating no description has been provided.
1770
   */
1771
0
  std::string get_description() const { return m_description; }
1772
1773
  /**
1774
   * Set the description.
1775
   *
1776
   * Human readable description for the item or group.
1777
   */
1778
0
  void set_description(const std::string description) { m_description = description; }
1779
1780
  /**
1781
   * Tags.
1782
   *
1783
   * Comma separated user defined tags applicable to the item or group.
1784
   * May be empty, indicating no tags have been assigned.
1785
   */
1786
0
  std::string get_tags() const { return m_tags; }
1787
1788
  /**
1789
   * Set the tags.
1790
   *
1791
   * Comma separated user defined tags applicable to the item or group.
1792
   */
1793
0
  void set_tags(const std::string tags) { m_tags = tags; }
1794
1795
0
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::optional; }
1796
1797
protected:
1798
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1799
1800
private:
1801
  std::string m_lang;
1802
  std::string m_name;
1803
  std::string m_description;
1804
  std::string m_tags;
1805
};
1806
1807
1808
void initialize_heif_tai_clock_info(heif_tai_clock_info* taic);
1809
void initialize_heif_tai_timestamp_packet(heif_tai_timestamp_packet* itai);
1810
1811
1812
class Box_taic : public FullBox
1813
{
1814
public:
1815
  Box_taic()
1816
0
  {
1817
0
    set_short_type(fourcc("taic"));
1818
0
    initialize_heif_tai_clock_info(&m_info);
1819
0
  }
1820
1821
  static std::string dump(const heif_tai_clock_info& info, Indent&);
1822
1823
  std::string dump(Indent&) const override;
1824
1825
0
  const char* debug_box_name() const override { return "TAI Clock Information"; }
1826
1827
  Error write(StreamWriter& writer) const override;
1828
1829
  /**
1830
   * time_uncertainty.
1831
   * 
1832
   * The standard deviation measurement uncertainty in nanoseconds
1833
   * for the timestamp generation process. 
1834
   */
1835
0
  void set_time_uncertainty(uint64_t time_uncertainty) { m_info.time_uncertainty = time_uncertainty;}
1836
  
1837
  /**
1838
   * clock_resolution.
1839
   * 
1840
   * Specifies the resolution of the receptor clock in nanoseconds.
1841
   * For example, a microsecond clock has a clock_resolution of 1000.
1842
   */
1843
0
  void set_clock_resolution(uint32_t clock_resolution) { m_info.clock_resolution = clock_resolution; }
1844
  
1845
  /**
1846
   * clock_drift_rate.
1847
   * 
1848
   * The difference between the synchronized and unsynchronized
1849
   * time, over a period of one second. 
1850
   */
1851
0
  void set_clock_drift_rate(int32_t clock_drift_rate) { m_info.clock_drift_rate = clock_drift_rate; }
1852
  
1853
  /**
1854
   * clock_type.
1855
   * 
1856
   * 0 = Clock type is unknown
1857
   * 1 = The clock does not synchronize to an atomic source of absolute TAI time
1858
   * 2 = The clock can synchronize to an atomic source of absolute TAI time
1859
   */
1860
0
  void set_clock_type(uint8_t clock_type) { m_info.clock_type = clock_type; }
1861
1862
0
  uint64_t get_time_uncertainty() const { return m_info.time_uncertainty; }
1863
  
1864
0
  uint32_t get_clock_resolution() const { return m_info.clock_resolution; }
1865
  
1866
0
  int32_t get_clock_drift_rate() const { return m_info.clock_drift_rate; }
1867
  
1868
0
  uint8_t get_clock_type() const { return m_info.clock_type; }
1869
1870
0
  void set_from_tai_clock_info(const heif_tai_clock_info* info) {
1871
0
    heif_tai_clock_info_copy(&m_info, info);
1872
0
  }
1873
1874
  const heif_tai_clock_info* get_tai_clock_info() const
1875
0
  {
1876
0
    return &m_info;
1877
0
  }
1878
1879
  bool operator==(const Box& other) const override;
1880
1881
protected:
1882
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1883
1884
private:
1885
  heif_tai_clock_info m_info;
1886
};
1887
1888
bool operator==(const heif_tai_clock_info& a,
1889
                const heif_tai_clock_info& b);
1890
1891
1892
class Box_itai : public FullBox
1893
{
1894
public:
1895
  Box_itai()
1896
0
  {
1897
0
    set_short_type(fourcc("itai"));
1898
0
    initialize_heif_tai_timestamp_packet(&m_timestamp);
1899
0
  }
1900
1901
  std::string dump(Indent&) const override;
1902
1903
0
  const char* debug_box_name() const override { return "Item TAI Timestamp"; }
1904
1905
  Error write(StreamWriter& writer) const override;
1906
1907
  static std::vector<uint8_t> encode_tai_to_bitstream(const heif_tai_timestamp_packet*);
1908
1909
  static Result<heif_tai_timestamp_packet> decode_tai_from_vector(const std::vector<uint8_t>&);
1910
1911
  /**
1912
   * The number of nanoseconds since the TAI epoch of 1958-01-01T00:00:00.0Z.
1913
   */
1914
0
  void set_tai_timestamp(uint64_t timestamp) { m_timestamp.tai_timestamp = timestamp; }
1915
1916
  /**
1917
  * synchronization_state (0=unsynchronized, 1=synchronized)
1918
  */
1919
0
  void set_synchronization_state(bool state) { m_timestamp.synchronization_state = state; }
1920
1921
  /**
1922
  * timestamp_generation_failure (0=generated, 1=failed)
1923
  */
1924
0
  void set_timestamp_generation_failure(bool failure) { m_timestamp.timestamp_generation_failure = failure; }
1925
1926
  /**
1927
   * timestamp_is_modified (0=original 1=modified)
1928
   */
1929
0
  void set_timestamp_is_modified(bool is_modified) { m_timestamp.timestamp_is_modified = is_modified; }
1930
1931
0
  uint64_t get_tai_timestamp() const { return m_timestamp.tai_timestamp; }
1932
1933
0
  bool get_synchronization_state() const { return m_timestamp.synchronization_state; }
1934
1935
0
  bool get_timestamp_generation_failure() const { return m_timestamp.timestamp_generation_failure; }
1936
1937
0
  bool get_timestamp_is_modified() const { return m_timestamp.timestamp_is_modified; }
1938
1939
0
  void set_from_tai_timestamp_packet(const heif_tai_timestamp_packet* tai) {
1940
0
    heif_tai_timestamp_packet_copy(&m_timestamp, tai);
1941
0
  }
1942
1943
  const heif_tai_timestamp_packet* get_tai_timestamp_packet() const
1944
0
  {
1945
0
    return &m_timestamp;
1946
0
  }
1947
1948
  bool operator==(const Box& other) const override;
1949
1950
protected:
1951
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1952
1953
private:
1954
  heif_tai_timestamp_packet m_timestamp;
1955
};
1956
1957
class Box_gimi_content_id : public Box
1958
{
1959
public:
1960
  Box_gimi_content_id()
1961
1
  {
1962
1
    set_uuid_type(std::vector<uint8_t>{0x26, 0x1e, 0xf3, 0x74, 0x1d, 0x97, 0x5b, 0xba, 0xac, 0xbd, 0x9d, 0x2c, 0x8e, 0xa7, 0x35, 0x22});
1963
1
  }
1964
1965
0
  bool is_essential() const override { return false; }
1966
1967
0
  bool is_transformative_property() const override { return false; }
1968
1969
  std::string dump(Indent&) const override;
1970
1971
0
  const char* debug_box_name() const override { return "GIMI Content ID"; }
1972
1973
0
  std::string get_content_id() const { return m_content_id; }
1974
1975
0
  void set_content_id(const std::string& id) { m_content_id = id; }
1976
1977
0
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::ignorable; }
1978
1979
protected:
1980
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1981
1982
  Error write(StreamWriter& writer) const override;
1983
1984
private:
1985
  std::string m_content_id;
1986
};
1987
1988
1989
bool operator==(const heif_tai_timestamp_packet& a,
1990
                const heif_tai_timestamp_packet& b);
1991
1992
1993
/**
1994
 * Extended language property.
1995
 *
1996
 * Permits the association of language information with an item.
1997
 *
1998
 * See ISO/IEC 23008-12:2025(E) Section 6.10.2.2 and ISO/IEC 14496-12:2022(E) Section 8.4.6.
1999
 */
2000
class Box_elng : public FullBox
2001
{
2002
public:
2003
  Box_elng()
2004
5
  {
2005
5
    set_short_type(fourcc("elng"));
2006
5
  }
2007
2008
  std::string dump(Indent&) const override;
2009
2010
0
  const char* debug_box_name() const override { return "Extended language"; }
2011
2012
  Error write(StreamWriter& writer) const override;
2013
2014
  /**
2015
   * Language.
2016
   *
2017
   * An RFC 5646 (IETF BCP 47) compliant language identifier for the language of the text.
2018
   * Examples: "en-AU", "de-DE", or "zh-CN“.
2019
   */
2020
0
  std::string get_extended_language() const { return m_lang; }
2021
2022
  /**
2023
   * Set the language.
2024
   *
2025
   * An RFC 5646 (IETF BCP 47) compliant language identifier for the language of the text.
2026
   * Examples: "en-AU", "de-DE", or "zh-CN“.
2027
   */
2028
0
  void set_lang(const std::string lang) { m_lang = lang; }
2029
2030
0
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::optional; }
2031
2032
protected:
2033
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
2034
2035
private:
2036
  std::string m_lang;
2037
};
2038
2039
#endif