Coverage Report

Created: 2026-04-01 07:49

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