Coverage Report

Created: 2026-07-30 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libheif/libheif/bitstream.cc
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
#include "bitstream.h"
22
23
#include <utility>
24
#include <cstring>
25
#include <cassert>
26
27
#include "common_utils.h"
28
29
#if !defined(HAVE_BIT)
30
#include <type_traits>
31
#else
32
#include <bit>
33
#endif
34
35
426k
#define MAX_UVLC_LEADING_ZEROS 20
36
37
38
StreamReader_istream::StreamReader_istream(std::unique_ptr<std::istream>&& istr)
39
0
    : m_istr(std::move(istr))
40
0
{
41
0
  m_istr->seekg(0, std::ios_base::end);
42
0
  m_length = m_istr->tellg();
43
0
  m_istr->seekg(0, std::ios_base::beg);
44
0
}
45
46
uint64_t StreamReader_istream::get_position() const
47
0
{
48
0
  return m_istr->tellg();
49
0
}
50
51
StreamReader::grow_status StreamReader_istream::wait_for_file_size(uint64_t target_size)
52
0
{
53
0
  return (target_size > m_length) ? grow_status::size_beyond_eof : grow_status::size_reached;
54
0
}
55
56
bool StreamReader_istream::read(void* data, size_t size)
57
0
{
58
0
  uint64_t end_pos = get_position() + size;
59
0
  if (end_pos > m_length) {
60
0
    return false;
61
0
  }
62
63
0
  m_istr->read((char*) data, size);
64
0
  return true;
65
0
}
66
67
bool StreamReader_istream::seek(uint64_t position)
68
0
{
69
0
  if (position > m_length)
70
0
    return false;
71
72
0
  m_istr->seekg(position, std::ios_base::beg);
73
0
  return true;
74
0
}
75
76
77
StreamReader_memory::StreamReader_memory(const uint8_t* data, size_t size, bool copy)
78
29.4k
    : m_length(size),
79
29.4k
      m_position(0)
80
29.4k
{
81
29.4k
  if (copy) {
82
25.6k
    m_owned_data = new uint8_t[m_length];
83
25.6k
    memcpy(m_owned_data, data, size);
84
85
25.6k
    m_data = m_owned_data;
86
25.6k
  }
87
3.76k
  else {
88
3.76k
    m_data = data;
89
3.76k
  }
90
29.4k
}
91
92
StreamReader_memory::~StreamReader_memory()
93
29.4k
{
94
29.4k
  if (m_owned_data) {
95
25.6k
    delete[] m_owned_data;
96
25.6k
  }
97
29.4k
}
98
99
uint64_t StreamReader_memory::get_position() const
100
1.14M
{
101
1.14M
  return m_position;
102
1.14M
}
103
104
StreamReader::grow_status StreamReader_memory::wait_for_file_size(uint64_t target_size)
105
1.13M
{
106
1.13M
  return (target_size > m_length) ? grow_status::size_beyond_eof : grow_status::size_reached;
107
1.13M
}
108
109
bool StreamReader_memory::read(void* data, size_t size)
110
5.37M
{
111
5.37M
  uint64_t end_pos = m_position + size;
112
5.37M
  if (end_pos > m_length) {
113
0
    return false;
114
0
  }
115
116
5.37M
  memcpy(data, &m_data[m_position], size);
117
5.37M
  m_position += size;
118
119
5.37M
  return true;
120
5.37M
}
121
122
bool StreamReader_memory::seek(uint64_t position)
123
271k
{
124
271k
  if (position > m_length)
125
0
    return false;
126
127
271k
  m_position = position;
128
271k
  return true;
129
271k
}
130
131
132
StreamReader_CApi::StreamReader_CApi(const heif_reader* func_table, void* userdata)
133
0
    : m_func_table(func_table), m_userdata(userdata)
134
0
{
135
0
}
136
137
StreamReader::grow_status StreamReader_CApi::wait_for_file_size(uint64_t target_size)
138
0
{
139
0
  heif_reader_grow_status status = m_func_table->wait_for_file_size(target_size, m_userdata);
140
0
  switch (status) {
141
0
    case heif_reader_grow_status_size_reached:
142
0
      return grow_status::size_reached;
143
0
    case heif_reader_grow_status_timeout:
144
0
      return grow_status::timeout;
145
0
    case heif_reader_grow_status_size_beyond_eof:
146
0
      return grow_status::size_beyond_eof;
147
0
    default:
148
0
      assert(0);
149
0
      return grow_status::size_beyond_eof;
150
0
  }
151
0
}
152
153
154
BitstreamRange::BitstreamRange(std::shared_ptr<StreamReader> istr,
155
                               size_t length,
156
                               BitstreamRange* parent)
157
521k
    : m_istr(std::move(istr)), m_parent_range(parent), m_remaining(length)
158
521k
{
159
521k
  if (parent) {
160
492k
    m_nesting_level = parent->m_nesting_level + 1;
161
492k
  }
162
521k
}
163
164
165
BitstreamRange::BitstreamRange(std::shared_ptr<StreamReader> istr,
166
                               size_t start,
167
                               size_t end) // one past end
168
173k
  : m_istr(std::move(istr)), m_remaining(end - start)
169
173k
{
170
173k
  assert(end >= start);
171
172
173k
  bool success = m_istr->seek(start);
173
173k
  assert(success);
174
173k
  (void)success; // TODO
175
173k
}
176
177
178
StreamReader::grow_status BitstreamRange::wait_until_range_is_available()
179
0
{
180
0
  return m_istr->wait_for_file_size(m_istr->get_position() + m_remaining);
181
0
}
182
183
184
uint8_t BitstreamRange::read8()
185
1.93M
{
186
1.93M
  if (!prepare_read(1)) {
187
134k
    return 0;
188
134k
  }
189
190
1.79M
  uint8_t buf;
191
192
1.79M
  auto istr = get_istream();
193
1.79M
  bool success = istr->read((char*) &buf, 1);
194
195
1.79M
  if (!success) {
196
0
    set_eof_while_reading();
197
0
    return 0;
198
0
  }
199
200
1.79M
  return buf;
201
1.79M
}
202
203
204
uint16_t BitstreamRange::read16()
205
953k
{
206
953k
  if (!prepare_read(2)) {
207
17.0k
    return 0;
208
17.0k
  }
209
210
936k
  uint8_t buf[2];
211
212
936k
  auto istr = get_istream();
213
936k
  bool success = istr->read((char*) buf, 2);
214
215
936k
  if (!success) {
216
0
    set_eof_while_reading();
217
0
    return 0;
218
0
  }
219
220
936k
  return static_cast<uint16_t>((buf[0] << 8) | (buf[1]));
221
936k
}
222
223
224
int16_t BitstreamRange::read16s()
225
3.79k
{
226
3.79k
  uint16_t v = read16();
227
228
3.79k
  if (v & 0x8000) {
229
655
    auto val = static_cast<int16_t>((~v) & 0x7fff);
230
655
    return static_cast<int16_t>(-val - 1);
231
655
  }
232
3.13k
  else {
233
3.13k
    return static_cast<int16_t>(v);
234
3.13k
  }
235
3.79k
}
236
237
238
uint32_t BitstreamRange::read24()
239
371
{
240
371
  if (!prepare_read(3)) {
241
0
    return 0;
242
0
  }
243
244
371
  uint8_t buf[3];
245
246
371
  auto istr = get_istream();
247
371
  bool success = istr->read((char*) buf, 3);
248
249
371
  if (!success) {
250
0
    set_eof_while_reading();
251
0
    return 0;
252
0
  }
253
254
371
  return (uint32_t) ((buf[0] << 16) |
255
371
                     (buf[1] << 8) |
256
371
                     (buf[2]));
257
371
}
258
259
uint32_t BitstreamRange::read32()
260
228M
{
261
228M
  if (!prepare_read(4)) {
262
226M
    return 0;
263
226M
  }
264
265
2.12M
  uint8_t buf[4];
266
267
2.12M
  auto istr = get_istream();
268
2.12M
  bool success = istr->read((char*) buf, 4);
269
270
2.12M
  if (!success) {
271
0
    set_eof_while_reading();
272
0
    return 0;
273
0
  }
274
275
2.12M
  return four_bytes_to_uint32(buf[0], buf[1], buf[2], buf[3]);
276
2.12M
}
277
278
279
uint64_t BitstreamRange::read_uint(int len)
280
75.0k
{
281
75.0k
  switch (len)
282
75.0k
  {
283
848
    case 8:
284
848
      return read8();
285
72.8k
    case 16:
286
72.8k
      return read16();
287
371
    case 24:
288
371
      return read24();
289
382
    case 32:
290
382
      return read32();
291
561
    case 64:
292
561
      return read64();
293
0
    default:
294
0
      assert(false);
295
0
      return 0;
296
75.0k
  }
297
75.0k
}
298
299
300
int32_t BitstreamRange::read32s()
301
6.02k
{
302
6.02k
  uint32_t v = read32();
303
304
6.02k
  if (v & 0x80000000) {
305
316
    return -static_cast<int32_t>((~v) & 0x7fffffff) -1;
306
316
  }
307
5.70k
  else {
308
5.70k
    return static_cast<int32_t>(v);
309
5.70k
  }
310
6.02k
}
311
312
313
uint64_t BitstreamRange::read64()
314
2.41k
{
315
2.41k
  if (!prepare_read(8)) {
316
47
    return 0;
317
47
  }
318
319
2.36k
  uint8_t buf[8];
320
321
2.36k
  auto istr = get_istream();
322
2.36k
  bool success = istr->read((char*) buf, 8);
323
324
2.36k
  if (!success) {
325
0
    set_eof_while_reading();
326
0
    return 0;
327
0
  }
328
329
2.36k
  return ((static_cast<uint64_t>(buf[0]) << 56) |
330
2.36k
          (static_cast<uint64_t>(buf[1]) << 48) |
331
2.36k
          (static_cast<uint64_t>(buf[2]) << 40) |
332
2.36k
          (static_cast<uint64_t>(buf[3]) << 32) |
333
2.36k
          (static_cast<uint64_t>(buf[4]) << 24) |
334
2.36k
          (static_cast<uint64_t>(buf[5]) << 16) |
335
2.36k
          (static_cast<uint64_t>(buf[6]) << 8) |
336
2.36k
          (static_cast<uint64_t>(buf[7])));
337
2.36k
}
338
339
340
int64_t BitstreamRange::read64s()
341
314
{
342
314
  uint64_t v = read64();
343
344
314
  if (v & 0x8000000000000000) {
345
224
    return -static_cast<int64_t >((~v) & 0x7fffffffffffffff) -1;
346
224
  }
347
90
  else {
348
90
    return static_cast<int64_t >(v);
349
90
  }
350
314
}
351
352
353
float BitstreamRange::read_float32()
354
226M
{
355
226M
#if __cpp_lib_bit_cast >= 201806L
356
226M
  uint32_t i = read32();
357
226M
  return std::bit_cast<float>(i); // this works directly on the value layout, thus we do not have to worry about memory layout
358
#else
359
  // compiler too old to support bit_cast
360
361
  // TODO: I am not sure this works everywhere as there seem to be systems where
362
  //       the float byte order is different from the integer endianness
363
  //       https://en.wikipedia.org/wiki/Endianness#Floating_point
364
  uint32_t i = read32();
365
  float f;
366
  memcpy(&f, &i, sizeof(float));
367
  return f;
368
#endif
369
226M
}
370
371
372
void StreamWriter::write_float32(float v)
373
0
{
374
0
#if __cpp_lib_bit_cast >= 201806L
375
0
  write32(std::bit_cast<uint32_t>(v)); // this works directly on the value layout, thus we do not have to worry about memory layout
376
#else
377
  // compiler too old to support bit_cast
378
379
  // TODO: I am not sure this works everywhere as there seem to be systems where
380
  //       the float byte order is different from the integer endianness
381
  //       https://en.wikipedia.org/wiki/Endianness#Floating_point
382
  uint32_t i;
383
  memcpy(&i, &v, sizeof(float));
384
  write32(i);
385
#endif
386
0
}
387
388
389
std::string BitstreamRange::read_string()
390
114k
{
391
114k
  std::string str;
392
393
  // Reading a string when no more data is available, returns an empty string.
394
  // Such a case happens, for example, when reading a 'url' box without content.
395
114k
  if (eof()) {
396
2.23k
    return std::string();
397
2.23k
  }
398
399
111k
  auto istr = get_istream();
400
401
336k
  for (;;) {
402
336k
    if (!prepare_read(1)) {
403
0
      return std::string();
404
0
    }
405
406
336k
    char c;
407
336k
    bool success = istr->read(&c, 1);
408
409
336k
    if (!success) {
410
0
      set_eof_while_reading();
411
0
      return std::string();
412
0
    }
413
414
336k
    if (c == 0 || m_remaining==0) {
415
111k
      break;
416
111k
    }
417
224k
    else {
418
224k
      str += (char) c;
419
224k
    }
420
336k
  }
421
422
111k
  return str;
423
111k
}
424
425
426
std::string BitstreamRange::read_fixed_string(int len)
427
455
{
428
455
  std::string str;
429
430
455
  if (!prepare_read(len)) {
431
21
    return std::string();
432
21
  }
433
434
434
  auto istr = get_istream();
435
436
434
  uint8_t n;
437
434
  bool success = istr->read(&n, 1);
438
434
  if (!success || n > len - 1) {
439
205
    return {};
440
205
  }
441
442
2.30k
  for (int i = 0; i < n; i++) {
443
2.08k
    char c;
444
2.08k
    success = istr->read(&c, 1);
445
446
2.08k
    if (!success) {
447
0
      set_eof_while_reading();
448
0
      return std::string();
449
0
    }
450
451
2.08k
    str += (char) c;
452
2.08k
  }
453
454
229
  istr->seek_cur(len-n-1);
455
456
229
  return str;
457
229
}
458
459
460
std::string BitstreamRange::read_string_until_eof()
461
181
{
462
181
  size_t n = get_remaining_bytes();
463
464
181
  [[maybe_unused]] bool success = prepare_read(n);
465
181
  assert(success); // we are reading exactly the rest of the box
466
467
181
  std::string str;
468
181
  str.resize(n);
469
181
  get_istream()->read(str.data(), n);
470
471
181
  return str;
472
181
}
473
474
475
bool BitstreamRange::read(uint8_t* data, size_t n)
476
117k
{
477
117k
  if (!prepare_read(n)) {
478
83
    return false;
479
83
  }
480
481
117k
  auto istr = get_istream();
482
117k
  bool success = istr->read(data, n);
483
484
117k
  if (!success) {
485
0
    set_eof_while_reading();
486
0
  }
487
488
117k
  return success;
489
117k
}
490
491
492
bool BitstreamRange::prepare_read(size_t nBytes)
493
245M
{
494
  // Note: we do not test for negative nBytes anymore because we now use the unsigned size_t
495
496
245M
  if (m_remaining < nBytes) {
497
    // --- not enough data left in box -> move to end of box and set error flag
498
499
226M
    skip_to_end_of_box();
500
501
226M
    m_error = true;
502
226M
    return false;
503
226M
  }
504
19.1M
  else {
505
    // --- this is the normal case (m_remaining >= nBytes)
506
507
19.1M
    if (m_parent_range) {
508
13.7M
      if (!m_parent_range->prepare_read(nBytes)) {
509
0
        return false;
510
0
      }
511
13.7M
    }
512
513
19.1M
    m_remaining -= nBytes;
514
515
19.1M
    return true;
516
19.1M
  }
517
245M
}
518
519
520
StreamReader::grow_status BitstreamRange::wait_for_available_bytes(size_t nBytes)
521
1.08M
{
522
1.08M
  int64_t target_size = m_istr->get_position() + nBytes;
523
524
1.08M
  return m_istr->wait_for_file_size(target_size);
525
1.08M
}
526
527
528
void BitstreamRange::skip_without_advancing_file_pos(size_t n)
529
150k
{
530
150k
  assert(n <= m_remaining);
531
532
150k
  m_remaining -= n;
533
534
150k
  if (m_parent_range) {
535
91.7k
    m_parent_range->skip_without_advancing_file_pos(n);
536
91.7k
  }
537
150k
}
538
539
540
BitReader::BitReader(const uint8_t* buffer, size_t len)
541
30.7k
  : data_start(buffer),
542
30.7k
    data_length(len)
543
30.7k
{
544
30.7k
  data = buffer;
545
30.7k
  bytes_remaining = len;
546
547
30.7k
  nextbits = 0;
548
30.7k
  nextbits_cnt = 0;
549
550
30.7k
  refill();
551
30.7k
}
552
553
554
void BitReader::reset()
555
0
{
556
0
  data = data_start;
557
0
  bytes_remaining = data_length;
558
559
0
  nextbits = 0;
560
0
  nextbits_cnt = 0;
561
562
0
  refill();
563
0
}
564
565
566
uint32_t BitReader::get_bits(int n)
567
1.45M
{
568
1.45M
  assert(n <= 32);
569
570
1.45M
  if (nextbits_cnt < n) {
571
106k
    refill();
572
106k
  }
573
574
1.45M
  uint64_t val = nextbits;
575
1.45M
  val >>= 64 - n;
576
577
1.45M
#if AVOID_FUZZER_FALSE_POSITIVE
578
  // Shifting an unsigned integer left such that some MSBs fall out is well defined in C++ despite the fuzzer claiming otherwise.
579
1.45M
  nextbits &= (0xffffffffffffffffULL >> n);
580
1.45M
#endif
581
582
1.45M
  nextbits <<= n;
583
1.45M
  nextbits_cnt -= n;
584
585
1.45M
  return static_cast<uint32_t>(val);
586
1.45M
}
587
588
589
uint8_t BitReader::get_bits8(int n)
590
200k
{
591
200k
  assert(n>0 && n <= 8);
592
200k
  return static_cast<uint8_t>(get_bits(n));
593
200k
}
594
595
uint16_t BitReader::get_bits16(int n)
596
4.75k
{
597
4.75k
  assert(n>0 && n <= 16);
598
4.75k
  return static_cast<uint16_t>(get_bits(n));
599
4.75k
}
600
601
uint32_t BitReader::get_bits32(int n)
602
55.3k
{
603
55.3k
  assert(n>0 && n <= 32);
604
55.3k
  return static_cast<uint32_t>(get_bits(n));
605
55.3k
}
606
607
int32_t BitReader::get_bits32s()
608
11.0k
{
609
11.0k
  uint32_t bits = get_bits(32);
610
11.0k
  return static_cast<int32_t>(bits);
611
11.0k
}
612
613
614
bool BitReader::get_flag()
615
85.5k
{
616
85.5k
  return (get_bits(1) == 0x01);
617
85.5k
}
618
619
std::vector<uint8_t> BitReader::read_bytes(uint32_t n)
620
5.61k
{
621
  // TODO: this implementation isn't very efficient
622
5.61k
  std::vector<uint8_t> bytes;
623
53.6k
  for (uint32_t i = 0; i < n; i++) {
624
48.0k
    bytes.push_back(get_bits8(8));
625
48.0k
  }
626
5.61k
  return bytes;
627
5.61k
}
628
629
int BitReader::get_bits_fast(int n)
630
0
{
631
0
  assert(nextbits_cnt >= n);
632
633
0
  uint64_t val = nextbits;
634
0
  val >>= 64 - n;
635
636
0
  nextbits <<= n;
637
0
  nextbits_cnt -= n;
638
639
0
  return (int) val;
640
0
}
641
642
int BitReader::peek_bits(int n)
643
0
{
644
0
  if (nextbits_cnt < n) {
645
0
    refill();
646
0
  }
647
648
0
  uint64_t val = nextbits;
649
0
  val >>= 64 - n;
650
651
0
  return (int) val;
652
0
}
653
654
void BitReader::skip_bytes(uint32_t nBytes)
655
13.8k
{
656
  // TODO: this is slow
657
226k
  while (nBytes) {
658
212k
    nBytes--;
659
212k
    skip_bits(8);
660
212k
  }
661
13.8k
}
662
663
void BitReader::skip_bits(int n)
664
406k
{
665
406k
  if (nextbits_cnt < n) {
666
61.3k
    refill();
667
61.3k
  }
668
669
406k
#if AVOID_FUZZER_FALSE_POSITIVE
670
406k
  nextbits &= (0xffffffffffffffffULL >> n);
671
406k
#endif
672
673
406k
  nextbits <<= n;
674
406k
  nextbits_cnt -= n;
675
406k
}
676
677
void BitReader::skip_bits_fast(int n)
678
0
{
679
0
#if AVOID_FUZZER_FALSE_POSITIVE
680
0
  nextbits &= (0xffffffffffffffffULL >> n);
681
0
#endif
682
683
0
  nextbits <<= n;
684
0
  nextbits_cnt -= n;
685
0
}
686
687
void BitReader::skip_to_byte_boundary()
688
20.2M
{
689
20.2M
  int nskip = (nextbits_cnt & 7);
690
691
20.2M
#if AVOID_FUZZER_FALSE_POSITIVE
692
20.2M
  nextbits &= (0xffffffffffffffffULL >> nskip);
693
20.2M
#endif
694
695
20.2M
  nextbits <<= nskip;
696
20.2M
  nextbits_cnt -= nskip;
697
20.2M
}
698
699
bool BitReader::get_uvlc(uint32_t* value)
700
156k
{
701
156k
  int num_zeros = 0;
702
703
581k
  while (get_bits(1) == 0) {
704
426k
    num_zeros++;
705
706
426k
    if (num_zeros > MAX_UVLC_LEADING_ZEROS) { return false; }
707
426k
  }
708
709
155k
  if (num_zeros != 0) {
710
81.1k
    uint32_t offset = get_bits(num_zeros);
711
81.1k
    *value = offset + (1u << num_zeros) - 1u;
712
81.1k
    assert(*value > 0);
713
81.1k
    return true;
714
81.1k
  }
715
73.9k
  else {
716
73.9k
    *value = 0;
717
73.9k
    return true;
718
73.9k
  }
719
155k
}
720
721
bool BitReader::get_svlc(int32_t* value)
722
15.4k
{
723
15.4k
  uint32_t v;
724
15.4k
  if (!get_uvlc(&v)) {
725
289
    return false;
726
289
  }
727
15.2k
  else if (v == 0) {
728
10.4k
    *value = 0;
729
10.4k
    return true;
730
10.4k
  }
731
732
4.75k
  bool negative = ((v & 1u) == 0);
733
4.75k
  *value = negative ? -static_cast<int32_t>(v / 2) : static_cast<int32_t>((v + 1) / 2);
734
4.75k
  return true;
735
15.4k
}
736
737
void BitReader::refill()
738
198k
{
739
#if 0
740
  // TODO: activate me once I'm sure this works
741
  while (nextbits_cnt <= 64-8 && bytes_remaining) {
742
    uint64_t newval = *data++;
743
    bytes_remaining--;
744
745
    nextbits_cnt += 8;
746
    newval <<= 64-nextbits_cnt;
747
    nextbits |= newval;
748
  }
749
#else
750
198k
  int shift = 64 - nextbits_cnt;
751
752
1.60M
  while (shift >= 8 && bytes_remaining) {
753
1.40M
    uint64_t newval = *data++;
754
1.40M
    bytes_remaining--;
755
756
1.40M
    shift -= 8;
757
1.40M
    newval <<= shift;
758
1.40M
    nextbits |= newval;
759
1.40M
  }
760
761
198k
  nextbits_cnt = 64 - shift;
762
198k
#endif
763
198k
}
764
765
766
// --- BitWriter ---
767
768
void BitWriter::write_bits(uint32_t value, int n)
769
0
{
770
0
  assert(n >= 0 && n <= 32);
771
772
0
  for (int i = n - 1; i >= 0; i--) {
773
0
    uint8_t bit = (value >> i) & 1;
774
0
    m_current_byte |= (bit << (7 - m_bits_in_current_byte));
775
0
    m_bits_in_current_byte++;
776
777
0
    if (m_bits_in_current_byte == 8) {
778
0
      m_data.push_back(m_current_byte);
779
0
      m_current_byte = 0;
780
0
      m_bits_in_current_byte = 0;
781
0
    }
782
0
  }
783
0
}
784
785
void BitWriter::write_bytes(const std::vector<uint8_t>& data)
786
0
{
787
0
  write_bytes(data.data(), data.size());
788
0
}
789
790
void BitWriter::write_bytes(const uint8_t* data, size_t len)
791
0
{
792
0
  assert(m_bits_in_current_byte == 0);
793
0
  m_data.insert(m_data.end(), data, data + len);
794
0
}
795
796
void BitWriter::skip_to_byte_boundary()
797
0
{
798
0
  if (m_bits_in_current_byte > 0) {
799
0
    m_data.push_back(m_current_byte);
800
0
    m_current_byte = 0;
801
0
    m_bits_in_current_byte = 0;
802
0
  }
803
0
}
804
805
std::vector<uint8_t> BitWriter::get_data() const
806
0
{
807
0
  std::vector<uint8_t> result = m_data;
808
0
  if (m_bits_in_current_byte > 0) {
809
0
    result.push_back(m_current_byte);
810
0
  }
811
0
  return result;
812
0
}
813
814
815
// --- StreamWriter ---
816
817
void StreamWriter::write8(uint8_t v)
818
9.96k
{
819
9.96k
  if (m_position == m_data.size()) {
820
9.96k
    m_data.push_back(v);
821
9.96k
    m_position++;
822
9.96k
  }
823
0
  else {
824
0
    m_data[m_position++] = v;
825
0
  }
826
9.96k
}
827
828
829
void StreamWriter::write16(uint16_t v)
830
19.3k
{
831
19.3k
  size_t required_size = m_position + 2;
832
833
19.3k
  if (required_size > m_data.size()) {
834
19.3k
    m_data.resize(required_size);
835
19.3k
  }
836
837
19.3k
  m_data[m_position++] = uint8_t((v >> 8) & 0xFF);
838
19.3k
  m_data[m_position++] = uint8_t(v & 0xFF);
839
19.3k
}
840
841
842
void StreamWriter::write16s(int16_t v16s)
843
0
{
844
0
  uint16_t v;
845
0
  if (v16s >= 0) {
846
0
    v = static_cast<uint16_t>(v16s);
847
0
  }
848
0
  else {
849
0
    auto val = static_cast<uint16_t>((-v16s-1));
850
0
    v = static_cast<uint16_t>(~val);
851
0
  }
852
853
0
  write16(v);
854
0
}
855
856
857
void StreamWriter::write24(uint32_t v)
858
0
{
859
0
  size_t required_size = m_position + 3;
860
861
0
  if (required_size > m_data.size()) {
862
0
    m_data.resize(required_size);
863
0
  }
864
865
0
  m_data[m_position++] = uint8_t((v >> 16) & 0xFF);
866
0
  m_data[m_position++] = uint8_t((v >> 8) & 0xFF);
867
0
  m_data[m_position++] = uint8_t(v & 0xFF);
868
0
}
869
870
871
void StreamWriter::write32(uint32_t v)
872
153k
{
873
153k
  size_t required_size = m_position + 4;
874
875
153k
  if (required_size > m_data.size()) {
876
48.8k
    m_data.resize(required_size);
877
48.8k
  }
878
879
153k
  m_data[m_position++] = uint8_t((v >> 24) & 0xFF);
880
153k
  m_data[m_position++] = uint8_t((v >> 16) & 0xFF);
881
153k
  m_data[m_position++] = uint8_t((v >> 8) & 0xFF);
882
153k
  m_data[m_position++] = uint8_t(v & 0xFF);
883
153k
}
884
885
886
void StreamWriter::write32s(int32_t v32s)
887
0
{
888
0
  uint32_t v;
889
0
  if (v32s >= 0) {
890
0
    v = static_cast<uint32_t>(v32s);
891
0
  }
892
0
  else {
893
0
    v = ~static_cast<uint32_t>((-v32s-1));
894
0
  }
895
896
0
  write32(v);
897
0
}
898
899
900
void StreamWriter::write64(uint64_t v)
901
0
{
902
0
  size_t required_size = m_position + 8;
903
904
0
  if (required_size > m_data.size()) {
905
0
    m_data.resize(required_size);
906
0
  }
907
908
0
  m_data[m_position++] = uint8_t((v >> 56) & 0xFF);
909
0
  m_data[m_position++] = uint8_t((v >> 48) & 0xFF);
910
0
  m_data[m_position++] = uint8_t((v >> 40) & 0xFF);
911
0
  m_data[m_position++] = uint8_t((v >> 32) & 0xFF);
912
0
  m_data[m_position++] = uint8_t((v >> 24) & 0xFF);
913
0
  m_data[m_position++] = uint8_t((v >> 16) & 0xFF);
914
0
  m_data[m_position++] = uint8_t((v >> 8) & 0xFF);
915
0
  m_data[m_position++] = uint8_t(v & 0xFF);
916
0
}
917
918
919
void StreamWriter::write64s(int64_t v)
920
0
{
921
0
  write64(reinterpret_cast<uint64_t&>(v));
922
0
}
923
924
925
void StreamWriter::write(int size, uint64_t value)
926
0
{
927
0
  if (size == 1) {
928
0
    assert(value <= 0xFF);
929
0
    write8((uint8_t) value);
930
0
  }
931
0
  else if (size == 2) {
932
0
    assert(value <= 0xFFFF);
933
0
    write16((uint16_t) value);
934
0
  }
935
0
  else if (size == 4) {
936
0
    assert(value <= 0xFFFFFFFF);
937
0
    write32((uint32_t) value);
938
0
  }
939
0
  else if (size == 8) {
940
0
    write64((uint64_t) value);
941
0
  }
942
0
  else {
943
0
    assert(false); // unimplemented size
944
0
  }
945
0
}
946
947
948
void StreamWriter::write(const std::string& str, bool end_with_null)
949
0
{
950
0
  size_t required_size = m_position + str.size() + (end_with_null ? 1 : 0);
951
952
0
  if (required_size > m_data.size()) {
953
0
    m_data.resize(required_size);
954
0
  }
955
956
0
  for (size_t i = 0; i < str.size(); i++) {
957
0
    m_data[m_position++] = str[i];
958
0
  }
959
960
0
  if (end_with_null) {
961
0
    m_data[m_position++] = 0;
962
0
  }
963
0
}
964
965
966
void StreamWriter::write_fixed_string(std::string s, size_t len)
967
0
{
968
0
  size_t required_size = m_position + len;
969
970
0
  if (required_size > m_data.size()) {
971
0
    m_data.resize(required_size);
972
0
  }
973
974
0
  size_t n_chars = std::min(s.length(), len - 1);
975
0
  assert(n_chars <= 255);
976
0
  m_data[m_position++] = static_cast<uint8_t>(n_chars);
977
978
0
  for (size_t i = 0; i < s.size() && i < len - 1; i++) {
979
0
    m_data[m_position++] = s[i];
980
0
  }
981
982
0
  for (size_t i = s.size(); i < len - 1; i++) {
983
0
    m_data[m_position++] = 0;
984
0
  }
985
0
}
986
987
988
void StreamWriter::write(const std::vector<uint8_t>& vec)
989
42.3k
{
990
42.3k
  size_t required_size = m_position + vec.size();
991
992
42.3k
  if (required_size > m_data.size()) {
993
42.3k
    m_data.resize(required_size);
994
42.3k
  }
995
996
42.3k
  memcpy(m_data.data() + m_position, vec.data(), vec.size());
997
42.3k
  m_position += vec.size();
998
42.3k
}
999
1000
1001
void StreamWriter::write(const StreamWriter& writer)
1002
0
{
1003
0
  size_t required_size = m_position + writer.get_data().size();
1004
1005
0
  if (required_size > m_data.size()) {
1006
0
    m_data.resize(required_size);
1007
0
  }
1008
1009
0
  const auto& data = writer.get_data();
1010
1011
0
  memcpy(m_data.data() + m_position, data.data(), data.size());
1012
1013
0
  m_position += data.size();
1014
0
}
1015
1016
1017
void StreamWriter::skip(int n)
1018
52.3k
{
1019
52.3k
  assert(m_position == m_data.size());
1020
52.3k
  m_data.resize(m_data.size() + n);
1021
52.3k
  m_position += n;
1022
52.3k
}
1023
1024
1025
void StreamWriter::insert(int nBytes)
1026
0
{
1027
0
  assert(nBytes >= 0);
1028
1029
0
  if (nBytes == 0) {
1030
0
    return;
1031
0
  }
1032
1033
0
  m_data.resize(m_data.size() + nBytes);
1034
1035
0
  if (m_position < m_data.size() - nBytes) {
1036
0
    memmove(m_data.data() + m_position + nBytes,
1037
0
            m_data.data() + m_position,
1038
0
            m_data.size() - nBytes - m_position);
1039
0
  }
1040
0
}