/src/libheif/libheif/bitstream.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_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 | 8.16k | 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 | 37.0k | { |
63 | 37.0k | return seek(get_position() + position_offset); |
64 | 37.0k | } |
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 | 11.1k | uint64_t request_range(uint64_t start, uint64_t end_pos) override { |
140 | 11.1k | return m_length; |
141 | 11.1k | } |
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 | | // wait_for_file_size() takes a signed int64_t, so we cannot probe a position |
210 | | // beyond INT64_MAX: it would wrap to a negative value and the reader would |
211 | | // misreport the size. No file accessed through this API can be that large, |
212 | | // so clamp the search range to INT64_MAX. (Callers may pass UINT64_MAX to |
213 | | // ask for the total file size.) |
214 | 0 | uint64_t hi = std::min<uint64_t>(end_pos, std::numeric_limits<int64_t>::max()); |
215 | |
|
216 | 0 | auto result = m_func_table->wait_for_file_size(static_cast<int64_t>(hi), m_userdata); |
217 | 0 | if (result == heif_reader_grow_status_size_reached) { |
218 | 0 | return hi; |
219 | 0 | } |
220 | 0 | else { |
221 | 0 | uint64_t pos = m_func_table->get_position(m_userdata); |
222 | 0 | return bisect_filesize(pos, hi); |
223 | 0 | } |
224 | 0 | } |
225 | 0 | } |
226 | | |
227 | 0 | uint64_t bisect_filesize(uint64_t mini, uint64_t maxi) { |
228 | | // mini - <= filesize |
229 | | // maxi - > filesize |
230 | |
|
231 | 0 | if (maxi == mini + 1) { |
232 | 0 | return mini; |
233 | 0 | } |
234 | | |
235 | | // Overflow-safe midpoint. 'maxi' is bounded by INT64_MAX (see request_range), |
236 | | // but computing (mini + maxi) directly could still overflow uint64_t. |
237 | 0 | uint64_t pos = mini + (maxi - mini) / 2; |
238 | 0 | auto result = m_func_table->wait_for_file_size(static_cast<int64_t>(pos), m_userdata); |
239 | 0 | if (result == heif_reader_grow_status_size_reached) { |
240 | 0 | return bisect_filesize(pos, maxi); |
241 | 0 | } |
242 | 0 | else { |
243 | 0 | return bisect_filesize(mini, pos); |
244 | 0 | } |
245 | 0 | } |
246 | | |
247 | 0 | void release_range(uint64_t start, uint64_t end_pos) override { |
248 | 0 | if (m_func_table->reader_api_version >= 2) { |
249 | 0 | m_func_table->release_file_range(start, end_pos, m_userdata); |
250 | 0 | } |
251 | 0 | } |
252 | | |
253 | 0 | void preload_range_hint(uint64_t start, uint64_t end_pos) override { |
254 | 0 | if (m_func_table->reader_api_version >= 2) { |
255 | 0 | m_func_table->preload_range_hint(start, end_pos, m_userdata); |
256 | 0 | } |
257 | 0 | } |
258 | | |
259 | | private: |
260 | | const heif_reader* m_func_table; |
261 | | void* m_userdata; |
262 | | }; |
263 | | |
264 | | |
265 | | // This class simplifies safely reading part of a file (e.g. a box). |
266 | | // It makes sure that we do not read past the boundaries of a box. |
267 | | class BitstreamRange |
268 | | { |
269 | | public: |
270 | | BitstreamRange(std::shared_ptr<StreamReader> istr, |
271 | | size_t length, |
272 | | BitstreamRange* parent = nullptr); |
273 | | |
274 | | BitstreamRange(std::shared_ptr<StreamReader> istr, |
275 | | size_t start, |
276 | | size_t end); // one past end |
277 | | |
278 | | // This function tries to make sure that the full data of this range is |
279 | | // available. You should call this before starting reading the range. |
280 | | // If you don't, you have to make sure that you do not read past the available data. |
281 | | StreamReader::grow_status wait_until_range_is_available(); |
282 | | |
283 | | uint8_t read8(); |
284 | | |
285 | | uint16_t read16(); |
286 | | |
287 | | int16_t read16s(); |
288 | | |
289 | | /** |
290 | | * Read 24 bit unsigned integer from the bitstream. |
291 | | * |
292 | | * The data is assumed to be in big endian format and is returned as a 32 bit value. |
293 | | */ |
294 | | uint32_t read24(); |
295 | | |
296 | | uint32_t read32(); |
297 | | |
298 | | int32_t read32s(); |
299 | | |
300 | | uint64_t read64(); |
301 | | |
302 | | uint64_t read_uint(int len); |
303 | | |
304 | | /** |
305 | | * Read 32 bit floating point value from the bitstream. |
306 | | * |
307 | | * The file data is assumed to be in big endian format. |
308 | | */ |
309 | | float read_float32(); |
310 | | |
311 | | int64_t read64s(); |
312 | | |
313 | | std::string read_string(); |
314 | | |
315 | | // A string stored with a fixed number of bytes. The first byte contains the string length and the extra bytes |
316 | | // are filled with a padding 0. |
317 | | std::string read_fixed_string(int len); |
318 | | |
319 | | std::string read_string_until_eof(); |
320 | | |
321 | | bool read(uint8_t* data, size_t n); |
322 | | |
323 | | bool prepare_read(size_t nBytes); |
324 | | |
325 | | StreamReader::grow_status wait_for_available_bytes(size_t nBytes); |
326 | | |
327 | | void skip_to_end_of_file() |
328 | 25 | { |
329 | | // we do not actually move the file position here (because the stream may still be incomplete), |
330 | | // but we set all m_remaining to zero |
331 | 25 | m_remaining = 0; |
332 | | |
333 | 25 | if (m_parent_range) { |
334 | 19 | m_parent_range->skip_to_end_of_file(); |
335 | 19 | } |
336 | 25 | } |
337 | | |
338 | | void skip(uint64_t n) |
339 | 25.3k | { |
340 | 25.3k | size_t actual_skip = std::min(static_cast<size_t>(n), m_remaining); |
341 | | |
342 | 25.3k | if (m_parent_range) { |
343 | | // also advance position in parent range |
344 | 25.3k | m_parent_range->skip_without_advancing_file_pos(actual_skip); |
345 | 25.3k | } |
346 | | |
347 | 25.3k | assert(actual_skip <= static_cast<uint64_t>(std::numeric_limits<int64_t>::max())); |
348 | | |
349 | 25.3k | m_istr->seek_cur(static_cast<int64_t>(actual_skip)); |
350 | 25.3k | m_remaining -= actual_skip; |
351 | 25.3k | } |
352 | | |
353 | | void skip_to_end_of_box() |
354 | 77.9M | { |
355 | 77.9M | if (m_remaining > 0) { |
356 | 10.6k | if (m_parent_range) { |
357 | | // also advance position in parent range |
358 | 10.5k | m_parent_range->skip_without_advancing_file_pos(m_remaining); |
359 | 10.5k | } |
360 | | |
361 | 10.6k | m_istr->seek_cur(m_remaining); |
362 | 10.6k | m_remaining = 0; |
363 | 10.6k | } |
364 | 77.9M | } |
365 | | |
366 | | void set_eof_while_reading() |
367 | 0 | { |
368 | 0 | m_remaining = 0; |
369 | |
|
370 | 0 | if (m_parent_range) { |
371 | 0 | m_parent_range->set_eof_while_reading(); |
372 | 0 | } |
373 | |
|
374 | 0 | m_error = true; |
375 | 0 | } |
376 | | |
377 | | bool eof() const |
378 | 90.3k | { |
379 | 90.3k | return m_remaining == 0; |
380 | 90.3k | } |
381 | | |
382 | | bool error() const |
383 | 118k | { |
384 | 118k | return m_error; |
385 | 118k | } |
386 | | |
387 | | Error get_error() const |
388 | 133k | { |
389 | 133k | if (m_error) { |
390 | 673 | return Error(heif_error_Invalid_input, |
391 | 673 | heif_suberror_End_of_data); |
392 | 673 | } |
393 | 132k | else { |
394 | 132k | return Error::Ok; |
395 | 132k | } |
396 | 133k | } |
397 | | |
398 | 474k | std::shared_ptr<StreamReader> get_istream() { return m_istr; } |
399 | | |
400 | 53.3k | int get_nesting_level() const { return m_nesting_level; } |
401 | | |
402 | 59.3k | size_t get_remaining_bytes() const { return m_remaining; } |
403 | | |
404 | | private: |
405 | | std::shared_ptr<StreamReader> m_istr; |
406 | | BitstreamRange* m_parent_range = nullptr; |
407 | | int m_nesting_level = 0; |
408 | | |
409 | | size_t m_remaining; |
410 | | bool m_error = false; |
411 | | |
412 | | // Note: 'nBytes' may not be larger than the number of remaining bytes |
413 | | void skip_without_advancing_file_pos(size_t nBytes); |
414 | | }; |
415 | | |
416 | | |
417 | | class BitReader |
418 | | { |
419 | | public: |
420 | | BitReader(const uint8_t* buffer, size_t len); |
421 | | |
422 | | void reset(); |
423 | | |
424 | | uint32_t get_bits(int n); |
425 | | |
426 | | uint8_t get_bits8(int n); |
427 | | |
428 | | uint16_t get_bits16(int n); |
429 | | |
430 | | uint32_t get_bits32(int n); |
431 | | |
432 | | int32_t get_bits32s(); |
433 | | |
434 | | /** |
435 | | * Get a one-bit flag value. |
436 | | * |
437 | | * @returns true if the next bit value is 1, otherwise false |
438 | | */ |
439 | | bool get_flag(); |
440 | | |
441 | | std::vector<uint8_t> read_bytes(uint32_t n); |
442 | | |
443 | | int get_bits_fast(int n); |
444 | | |
445 | | int peek_bits(int n); |
446 | | |
447 | | void skip_bytes(uint32_t nBytes); |
448 | | |
449 | | void skip_bits(int n); |
450 | | |
451 | | void skip_bits_fast(int n); |
452 | | |
453 | | void skip_to_byte_boundary(); |
454 | | |
455 | | bool get_uvlc(uint32_t* value); |
456 | | |
457 | | bool get_svlc(int32_t* value); |
458 | | |
459 | | size_t get_current_byte_index() const |
460 | 60.7M | { |
461 | 60.7M | return data_length - bytes_remaining - nextbits_cnt / 8; |
462 | 60.7M | } |
463 | | |
464 | | int64_t get_bits_remaining() const |
465 | 2.73k | { |
466 | 2.73k | return ((int64_t) bytes_remaining) * 8 + nextbits_cnt; |
467 | 2.73k | } |
468 | | |
469 | | private: |
470 | | const uint8_t* const data_start; |
471 | | const uint8_t* data; |
472 | | const size_t data_length; |
473 | | size_t bytes_remaining; |
474 | | |
475 | | uint64_t nextbits; // left-aligned bits |
476 | | int nextbits_cnt; |
477 | | |
478 | | void refill(); // refill to at least 56+1 bits |
479 | | }; |
480 | | |
481 | | |
482 | | class BitWriter |
483 | | { |
484 | | public: |
485 | | // Write n bits from the LSBs of value (n must be in [0,32]) |
486 | | void write_bits(uint32_t value, int n); |
487 | | |
488 | 0 | void write_bits8(uint8_t value, int n) { assert(n >= 0 && n <= 8); write_bits(value, n); } |
489 | | |
490 | 0 | void write_bits16(uint16_t value, int n) { assert(n >= 0 && n <= 16); write_bits(value, n); } |
491 | | |
492 | 0 | void write_bits32(uint32_t value, int n) { assert(n >= 0 && n <= 32); write_bits(value, n); } |
493 | | |
494 | 0 | void write_bits32s(int32_t value) { write_bits(static_cast<uint32_t>(value), 32); } |
495 | | |
496 | 0 | void write_flag(bool flag) { write_bits(flag ? 1 : 0, 1); } |
497 | | |
498 | | // Write raw bytes. Must be at a byte boundary. |
499 | | void write_bytes(const std::vector<uint8_t>& data); |
500 | | |
501 | | void write_bytes(const uint8_t* data, size_t len); |
502 | | |
503 | | // Pad with zero bits to the next byte boundary. No-op if already aligned. |
504 | | void skip_to_byte_boundary(); |
505 | | |
506 | | // Return all written data. Flushes any partial byte (zero-padded). |
507 | | std::vector<uint8_t> get_data() const; |
508 | | |
509 | 0 | int get_current_byte_index() const { return static_cast<int>(m_data.size()); } |
510 | | |
511 | 0 | int64_t get_bits_written() const { return static_cast<int64_t>(m_data.size()) * 8 + m_bits_in_current_byte; } |
512 | | |
513 | | private: |
514 | | std::vector<uint8_t> m_data; |
515 | | uint8_t m_current_byte = 0; |
516 | | int m_bits_in_current_byte = 0; // bits already written into m_current_byte (0-7), packed from MSB |
517 | | }; |
518 | | |
519 | | |
520 | | class StreamWriter |
521 | | { |
522 | | public: |
523 | | void write8(uint8_t); |
524 | | |
525 | | void write16(uint16_t); |
526 | | |
527 | | void write16s(int16_t); |
528 | | |
529 | | void write24(uint32_t); |
530 | | |
531 | | void write32(uint32_t); |
532 | | |
533 | | void write32s(int32_t); |
534 | | |
535 | | void write64(uint64_t); |
536 | | |
537 | | void write_float32(float); |
538 | | |
539 | | void write64s(int64_t); |
540 | | |
541 | | void write(int size, uint64_t value); |
542 | | |
543 | | void write(const std::string&, bool end_with_null = true); |
544 | | |
545 | | void write_fixed_string(std::string s, size_t len); |
546 | | |
547 | | void write(const std::vector<uint8_t>&); |
548 | | |
549 | | void write(const StreamWriter&); |
550 | | |
551 | | void skip(int n); |
552 | | |
553 | | void insert(int nBytes); |
554 | | |
555 | 580 | size_t data_size() const { return m_data.size(); } |
556 | | |
557 | 580 | size_t get_position() const { return m_position; } |
558 | | |
559 | 580 | void set_position(size_t pos) { m_position = pos; } |
560 | | |
561 | 580 | void set_position_to_end() { m_position = m_data.size(); } |
562 | | |
563 | 580 | const std::vector<uint8_t> get_data() const { return m_data; } |
564 | | |
565 | | private: |
566 | | std::vector<uint8_t> m_data; |
567 | | size_t m_position = 0; |
568 | | }; |
569 | | |
570 | | #endif |