1 /*
2 * Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #ifndef NET_DCSCTP_PACKET_BOUNDED_BYTE_READER_H_
12 #define NET_DCSCTP_PACKET_BOUNDED_BYTE_READER_H_
13
14 #include <cstdint>
15
16 #include "api/array_view.h"
17
18 namespace dcsctp {
19
20 // TODO(boivie): These generic functions - and possibly this entire class -
21 // could be a candidate to have added to rtc_base/. They should use compiler
22 // intrinsics as well.
23 namespace internal {
24 // Loads a 8-bit unsigned word at `data`.
LoadBigEndian8(const uint8_t * data)25 inline uint8_t LoadBigEndian8(const uint8_t* data) {
26 return data[0];
27 }
28
29 // Loads a 16-bit unsigned word at `data`.
LoadBigEndian16(const uint8_t * data)30 inline uint16_t LoadBigEndian16(const uint8_t* data) {
31 return (data[0] << 8) | data[1];
32 }
33
34 // Loads a 32-bit unsigned word at `data`.
LoadBigEndian32(const uint8_t * data)35 inline uint32_t LoadBigEndian32(const uint8_t* data) {
36 return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
37 }
38 } // namespace internal
39
40 // BoundedByteReader wraps an ArrayView and divides it into two parts; A fixed
41 // size - which is the template parameter - and a variable size, which is what
42 // remains in `data` after the `FixedSize`.
43 //
44 // The BoundedByteReader provides methods to load/read big endian numbers from
45 // the FixedSize portion of the buffer, and these are read with static bounds
46 // checking, to avoid out-of-bounds accesses without a run-time penalty.
47 //
48 // The variable sized portion can either be used to create sub-readers, which
49 // themselves would provide compile-time bounds-checking, or the entire variable
50 // sized portion can be retrieved as an ArrayView.
51 template <int FixedSize>
52 class BoundedByteReader {
53 public:
BoundedByteReader(rtc::ArrayView<const uint8_t> data)54 explicit BoundedByteReader(rtc::ArrayView<const uint8_t> data) : data_(data) {
55 RTC_CHECK(data.size() >= FixedSize);
56 }
57
58 template <size_t offset>
Load8()59 uint8_t Load8() const {
60 static_assert(offset + sizeof(uint8_t) <= FixedSize, "Out-of-bounds");
61 return internal::LoadBigEndian8(&data_[offset]);
62 }
63
64 template <size_t offset>
Load16()65 uint16_t Load16() const {
66 static_assert(offset + sizeof(uint16_t) <= FixedSize, "Out-of-bounds");
67 static_assert((offset % sizeof(uint16_t)) == 0, "Unaligned access");
68 return internal::LoadBigEndian16(&data_[offset]);
69 }
70
71 template <size_t offset>
Load32()72 uint32_t Load32() const {
73 static_assert(offset + sizeof(uint32_t) <= FixedSize, "Out-of-bounds");
74 static_assert((offset % sizeof(uint32_t)) == 0, "Unaligned access");
75 return internal::LoadBigEndian32(&data_[offset]);
76 }
77
78 template <size_t SubSize>
sub_reader(size_t variable_offset)79 BoundedByteReader<SubSize> sub_reader(size_t variable_offset) const {
80 RTC_CHECK(FixedSize + variable_offset + SubSize <= data_.size());
81
82 rtc::ArrayView<const uint8_t> sub_span =
83 data_.subview(FixedSize + variable_offset, SubSize);
84 return BoundedByteReader<SubSize>(sub_span);
85 }
86
variable_data_size()87 size_t variable_data_size() const { return data_.size() - FixedSize; }
88
variable_data()89 rtc::ArrayView<const uint8_t> variable_data() const {
90 return data_.subview(FixedSize, data_.size() - FixedSize);
91 }
92
93 private:
94 const rtc::ArrayView<const uint8_t> data_;
95 };
96
97 } // namespace dcsctp
98
99 #endif // NET_DCSCTP_PACKET_BOUNDED_BYTE_READER_H_
100