Coverage Report

Created: 2026-04-01 07:49

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
42.3k
  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
4.33M
  virtual ~BoxHeader() = default;
116
117
  constexpr static uint64_t size_until_end_of_file = 0;
118
119
8.29M
  uint64_t get_box_size() const { return m_size; }
120
121
3.51M
  bool has_fixed_box_size() const { return m_size != 0; }
122
123
6.05M
  uint32_t get_header_size() const { return m_header_size; }
124
125
3.87M
  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
2.14M
  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
2.14M
  Box() = default;
181
182
  void set_short_header(const BoxHeader& hdr)
183
1.69M
  {
184
1.69M
    *(BoxHeader*) this = hdr;
185
1.69M
  }
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
543k
  {
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.90M
    for (auto& box : m_children) {
210
1.90M
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
367k
        return typed_box;
212
367k
      }
213
1.90M
    }
214
215
175k
    return nullptr;
216
543k
  }
std::__1::shared_ptr<Box_tkhd> Box::get_child_box<Box_tkhd>() const
Line
Count
Source
206
356
  {
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
455
    for (auto& box : m_children) {
210
455
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
332
        return typed_box;
212
332
      }
213
455
    }
214
215
24
    return nullptr;
216
356
  }
std::__1::shared_ptr<Box_edts> Box::get_child_box<Box_edts>() const
Line
Count
Source
206
332
  {
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
781
    for (auto& box : m_children) {
210
781
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
170
        return typed_box;
212
170
      }
213
781
    }
214
215
162
    return nullptr;
216
332
  }
std::__1::shared_ptr<Box_elst> Box::get_child_box<Box_elst>() const
Line
Count
Source
206
170
  {
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
170
    for (auto& box : m_children) {
210
168
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
159
        return typed_box;
212
159
      }
213
168
    }
214
215
11
    return nullptr;
216
170
  }
std::__1::shared_ptr<Box_mdia> Box::get_child_box<Box_mdia>() const
Line
Count
Source
206
865
  {
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.33k
    for (auto& box : m_children) {
210
2.33k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
818
        return typed_box;
212
818
      }
213
2.33k
    }
214
215
47
    return nullptr;
216
865
  }
std::__1::shared_ptr<Box_tref> Box::get_child_box<Box_tref>() const
Line
Count
Source
206
332
  {
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
986
    for (auto& box : m_children) {
210
986
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
3
        return typed_box;
212
3
      }
213
986
    }
214
215
329
    return nullptr;
216
332
  }
std::__1::shared_ptr<Box_hdlr> Box::get_child_box<Box_hdlr>() const
Line
Count
Source
206
59.5k
  {
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
64.5k
    for (auto& box : m_children) {
210
64.5k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
58.7k
        return typed_box;
212
58.7k
      }
213
64.5k
    }
214
215
843
    return nullptr;
216
59.5k
  }
std::__1::shared_ptr<Box_minf> Box::get_child_box<Box_minf>() const
Line
Count
Source
206
332
  {
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.02k
    for (auto& box : m_children) {
210
1.02k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
301
        return typed_box;
212
301
      }
213
1.02k
    }
214
215
31
    return nullptr;
216
332
  }
std::__1::shared_ptr<Box_mdhd> Box::get_child_box<Box_mdhd>() const
Line
Count
Source
206
301
  {
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
340
    for (auto& box : m_children) {
210
340
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
283
        return typed_box;
212
283
      }
213
340
    }
214
215
18
    return nullptr;
216
301
  }
std::__1::shared_ptr<Box_stbl> Box::get_child_box<Box_stbl>() const
Line
Count
Source
206
283
  {
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
855
    for (auto& box : m_children) {
210
855
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
261
        return typed_box;
212
261
      }
213
855
    }
214
215
22
    return nullptr;
216
283
  }
std::__1::shared_ptr<Box_stsd> Box::get_child_box<Box_stsd>() const
Line
Count
Source
206
261
  {
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
387
    for (auto& box : m_children) {
210
387
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
237
        return typed_box;
212
237
      }
213
387
    }
214
215
24
    return nullptr;
216
261
  }
std::__1::shared_ptr<Box_stsc> Box::get_child_box<Box_stsc>() const
Line
Count
Source
206
237
  {
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.13k
    for (auto& box : m_children) {
210
1.13k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
214
        return typed_box;
212
214
      }
213
1.13k
    }
214
215
23
    return nullptr;
216
237
  }
std::__1::shared_ptr<Box_stco> Box::get_child_box<Box_stco>() const
Line
Count
Source
206
214
  {
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.48k
    for (auto& box : m_children) {
210
1.48k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
206
        return typed_box;
212
206
      }
213
1.48k
    }
214
215
8
    return nullptr;
216
214
  }
std::__1::shared_ptr<Box_stsz> Box::get_child_box<Box_stsz>() const
Line
Count
Source
206
206
  {
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.17k
    for (auto& box : m_children) {
210
1.17k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
202
        return typed_box;
212
202
      }
213
1.17k
    }
214
215
4
    return nullptr;
216
206
  }
std::__1::shared_ptr<Box_stts> Box::get_child_box<Box_stts>() const
Line
Count
Source
206
202
  {
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
464
    for (auto& box : m_children) {
210
464
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
190
        return typed_box;
212
190
      }
213
464
    }
214
215
12
    return nullptr;
216
202
  }
std::__1::shared_ptr<Box_auxi> Box::get_child_box<Box_auxi>() const
Line
Count
Source
206
7.13k
  {
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.6k
    for (auto& box : m_children) {
210
10.6k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
2
        return typed_box;
212
2
      }
213
10.6k
    }
214
215
7.13k
    return nullptr;
216
7.13k
  }
std::__1::shared_ptr<Box_taic> Box::get_child_box<Box_taic>() const
Line
Count
Source
206
7.13k
  {
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.6k
    for (auto& box : m_children) {
210
10.6k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
0
        return typed_box;
212
0
      }
213
10.6k
    }
214
215
7.13k
    return nullptr;
216
7.13k
  }
std::__1::shared_ptr<Box_meta> Box::get_child_box<Box_meta>() const
Line
Count
Source
206
147
  {
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
460
    for (auto& box : m_children) {
210
460
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
0
        return typed_box;
212
0
      }
213
460
    }
214
215
147
    return nullptr;
216
147
  }
std::__1::shared_ptr<Box_iloc> Box::get_child_box<Box_iloc>() const
Line
Count
Source
206
58.0k
  {
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
179k
    for (auto& box : m_children) {
210
179k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
57.9k
        return typed_box;
212
57.9k
      }
213
179k
    }
214
215
102
    return nullptr;
216
58.0k
  }
std::__1::shared_ptr<Box_idat> Box::get_child_box<Box_idat>() const
Line
Count
Source
206
57.9k
  {
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
306k
    for (auto& box : m_children) {
210
306k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
2.30k
        return typed_box;
212
2.30k
      }
213
306k
    }
214
215
55.6k
    return nullptr;
216
57.9k
  }
std::__1::shared_ptr<Box_iinf> Box::get_child_box<Box_iinf>() const
Line
Count
Source
206
58.7k
  {
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
233k
    for (auto& box : m_children) {
210
233k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
58.2k
        return typed_box;
212
58.2k
      }
213
233k
    }
214
215
520
    return nullptr;
216
58.7k
  }
std::__1::shared_ptr<Box_mvhd> Box::get_child_box<Box_mvhd>() const
Line
Count
Source
206
1.08k
  {
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.47k
    for (auto& box : m_children) {
210
1.47k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
988
        return typed_box;
212
988
      }
213
1.47k
    }
214
215
96
    return nullptr;
216
1.08k
  }
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
std::__1::shared_ptr<Box_hvcC> Box::get_child_box<Box_hvcC>() const
Line
Count
Source
206
21
  {
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
25
    for (auto& box : m_children) {
210
25
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
15
        return typed_box;
212
15
      }
213
25
    }
214
215
6
    return nullptr;
216
21
  }
std::__1::shared_ptr<Box_pitm> Box::get_child_box<Box_pitm>() const
Line
Count
Source
206
57.7k
  {
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
119k
    for (auto& box : m_children) {
210
119k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
57.7k
        return typed_box;
212
57.7k
      }
213
119k
    }
214
215
22
    return nullptr;
216
57.7k
  }
std::__1::shared_ptr<Box_iprp> Box::get_child_box<Box_iprp>() const
Line
Count
Source
206
57.7k
  {
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
297k
    for (auto& box : m_children) {
210
297k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
57.6k
        return typed_box;
212
57.6k
      }
213
297k
    }
214
215
67
    return nullptr;
216
57.7k
  }
std::__1::shared_ptr<Box_ipco> Box::get_child_box<Box_ipco>() const
Line
Count
Source
206
57.6k
  {
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
57.7k
    for (auto& box : m_children) {
210
57.7k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
57.6k
        return typed_box;
212
57.6k
      }
213
57.7k
    }
214
215
38
    return nullptr;
216
57.6k
  }
std::__1::shared_ptr<Box_iref> Box::get_child_box<Box_iref>() const
Line
Count
Source
206
57.9k
  {
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
299k
    for (auto& box : m_children) {
210
299k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
11.0k
        return typed_box;
212
11.0k
      }
213
299k
    }
214
215
46.8k
    return nullptr;
216
57.9k
  }
std::__1::shared_ptr<Box_grpl> Box::get_child_box<Box_grpl>() const
Line
Count
Source
206
57.9k
  {
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
309k
    for (auto& box : m_children) {
210
309k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
1.47k
        return typed_box;
212
1.47k
      }
213
309k
    }
214
215
56.4k
    return nullptr;
216
57.9k
  }
Unexecuted instantiation: std::__1::shared_ptr<Box_infe> Box::get_child_box<Box_infe>() const
std::__1::shared_ptr<Box_av1C> Box::get_child_box<Box_av1C>() const
Line
Count
Source
206
13
  {
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
19
    for (auto& box : m_children) {
210
19
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
11
        return typed_box;
212
11
      }
213
19
    }
214
215
2
    return nullptr;
216
13
  }
std::__1::shared_ptr<Box_vvcC> Box::get_child_box<Box_vvcC>() const
Line
Count
Source
206
1
  {
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
4
    for (auto& box : m_children) {
210
4
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
0
        return typed_box;
212
0
      }
213
4
    }
214
215
1
    return nullptr;
216
1
  }
std::__1::shared_ptr<Box_avcC> Box::get_child_box<Box_avcC>() const
Line
Count
Source
206
111
  {
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
149
    for (auto& box : m_children) {
210
149
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
93
        return typed_box;
212
93
      }
213
149
    }
214
215
18
    return nullptr;
216
111
  }
std::__1::shared_ptr<Box_uncC> Box::get_child_box<Box_uncC>() const
Line
Count
Source
206
4
  {
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
    for (auto& box : m_children) {
210
10
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
0
        return typed_box;
212
0
      }
213
10
    }
214
215
4
    return nullptr;
216
4
  }
std::__1::shared_ptr<Box_cmpd> Box::get_child_box<Box_cmpd>() const
Line
Count
Source
206
4
  {
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
    for (auto& box : m_children) {
210
10
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
0
        return typed_box;
212
0
      }
213
10
    }
214
215
4
    return nullptr;
216
4
  }
std::__1::shared_ptr<Box_cpat> Box::get_child_box<Box_cpat>() const
Line
Count
Source
206
4
  {
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
    for (auto& box : m_children) {
210
10
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
0
        return typed_box;
212
0
      }
213
10
    }
214
215
4
    return nullptr;
216
4
  }
std::__1::shared_ptr<Box_cmpC> Box::get_child_box<Box_cmpC>() const
Line
Count
Source
206
4
  {
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
    for (auto& box : m_children) {
210
10
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
0
        return typed_box;
212
0
      }
213
10
    }
214
215
4
    return nullptr;
216
4
  }
std::__1::shared_ptr<Box_icef> Box::get_child_box<Box_icef>() const
Line
Count
Source
206
4
  {
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
    for (auto& box : m_children) {
210
10
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
0
        return typed_box;
212
0
      }
213
10
    }
214
215
4
    return nullptr;
216
4
  }
std::__1::shared_ptr<Box_cloc> Box::get_child_box<Box_cloc>() const
Line
Count
Source
206
4
  {
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
    for (auto& box : m_children) {
210
10
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
0
        return typed_box;
212
0
      }
213
10
    }
214
215
4
    return nullptr;
216
4
  }
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
217
218
  template<typename T> bool replace_child_box(const std::shared_ptr<T>& box)
219
0
  {
220
0
    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
0
    append_child_box(box);
228
0
    return false;
229
0
  }
Unexecuted instantiation: bool Box::replace_child_box<Box_pitm>(std::__1::shared_ptr<Box_pitm> const&)
Unexecuted instantiation: bool Box::replace_child_box<Box_ipco>(std::__1::shared_ptr<Box_ipco> const&)
Unexecuted instantiation: bool Box::replace_child_box<Box_ipma>(std::__1::shared_ptr<Box_ipma> const&)
Unexecuted instantiation: bool Box::replace_child_box<Box_iloc>(std::__1::shared_ptr<Box_iloc> const&)
Unexecuted instantiation: bool Box::replace_child_box<Box_iref>(std::__1::shared_ptr<Box_iref> const&)
230
231
  template<typename T>
232
  std::vector<std::shared_ptr<T>> get_child_boxes() const
233
116k
  {
234
116k
    std::vector<std::shared_ptr<T>> result;
235
250k
    for (auto& box : m_children) {
236
250k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
237
177k
        result.push_back(typed_box);
238
177k
      }
239
250k
    }
240
241
116k
    return result;
242
116k
  }
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
Line
Count
Source
233
147
  {
234
147
    std::vector<std::shared_ptr<T>> result;
235
1.15k
    for (auto& box : m_children) {
236
1.15k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
237
0
        result.push_back(typed_box);
238
0
      }
239
1.15k
    }
240
241
147
    return result;
242
147
  }
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
Line
Count
Source
233
147
  {
234
147
    std::vector<std::shared_ptr<T>> result;
235
1.15k
    for (auto& box : m_children) {
236
1.15k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
237
0
        result.push_back(typed_box);
238
0
      }
239
1.15k
    }
240
241
147
    return result;
242
147
  }
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
58.2k
  {
234
58.2k
    std::vector<std::shared_ptr<T>> result;
235
130k
    for (auto& box : m_children) {
236
130k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
237
118k
        result.push_back(typed_box);
238
118k
      }
239
130k
    }
240
241
58.2k
    return result;
242
58.2k
  }
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
494
  {
234
494
    std::vector<std::shared_ptr<T>> result;
235
1.89k
    for (auto& box : m_children) {
236
1.89k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
237
685
        result.push_back(typed_box);
238
685
      }
239
1.89k
    }
240
241
494
    return result;
242
494
  }
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
57.6k
  {
234
57.6k
    std::vector<std::shared_ptr<T>> result;
235
116k
    for (auto& box : m_children) {
236
116k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
237
58.5k
        result.push_back(typed_box);
238
58.5k
      }
239
116k
    }
240
241
57.6k
    return result;
242
57.6k
  }
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
Line
Count
Source
233
4
  {
234
4
    std::vector<std::shared_ptr<T>> result;
235
10
    for (auto& box : m_children) {
236
10
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
237
0
        result.push_back(typed_box);
238
0
      }
239
10
    }
240
241
4
    return result;
242
4
  }
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
Line
Count
Source
233
4
  {
234
4
    std::vector<std::shared_ptr<T>> result;
235
10
    for (auto& box : m_children) {
236
10
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
237
0
        result.push_back(typed_box);
238
0
      }
239
10
    }
240
241
4
    return result;
242
4
  }
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
Line
Count
Source
233
4
  {
234
4
    std::vector<std::shared_ptr<T>> result;
235
10
    for (auto& box : m_children) {
236
10
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
237
0
        result.push_back(typed_box);
238
0
      }
239
10
    }
240
241
4
    return result;
242
4
  }
243
244
208k
  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
0
  {
248
0
    m_children.push_back(box);
249
0
    return (int) m_children.size() - 1;
250
0
  }
251
252
163k
  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
196k
  void set_output_position(uint64_t pos) { m_output_position = pos; }
263
264
99.8k
  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
1.46M
  uint8_t get_version() const { return m_version; }
323
324
0
  void set_version(uint8_t version) { m_version = version; }
325
326
718k
  uint32_t get_flags() const { return m_flags; }
327
328
2.99k
  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
141k
  {
351
141k
    set_short_type(short_type);
352
141k
  }
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
123k
  {
375
123k
    set_short_type(fourcc("ERR "));
376
377
123k
    m_box_type_with_parse_error = box4cc;
378
123k
    m_error = std::move(err);
379
123k
    m_fatality = fatality;
380
123k
  }
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
1.88k
  [[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
867k
  {
406
867k
    set_short_type(fourcc("ftyp"));
407
867k
  }
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
79.5k
  std::vector<uint32_t> list_brands() const { return m_compatible_brands; }
416
417
0
  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
0
  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
406
  {
446
406
    set_short_type(fourcc("free"));
447
406
  }
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
102k
  {
465
102k
    set_short_type(fourcc("meta"));
466
102k
  }
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
61.7k
  {
482
61.7k
    set_short_type(fourcc("hdlr"));
483
61.7k
  }
484
485
  std::string dump(Indent&) const override;
486
487
0
  const char* debug_box_name() const override { return "Handler Reference"; }
488
489
116k
  uint32_t get_handler_type() const { return m_handler_type; }
490
491
0
  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
62.9k
  {
513
62.9k
    set_short_type(fourcc("pitm"));
514
62.9k
  }
515
516
  std::string dump(Indent&) const override;
517
518
0
  const char* debug_box_name() const override { return "Primary Item"; }
519
520
82.7k
  heif_item_id get_item_ID() const { return m_item_ID; }
521
522
0
  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
59.9k
  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
0
  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
126k
  {
643
126k
    set_short_type(fourcc("infe"));
644
126k
  }
645
646
  std::string dump(Indent&) const override;
647
648
0
  const char* debug_box_name() const override { return "Item Info Entry"; }
649
650
91.9k
  bool is_hidden_item() const { return m_hidden_item; }
651
652
  void set_hidden_item(bool hidden);
653
654
348k
  heif_item_id get_item_ID() const { return m_item_ID; }
655
656
0
  void set_item_ID(heif_item_id id) { m_item_ID = id; }
657
658
694k
  uint32_t get_item_type_4cc() const { return m_item_type_4cc; }
659
660
0
  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
134k
  const std::string& get_content_type() const { return m_content_type; }
667
668
1.04k
  const std::string& get_content_encoding() const { return m_content_encoding; }
669
670
0
  void set_content_type(const std::string& content_type) { m_content_type = content_type; }
671
672
0
  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
19.2k
  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
64.2k
  {
705
64.2k
    set_short_type(fourcc("iinf"));
706
64.2k
  }
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
61.7k
  {
729
61.7k
    set_short_type(fourcc("iprp"));
730
61.7k
  }
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
60.9k
  {
746
60.9k
    set_short_type(fourcc("ipco"));
747
60.9k
  }
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
69.3k
  {
777
69.3k
    set_short_type(fourcc("ispe"));
778
69.3k
  }
779
780
134k
  uint32_t get_width() const { return m_image_width; }
781
782
134k
  uint32_t get_height() const { return m_image_height; }
783
784
  void set_size(uint32_t width, uint32_t height)
785
4
  {
786
4
    m_image_width = width;
787
4
    m_image_height = height;
788
4
  }
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
61.7k
  {
815
61.7k
    set_short_type(fourcc("ipma"));
816
61.7k
  }
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
8.43k
  {
862
8.43k
    set_short_type(fourcc("auxC"));
863
8.43k
  }
864
865
6.31k
  const std::string& get_aux_type() const { return m_aux_type; }
866
867
0
  void set_aux_type(const std::string& type) { m_aux_type = type; }
868
869
61
  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
2.74k
  {
893
2.74k
    set_short_type(fourcc("irot"));
894
2.74k
  }
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
3.08k
  int get_rotation_ccw() const { return m_rotation; }
905
906
  // Only these multiples of 90 are allowed: 0, 90, 180, 270.
907
0
  void set_rotation_ccw(int rot) { m_rotation = rot; }
908
909
73
  [[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
2.35k
  {
926
2.35k
    set_short_type(fourcc("imir"));
927
2.35k
  }
928
929
0
  bool is_essential() const override { return true; }
930
931
0
  bool is_transformative_property() const override { return true; }
932
933
1.64k
  heif_transform_mirror_direction get_mirror_direction() const { return m_axis; }
934
935
0
  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
1.13k
  [[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_clap : public Box
954
{
955
public:
956
  Box_clap()
957
10.5k
  {
958
10.5k
    set_short_type(fourcc("clap"));
959
10.5k
  }
960
961
0
  bool is_essential() const override { return true; }
962
963
0
  bool is_transformative_property() const override { return true; }
964
965
  std::string dump(Indent&) const override;
966
967
0
  const char* debug_box_name() const override { return "Clean Aperture"; }
968
969
  int left_rounded(uint32_t image_width) const;  // first column
970
  int right_rounded(uint32_t image_width) const; // last column that is part of the cropped image
971
  int top_rounded(uint32_t image_height) const;   // first row
972
  int bottom_rounded(uint32_t image_height) const; // last row included in the cropped image
973
974
  double left(int image_width) const;
975
  double top(int image_height) const;
976
977
  int get_width_rounded() const;
978
979
  int get_height_rounded() const;
980
981
  void set(uint32_t clap_width, uint32_t clap_height,
982
           uint32_t image_width, uint32_t image_height);
983
984
8.43k
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::ignorable; }
985
986
protected:
987
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
988
989
  Error write(StreamWriter& writer) const override;
990
991
private:
992
  Fraction m_clean_aperture_width;
993
  Fraction m_clean_aperture_height;
994
  Fraction m_horizontal_offset;
995
  Fraction m_vertical_offset;
996
};
997
998
999
class Box_iref : public FullBox
1000
{
1001
public:
1002
  Box_iref()
1003
12.8k
  {
1004
12.8k
    set_short_type(fourcc("iref"));
1005
12.8k
  }
1006
1007
  struct Reference
1008
  {
1009
    BoxHeader header;
1010
1011
    heif_item_id from_item_ID;
1012
    std::vector<heif_item_id> to_item_ID;
1013
  };
1014
1015
1016
  std::string dump(Indent&) const override;
1017
1018
0
  const char* debug_box_name() const override { return "Item Reference"; }
1019
1020
  bool has_references(heif_item_id itemID) const;
1021
1022
  std::vector<heif_item_id> get_references(heif_item_id itemID, uint32_t ref_type) const;
1023
1024
  std::vector<Reference> get_references_from(heif_item_id itemID) const;
1025
1026
  void add_references(heif_item_id from_id, uint32_t type, const std::vector<heif_item_id>& to_ids);
1027
1028
  void overwrite_reference(heif_item_id from_id, uint32_t type, uint32_t reference_idx, heif_item_id to_item);
1029
1030
protected:
1031
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1032
1033
  Error write(StreamWriter& writer) const override;
1034
1035
  void derive_box_version() override;
1036
1037
  Error check_for_double_references() const;
1038
1039
private:
1040
  std::vector<Reference> m_references;
1041
};
1042
1043
1044
class Box_idat : public Box
1045
{
1046
public:
1047
  std::string dump(Indent&) const override;
1048
1049
0
  const char* debug_box_name() const override { return "Item Data"; }
1050
1051
  Error read_data(const std::shared_ptr<StreamReader>& istr,
1052
                  uint64_t start, uint64_t length,
1053
                  std::vector<uint8_t>& out_data,
1054
                  const heif_security_limits* limits) const;
1055
1056
  int append_data(const std::vector<uint8_t>& data)
1057
0
  {
1058
0
    auto pos = m_data_for_writing.size();
1059
0
1060
0
    m_data_for_writing.insert(m_data_for_writing.end(),
1061
0
                              data.begin(),
1062
0
                              data.end());
1063
0
1064
0
    return (int) pos;
1065
0
  }
1066
1067
  Error write(StreamWriter& writer) const override;
1068
1069
protected:
1070
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1071
1072
  std::streampos m_data_start_pos;
1073
1074
  std::vector<uint8_t> m_data_for_writing;
1075
};
1076
1077
1078
class Box_grpl : public Box
1079
{
1080
public:
1081
  Box_grpl()
1082
1.96k
  {
1083
1.96k
    set_short_type(fourcc("grpl"));
1084
1.96k
  }
1085
1086
  std::string dump(Indent&) const override;
1087
1088
0
  const char* debug_box_name() const override { return "Groups List"; }
1089
1090
protected:
1091
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1092
};
1093
1094
1095
class Box_EntityToGroup : public FullBox
1096
{
1097
public:
1098
  std::string dump(Indent&) const override;
1099
1100
  Error write(StreamWriter& writer) const override;
1101
1102
0
  void set_group_id(heif_entity_group_id id) { group_id = id; }
1103
1104
0
  heif_entity_group_id get_group_id() const { return group_id; }
1105
1106
0
  void set_item_ids(const std::vector<heif_item_id>& ids) { entity_ids = ids; }
1107
1108
0
  const std::vector<heif_item_id>& get_item_ids() const { return entity_ids; }
1109
1110
protected:
1111
  heif_entity_group_id group_id = 0;
1112
  std::vector<heif_item_id> entity_ids;
1113
1114
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1115
1116
  void write_entity_group_ids(StreamWriter& writer) const;
1117
};
1118
1119
1120
class Box_ster : public Box_EntityToGroup
1121
{
1122
public:
1123
  Box_ster()
1124
111
  {
1125
111
    set_short_type(fourcc("ster"));
1126
111
  }
1127
1128
  std::string dump(Indent&) const override;
1129
1130
0
  const char* debug_box_name() const override { return "Stereo pair"; }
1131
1132
0
  heif_item_id get_left_image() const { return entity_ids[0]; }
1133
0
  heif_item_id get_right_image() const { return entity_ids[1]; }
1134
1135
protected:
1136
1137
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1138
};
1139
1140
1141
class Box_pymd : public Box_EntityToGroup
1142
{
1143
public:
1144
  Box_pymd()
1145
516
  {
1146
516
    set_short_type(fourcc("pymd"));
1147
516
  }
1148
1149
  std::string dump(Indent&) const override;
1150
1151
0
  const char* debug_box_name() const override { return "Image pyramid group"; }
1152
1153
  Error write(StreamWriter& writer) const override;
1154
1155
  struct LayerInfo {
1156
    uint16_t layer_binning;
1157
    uint16_t tiles_in_layer_row_minus1;
1158
    uint16_t tiles_in_layer_column_minus1;
1159
  };
1160
1161
  void set_layers(uint16_t _tile_size_x,
1162
                  uint16_t _tile_size_y,
1163
                  const std::vector<LayerInfo>& layers,
1164
                  const std::vector<heif_item_id>& layer_item_ids) // low to high resolution
1165
0
  {
1166
0
    set_item_ids(layer_item_ids);
1167
0
    m_layer_infos = layers;
1168
0
    tile_size_x = _tile_size_x;
1169
0
    tile_size_y = _tile_size_y;
1170
0
  }
1171
1172
0
  const std::vector<LayerInfo>& get_layers() const { return m_layer_infos; }
1173
1174
273
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::ignorable; }
1175
1176
protected:
1177
  uint16_t tile_size_x = 0;
1178
  uint16_t tile_size_y = 0;
1179
1180
  std::vector<LayerInfo> m_layer_infos;
1181
1182
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1183
};
1184
1185
1186
1187
1188
class Box_dinf : public Box
1189
{
1190
public:
1191
  Box_dinf()
1192
1.85k
  {
1193
1.85k
    set_short_type(fourcc("dinf"));
1194
1.85k
  }
1195
1196
  std::string dump(Indent&) const override;
1197
1198
0
  const char* debug_box_name() const override { return "Data Information"; }
1199
1200
protected:
1201
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1202
};
1203
1204
1205
class Box_dref : public FullBox
1206
{
1207
public:
1208
  Box_dref()
1209
1.78k
  {
1210
1.78k
    set_short_type(fourcc("dref"));
1211
1.78k
  }
1212
1213
  std::string dump(Indent&) const override;
1214
1215
0
  const char* debug_box_name() const override { return "Data Reference"; }
1216
1217
  Error write(StreamWriter& writer) const override;
1218
1219
protected:
1220
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1221
};
1222
1223
1224
class Box_url : public FullBox
1225
{
1226
public:
1227
  Box_url()
1228
1.26k
  {
1229
1.26k
    set_short_type(fourcc("url "));
1230
1.26k
    set_flags(1);
1231
1.26k
  }
1232
1233
  std::string dump(Indent&) const override;
1234
1235
0
  const char* debug_box_name() const override { return "Data Entry URL"; }
1236
1237
0
  bool is_same_file() const { return m_location.empty(); }
1238
1239
0
  void set_location(const std::string& loc) { m_location = loc; set_flags(m_location.empty() ? 1 : 0); }
1240
1241
0
  void set_location_same_file() { m_location.clear(); set_flags(1); }
1242
1243
  Error write(StreamWriter& writer) const override;
1244
1245
protected:
1246
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1247
1248
  std::string m_location;
1249
};
1250
1251
class Box_pixi : public FullBox
1252
{
1253
public:
1254
  Box_pixi()
1255
33.9k
  {
1256
33.9k
    set_short_type(fourcc("pixi"));
1257
33.9k
  }
1258
1259
0
  int get_num_channels() const { return (int) m_bits_per_channel.size(); }
1260
1261
0
  int get_bits_per_channel(int channel) const { return m_bits_per_channel[channel]; }
1262
1263
  void add_channel_bits(uint8_t c)
1264
0
  {
1265
0
    m_bits_per_channel.push_back(c);
1266
0
  }
1267
1268
  std::string dump(Indent&) const override;
1269
1270
0
  const char* debug_box_name() const override { return "Pixel Information"; }
1271
1272
  Error write(StreamWriter& writer) const override;
1273
1274
3.58k
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::optional; }
1275
1276
protected:
1277
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1278
1279
private:
1280
  std::vector<uint8_t> m_bits_per_channel;
1281
};
1282
1283
1284
class Box_pasp : public Box
1285
{
1286
public:
1287
  Box_pasp()
1288
3.21k
  {
1289
3.21k
    set_short_type(fourcc("pasp"));
1290
3.21k
  }
1291
1292
  uint32_t hSpacing = 1;
1293
  uint32_t vSpacing = 1;
1294
1295
  std::string dump(Indent&) const override;
1296
1297
0
  const char* debug_box_name() const override { return "Pixel Aspect Ratio"; }
1298
1299
  Error write(StreamWriter& writer) const override;
1300
1301
30
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::optional; }
1302
1303
protected:
1304
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1305
};
1306
1307
1308
class Box_lsel : public Box
1309
{
1310
public:
1311
  Box_lsel()
1312
609
  {
1313
609
    set_short_type(fourcc("lsel"));
1314
609
  }
1315
1316
  uint16_t layer_id = 0;
1317
1318
  std::string dump(Indent&) const override;
1319
1320
0
  const char* debug_box_name() const override { return "Layer Selection"; }
1321
1322
  Error write(StreamWriter& writer) const override;
1323
1324
89
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::optional; }
1325
1326
protected:
1327
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1328
};
1329
1330
1331
class Box_clli : public Box
1332
{
1333
public:
1334
  Box_clli()
1335
194
  {
1336
194
    set_short_type(fourcc("clli"));
1337
1338
194
    clli.max_content_light_level = 0;
1339
194
    clli.max_pic_average_light_level = 0;
1340
194
  }
1341
1342
  heif_content_light_level clli;
1343
1344
  std::string dump(Indent&) const override;
1345
1346
0
  const char* debug_box_name() const override { return "Content Light Level Information"; }
1347
1348
  Error write(StreamWriter& writer) const override;
1349
1350
30
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::optional; }
1351
1352
protected:
1353
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1354
};
1355
1356
1357
class Box_mdcv : public Box
1358
{
1359
public:
1360
  Box_mdcv();
1361
1362
  heif_mastering_display_colour_volume mdcv;
1363
1364
  std::string dump(Indent&) const override;
1365
1366
0
  const char* debug_box_name() const override { return "Master Display Colour Volume"; }
1367
1368
  Error write(StreamWriter& writer) const override;
1369
1370
265
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::optional; }
1371
1372
protected:
1373
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1374
};
1375
1376
1377
class Box_amve : public Box
1378
{
1379
public:
1380
  Box_amve();
1381
1382
  heif_ambient_viewing_environment amve;
1383
1384
  std::string dump(Indent&) const override;
1385
1386
0
  const char* debug_box_name() const override { return "Ambient Viewing Environment"; }
1387
1388
  Error write(StreamWriter& writer) const override;
1389
1390
55
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::optional; }
1391
1392
protected:
1393
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1394
};
1395
1396
1397
class Box_cclv : public Box
1398
{
1399
public:
1400
  Box_cclv();
1401
1402
0
  bool ccv_primaries_are_valid() const { return m_ccv_primaries_valid; }
1403
0
  int32_t get_ccv_primary_x0() const { return m_ccv_primaries_x[0]; }
1404
0
  int32_t get_ccv_primary_y0() const { return m_ccv_primaries_y[0]; }
1405
0
  int32_t get_ccv_primary_x1() const { return m_ccv_primaries_x[1]; }
1406
0
  int32_t get_ccv_primary_y1() const { return m_ccv_primaries_y[1]; }
1407
0
  int32_t get_ccv_primary_x2() const { return m_ccv_primaries_x[2]; }
1408
0
  int32_t get_ccv_primary_y2() const { return m_ccv_primaries_y[2]; }
1409
  void set_primaries(int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t x2, int32_t y2);
1410
1411
0
  bool min_luminance_is_valid() const { return m_ccv_min_luminance_value.has_value(); }
1412
0
  uint32_t get_min_luminance() const { return *m_ccv_min_luminance_value; }
1413
0
  void set_min_luminance(uint32_t luminance) { m_ccv_min_luminance_value = luminance; }
1414
1415
0
  bool max_luminance_is_valid() const { return m_ccv_max_luminance_value.has_value(); }
1416
0
  uint32_t get_max_luminance() const { return *m_ccv_max_luminance_value; }
1417
0
  void set_max_luminance(uint32_t luminance) { m_ccv_max_luminance_value = luminance; }
1418
1419
0
  bool avg_luminance_is_valid() const { return m_ccv_avg_luminance_value.has_value(); }
1420
0
  uint32_t get_avg_luminance() const { return *m_ccv_avg_luminance_value; }
1421
0
  void set_avg_luminance(uint32_t luminance) { m_ccv_avg_luminance_value = luminance; }
1422
1423
  std::string dump(Indent&) const override;
1424
1425
  // TODO const char* debug_box_name() const override { return ""; }
1426
1427
  Error write(StreamWriter& writer) const override;
1428
1429
0
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::optional; }
1430
1431
protected:
1432
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1433
1434
private:
1435
  bool m_ccv_primaries_valid = false;
1436
  int32_t m_ccv_primaries_x[3] {};
1437
  int32_t m_ccv_primaries_y[3] {};
1438
1439
  std::optional<uint32_t> m_ccv_min_luminance_value;
1440
  std::optional<uint32_t> m_ccv_max_luminance_value;
1441
  std::optional<uint32_t> m_ccv_avg_luminance_value;
1442
};
1443
1444
1445
class Box_cmin : public FullBox
1446
{
1447
public:
1448
  Box_cmin()
1449
816
  {
1450
816
    set_short_type(fourcc("cmin"));
1451
816
  }
1452
1453
  struct AbsoluteIntrinsicMatrix;
1454
1455
  struct RelativeIntrinsicMatrix
1456
  {
1457
    double focal_length_x = 0;
1458
    double principal_point_x = 0;
1459
    double principal_point_y = 0;
1460
1461
    bool is_anisotropic = false;
1462
    double focal_length_y = 0;
1463
    double skew = 0;
1464
1465
    void compute_focal_length(int image_width, int image_height,
1466
                              double& out_focal_length_x, double& out_focal_length_y) const;
1467
1468
    void compute_principal_point(int image_width, int image_height,
1469
                                 double& out_principal_point_x, double& out_principal_point_y) const;
1470
1471
    struct AbsoluteIntrinsicMatrix to_absolute(int image_width, int image_height) const;
1472
  };
1473
1474
  struct AbsoluteIntrinsicMatrix
1475
  {
1476
    double focal_length_x;
1477
    double focal_length_y;
1478
    double principal_point_x;
1479
    double principal_point_y;
1480
    double skew = 0;
1481
1482
0
    void apply_clap(const Box_clap* clap, int image_width, int image_height) {
1483
0
      principal_point_x -= clap->left(image_width);
1484
0
      principal_point_y -= clap->top(image_height);
1485
0
    }
1486
1487
1.40k
    void apply_imir(const Box_imir* imir, uint32_t image_width, uint32_t image_height) {
1488
1.40k
      switch (imir->get_mirror_direction()) {
1489
930
        case heif_transform_mirror_direction_horizontal:
1490
930
          focal_length_x *= -1;
1491
930
          skew *= -1;
1492
930
          principal_point_x = image_width - 1 - principal_point_x;
1493
930
          break;
1494
473
        case heif_transform_mirror_direction_vertical:
1495
473
          focal_length_y *= -1;
1496
473
          principal_point_y = image_height - 1 - principal_point_y;
1497
473
          break;
1498
0
        case heif_transform_mirror_direction_invalid:
1499
0
          break;
1500
1.40k
      }
1501
1.40k
    }
1502
  };
1503
1504
  std::string dump(Indent&) const override;
1505
1506
0
  const char* debug_box_name() const override { return "Camera Intrinsic Matrix"; }
1507
1508
0
  RelativeIntrinsicMatrix get_intrinsic_matrix() const { return m_matrix; }
1509
1510
  void set_intrinsic_matrix(RelativeIntrinsicMatrix matrix);
1511
1512
734
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::optional; }
1513
1514
protected:
1515
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1516
1517
  Error write(StreamWriter& writer) const override;
1518
1519
private:
1520
  RelativeIntrinsicMatrix m_matrix;
1521
1522
  uint32_t m_denominatorShift = 0;
1523
  uint32_t m_skewDenominatorShift = 0;
1524
};
1525
1526
1527
class Box_cmex : public FullBox
1528
{
1529
public:
1530
  Box_cmex()
1531
11.6k
  {
1532
11.6k
    set_short_type(fourcc("cmex"));
1533
11.6k
  }
1534
1535
  struct ExtrinsicMatrix
1536
  {
1537
    // in micrometers (um)
1538
    int32_t pos_x = 0;
1539
    int32_t pos_y = 0;
1540
    int32_t pos_z = 0;
1541
1542
    bool rotation_as_quaternions = true;
1543
    bool orientation_is_32bit = false;
1544
1545
    double quaternion_x = 0;
1546
    double quaternion_y = 0;
1547
    double quaternion_z = 0;
1548
    double quaternion_w = 1.0;
1549
1550
    // rotation angle in degrees
1551
    double rotation_yaw = 0;   //  [-180 ; 180)
1552
    double rotation_pitch = 0; //  [-90 ; 90]
1553
    double rotation_roll = 0;  //  [-180 ; 180)
1554
1555
    uint32_t world_coordinate_system_id = 0;
1556
1557
    // Returns rotation matrix in row-major order.
1558
    std::array<double,9> calculate_rotation_matrix() const;
1559
  };
1560
1561
  std::string dump(Indent&) const override;
1562
1563
0
  const char* debug_box_name() const override { return "Camera Extrinsic Matrix"; }
1564
1565
3
  ExtrinsicMatrix get_extrinsic_matrix() const { return m_matrix; }
1566
1567
  Error set_extrinsic_matrix(ExtrinsicMatrix matrix);
1568
1569
8.21k
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::optional; }
1570
1571
protected:
1572
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1573
1574
  Error write(StreamWriter& writer) const override;
1575
1576
private:
1577
  ExtrinsicMatrix m_matrix;
1578
1579
  bool m_has_pos_x = false;
1580
  bool m_has_pos_y = false;
1581
  bool m_has_pos_z = false;
1582
  bool m_has_orientation = false;
1583
  bool m_has_world_coordinate_system_id = false;
1584
1585
  enum Flags
1586
  {
1587
    pos_x_present = 0x01,
1588
    pos_y_present = 0x02,
1589
    pos_z_present = 0x04,
1590
    orientation_present = 0x08,
1591
    rot_large_field_size = 0x10,
1592
    id_present = 0x20
1593
  };
1594
};
1595
1596
1597
1598
1599
/**
1600
 * User Description property.
1601
 *
1602
 * Permits the association of items or entity groups with a user-defined name, description and tags;
1603
 * there may be multiple udes properties, each with a different language code.
1604
 *
1605
 * See ISO/IEC 23008-12:2022(E) Section 6.5.20.
1606
 */
1607
class Box_udes : public FullBox
1608
{
1609
public:
1610
  Box_udes()
1611
1.38k
  {
1612
1.38k
    set_short_type(fourcc("udes"));
1613
1.38k
  }
1614
1615
  std::string dump(Indent&) const override;
1616
1617
0
  const char* debug_box_name() const override { return "User Description"; }
1618
1619
  Error write(StreamWriter& writer) const override;
1620
1621
  /**
1622
   * Language tag.
1623
   *
1624
   * An RFC 5646 compliant language identifier for the language of the text contained in the other properties.
1625
   * Examples: "en-AU", "de-DE", or "zh-CN“.
1626
   * When is empty, the language is unknown or not undefined.
1627
   */
1628
0
  std::string get_lang() const { return m_lang; }
1629
1630
  /**
1631
   * Set the language tag.
1632
   *
1633
   * An RFC 5646 compliant language identifier for the language of the text contained in the other properties.
1634
   * Examples: "en-AU", "de-DE", or "zh-CN“.
1635
   */
1636
0
  void set_lang(const std::string lang) { m_lang = lang; }
1637
1638
  /**
1639
   * Name.
1640
   *
1641
   * Human readable name for the item or group being described.
1642
   * May be empty, indicating no name is applicable.
1643
   */
1644
0
  std::string get_name() const { return m_name; }
1645
1646
  /**
1647
  * Set the name.
1648
  *
1649
  * Human readable name for the item or group being described.
1650
  */
1651
0
  void set_name(const std::string name) { m_name = name; }
1652
1653
  /**
1654
   * Description.
1655
   *
1656
   * Human readable description for the item or group.
1657
   * May be empty, indicating no description has been provided.
1658
   */
1659
0
  std::string get_description() const { return m_description; }
1660
1661
  /**
1662
   * Set the description.
1663
   *
1664
   * Human readable description for the item or group.
1665
   */
1666
0
  void set_description(const std::string description) { m_description = description; }
1667
1668
  /**
1669
   * Tags.
1670
   *
1671
   * Comma separated user defined tags applicable to the item or group.
1672
   * May be empty, indicating no tags have been assigned.
1673
   */
1674
0
  std::string get_tags() const { return m_tags; }
1675
1676
  /**
1677
   * Set the tags.
1678
   *
1679
   * Comma separated user defined tags applicable to the item or group.
1680
   */
1681
0
  void set_tags(const std::string tags) { m_tags = tags; }
1682
1683
631
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::optional; }
1684
1685
protected:
1686
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1687
1688
private:
1689
  std::string m_lang;
1690
  std::string m_name;
1691
  std::string m_description;
1692
  std::string m_tags;
1693
};
1694
1695
1696
void initialize_heif_tai_clock_info(heif_tai_clock_info* taic);
1697
void initialize_heif_tai_timestamp_packet(heif_tai_timestamp_packet* itai);
1698
1699
1700
class Box_taic : public FullBox
1701
{
1702
public:
1703
  Box_taic()
1704
37
  {
1705
37
    set_short_type(fourcc("taic"));
1706
37
    initialize_heif_tai_clock_info(&m_info);
1707
37
  }
1708
1709
  static std::string dump(const heif_tai_clock_info& info, Indent&);
1710
1711
  std::string dump(Indent&) const override;
1712
1713
0
  const char* debug_box_name() const override { return "TAI Clock Information"; }
1714
1715
  Error write(StreamWriter& writer) const override;
1716
1717
  /**
1718
   * time_uncertainty.
1719
   * 
1720
   * The standard deviation measurement uncertainty in nanoseconds
1721
   * for the timestamp generation process. 
1722
   */
1723
0
  void set_time_uncertainty(uint64_t time_uncertainty) { m_info.time_uncertainty = time_uncertainty;}
1724
  
1725
  /**
1726
   * clock_resolution.
1727
   * 
1728
   * Specifies the resolution of the receptor clock in nanoseconds.
1729
   * For example, a microsecond clock has a clock_resolution of 1000.
1730
   */
1731
0
  void set_clock_resolution(uint32_t clock_resolution) { m_info.clock_resolution = clock_resolution; }
1732
  
1733
  /**
1734
   * clock_drift_rate.
1735
   * 
1736
   * The difference between the synchronized and unsynchronized
1737
   * time, over a period of one second. 
1738
   */
1739
0
  void set_clock_drift_rate(int32_t clock_drift_rate) { m_info.clock_drift_rate = clock_drift_rate; }
1740
  
1741
  /**
1742
   * clock_type.
1743
   * 
1744
   * 0 = Clock type is unknown
1745
   * 1 = The clock does not synchronize to an atomic source of absolute TAI time
1746
   * 2 = The clock can synchronize to an atomic source of absolute TAI time
1747
   */
1748
0
  void set_clock_type(uint8_t clock_type) { m_info.clock_type = clock_type; }
1749
1750
0
  uint64_t get_time_uncertainty() const { return m_info.time_uncertainty; }
1751
  
1752
0
  uint32_t get_clock_resolution() const { return m_info.clock_resolution; }
1753
  
1754
0
  int32_t get_clock_drift_rate() const { return m_info.clock_drift_rate; }
1755
  
1756
0
  uint8_t get_clock_type() const { return m_info.clock_type; }
1757
1758
0
  void set_from_tai_clock_info(const heif_tai_clock_info* info) {
1759
0
    heif_tai_clock_info_copy(&m_info, info);
1760
0
  }
1761
1762
  const heif_tai_clock_info* get_tai_clock_info() const
1763
0
  {
1764
0
    return &m_info;
1765
0
  }
1766
1767
  bool operator==(const Box& other) const override;
1768
1769
protected:
1770
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1771
1772
private:
1773
  heif_tai_clock_info m_info;
1774
};
1775
1776
bool operator==(const heif_tai_clock_info& a,
1777
                const heif_tai_clock_info& b);
1778
1779
1780
class Box_itai : public FullBox
1781
{
1782
public:
1783
  Box_itai()
1784
219
  {
1785
219
    set_short_type(fourcc("itai"));
1786
219
    initialize_heif_tai_timestamp_packet(&m_timestamp);
1787
219
  }
1788
1789
  std::string dump(Indent&) const override;
1790
1791
0
  const char* debug_box_name() const override { return "Item TAI Timestamp"; }
1792
1793
  Error write(StreamWriter& writer) const override;
1794
1795
  static std::vector<uint8_t> encode_tai_to_bitstream(const heif_tai_timestamp_packet*);
1796
1797
  static Result<heif_tai_timestamp_packet> decode_tai_from_vector(const std::vector<uint8_t>&);
1798
1799
  /**
1800
   * The number of nanoseconds since the TAI epoch of 1958-01-01T00:00:00.0Z.
1801
   */
1802
0
  void set_tai_timestamp(uint64_t timestamp) { m_timestamp.tai_timestamp = timestamp; }
1803
1804
  /**
1805
  * synchronization_state (0=unsynchronized, 1=synchronized)
1806
  */
1807
0
  void set_synchronization_state(bool state) { m_timestamp.synchronization_state = state; }
1808
1809
  /**
1810
  * timestamp_generation_failure (0=generated, 1=failed)
1811
  */
1812
0
  void set_timestamp_generation_failure(bool failure) { m_timestamp.timestamp_generation_failure = failure; }
1813
1814
  /**
1815
   * timestamp_is_modified (0=original 1=modified)
1816
   */
1817
0
  void set_timestamp_is_modified(bool is_modified) { m_timestamp.timestamp_is_modified = is_modified; }
1818
1819
0
  uint64_t get_tai_timestamp() const { return m_timestamp.tai_timestamp; }
1820
1821
0
  bool get_synchronization_state() const { return m_timestamp.synchronization_state; }
1822
1823
0
  bool get_timestamp_generation_failure() const { return m_timestamp.timestamp_generation_failure; }
1824
1825
0
  bool get_timestamp_is_modified() const { return m_timestamp.timestamp_is_modified; }
1826
1827
0
  void set_from_tai_timestamp_packet(const heif_tai_timestamp_packet* tai) {
1828
0
    heif_tai_timestamp_packet_copy(&m_timestamp, tai);
1829
0
  }
1830
1831
  const heif_tai_timestamp_packet* get_tai_timestamp_packet() const
1832
0
  {
1833
0
    return &m_timestamp;
1834
0
  }
1835
1836
  bool operator==(const Box& other) const override;
1837
1838
protected:
1839
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1840
1841
private:
1842
  heif_tai_timestamp_packet m_timestamp;
1843
};
1844
1845
class Box_gimi_content_id : public Box
1846
{
1847
public:
1848
  Box_gimi_content_id()
1849
70
  {
1850
70
    set_uuid_type(std::vector<uint8_t>{0x26, 0x1e, 0xf3, 0x74, 0x1d, 0x97, 0x5b, 0xba, 0xac, 0xbd, 0x9d, 0x2c, 0x8e, 0xa7, 0x35, 0x22});
1851
70
  }
1852
1853
0
  bool is_essential() const override { return false; }
1854
1855
0
  bool is_transformative_property() const override { return false; }
1856
1857
  std::string dump(Indent&) const override;
1858
1859
0
  const char* debug_box_name() const override { return "GIMI Content ID"; }
1860
1861
0
  std::string get_content_id() const { return m_content_id; }
1862
1863
0
  void set_content_id(const std::string& id) { m_content_id = id; }
1864
1865
0
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::ignorable; }
1866
1867
protected:
1868
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1869
1870
  Error write(StreamWriter& writer) const override;
1871
1872
private:
1873
  std::string m_content_id;
1874
};
1875
1876
1877
bool operator==(const heif_tai_timestamp_packet& a,
1878
                const heif_tai_timestamp_packet& b);
1879
1880
1881
/**
1882
 * Extended language property.
1883
 *
1884
 * Permits the association of language information with an item.
1885
 *
1886
 * See ISO/IEC 23008-12:2025(E) Section 6.10.2.2 and ISO/IEC 14496-12:2022(E) Section 8.4.6.
1887
 */
1888
class Box_elng : public FullBox
1889
{
1890
public:
1891
  Box_elng()
1892
7
  {
1893
7
    set_short_type(fourcc("elng"));
1894
7
  }
1895
1896
  std::string dump(Indent&) const override;
1897
1898
0
  const char* debug_box_name() const override { return "Extended language"; }
1899
1900
  Error write(StreamWriter& writer) const override;
1901
1902
  /**
1903
   * Language.
1904
   *
1905
   * An RFC 5646 (IETF BCP 47) compliant language identifier for the language of the text.
1906
   * Examples: "en-AU", "de-DE", or "zh-CN“.
1907
   */
1908
0
  std::string get_extended_language() const { return m_lang; }
1909
1910
  /**
1911
   * Set the language.
1912
   *
1913
   * An RFC 5646 (IETF BCP 47) compliant language identifier for the language of the text.
1914
   * Examples: "en-AU", "de-DE", or "zh-CN“.
1915
   */
1916
0
  void set_lang(const std::string lang) { m_lang = lang; }
1917
1918
4
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::optional; }
1919
1920
protected:
1921
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1922
1923
private:
1924
  std::string m_lang;
1925
};
1926
1927
#endif