pjmsg_mcap_wrapper
Loading...
Searching...
No Matches
internal.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "types.hpp"
4#include <cstring>
5
6// Do not compile on systems with non-8-bit bytes
8
9namespace mcap {
10
11namespace internal {
12
13constexpr uint64_t MinHeaderLength = /* magic bytes */ sizeof(Magic) +
14 /* opcode */ 1 +
15 /* record length */ 8 +
16 /* profile length */ 4 +
17 /* library length */ 4;
18constexpr uint64_t FooterLength = /* opcode */ 1 +
19 /* record length */ 8 +
20 /* summary start */ 8 +
21 /* summary offset start */ 8 +
22 /* summary crc */ 4 +
23 /* magic bytes */ sizeof(Magic);
24
25inline std::string ToHex(uint8_t byte) {
26 std::string result{2, '\0'};
27 result[0] = "0123456789ABCDEF"[(uint8_t(byte) >> 4) & 0x0F];
28 result[1] = "0123456789ABCDEF"[uint8_t(byte) & 0x0F];
29 return result;
30}
32 return ToHex(uint8_t(byte));
33}
34
35inline std::string to_string(const std::string& arg) {
36 return arg;
37}
39 return std::string(arg);
40}
41inline std::string to_string(const char* arg) {
42 return std::string(arg);
43}
44template <typename... T>
45[[nodiscard]] inline std::string StrCat(T&&... args) {
47 using std::to_string;
48 return ("" + ... + to_string(std::forward<T>(args)));
49}
50
51inline uint32_t KeyValueMapSize(const KeyValueMap& map) {
52 size_t size = 0;
53 for (const auto& [key, value] : map) {
54 size += 4 + key.size() + 4 + value.size();
55 }
56 return (uint32_t)(size);
57}
58
59inline const std::string CompressionString(Compression compression) {
60 switch (compression) {
62 default:
63 return std::string{};
65 return "lz4";
67 return "zstd";
68 }
69}
70
71inline uint16_t ParseUint16(const std::byte* data) {
72 return uint16_t(data[0]) | (uint16_t(data[1]) << 8);
73}
74
75inline uint32_t ParseUint32(const std::byte* data) {
76 return uint32_t(data[0]) | (uint32_t(data[1]) << 8) | (uint32_t(data[2]) << 16) |
77 (uint32_t(data[3]) << 24);
78}
79
80inline Status ParseUint32(const std::byte* data, uint64_t maxSize, uint32_t* output) {
81 if (maxSize < 4) {
82 const auto msg = StrCat("cannot read uint32 from ", maxSize, " bytes");
84 }
85 *output = ParseUint32(data);
87}
88
89inline uint64_t ParseUint64(const std::byte* data) {
90 return uint64_t(data[0]) | (uint64_t(data[1]) << 8) | (uint64_t(data[2]) << 16) |
91 (uint64_t(data[3]) << 24) | (uint64_t(data[4]) << 32) | (uint64_t(data[5]) << 40) |
92 (uint64_t(data[6]) << 48) | (uint64_t(data[7]) << 56);
93}
94
95inline Status ParseUint64(const std::byte* data, uint64_t maxSize, uint64_t* output) {
96 if (maxSize < 8) {
97 const auto msg = StrCat("cannot read uint64 from ", maxSize, " bytes");
99 }
100 *output = ParseUint64(data);
101 return StatusCode::Success;
102}
103
104inline Status ParseStringView(const std::byte* data, uint64_t maxSize, std::string_view* output) {
105 uint32_t size = 0;
106 if (auto status = ParseUint32(data, maxSize, &size); !status.ok()) {
107 const auto msg = StrCat("cannot read string size: ", status.message);
109 }
110 if (uint64_t(size) > (maxSize - 4)) {
111 const auto msg = StrCat("string size ", size, " exceeds remaining bytes ", (maxSize - 4));
113 }
114 *output = std::string_view(reinterpret_cast<const char*>(data + 4), size);
115 return StatusCode::Success;
116}
117
118inline Status ParseString(const std::byte* data, uint64_t maxSize, std::string* output) {
119 uint32_t size = 0;
120 if (auto status = ParseUint32(data, maxSize, &size); !status.ok()) {
121 return status;
122 }
123 if (uint64_t(size) > (maxSize - 4)) {
124 const auto msg = StrCat("string size ", size, " exceeds remaining bytes ", (maxSize - 4));
126 }
127 *output = std::string(reinterpret_cast<const char*>(data + 4), size);
128 return StatusCode::Success;
129}
130
131inline Status ParseByteArray(const std::byte* data, uint64_t maxSize, ByteArray* output) {
132 uint32_t size = 0;
133 if (auto status = ParseUint32(data, maxSize, &size); !status.ok()) {
134 return status;
135 }
136 if (uint64_t(size) > (maxSize - 4)) {
137 const auto msg = StrCat("byte array size ", size, " exceeds remaining bytes ", (maxSize - 4));
139 }
140 output->resize(size);
141 // output->data() may return nullptr if 'output' is empty, but memcpy() does not accept nullptr.
142 // 'output' will be empty only if the 'size' is equal to 0.
143 if (size > 0) {
144 std::memcpy(output->data(), data + 4, size);
145 }
146 return StatusCode::Success;
147}
148
149inline Status ParseKeyValueMap(const std::byte* data, uint64_t maxSize, KeyValueMap* output) {
150 uint32_t sizeInBytes = 0;
151 if (auto status = ParseUint32(data, maxSize, &sizeInBytes); !status.ok()) {
152 return status;
153 }
154 if (sizeInBytes > (maxSize - 4)) {
155 const auto msg =
156 StrCat("key-value map size ", sizeInBytes, " exceeds remaining bytes ", (maxSize - 4));
158 }
159
160 // Account for the byte size prefix in sizeInBytes to make the bounds checking
161 // below simpler
162 sizeInBytes += 4;
163
164 output->clear();
165 uint64_t pos = 4;
166 while (pos < sizeInBytes) {
168 if (auto status = ParseStringView(data + pos, sizeInBytes - pos, &key); !status.ok()) {
169 const auto msg = StrCat("cannot read key-value map key at pos ", pos, ": ", status.message);
171 }
172 pos += 4 + key.size();
173 std::string_view value;
174 if (auto status = ParseStringView(data + pos, sizeInBytes - pos, &value); !status.ok()) {
175 const auto msg = StrCat("cannot read key-value map value for key \"", key, "\" at pos ", pos,
176 ": ", status.message);
178 }
179 pos += 4 + value.size();
180 output->emplace(key, value);
181 }
182 return StatusCode::Success;
183}
184
185inline std::string MagicToHex(const std::byte* data) {
186 return internal::ToHex(data[0]) + internal::ToHex(data[1]) + internal::ToHex(data[2]) +
187 internal::ToHex(data[3]) + internal::ToHex(data[4]) + internal::ToHex(data[5]) +
188 internal::ToHex(data[6]) + internal::ToHex(data[7]);
189}
190
191} // namespace internal
192
193} // namespace mcap
T clear(T... args)
T data(T... args)
T emplace(T... args)
T internal(T... args)
T memcpy(T... args)
Status ParseByteArray(const std::byte *data, uint64_t maxSize, ByteArray *output)
Definition internal.hpp:131
uint64_t ParseUint64(const std::byte *data)
Definition internal.hpp:89
constexpr uint64_t FooterLength
Definition internal.hpp:18
std::string MagicToHex(const std::byte *data)
Definition internal.hpp:185
std::string StrCat(T &&... args)
Definition internal.hpp:45
uint32_t KeyValueMapSize(const KeyValueMap &map)
Definition internal.hpp:51
constexpr uint64_t MinHeaderLength
Definition internal.hpp:13
uint32_t ParseUint32(const std::byte *data)
Definition internal.hpp:75
std::string ToHex(uint8_t byte)
Definition internal.hpp:25
Status ParseStringView(const std::byte *data, uint64_t maxSize, std::string_view *output)
Definition internal.hpp:104
const std::string CompressionString(Compression compression)
Definition internal.hpp:59
uint16_t ParseUint16(const std::byte *data)
Definition internal.hpp:71
std::string to_string(const std::string &arg)
Definition internal.hpp:35
Status ParseString(const std::byte *data, uint64_t maxSize, std::string *output)
Definition internal.hpp:118
Status ParseKeyValueMap(const std::byte *data, uint64_t maxSize, KeyValueMap *output)
Definition internal.hpp:149
Definition crc32.hpp:5
Compression
Supported MCAP compression algorithms.
Definition types.hpp:37
constexpr uint8_t Magic[]
Definition types.hpp:29
T resize(T... args)
T size(T... args)
Wraps a status code and string message carrying additional context.
Definition errors.hpp:36
T to_string(T... args)