Vanetza
 
Loading...
Searching...
No Matches
length_coding.cpp
1#include <vanetza/security/v2/length_coding.hpp>
2#include <cassert>
3#include <cmath>
4#include <iterator>
5#include <list>
6
7namespace vanetza
8{
9namespace security
10{
11namespace v2
12{
13
14std::size_t count_leading_ones(uint8_t v)
15{
16 std::size_t count = 0;
17 while ((v & 0x80) != 0) {
18 v <<= 1;
19 ++count;
20 }
21 return count;
22}
23
24std::size_t length_coding_size(std::uintmax_t length) {
25 std::size_t size = 1;
26 while ((length & ~0x7f) != 0) {
27 // prefix enlongates by one additional leading "1" per shift
28 length >>= 7; // shift by 7
29 ++size;
30 }
31 return size;
32}
33
34ByteBuffer encode_length(std::uintmax_t length)
35{
36 static_assert(sizeof(std::uintmax_t) <= 8, "size of length type exceeds implementation capabilities");
37 std::list<uint8_t> length_info;
38
39 while (length != 0) {
40 length_info.push_front(static_cast<uint8_t>(length));
41 length >>= 8;
42 }
43
44 unsigned prefix_length = length_info.size();
45 if (prefix_length == 0) {
46 // Zero-size encoding
47 length_info.push_back(0x00);
48 }
49 else {
50 assert(prefix_length <= 8);
51 uint8_t prefix_mask = ~((1 << (8 - prefix_length)) - 1);
52 if ((length_info.front() & ~prefix_mask) != length_info.front()) {
53 // additional byte needed for prefix
54 length_info.push_front(prefix_mask);
55 }
56 else {
57 // enough free bits available for prefix
58 length_info.front() |= (prefix_mask << 1);
59 }
60 // Huge lengths have all bits set in leading prefix bytes
61 length_info.insert(length_info.begin(), prefix_length / 8, 0xff);
62 }
63
64 return ByteBuffer(length_info.begin(), length_info.end());
65}
66
67std::tuple<ByteBuffer::const_iterator, std::uintmax_t> decode_length(const ByteBuffer& buffer)
68{
69 if (!buffer.empty()) {
70 std::size_t additional_prefix = count_leading_ones(buffer.front());
71
72 if (additional_prefix >= sizeof(std::uintmax_t)) {
73 // encoded length is wider than uintmax_t, we cannot represent this number
74 return std::make_tuple(buffer.begin(), 0);
75 } else if (buffer.size() > additional_prefix) {
76 uint8_t prefix_mask = (1 << (8 - additional_prefix)) - 1;
77 std::uintmax_t length = buffer.front() & prefix_mask;
78 for (std::size_t i = 1; i <= additional_prefix; ++i) {
79 length <<= 8;
80 length |= buffer[i];
81 }
82
83 auto start = buffer.begin();
84 std::advance(start, additional_prefix + 1);
85 return std::make_tuple(start, length);
86 }
87 }
88
89 return std::make_tuple(buffer.end(), 0);
90}
91
92} // namespace v2
93} // namespace security
94} // namespace vanextza