/src/libultrahdr/third_party/libheif/libheif/file_layout.cc
Line | Count | Source |
1 | | /* |
2 | | * HEIF codec. |
3 | | * Copyright (c) 2024 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 | | #include "file_layout.h" |
22 | | |
23 | | |
24 | | FileLayout::FileLayout() |
25 | 31.6k | { |
26 | 31.6k | auto ftyp = std::make_shared<Box_ftyp>(); |
27 | 31.6k | ftyp->set_output_position(0); |
28 | 31.6k | m_boxes.push_back(ftyp); |
29 | | |
30 | | // TODO: these variables are not used yet |
31 | 31.6k | (void)m_writeMode; |
32 | 31.6k | (void)m_file_size; |
33 | 31.6k | } |
34 | | |
35 | | |
36 | | Error FileLayout::read(const std::shared_ptr<StreamReader>& stream, const heif_security_limits* limits) |
37 | 15.8k | { |
38 | 15.8k | m_boxes.clear(); |
39 | | |
40 | 15.8k | m_stream_reader = stream; |
41 | | |
42 | | // --- read initial range, large enough to cover 'ftyp' box |
43 | | |
44 | 15.8k | m_max_length = stream->request_range(0, INITIAL_FTYP_REQUEST); |
45 | | |
46 | 15.8k | if (m_max_length < MAXIMUM_BOX_HEADER_SIZE) { |
47 | 5.79k | return {heif_error_Invalid_input, |
48 | 5.79k | heif_suberror_Unspecified, |
49 | 5.79k | "File size too small."}; |
50 | 5.79k | } |
51 | | |
52 | | // --- read 'ftyp' box header |
53 | | |
54 | 10.0k | BitstreamRange ftyp_hdr_range(m_stream_reader, m_max_length); |
55 | 10.0k | BoxHeader ftyp_header; |
56 | 10.0k | Error err; |
57 | 10.0k | err = ftyp_header.parse_header(ftyp_hdr_range); |
58 | 10.0k | if (err) { |
59 | 43 | return err; |
60 | 43 | } |
61 | | |
62 | | // --- check whether it is a valid 'ftyp' box header |
63 | | |
64 | 9.98k | if (ftyp_header.get_short_type() != fourcc("ftyp")) { |
65 | 0 | return {heif_error_Invalid_input, |
66 | 0 | heif_suberror_No_ftyp_box, |
67 | 0 | "File does not start with 'ftyp' box."}; |
68 | 0 | } |
69 | | |
70 | 9.98k | uint64_t ftyp_size = ftyp_header.get_box_size(); |
71 | | |
72 | 9.98k | if (ftyp_size == 0) { |
73 | 8 | return {heif_error_Invalid_input, |
74 | 8 | heif_suberror_No_ftyp_box, |
75 | 8 | "ftyp box shall not be the only box in the file"}; |
76 | 8 | } |
77 | | |
78 | 9.97k | if (ftyp_size > m_max_length) { |
79 | 119 | return {heif_error_Invalid_input, |
80 | 119 | heif_suberror_No_ftyp_box, |
81 | 119 | "ftyp box larger than initial read range"}; |
82 | 119 | } |
83 | | |
84 | | // --- read the 'ftyp' box |
85 | | |
86 | 9.85k | BitstreamRange ftyp_range(m_stream_reader, 0, ftyp_size); |
87 | 9.85k | std::shared_ptr<Box> ftyp_box; |
88 | 9.85k | err = Box::read(ftyp_range, &ftyp_box, limits); |
89 | | |
90 | 9.85k | m_boxes.push_back(ftyp_box); |
91 | 9.85k | m_ftyp_box = std::dynamic_pointer_cast<Box_ftyp>(ftyp_box); |
92 | | |
93 | | |
94 | | // --- skip through box headers until we find the 'meta' box |
95 | | |
96 | 9.85k | uint64_t next_box_start = ftyp_size; |
97 | | |
98 | 11.6k | for (;;) { |
99 | | // TODO: overflow |
100 | 11.6k | uint64_t next_box_header_end = next_box_start + MAXIMUM_BOX_HEADER_SIZE; |
101 | 11.6k | if (next_box_header_end > m_max_length) { |
102 | 1.74k | m_max_length = stream->request_range(next_box_start, next_box_header_end); |
103 | 1.74k | } |
104 | | |
105 | 11.6k | if (next_box_header_end > m_max_length) { |
106 | 1.74k | return {heif_error_Invalid_input, |
107 | 1.74k | heif_suberror_Unspecified, |
108 | 1.74k | "Insufficient input data"}; |
109 | 1.74k | } |
110 | | |
111 | 9.86k | BitstreamRange box_range(m_stream_reader, next_box_start, m_max_length); |
112 | 9.86k | BoxHeader box_header; |
113 | 9.86k | err = box_header.parse_header(box_range); |
114 | 9.86k | if (err) { |
115 | 18 | return err; |
116 | 18 | } |
117 | | |
118 | 9.84k | if (box_header.get_short_type() == fourcc("meta")) { |
119 | 8.06k | const uint64_t meta_box_start = next_box_start; |
120 | 8.06k | if (box_header.get_box_size() == 0) { |
121 | | // TODO: get file-size from stream and compute box size |
122 | 8 | return {heif_error_Invalid_input, |
123 | 8 | heif_suberror_No_meta_box, |
124 | 8 | "Cannot read meta box with unspecified size"}; |
125 | 8 | } |
126 | | |
127 | | // TODO: overflow |
128 | 8.06k | uint64_t end_of_meta_box = meta_box_start + box_header.get_box_size(); |
129 | 8.06k | if (m_max_length < end_of_meta_box) { |
130 | 905 | m_max_length = m_stream_reader->request_range(meta_box_start, end_of_meta_box); |
131 | 905 | } |
132 | | |
133 | 8.06k | if (m_max_length < end_of_meta_box) { |
134 | 905 | return {heif_error_Invalid_input, |
135 | 905 | heif_suberror_No_meta_box, |
136 | 905 | "Cannot read full meta box"}; |
137 | 905 | } |
138 | | |
139 | 7.15k | BitstreamRange meta_box_range(m_stream_reader, meta_box_start, end_of_meta_box); |
140 | 7.15k | std::shared_ptr<Box> meta_box; |
141 | 7.15k | err = Box::read(meta_box_range, &meta_box, limits); |
142 | 7.15k | if (err) { |
143 | 5.44k | return err; |
144 | 5.44k | } |
145 | | |
146 | 1.71k | m_boxes.push_back(meta_box); |
147 | 1.71k | m_meta_box = std::dynamic_pointer_cast<Box_meta>(meta_box); |
148 | 1.71k | break; |
149 | 7.15k | } |
150 | | |
151 | | #if ENABLE_EXPERIMENTAL_MINI_FORMAT |
152 | | // TODO: this is basically the same as the meta box case above, with different error handling. |
153 | | if (box_header.get_short_type() == fourcc("mini")) { |
154 | | const uint64_t mini_box_start = next_box_start; |
155 | | if (box_header.get_box_size() == 0) { |
156 | | // TODO: get file-size from stream and compute box size |
157 | | return {heif_error_Invalid_input, |
158 | | heif_suberror_Invalid_mini_box, |
159 | | "Cannot read mini box with unspecified size"}; |
160 | | } |
161 | | uint64_t end_of_mini_box = mini_box_start + box_header.get_box_size(); |
162 | | if (m_max_length < end_of_mini_box) { |
163 | | m_max_length = m_stream_reader->request_range(mini_box_start, end_of_mini_box); |
164 | | } |
165 | | |
166 | | if (m_max_length < end_of_mini_box) { |
167 | | return {heif_error_Invalid_input, |
168 | | heif_suberror_Invalid_mini_box, |
169 | | "Cannot read full mini box"}; |
170 | | } |
171 | | BitstreamRange mini_box_range(m_stream_reader, mini_box_start, end_of_mini_box); |
172 | | std::shared_ptr<Box> mini_box; |
173 | | err = Box::read(mini_box_range, &mini_box, heif_get_global_security_limits()); |
174 | | if (err) { |
175 | | std::cout << "error reading mini box" << std::endl; |
176 | | return err; |
177 | | } |
178 | | |
179 | | m_boxes.push_back(mini_box); |
180 | | m_mini_box = std::dynamic_pointer_cast<Box_mini>(mini_box); |
181 | | if (m_mini_box == nullptr) { |
182 | | std::cout << "error casting mini box" << std::endl; |
183 | | } |
184 | | return Error::Ok; |
185 | | } |
186 | | #endif |
187 | | |
188 | 1.78k | if (box_header.get_box_size() == 0) { |
189 | 25 | return {heif_error_Invalid_input, |
190 | 25 | heif_suberror_No_meta_box, |
191 | 25 | "No meta box found"}; |
192 | 25 | } |
193 | | |
194 | | // TODO: overflow |
195 | 1.75k | next_box_start = next_box_start + box_header.get_box_size(); |
196 | 1.75k | } |
197 | | |
198 | 1.71k | return Error::Ok; |
199 | 9.85k | } |
200 | | |
201 | | |
202 | | void FileLayout::set_write_mode(WriteMode writeMode, const std::shared_ptr<StreamWriter>& writer) |
203 | 0 | { |
204 | |
|
205 | 0 | } |
206 | | |
207 | | |
208 | | Error FileLayout::write(std::shared_ptr<StreamWriter>& stream) |
209 | 0 | { |
210 | 0 | return Error::Ok; |
211 | 0 | } |