/src/libheif/libheif/bitstream.h
Line | Count | Source (jump to first uncovered line) |
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_BITSTREAM_H |
22 | | #define LIBHEIF_BITSTREAM_H |
23 | | |
24 | | #include <cinttypes> |
25 | | #include <cstddef> |
26 | | |
27 | | #include <vector> |
28 | | #include <string> |
29 | | #include <memory> |
30 | | #include <limits> |
31 | | #include <istream> |
32 | | #include <string> |
33 | | #include <cassert> |
34 | | |
35 | | #include "error.h" |
36 | | #include <algorithm> |
37 | | |
38 | | |
39 | | class StreamReader |
40 | | { |
41 | | public: |
42 | 19.0k | virtual ~StreamReader() = default; |
43 | | |
44 | | virtual uint64_t get_position() const = 0; |
45 | | |
46 | | enum class grow_status : uint8_t |
47 | | { |
48 | | size_reached, // requested size has been reached |
49 | | timeout, // size has not been reached yet, but it may still grow further |
50 | | size_beyond_eof // size has not been reached and never will. The file has grown to its full size |
51 | | }; |
52 | | |
53 | | // a StreamReader can maintain a timeout for waiting for new data |
54 | | virtual grow_status wait_for_file_size(uint64_t target_size) = 0; |
55 | | |
56 | | // returns 'false' when we read out of the available file size |
57 | | virtual bool read(void* data, size_t size) = 0; |
58 | | |
59 | | virtual bool seek(uint64_t position) = 0; |
60 | | |
61 | | bool seek_cur(uint64_t position_offset) |
62 | 13.5k | { |
63 | 13.5k | return seek(get_position() + position_offset); |
64 | 13.5k | } |
65 | | |
66 | | // Informs the reader implementation that we will process data in the given range. |
67 | | // The reader can use this information to retrieve a larger chunk of data instead of individual read() calls. |
68 | | // Returns the file size that was made available, but you still have to check each read() call. |
69 | | // Returning a value shorter than the requested range end indicates to libheif that the data is not available. |
70 | | // Returns 0 on error. |
71 | 0 | virtual uint64_t request_range(uint64_t start, uint64_t end_pos) { |
72 | 0 | return std::numeric_limits<uint64_t>::max(); |
73 | 0 | } |
74 | | |
75 | 0 | virtual void release_range(uint64_t start, uint64_t end_pos) { } |
76 | | |
77 | 0 | virtual void preload_range_hint(uint64_t start, uint64_t end_pos) { } |
78 | | |
79 | 0 | Error get_error() const { |
80 | 0 | return m_last_error; |
81 | 0 | } |
82 | | |
83 | 0 | void clear_last_error() { m_last_error = {}; } |
84 | | |
85 | | protected: |
86 | | Error m_last_error; |
87 | | }; |
88 | | |
89 | | #include <iostream> |
90 | | |
91 | | class StreamReader_istream : public StreamReader |
92 | | { |
93 | | public: |
94 | | StreamReader_istream(std::unique_ptr<std::istream>&& istr); |
95 | | |
96 | | uint64_t get_position() const override; |
97 | | |
98 | | grow_status wait_for_file_size(uint64_t target_size) override; |
99 | | |
100 | | bool read(void* data, size_t size) override; |
101 | | |
102 | | bool seek(uint64_t position) override; |
103 | | |
104 | 0 | uint64_t request_range(uint64_t start, uint64_t end_pos) override { |
105 | | // std::cout << "[istream] request_range " << start << " - " << end_pos << "\n"; |
106 | 0 | return std::min(end_pos, m_length); |
107 | 0 | } |
108 | | |
109 | 0 | void release_range(uint64_t start, uint64_t end_pos) override { |
110 | | // std::cout << "[istream] release_range " << start << " - " << end_pos << "\n"; |
111 | 0 | } |
112 | | |
113 | 0 | void preload_range_hint(uint64_t start, uint64_t end_pos) override { |
114 | | // std::cout << "[istream] preload_range_hint " << start << " - " << end_pos << "\n"; |
115 | 0 | } |
116 | | |
117 | | private: |
118 | | std::unique_ptr<std::istream> m_istr; |
119 | | uint64_t m_length; |
120 | | }; |
121 | | |
122 | | |
123 | | class StreamReader_memory : public StreamReader |
124 | | { |
125 | | public: |
126 | | StreamReader_memory(const uint8_t* data, size_t size, bool copy); |
127 | | |
128 | | ~StreamReader_memory() override; |
129 | | |
130 | | uint64_t get_position() const override; |
131 | | |
132 | | grow_status wait_for_file_size(uint64_t target_size) override; |
133 | | |
134 | | bool read(void* data, size_t size) override; |
135 | | |
136 | | bool seek(uint64_t position) override; |
137 | | |
138 | | // end_pos is last byte to read + 1. I.e. like a file size. |
139 | 52.0k | uint64_t request_range(uint64_t start, uint64_t end_pos) override { |
140 | 52.0k | return m_length; |
141 | 52.0k | } |
142 | | |
143 | | private: |
144 | | const uint8_t* m_data; |
145 | | uint64_t m_length; |
146 | | uint64_t m_position; |
147 | | |
148 | | // if we made a copy of the data, we store a pointer to the owned memory area here |
149 | | uint8_t* m_owned_data = nullptr; |
150 | | }; |
151 | | |
152 | | |
153 | | class StreamReader_CApi : public StreamReader |
154 | | { |
155 | | public: |
156 | | StreamReader_CApi(const heif_reader* func_table, void* userdata); |
157 | | |
158 | 0 | uint64_t get_position() const override { return m_func_table->get_position(m_userdata); } |
159 | | |
160 | | StreamReader::grow_status wait_for_file_size(uint64_t target_size) override; |
161 | | |
162 | 0 | bool read(void* data, size_t size) override { return !m_func_table->read(data, size, m_userdata); } |
163 | | |
164 | 0 | bool seek(uint64_t position) override { return !m_func_table->seek(position, m_userdata); } |
165 | | |
166 | 0 | uint64_t request_range(uint64_t start, uint64_t end_pos) override { |
167 | 0 | if (m_func_table->reader_api_version >= 2) { |
168 | 0 | heif_reader_range_request_result result = m_func_table->request_range(start, end_pos, m_userdata); |
169 | | |
170 | | // convert error message string and release input string memory |
171 | |
|
172 | 0 | std::string error_msg; |
173 | 0 | if (result.reader_error_msg) { |
174 | 0 | error_msg = std::string{result.reader_error_msg}; |
175 | |
|
176 | 0 | if (m_func_table->release_error_msg) { |
177 | 0 | m_func_table->release_error_msg(result.reader_error_msg); |
178 | 0 | } |
179 | 0 | } |
180 | |
|
181 | 0 | switch (result.status) { |
182 | 0 | case heif_reader_grow_status_size_reached: |
183 | 0 | return end_pos; |
184 | 0 | case heif_reader_grow_status_timeout: |
185 | 0 | return 0; // invalid return value from callback |
186 | 0 | case heif_reader_grow_status_size_beyond_eof: |
187 | 0 | m_last_error = {heif_error_Invalid_input, heif_suberror_End_of_data, "Read beyond file size"}; |
188 | 0 | return result.range_end; |
189 | 0 | case heif_reader_grow_status_error: { |
190 | 0 | if (result.reader_error_msg) { |
191 | 0 | std::stringstream sstr; |
192 | 0 | sstr << "Input error (" << result.reader_error_code << ") : " << error_msg; |
193 | 0 | m_last_error = {heif_error_Invalid_input, heif_suberror_Unspecified, sstr.str()}; |
194 | 0 | } |
195 | 0 | else { |
196 | 0 | std::stringstream sstr; |
197 | 0 | sstr << "Input error (" << result.reader_error_code << ")"; |
198 | 0 | m_last_error = {heif_error_Invalid_input, heif_suberror_Unspecified, sstr.str()}; |
199 | 0 | } |
200 | |
|
201 | 0 | return 0; // error occurred |
202 | 0 | } |
203 | 0 | default: |
204 | 0 | m_last_error = {heif_error_Invalid_input, heif_suberror_Unspecified, "Invalid input reader return value"}; |
205 | 0 | return 0; |
206 | 0 | } |
207 | 0 | } |
208 | 0 | else { |
209 | 0 | auto result = m_func_table->wait_for_file_size(end_pos, m_userdata); |
210 | 0 | if (result == heif_reader_grow_status_size_reached) { |
211 | 0 | return end_pos; |
212 | 0 | } |
213 | 0 | else { |
214 | 0 | uint64_t pos = m_func_table->get_position(m_userdata); |
215 | 0 | return bisect_filesize(pos,end_pos); |
216 | 0 | } |
217 | 0 | } |
218 | 0 | } |
219 | | |
220 | 0 | uint64_t bisect_filesize(uint64_t mini, uint64_t maxi) { |
221 | | // mini - <= filesize |
222 | | // maxi - > filesize |
223 | |
|
224 | 0 | if (maxi == mini + 1) { |
225 | 0 | return mini; |
226 | 0 | } |
227 | | |
228 | 0 | uint64_t pos = (mini + maxi) / 2; |
229 | 0 | auto result = m_func_table->wait_for_file_size(pos, m_userdata); |
230 | 0 | if (result == heif_reader_grow_status_size_reached) { |
231 | 0 | return bisect_filesize(pos, maxi); |
232 | 0 | } |
233 | 0 | else { |
234 | 0 | return bisect_filesize(mini, pos); |
235 | 0 | } |
236 | 0 | } |
237 | | |
238 | 0 | void release_range(uint64_t start, uint64_t end_pos) override { |
239 | 0 | if (m_func_table->reader_api_version >= 2) { |
240 | 0 | m_func_table->release_file_range(start, end_pos, m_userdata); |
241 | 0 | } |
242 | 0 | } |
243 | | |
244 | 0 | void preload_range_hint(uint64_t start, uint64_t end_pos) override { |
245 | 0 | if (m_func_table->reader_api_version >= 2) { |
246 | 0 | m_func_table->preload_range_hint(start, end_pos, m_userdata); |
247 | 0 | } |
248 | 0 | } |
249 | | |
250 | | private: |
251 | | const heif_reader* m_func_table; |
252 | | void* m_userdata; |
253 | | }; |
254 | | |
255 | | |
256 | | // This class simplifies safely reading part of a file (e.g. a box). |
257 | | // It makes sure that we do not read past the boundaries of a box. |
258 | | class BitstreamRange |
259 | | { |
260 | | public: |
261 | | BitstreamRange(std::shared_ptr<StreamReader> istr, |
262 | | size_t length, |
263 | | BitstreamRange* parent = nullptr); |
264 | | |
265 | | BitstreamRange(std::shared_ptr<StreamReader> istr, |
266 | | size_t start, |
267 | | size_t end); // one past end |
268 | | |
269 | | // This function tries to make sure that the full data of this range is |
270 | | // available. You should call this before starting reading the range. |
271 | | // If you don't, you have to make sure that you do not read past the available data. |
272 | | StreamReader::grow_status wait_until_range_is_available(); |
273 | | |
274 | | uint8_t read8(); |
275 | | |
276 | | uint16_t read16(); |
277 | | |
278 | | int16_t read16s(); |
279 | | |
280 | | /** |
281 | | * Read 24 bit unsigned integer from the bitstream. |
282 | | * |
283 | | * The data is assumed to be in big endian format and is returned as a 32 bit value. |
284 | | */ |
285 | | uint32_t read24(); |
286 | | |
287 | | uint32_t read32(); |
288 | | |
289 | | int32_t read32s(); |
290 | | |
291 | | uint64_t read64(); |
292 | | |
293 | | uint64_t read_uint(int len); |
294 | | |
295 | | /** |
296 | | * Read 32 bit floating point value from the bitstream. |
297 | | * |
298 | | * The file data is assumed to be in big endian format. |
299 | | */ |
300 | | float read_float32(); |
301 | | |
302 | | int64_t read64s(); |
303 | | |
304 | | std::string read_string(); |
305 | | |
306 | | // A string stored with a fixed number of bytes. The first byte contains the string length and the extra bytes |
307 | | // are filled with a padding 0. |
308 | | std::string read_fixed_string(int len); |
309 | | |
310 | | bool read(uint8_t* data, size_t n); |
311 | | |
312 | | bool prepare_read(size_t nBytes); |
313 | | |
314 | | StreamReader::grow_status wait_for_available_bytes(size_t nBytes); |
315 | | |
316 | | void skip_to_end_of_file() |
317 | 15 | { |
318 | | // we do not actually move the file position here (because the stream may still be incomplete), |
319 | | // but we set all m_remaining to zero |
320 | 15 | m_remaining = 0; |
321 | | |
322 | 15 | if (m_parent_range) { |
323 | 11 | m_parent_range->skip_to_end_of_file(); |
324 | 11 | } |
325 | 15 | } |
326 | | |
327 | | void skip(uint64_t n) |
328 | 112 | { |
329 | 112 | size_t actual_skip = std::min(static_cast<size_t>(n), m_remaining); |
330 | | |
331 | 112 | if (m_parent_range) { |
332 | | // also advance position in parent range |
333 | 112 | m_parent_range->skip_without_advancing_file_pos(actual_skip); |
334 | 112 | } |
335 | | |
336 | 112 | assert(actual_skip <= static_cast<uint64_t>(std::numeric_limits<int64_t>::max())); |
337 | | |
338 | 112 | m_istr->seek_cur(static_cast<int64_t>(actual_skip)); |
339 | 112 | m_remaining -= actual_skip; |
340 | 112 | } |
341 | | |
342 | | void skip_to_end_of_box() |
343 | 18.8M | { |
344 | 18.8M | if (m_remaining > 0) { |
345 | 13.4k | if (m_parent_range) { |
346 | | // also advance position in parent range |
347 | 13.4k | m_parent_range->skip_without_advancing_file_pos(m_remaining); |
348 | 13.4k | } |
349 | | |
350 | 13.4k | m_istr->seek_cur(m_remaining); |
351 | 13.4k | m_remaining = 0; |
352 | 13.4k | } |
353 | 18.8M | } |
354 | | |
355 | | void set_eof_while_reading() |
356 | 0 | { |
357 | 0 | m_remaining = 0; |
358 | |
|
359 | 0 | if (m_parent_range) { |
360 | 0 | m_parent_range->set_eof_while_reading(); |
361 | 0 | } |
362 | |
|
363 | 0 | m_error = true; |
364 | 0 | } |
365 | | |
366 | | bool eof() const |
367 | 399k | { |
368 | 399k | return m_remaining == 0; |
369 | 399k | } |
370 | | |
371 | | bool error() const |
372 | 598k | { |
373 | 598k | return m_error; |
374 | 598k | } |
375 | | |
376 | | Error get_error() const |
377 | 677k | { |
378 | 677k | if (m_error) { |
379 | 663 | return Error(heif_error_Invalid_input, |
380 | 663 | heif_suberror_End_of_data); |
381 | 663 | } |
382 | 676k | else { |
383 | 676k | return Error::Ok; |
384 | 676k | } |
385 | 677k | } |
386 | | |
387 | 3.08M | std::shared_ptr<StreamReader> get_istream() { return m_istr; } |
388 | | |
389 | 244k | int get_nesting_level() const { return m_nesting_level; } |
390 | | |
391 | 255k | size_t get_remaining_bytes() const { return m_remaining; } |
392 | | |
393 | | private: |
394 | | std::shared_ptr<StreamReader> m_istr; |
395 | | BitstreamRange* m_parent_range = nullptr; |
396 | | int m_nesting_level = 0; |
397 | | |
398 | | size_t m_remaining; |
399 | | bool m_error = false; |
400 | | |
401 | | // Note: 'nBytes' may not be larger than the number of remaining bytes |
402 | | void skip_without_advancing_file_pos(size_t nBytes); |
403 | | }; |
404 | | |
405 | | |
406 | | class BitReader |
407 | | { |
408 | | public: |
409 | | BitReader(const uint8_t* buffer, int len); |
410 | | |
411 | | uint32_t get_bits(int n); |
412 | | |
413 | | uint8_t get_bits8(int n); |
414 | | |
415 | | uint16_t get_bits16(int n); |
416 | | |
417 | | uint32_t get_bits32(int n); |
418 | | |
419 | | int32_t get_bits32s(); |
420 | | |
421 | | /** |
422 | | * Get a one-bit flag value. |
423 | | * |
424 | | * @returns true if the next bit value is 1, otherwise false |
425 | | */ |
426 | | bool get_flag(); |
427 | | |
428 | | std::vector<uint8_t> read_bytes(uint32_t n); |
429 | | |
430 | | int get_bits_fast(int n); |
431 | | |
432 | | int peek_bits(int n); |
433 | | |
434 | | void skip_bytes(int nBytes); |
435 | | |
436 | | void skip_bits(int n); |
437 | | |
438 | | void skip_bits_fast(int n); |
439 | | |
440 | | void skip_to_byte_boundary(); |
441 | | |
442 | | bool get_uvlc(int* value); |
443 | | |
444 | | bool get_svlc(int* value); |
445 | | |
446 | | int get_current_byte_index() const |
447 | 0 | { |
448 | 0 | return data_length - bytes_remaining - nextbits_cnt / 8; |
449 | 0 | } |
450 | | |
451 | | int64_t get_bits_remaining() const |
452 | 0 | { |
453 | 0 | return ((int64_t) bytes_remaining) * 8 + nextbits_cnt; |
454 | 0 | } |
455 | | |
456 | | private: |
457 | | const uint8_t* data; |
458 | | int data_length; |
459 | | int bytes_remaining; |
460 | | |
461 | | uint64_t nextbits; // left-aligned bits |
462 | | int nextbits_cnt; |
463 | | |
464 | | void refill(); // refill to at least 56+1 bits |
465 | | }; |
466 | | |
467 | | |
468 | | class StreamWriter |
469 | | { |
470 | | public: |
471 | | void write8(uint8_t); |
472 | | |
473 | | void write16(uint16_t); |
474 | | |
475 | | void write16s(int16_t); |
476 | | |
477 | | void write24(uint32_t); |
478 | | |
479 | | void write32(uint32_t); |
480 | | |
481 | | void write32s(int32_t); |
482 | | |
483 | | void write64(uint64_t); |
484 | | |
485 | | void write_float32(float); |
486 | | |
487 | | void write64s(int64_t); |
488 | | |
489 | | void write(int size, uint64_t value); |
490 | | |
491 | | void write(const std::string&); |
492 | | |
493 | | void write_fixed_string(std::string s, size_t len); |
494 | | |
495 | | void write(const std::vector<uint8_t>&); |
496 | | |
497 | | void write(const StreamWriter&); |
498 | | |
499 | | void skip(int n); |
500 | | |
501 | | void insert(int nBytes); |
502 | | |
503 | 0 | size_t data_size() const { return m_data.size(); } |
504 | | |
505 | 0 | size_t get_position() const { return m_position; } |
506 | | |
507 | 0 | void set_position(size_t pos) { m_position = pos; } |
508 | | |
509 | 0 | void set_position_to_end() { m_position = m_data.size(); } |
510 | | |
511 | 0 | const std::vector<uint8_t> get_data() const { return m_data; } |
512 | | |
513 | | private: |
514 | | std::vector<uint8_t> m_data; |
515 | | size_t m_position = 0; |
516 | | }; |
517 | | |
518 | | #endif |