Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2026 by Thun Lu. All rights reserved.
3 : : * Author: Thun Lu <thun.lu@zohomail.cn>
4 : : * Repo: https://github.com/thun-res/vlink
5 : : * _ __ __ _ __
6 : : * | | / / / / (_) ____ / /__
7 : : * | | / / / / / / / __ \ / //_/
8 : : * | |/ / / /___ / / / / / / / ,<
9 : : * |___/ /_____/ /_/ /_/ /_/ /_/|_|
10 : : *
11 : : * Licensed under the Apache License, Version 2.0 (the "License");
12 : : * you may not use this file except in compliance with the License.
13 : : * You may obtain a copy of the License at
14 : : *
15 : : * http://www.apache.org/licenses/LICENSE-2.0
16 : : *
17 : : * Unless required by applicable law or agreed to in writing, software
18 : : * distributed under the License is distributed on an "AS IS" BASIS,
19 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 : : * See the License for the specific language governing permissions and
21 : : * limitations under the License.
22 : : */
23 : :
24 : : #include "./extension/someip_serializer.h"
25 : :
26 : : #include <algorithm>
27 : : #include <cstring>
28 : : #include <iostream>
29 : : #include <limits>
30 : : #include <utility>
31 : :
32 : : namespace vlink {
33 : :
34 : : namespace SomeipSerializer { // NOLINT(readability-identifier-naming)
35 : :
36 : : static constexpr uint8_t kUtf8Bom[] = {0xEF, 0xBB, 0xBF};
37 : : static constexpr uint8_t kUtf16BomBig[] = {0xFE, 0xFF};
38 : : static constexpr uint8_t kUtf16BomLittle[] = {0xFF, 0xFE};
39 : : static constexpr size_t kUtf16UnitSize = 2U;
40 : : static constexpr size_t kHeaderSize = 16U;
41 : :
42 : : // Writer
43 : 173 : Writer::Writer(uint8_t* data, size_t capacity, size_t alignment, Endian endian) noexcept
44 : 173 : : data_(data), capacity_(std::min(capacity, kMaxPayloadSize)), alignment_(alignment), endian_(endian) {}
45 : :
46 : 790023 : size_t Writer::position() const noexcept { return position_; }
47 : :
48 : 79 : bool Writer::is_size_only() const noexcept { return data_ == nullptr; }
49 : :
50 : 30 : Writer Writer::size_only() const noexcept {
51 : 30 : Writer result = *this;
52 : 30 : result.data_ = nullptr;
53 : :
54 : 30 : return result;
55 : : }
56 : :
57 : 402 : bool Writer::append(const uint8_t* data, size_t size) noexcept {
58 [ + + ]: 402 : if VUNLIKELY (size > capacity_ - position_) {
59 : 2 : return false;
60 : : }
61 : :
62 [ + + + + ]: 400 : if (data_ && size > 0U) {
63 : 157 : std::memcpy(data_ + position_, data, size);
64 : : }
65 : :
66 : 400 : position_ += size;
67 : :
68 : 400 : return true;
69 : : }
70 : :
71 : 395184 : bool Writer::append_unsigned(uint64_t value, size_t width) noexcept { return append_unsigned(value, width, endian_); }
72 : :
73 : 395265 : bool Writer::append_unsigned(uint64_t value, size_t width, Endian endian) noexcept {
74 [ + + + + : 395265 : if VUNLIKELY (width == 0U || width > sizeof(value) || width > capacity_ - position_) {
+ + - + +
+ ]
75 : 2 : return false;
76 : : }
77 : :
78 [ + + ]: 791101 : for (size_t index = 0; index < width; ++index) {
79 [ + + ]: 395838 : const size_t shift = (endian == Endian::kBig ? width - index - 1U : index) * 8U;
80 : :
81 [ + + ]: 395838 : if (data_) {
82 : 132072 : data_[position_ + index] = static_cast<uint8_t>((value >> shift) & 0xFFU);
83 : : }
84 : : }
85 : :
86 : 395263 : position_ += width;
87 : :
88 : 395263 : return true;
89 : : }
90 : :
91 : 364 : bool Writer::begin_length_delimited(size_t& length_position, size_t& data_position, size_t width) noexcept {
92 [ + + + + : 364 : if VUNLIKELY (width != 1U && width != 2U && width != 4U) {
+ + - + -
+ ]
93 : 0 : return false;
94 : : }
95 : :
96 : 364 : length_position = position_;
97 : :
98 [ + + ]: 364 : if VUNLIKELY (width > capacity_ - position_) {
99 : 1 : return false;
100 : : }
101 : :
102 : 363 : position_ += width;
103 : 363 : data_position = position_;
104 : :
105 : 363 : return true;
106 : : }
107 : :
108 : 340 : bool Writer::end_length_delimited(size_t length_position, size_t data_position, size_t width) noexcept {
109 [ + + + + : 340 : if VUNLIKELY ((width != 1U && width != 2U && width != 4U) || position_ < data_position) {
+ + - + +
- - + -
+ ]
110 : 0 : return false;
111 : : }
112 : :
113 : 340 : const size_t byte_length = position_ - data_position;
114 : 340 : const uint64_t max_length = (uint64_t{1U} << (width * 8U)) - 1U;
115 : :
116 [ + + - + : 340 : if VUNLIKELY (byte_length > max_length || length_position > capacity_ || width > capacity_ - length_position) {
+ + - + +
+ ]
117 : 1 : return false;
118 : : }
119 : :
120 [ + + ]: 339 : if (data_) {
121 [ + + ]: 576 : for (size_t index = 0U; index < width; ++index) {
122 : 421 : const size_t shift = (width - index - 1U) * 8U;
123 : 421 : data_[length_position + index] = static_cast<uint8_t>((byte_length >> shift) & 0xFFU);
124 : : }
125 : : }
126 : :
127 : 339 : return true;
128 : : }
129 : :
130 : 116 : bool Writer::align() noexcept {
131 [ + + ]: 116 : if VLIKELY (alignment_ == 1U) {
132 : 95 : return true;
133 : : }
134 : :
135 : 21 : const size_t mask = alignment_ - 1U;
136 : 21 : const size_t remainder = ((position_ & mask) + (kHeaderSize & mask)) & mask;
137 : 21 : const size_t padding = (alignment_ - remainder) & mask;
138 : :
139 [ - + ]: 21 : if VUNLIKELY (padding > capacity_ - position_) {
140 : 0 : return false;
141 : : }
142 : :
143 [ + + + + ]: 21 : if (data_ && padding > 0U) {
144 : 8 : std::memset(data_ + position_, 0, padding);
145 : : }
146 : :
147 : 21 : position_ += padding;
148 : :
149 : 21 : return true;
150 : : }
151 : :
152 : : // Reader
153 : 108 : Reader::Reader(const uint8_t* data, size_t size, size_t alignment, Endian endian) noexcept
154 : 108 : : data_(data), size_(size), alignment_(alignment), endian_(endian) {}
155 : :
156 : 197332 : size_t Reader::position() const noexcept { return position_; }
157 : :
158 : 113 : size_t Reader::size() const noexcept { return size_; }
159 : :
160 [ + + ]: 71 : const uint8_t* Reader::current_data() const noexcept { return position_ < size_ ? data_ + position_ : nullptr; }
161 : :
162 : 9 : bool Reader::read(uint8_t* data, size_t size, size_t end) noexcept {
163 [ + - - + : 9 : if VUNLIKELY (end > size_ || position_ > end || size > end - position_) {
+ - + + +
+ ]
164 : 1 : return false;
165 : : }
166 : :
167 [ + - ]: 8 : if (size > 0U) {
168 : 8 : std::memcpy(data, data_ + position_, size);
169 : : }
170 : :
171 : 8 : position_ += size;
172 : :
173 : 8 : return true;
174 : : }
175 : :
176 : 204 : bool Reader::skip(size_t size, size_t end) noexcept {
177 [ + - - + : 204 : if VUNLIKELY (end > size_ || position_ > end || size > end - position_) {
+ - + + +
+ ]
178 : 1 : return false;
179 : : }
180 : :
181 : 203 : position_ += size;
182 : :
183 : 203 : return true;
184 : : }
185 : :
186 : 65783 : bool Reader::read_unsigned(uint64_t& value, size_t width, size_t end) noexcept {
187 : 65783 : return read_unsigned(value, width, endian_, end);
188 : : }
189 : :
190 : 65850 : bool Reader::read_unsigned(uint64_t& value, size_t width, Endian endian, size_t end) noexcept {
191 [ + - - + : 65850 : if VUNLIKELY (width == 0U || width > sizeof(value) || end > size_ || position_ > end || width > end - position_) {
+ - - + +
- - + + -
+ + + + ]
192 : 5 : return false;
193 : : }
194 : :
195 : 65845 : value = 0;
196 : :
197 [ + + ]: 132044 : for (size_t index = 0; index < width; ++index) {
198 [ + + ]: 66199 : const size_t shift = (endian == Endian::kBig ? width - index - 1U : index) * 8U;
199 : 66199 : value |= static_cast<uint64_t>(data_[position_ + index]) << shift;
200 : : }
201 : :
202 : 65845 : position_ += width;
203 : :
204 : 65845 : return true;
205 : : }
206 : :
207 : 204 : bool Reader::begin_length_delimited(size_t end, size_t& value_end, size_t width) noexcept {
208 [ + + + + : 204 : if VUNLIKELY ((width != 1U && width != 2U && width != 4U) || end > size_ || position_ > end ||
+ + - + +
- - + + -
- + + - -
+ - + ]
209 : : width > end - position_) {
210 : 0 : return false;
211 : : }
212 : :
213 : 204 : uint32_t byte_length = 0U;
214 : :
215 [ + + ]: 748 : for (size_t index = 0U; index < width; ++index) {
216 : 544 : byte_length = (byte_length << 8U) | data_[position_ + index];
217 : : }
218 : :
219 : 204 : position_ += width;
220 : :
221 [ + + ]: 204 : if VUNLIKELY (byte_length > end - position_) {
222 : 3 : return false;
223 : : }
224 : :
225 : 201 : value_end = position_ + static_cast<size_t>(byte_length);
226 : :
227 : 201 : return true;
228 : : }
229 : :
230 : 53 : bool Reader::align(size_t end) noexcept {
231 [ + + ]: 53 : if VLIKELY (alignment_ == 1U) {
232 : 45 : return true;
233 : : }
234 : :
235 : 8 : const size_t mask = alignment_ - 1U;
236 : 8 : const size_t remainder = ((position_ & mask) + (kHeaderSize & mask)) & mask;
237 : 8 : const size_t padding = (alignment_ - remainder) & mask;
238 : :
239 : 8 : return skip(padding, end);
240 : : }
241 : :
242 : : // detail
243 : : namespace detail {
244 : :
245 : 162 : static bool is_valid_utf8(const uint8_t* data, size_t size, size_t maximum) noexcept {
246 : 162 : size_t position = 0;
247 : 162 : size_t count = 0;
248 : :
249 [ + + ]: 474 : while (position < size) {
250 : 335 : const uint8_t first = data[position];
251 : :
252 [ + + ]: 335 : if VLIKELY (first <= 0x7FU) {
253 : 298 : ++position;
254 : :
255 [ + + ]: 298 : if (maximum != std::numeric_limits<size_t>::max()) {
256 : 116 : ++count;
257 [ + + ]: 116 : if VUNLIKELY (count > maximum) {
258 : 10 : return false;
259 : : }
260 : : }
261 : :
262 : 288 : continue;
263 : : }
264 : :
265 : 37 : size_t continuation_count = 0;
266 : 37 : uint8_t second_min = 0x80U;
267 : 37 : uint8_t second_max = 0xBFU;
268 : :
269 [ + + + + ]: 37 : if (first >= 0xC2U && first <= 0xDFU) {
270 : 6 : continuation_count = 1U;
271 [ + + + + ]: 31 : } else if (first >= 0xE0U && first <= 0xEFU) {
272 : 16 : continuation_count = 2U;
273 [ + + ]: 16 : second_min = first == 0xE0U ? 0xA0U : 0x80U;
274 [ + + ]: 16 : second_max = first == 0xEDU ? 0x9FU : 0xBFU;
275 [ + + + - ]: 15 : } else if (first >= 0xF0U && first <= 0xF4U) {
276 : 13 : continuation_count = 3U;
277 [ + + ]: 13 : second_min = first == 0xF0U ? 0x90U : 0x80U;
278 [ + + ]: 13 : second_max = first == 0xF4U ? 0x8FU : 0xBFU;
279 : : } else {
280 : 2 : return false;
281 : : }
282 : :
283 [ + + ]: 35 : if VUNLIKELY (continuation_count > size - position - 1U) {
284 : 1 : return false;
285 : : }
286 : :
287 : 34 : const uint8_t second = data[position + 1U];
288 : :
289 [ + + + + : 34 : if VUNLIKELY (second < second_min || second > second_max) {
+ + ]
290 : 8 : return false;
291 : : }
292 : :
293 [ + + ]: 53 : for (size_t index = 2U; index <= continuation_count; ++index) {
294 : 29 : const uint8_t continuation = data[position + index];
295 : :
296 [ + + - + : 29 : if VUNLIKELY (continuation < 0x80U || continuation > 0xBFU) {
+ + ]
297 : 2 : return false;
298 : : }
299 : : }
300 : :
301 : 24 : position += continuation_count + 1U;
302 : :
303 [ + + ]: 24 : if (maximum != std::numeric_limits<size_t>::max()) {
304 : 3 : ++count;
305 [ - + ]: 3 : if VUNLIKELY (count > maximum) {
306 : 0 : return false;
307 : : }
308 : : }
309 : : }
310 : :
311 : 139 : return true;
312 : : }
313 : :
314 : 30 : static bool is_valid_utf16(const char16_t* data, size_t size, size_t maximum) noexcept {
315 : 30 : size_t position = 0;
316 : 30 : size_t count = 0;
317 : :
318 [ + + ]: 69 : while (position < size) {
319 : 41 : const auto unit = static_cast<uint16_t>(data[position]);
320 : :
321 [ + + - + : 41 : if VLIKELY (unit < 0xD800U || unit > 0xDFFFU) {
+ + ]
322 : 35 : ++position;
323 : :
324 [ + + ]: 35 : if (maximum != std::numeric_limits<size_t>::max()) {
325 : 27 : ++count;
326 [ + + ]: 27 : if VUNLIKELY (count > maximum) {
327 : 1 : return false;
328 : : }
329 : : }
330 : :
331 : 34 : continue;
332 : : }
333 : :
334 [ + - + + : 6 : if VUNLIKELY (unit > 0xDBFFU || position + 1U == size) {
+ + ]
335 : 1 : return false;
336 : : }
337 : :
338 : 5 : const auto low = static_cast<uint16_t>(data[position + 1U]);
339 : :
340 [ + - - + : 5 : if VUNLIKELY (low < 0xDC00U || low > 0xDFFFU) {
- + ]
341 : 0 : return false;
342 : : }
343 : :
344 : 5 : position += 2U;
345 : :
346 [ + + ]: 5 : if (maximum != std::numeric_limits<size_t>::max()) {
347 : 3 : ++count;
348 [ - + ]: 3 : if VUNLIKELY (count > maximum) {
349 : 0 : return false;
350 : : }
351 : : }
352 : : }
353 : :
354 : 28 : return true;
355 : : }
356 : :
357 : 25 : static bool write_zeroes(Writer& writer, size_t size) noexcept {
358 [ + + ]: 25 : if (writer.is_size_only()) {
359 : 13 : return writer.append(nullptr, size);
360 : : }
361 : :
362 : : static constexpr uint8_t kZeroes[256] = {};
363 : :
364 [ - + ]: 12 : while (size > sizeof(kZeroes)) {
365 [ # # ]: 0 : if VUNLIKELY (!writer.append(kZeroes, sizeof(kZeroes))) {
366 : 0 : return false;
367 : : }
368 : :
369 : 0 : size -= sizeof(kZeroes);
370 : : }
371 : :
372 : 12 : return writer.append(kZeroes, size);
373 : : }
374 : :
375 : 104 : static bool write_utf8_body(Writer& writer, const std::string& value, size_t maximum, bool strip_leading_bom) noexcept {
376 : 104 : const auto* data = reinterpret_cast<const uint8_t*>(value.data());
377 : : const size_t offset =
378 [ + + + + ]: 88 : strip_leading_bom && value.size() >= sizeof(kUtf8Bom) && std::memcmp(data, kUtf8Bom, sizeof(kUtf8Bom)) == 0
379 [ + + ]: 192 : ? sizeof(kUtf8Bom)
380 : 104 : : 0U;
381 : :
382 [ + + ]: 104 : if VUNLIKELY (!is_valid_utf8(data + offset, value.size() - offset, maximum)) {
383 : 13 : return false;
384 : : }
385 : :
386 : 91 : const uint8_t terminator = 0U;
387 : :
388 [ + - + - : 182 : return writer.append(kUtf8Bom, sizeof(kUtf8Bom)) && writer.append(data + offset, value.size() - offset) &&
+ - ]
389 : 182 : writer.append(&terminator, sizeof(terminator));
390 : : }
391 : :
392 : 28 : static bool write_utf16_body(Writer& writer, const std::u16string& value, Endian encoding, size_t maximum,
393 : : bool strip_leading_bom) noexcept {
394 [ + + + - : 28 : const size_t offset = strip_leading_bom && !value.empty() && value.front() == u'\uFEFF' ? 1U : 0U;
+ + ]
395 : :
396 [ + + ]: 28 : if VUNLIKELY (!is_valid_utf16(value.data() + offset, value.size() - offset, maximum)) {
397 : 2 : return false;
398 : : }
399 : :
400 [ + + ]: 26 : if (writer.is_size_only()) {
401 [ + - + - : 28 : return writer.append(nullptr, kUtf16UnitSize) && writer.append(nullptr, (value.size() - offset) * kUtf16UnitSize) &&
+ - ]
402 : 28 : writer.append(nullptr, kUtf16UnitSize);
403 : : }
404 : :
405 [ + + ]: 12 : const uint8_t* bom = encoding == Endian::kBig ? kUtf16BomBig : kUtf16BomLittle;
406 : :
407 [ - + ]: 12 : if VUNLIKELY (!writer.append(bom, kUtf16UnitSize)) {
408 : 0 : return false;
409 : : }
410 : :
411 : : uint8_t chunk[256];
412 : 12 : size_t filled = 0U;
413 : :
414 [ + + ]: 30 : for (size_t index = offset; index < value.size(); ++index) {
415 : 18 : const auto bits = static_cast<uint16_t>(value[index]);
416 : :
417 [ + + ]: 18 : chunk[filled] = static_cast<uint8_t>(encoding == Endian::kBig ? bits >> 8U : bits & 0xFFU);
418 [ + + ]: 18 : chunk[filled + 1U] = static_cast<uint8_t>(encoding == Endian::kBig ? bits & 0xFFU : bits >> 8U);
419 : 18 : filled += kUtf16UnitSize;
420 : :
421 [ - + ]: 18 : if (filled == sizeof(chunk)) {
422 [ # # ]: 0 : if VUNLIKELY (!writer.append(chunk, filled)) {
423 : 0 : return false;
424 : : }
425 : :
426 : 0 : filled = 0U;
427 : : }
428 : : }
429 : :
430 : 12 : chunk[filled] = 0U;
431 : 12 : chunk[filled + 1U] = 0U;
432 : :
433 : 12 : return writer.append(chunk, filled + kUtf16UnitSize);
434 : : }
435 : :
436 : 25 : bool write_value(Writer& writer, bool value) noexcept {
437 [ + + ]: 25 : return writer.append_unsigned(value ? 1U : 0U, sizeof(uint8_t));
438 : : }
439 : :
440 : 394887 : bool write_value(Writer& writer, uint8_t value) noexcept { return writer.append_unsigned(value, sizeof(value)); }
441 : :
442 : 136 : bool write_value(Writer& writer, uint16_t value) noexcept { return writer.append_unsigned(value, sizeof(value)); }
443 : :
444 : 38 : bool write_value(Writer& writer, uint32_t value) noexcept { return writer.append_unsigned(value, sizeof(value)); }
445 : :
446 : 2 : bool write_value(Writer& writer, uint64_t value) noexcept { return writer.append_unsigned(value, sizeof(value)); }
447 : :
448 : 2 : bool write_value(Writer& writer, int8_t value) noexcept {
449 : 2 : return writer.append_unsigned(static_cast<uint8_t>(value), sizeof(value));
450 : : }
451 : :
452 : 33 : bool write_value(Writer& writer, int16_t value) noexcept {
453 : 33 : return writer.append_unsigned(static_cast<uint16_t>(value), sizeof(value));
454 : : }
455 : :
456 : 36 : bool write_value(Writer& writer, int32_t value) noexcept {
457 : 36 : return writer.append_unsigned(static_cast<uint32_t>(value), sizeof(value));
458 : : }
459 : :
460 : 2 : bool write_value(Writer& writer, int64_t value) noexcept {
461 : 2 : return writer.append_unsigned(static_cast<uint64_t>(value), sizeof(value));
462 : : }
463 : :
464 : 18 : bool write_value(Writer& writer, float value) noexcept {
465 : : static_assert(sizeof(float) == sizeof(uint32_t), "SOME/IP float must use IEEE 754 binary32 storage.");
466 : : static_assert(std::numeric_limits<float>::is_iec559, "SOME/IP float requires IEEE 754 semantics.");
467 : :
468 : 18 : uint32_t bits = 0;
469 : 18 : std::memcpy(&bits, &value, sizeof(bits));
470 : :
471 : 18 : return writer.append_unsigned(bits, sizeof(bits));
472 : : }
473 : :
474 : 2 : bool write_value(Writer& writer, double value) noexcept {
475 : : static_assert(sizeof(double) == sizeof(uint64_t), "SOME/IP double must use IEEE 754 binary64 storage.");
476 : : static_assert(std::numeric_limits<double>::is_iec559, "SOME/IP double requires IEEE 754 semantics.");
477 : :
478 : 2 : uint64_t bits = 0;
479 : 2 : std::memcpy(&bits, &value, sizeof(bits));
480 : :
481 : 2 : return writer.append_unsigned(bits, sizeof(bits));
482 : : }
483 : :
484 : 83 : bool write_value(Writer& writer, const std::string& value, size_t len, size_t maximum) noexcept {
485 : 83 : size_t length_position = 0;
486 : 83 : size_t data_position = 0;
487 : :
488 [ + + ]: 166 : return writer.begin_length_delimited(length_position, data_position, len) &&
489 [ + - + - ]: 166 : write_value_body(writer, value, maximum) && writer.end_length_delimited(length_position, data_position, len);
490 : : }
491 : :
492 : 16 : bool write_value(Writer& writer, const Bytes& value, size_t len, size_t maximum) noexcept {
493 : 16 : size_t length_position = 0;
494 : 16 : size_t data_position = 0;
495 : :
496 [ + - ]: 32 : return writer.begin_length_delimited(length_position, data_position, len) &&
497 [ + - + - ]: 32 : write_value_body(writer, value, maximum) && writer.end_length_delimited(length_position, data_position, len);
498 : : }
499 : :
500 : 16 : bool write_value(Writer& writer, const std::u16string& value, size_t len, Endian encoding, size_t maximum) noexcept {
501 : 16 : size_t length_position = 0;
502 : 16 : size_t data_position = 0;
503 : :
504 [ + + ]: 32 : return writer.begin_length_delimited(length_position, data_position, len) &&
505 [ + - + - ]: 32 : write_value_body(writer, value, encoding, maximum) &&
506 : 30 : writer.end_length_delimited(length_position, data_position, len);
507 : : }
508 : :
509 : 17 : bool write_fixed_value(Writer& writer, const std::string& value, size_t size, size_t len, size_t maximum) noexcept {
510 [ + - + + : 17 : if VUNLIKELY (size < sizeof(kUtf8Bom) + 1U || value.size() > size - sizeof(kUtf8Bom) - 1U) {
+ + ]
511 : 1 : return false;
512 : : }
513 : :
514 : 16 : size_t length_position = 0U;
515 : 16 : size_t data_position = 0U;
516 : :
517 [ + + - + : 16 : if VUNLIKELY (len > 0U && !writer.begin_length_delimited(length_position, data_position, len)) {
- + ]
518 : 0 : return false;
519 : : }
520 : :
521 [ + + - + : 16 : if VUNLIKELY (!write_utf8_body(writer, value, maximum, false) ||
+ + ]
522 : : !write_zeroes(writer, size - sizeof(kUtf8Bom) - value.size() - 1U)) {
523 : 3 : return false;
524 : : }
525 : :
526 [ + + + - ]: 13 : return len == 0U || writer.end_length_delimited(length_position, data_position, len);
527 : : }
528 : :
529 : 14 : bool write_fixed_value(Writer& writer, const std::u16string& value, size_t size, size_t len, Endian encoding,
530 : : size_t maximum) noexcept {
531 [ + - - + : 14 : if VUNLIKELY (size < kUtf16UnitSize * 2U || size % kUtf16UnitSize != 0U ||
+ - + + +
+ ]
532 : : value.size() > size / kUtf16UnitSize - 2U) {
533 : 2 : return false;
534 : : }
535 : :
536 : 12 : size_t length_position = 0U;
537 : 12 : size_t data_position = 0U;
538 : :
539 [ + + - + : 12 : if VUNLIKELY (len > 0U && !writer.begin_length_delimited(length_position, data_position, len)) {
- + ]
540 : 0 : return false;
541 : : }
542 : :
543 : 12 : const size_t encoded_size = (value.size() + 2U) * kUtf16UnitSize;
544 : :
545 [ + - - + : 12 : if VUNLIKELY (!write_utf16_body(writer, value, encoding, maximum, false) ||
- + ]
546 : : !write_zeroes(writer, size - encoded_size)) {
547 : 0 : return false;
548 : : }
549 : :
550 [ + + + - ]: 12 : return len == 0U || writer.end_length_delimited(length_position, data_position, len);
551 : : }
552 : :
553 : 15 : bool read_value(Reader& reader, bool& value, size_t end) noexcept {
554 : 15 : uint64_t raw = 0;
555 : :
556 [ - + ]: 15 : if VUNLIKELY (!reader.read_unsigned(raw, sizeof(uint8_t), end)) {
557 : 0 : return false;
558 : : }
559 : :
560 : 15 : value = (raw & 0x01U) != 0U;
561 : :
562 : 15 : return true;
563 : : }
564 : :
565 : 65608 : bool read_value(Reader& reader, uint8_t& value, size_t end) noexcept {
566 : 65608 : uint64_t raw = 0;
567 : :
568 [ + + ]: 65608 : if VUNLIKELY (!reader.read_unsigned(raw, sizeof(value), end)) {
569 : 1 : return false;
570 : : }
571 : :
572 : 65607 : value = static_cast<uint8_t>(raw);
573 : :
574 : 65607 : return true;
575 : : }
576 : :
577 : 104 : bool read_value(Reader& reader, uint16_t& value, size_t end) noexcept {
578 : 104 : uint64_t raw = 0;
579 : :
580 [ + + ]: 104 : if VUNLIKELY (!reader.read_unsigned(raw, sizeof(value), end)) {
581 : 1 : return false;
582 : : }
583 : :
584 : 103 : value = static_cast<uint16_t>(raw);
585 : :
586 : 103 : return true;
587 : : }
588 : :
589 : 50 : bool read_value(Reader& reader, uint32_t& value, size_t end) noexcept {
590 : 50 : uint64_t raw = 0;
591 : :
592 [ + + ]: 50 : if VUNLIKELY (!reader.read_unsigned(raw, sizeof(value), end)) {
593 : 1 : return false;
594 : : }
595 : :
596 : 49 : value = static_cast<uint32_t>(raw);
597 : :
598 : 49 : return true;
599 : : }
600 : :
601 : 3 : bool read_value(Reader& reader, uint64_t& value, size_t end) noexcept {
602 : 3 : return reader.read_unsigned(value, sizeof(value), end);
603 : : }
604 : :
605 : 1 : bool read_value(Reader& reader, int8_t& value, size_t end) noexcept {
606 : 1 : uint8_t raw = 0;
607 : :
608 [ - + ]: 1 : if VUNLIKELY (!read_value(reader, raw, end)) {
609 : 0 : return false;
610 : : }
611 : :
612 : 1 : std::memcpy(&value, &raw, sizeof(value));
613 : :
614 : 1 : return true;
615 : : }
616 : :
617 : 17 : bool read_value(Reader& reader, int16_t& value, size_t end) noexcept {
618 : 17 : uint16_t raw = 0;
619 : :
620 [ - + ]: 17 : if VUNLIKELY (!read_value(reader, raw, end)) {
621 : 0 : return false;
622 : : }
623 : :
624 : 17 : std::memcpy(&value, &raw, sizeof(value));
625 : :
626 : 17 : return true;
627 : : }
628 : :
629 : 22 : bool read_value(Reader& reader, int32_t& value, size_t end) noexcept {
630 : 22 : uint32_t raw = 0;
631 : :
632 [ - + ]: 22 : if VUNLIKELY (!read_value(reader, raw, end)) {
633 : 0 : return false;
634 : : }
635 : :
636 : 22 : std::memcpy(&value, &raw, sizeof(value));
637 : :
638 : 22 : return true;
639 : : }
640 : :
641 : 1 : bool read_value(Reader& reader, int64_t& value, size_t end) noexcept {
642 : 1 : uint64_t raw = 0;
643 : :
644 [ - + ]: 1 : if VUNLIKELY (!read_value(reader, raw, end)) {
645 : 0 : return false;
646 : : }
647 : :
648 : 1 : std::memcpy(&value, &raw, sizeof(value));
649 : :
650 : 1 : return true;
651 : : }
652 : :
653 : 8 : bool read_value(Reader& reader, float& value, size_t end) noexcept {
654 : 8 : uint32_t bits = 0;
655 : :
656 [ - + ]: 8 : if VUNLIKELY (!read_value(reader, bits, end)) {
657 : 0 : return false;
658 : : }
659 : :
660 : 8 : std::memcpy(&value, &bits, sizeof(value));
661 : :
662 : 8 : return true;
663 : : }
664 : :
665 : 1 : bool read_value(Reader& reader, double& value, size_t end) noexcept {
666 : 1 : uint64_t bits = 0;
667 : :
668 [ - + ]: 1 : if VUNLIKELY (!read_value(reader, bits, end)) {
669 : 0 : return false;
670 : : }
671 : :
672 : 1 : std::memcpy(&value, &bits, sizeof(value));
673 : :
674 : 1 : return true;
675 : : }
676 : :
677 : 46 : bool read_value(Reader& reader, std::string& value, size_t end, size_t len, size_t maximum) noexcept {
678 : 46 : size_t value_end = 0;
679 : :
680 [ + + + + ]: 46 : return reader.begin_length_delimited(end, value_end, len) && read_value_body(reader, value, value_end, maximum);
681 : : }
682 : :
683 : 8 : bool read_value(Reader& reader, Bytes& value, size_t end, size_t len, size_t maximum) noexcept {
684 : 8 : size_t value_end = 0;
685 : :
686 [ + - + - ]: 8 : return reader.begin_length_delimited(end, value_end, len) && read_value_body(reader, value, value_end, maximum);
687 : : }
688 : :
689 : 8 : bool read_value(Reader& reader, std::u16string& value, size_t end, size_t len, Endian encoding,
690 : : size_t maximum) noexcept {
691 : 8 : size_t value_end = 0;
692 : :
693 [ + - + + ]: 16 : return reader.begin_length_delimited(end, value_end, len) &&
694 : 16 : read_value_body(reader, value, value_end, encoding, maximum);
695 : : }
696 : :
697 : 9 : bool read_fixed_value(Reader& reader, std::string& value, size_t end, size_t size, size_t len,
698 : : size_t maximum) noexcept {
699 : 9 : size_t value_end = 0U;
700 : :
701 [ + + ]: 9 : if (len == 0U) {
702 [ + - + + : 7 : if VUNLIKELY (reader.position() > end || size > end - reader.position()) {
+ + ]
703 : 1 : return false;
704 : : }
705 : :
706 : 6 : value_end = reader.position() + size;
707 [ + - - + : 2 : } else if VUNLIKELY (!reader.begin_length_delimited(end, value_end, len) || value_end - reader.position() > size) {
- + ]
708 : 0 : return false;
709 : : }
710 : :
711 [ - + ]: 8 : if VUNLIKELY (!read_value_body(reader, value, value_end)) {
712 : 0 : return false;
713 : : }
714 : :
715 [ + - + + : 39 : while (!value.empty() && value.back() == '\0') {
+ + ]
716 : 31 : value.pop_back();
717 : : }
718 : :
719 [ + + + + ]: 13 : return maximum == std::numeric_limits<size_t>::max() ||
720 : 13 : is_valid_utf8(reinterpret_cast<const uint8_t*>(value.data()), value.size(), maximum);
721 : : }
722 : :
723 : 6 : bool read_fixed_value(Reader& reader, std::u16string& value, size_t end, size_t size, size_t len, Endian encoding,
724 : : size_t maximum) noexcept {
725 : 6 : size_t value_end = 0U;
726 : :
727 [ + + ]: 6 : if (len == 0U) {
728 [ + - - + : 3 : if VUNLIKELY (reader.position() > end || size > end - reader.position()) {
- + ]
729 : 0 : return false;
730 : : }
731 : :
732 : 3 : value_end = reader.position() + size;
733 [ + - - + : 3 : } else if VUNLIKELY (!reader.begin_length_delimited(end, value_end, len) || value_end - reader.position() > size) {
- + ]
734 : 0 : return false;
735 : : }
736 : :
737 [ - + ]: 6 : if VUNLIKELY (!read_value_body(reader, value, value_end, encoding)) {
738 : 0 : return false;
739 : : }
740 : :
741 [ + - + + : 13 : while (!value.empty() && value.back() == u'\0') {
+ + ]
742 : 7 : value.pop_back();
743 : : }
744 : :
745 [ + + + - ]: 6 : return maximum == std::numeric_limits<size_t>::max() || is_valid_utf16(value.data(), value.size(), maximum);
746 : : }
747 : :
748 : 55 : bool read_value_body(Reader& reader, std::string& value, size_t end, size_t maximum) noexcept {
749 : 55 : const size_t length = end - reader.position();
750 : :
751 [ - + ]: 55 : if VUNLIKELY (length < sizeof(kUtf8Bom) + 1U) {
752 : 0 : return false;
753 : : }
754 : :
755 : 55 : const auto* data = reader.current_data();
756 : 55 : const size_t value_size = length - sizeof(kUtf8Bom) - 1U;
757 : :
758 [ + - + + : 55 : if VUNLIKELY (!data || std::memcmp(data, kUtf8Bom, sizeof(kUtf8Bom)) != 0 || data[length - 1U] != 0U ||
+ + + + +
+ + + +
+ ]
759 : : !is_valid_utf8(data + sizeof(kUtf8Bom), value_size, maximum)) {
760 : 10 : return false;
761 : : }
762 : :
763 : 45 : value.assign(reinterpret_cast<const char*>(data + sizeof(kUtf8Bom)), value_size);
764 : :
765 : 45 : return reader.skip(length, end);
766 : : }
767 : :
768 : 14 : bool read_value_body(Reader& reader, std::u16string& value, size_t end, Endian encoding, size_t maximum) noexcept {
769 : 14 : const size_t length = end - reader.position();
770 : 14 : const size_t encoded_length = length & ~size_t{1U};
771 : :
772 [ + - - + : 14 : if VUNLIKELY (encoded_length < kUtf16UnitSize * 2U || encoded_length > kMaxPayloadSize) {
- + ]
773 : 0 : return false;
774 : : }
775 : :
776 : 14 : const auto* data = reader.current_data();
777 [ + + ]: 14 : const uint8_t* bom = encoding == Endian::kBig ? kUtf16BomBig : kUtf16BomLittle;
778 : :
779 [ + - + + : 14 : if VUNLIKELY (!data || std::memcmp(data, bom, kUtf16UnitSize) != 0 || data[encoded_length - 2U] != 0U ||
+ + + + +
+ + + +
+ ]
780 : : data[encoded_length - 1U] != 0U) {
781 : 3 : return false;
782 : : }
783 : :
784 : 11 : const uint8_t* units = data + kUtf16UnitSize;
785 : 11 : const size_t unit_count = encoded_length / kUtf16UnitSize - 2U;
786 : 11 : size_t code_point_count = 0U;
787 : :
788 [ + + ]: 30 : for (size_t index = 0U; index < unit_count; ++index) {
789 : 19 : const uint8_t first = units[index * kUtf16UnitSize];
790 : 19 : const uint8_t second = units[index * kUtf16UnitSize + 1U];
791 [ + + ]: 19 : const auto high = static_cast<uint16_t>(encoding == Endian::kBig ? first : second);
792 [ + + ]: 19 : const auto low = static_cast<uint16_t>(encoding == Endian::kBig ? second : first);
793 : 19 : const auto unit = static_cast<uint16_t>(static_cast<uint16_t>(high << 8U) | low);
794 : :
795 [ + + + - ]: 19 : if (unit >= 0xD800U && unit <= 0xDFFFU) {
796 [ + - - + : 1 : if VUNLIKELY (unit > 0xDBFFU || index + 1U == unit_count) {
- + ]
797 : 0 : return false;
798 : : }
799 : :
800 : 1 : const uint8_t next_first = units[(index + 1U) * kUtf16UnitSize];
801 : 1 : const uint8_t next_second = units[(index + 1U) * kUtf16UnitSize + 1U];
802 [ + - ]: 1 : const auto next_high = static_cast<uint16_t>(encoding == Endian::kBig ? next_first : next_second);
803 [ + - ]: 1 : const auto next_low = static_cast<uint16_t>(encoding == Endian::kBig ? next_second : next_first);
804 : 1 : const auto next = static_cast<uint16_t>(static_cast<uint16_t>(next_high << 8U) | next_low);
805 : :
806 [ + - - + : 1 : if VUNLIKELY (next < 0xDC00U || next > 0xDFFFU) {
- + ]
807 : 0 : return false;
808 : : }
809 : :
810 : 1 : ++index;
811 : : }
812 : :
813 [ + + ]: 19 : if (maximum != std::numeric_limits<size_t>::max()) {
814 : 3 : ++code_point_count;
815 [ - + ]: 3 : if VUNLIKELY (code_point_count > maximum) {
816 : 0 : return false;
817 : : }
818 : : }
819 : : }
820 : :
821 : 11 : value.clear();
822 : 11 : value.resize(unit_count);
823 : :
824 [ + + ]: 31 : for (size_t index = 0U; index < unit_count; ++index) {
825 : 20 : const uint8_t first = units[index * kUtf16UnitSize];
826 : 20 : const uint8_t second = units[index * kUtf16UnitSize + 1U];
827 [ + + ]: 20 : const auto high = static_cast<uint16_t>(encoding == Endian::kBig ? first : second);
828 [ + + ]: 20 : const auto low = static_cast<uint16_t>(encoding == Endian::kBig ? second : first);
829 : :
830 : 20 : value[index] = static_cast<char16_t>(static_cast<uint16_t>(high << 8U) | low);
831 : : }
832 : :
833 : 11 : return reader.skip(length, end);
834 : : }
835 : :
836 : 8 : bool read_value_body(Reader& reader, Bytes& value, size_t end, size_t maximum) noexcept {
837 : 8 : const size_t length = end - reader.position();
838 [ + + ]: 8 : const size_t kept = length < maximum ? length : maximum;
839 : :
840 [ + + ]: 8 : if (kept == 0U) {
841 : 1 : value.clear();
842 : :
843 : 1 : return reader.skip(length, end);
844 : : }
845 : :
846 [ + + + - : 7 : if (value.is_owner() && value.offset() == 0U && kept <= value.capacity()) {
+ - + + ]
847 [ + - - + : 5 : if VUNLIKELY (!value.resize(kept) || !reader.read(value.data(), kept, end)) {
- + ]
848 : 0 : return false;
849 : : }
850 : :
851 : 5 : return reader.skip(length - kept, end);
852 : : }
853 : :
854 : 2 : Bytes target = Bytes::create(kept);
855 : :
856 [ - + ]: 2 : if VUNLIKELY (target.empty()) {
857 : 0 : return false;
858 : : }
859 : :
860 [ - + ]: 2 : if VUNLIKELY (!reader.read(target.data(), kept, end)) {
861 : 0 : return false;
862 : : }
863 : :
864 : 2 : value = std::move(target);
865 : :
866 : 2 : return reader.skip(length - kept, end);
867 : 2 : }
868 : :
869 : 46 : bool read_tag(Reader& reader, uint8_t& wire_type, uint16_t& data_id, size_t end) noexcept {
870 : 46 : uint64_t raw = 0;
871 : :
872 [ + - + + : 46 : if VUNLIKELY (!reader.read_unsigned(raw, sizeof(uint16_t), Endian::kBig, end) || (raw & 0x8000U) != 0U) {
+ + ]
873 : 1 : return false;
874 : : }
875 : :
876 : 45 : wire_type = static_cast<uint8_t>((raw >> 12U) & 0x07U);
877 : 45 : data_id = static_cast<uint16_t>(raw & 0x0FFFU);
878 : :
879 : 45 : return true;
880 : : }
881 : :
882 : 10 : bool read_union_frame(Reader& reader, size_t len, size_t type_width, size_t end, uint64_t& selector,
883 : : size_t& data_end) noexcept {
884 [ + - + + : 10 : if VUNLIKELY ((len != 1U && len != 2U && len != 4U) || (type_width != 1U && type_width != 2U && type_width != 4U)) {
+ + - + +
- + + + +
+ + - + -
+ - + ]
885 : 0 : return false;
886 : : }
887 : :
888 : 10 : uint64_t byte_length = 0;
889 : :
890 [ + - - + : 10 : if VUNLIKELY (!reader.read_unsigned(byte_length, len, Endian::kBig, end) ||
+ - - + -
+ ]
891 : : !reader.read_unsigned(selector, type_width, Endian::kBig, end) ||
892 : : byte_length > end - reader.position()) {
893 : 0 : return false;
894 : : }
895 : :
896 : 10 : data_end = reader.position() + static_cast<size_t>(byte_length);
897 : :
898 : 10 : return true;
899 : : }
900 : :
901 : 88 : bool write_value_body(Writer& writer, const std::string& value, size_t maximum) noexcept {
902 : 88 : return write_utf8_body(writer, value, maximum, true);
903 : : }
904 : :
905 : 16 : bool write_value_body(Writer& writer, const std::u16string& value, Endian encoding, size_t maximum) noexcept {
906 : 16 : return write_utf16_body(writer, value, encoding, maximum, true);
907 : : }
908 : :
909 : 16 : bool write_value_body(Writer& writer, const Bytes& value, size_t maximum) noexcept {
910 [ + - + - ]: 16 : return value.size() <= maximum && writer.append(value.data(), value.size());
911 : : }
912 : :
913 : 64 : bool write_tag(Writer& writer, uint8_t wire_type, uint16_t data_id) noexcept {
914 : 64 : const auto tag = static_cast<uint16_t>((static_cast<uint16_t>(wire_type) << 12U) | data_id);
915 : :
916 : 64 : return writer.append_unsigned(tag, sizeof(uint16_t), Endian::kBig);
917 : : }
918 : :
919 : 15 : bool write_union_frame(Writer& writer, uint64_t selector, size_t len, size_t type_width, size_t& length_position,
920 : : size_t& content_position) noexcept {
921 [ + + + + : 15 : if VUNLIKELY (type_width != 1U && type_width != 2U && type_width != 4U) {
+ + - + -
+ ]
922 : 0 : return false;
923 : : }
924 : :
925 [ - + ]: 15 : if VUNLIKELY (selector > (uint64_t{1U} << (type_width * 8U)) - 1U) {
926 : 0 : return false;
927 : : }
928 : :
929 : 15 : size_t data_position = 0;
930 : :
931 [ + - - + : 15 : if VUNLIKELY (!writer.begin_length_delimited(length_position, data_position, len) ||
- + ]
932 : : !writer.append_unsigned(selector, type_width, Endian::kBig)) {
933 : 0 : return false;
934 : : }
935 : :
936 : 15 : content_position = writer.position();
937 : :
938 : 15 : return true;
939 : : }
940 : :
941 : 24 : bool begin_tlv_body(Reader& reader, uint8_t wire_type, size_t configured_len, size_t end, size_t& body_end) noexcept {
942 : 24 : size_t width = 0;
943 : :
944 [ + + ]: 24 : if (wire_type == 4U) {
945 : 6 : width = configured_len;
946 [ + - + - ]: 18 : } else if (wire_type >= 5U && wire_type <= 7U) {
947 : 18 : width = size_t{1U} << (wire_type - 5U);
948 : : } else {
949 : 0 : return false;
950 : : }
951 : :
952 : 24 : return reader.begin_length_delimited(end, body_end, width);
953 : : }
954 : :
955 : 45 : bool begin_tlv_complex(Writer& writer, uint16_t data_id, size_t len, bool dynamic, size_t& length_position,
956 : : size_t& data_position) noexcept {
957 : 45 : uint8_t wire_type = 7U;
958 : :
959 [ + + ]: 45 : if (!dynamic) {
960 : 10 : wire_type = 4U;
961 [ + + ]: 35 : } else if (len == 1U) {
962 : 29 : wire_type = 5U;
963 [ + + ]: 6 : } else if (len == 2U) {
964 : 4 : wire_type = 6U;
965 : : }
966 : :
967 [ + - + - ]: 45 : return write_tag(writer, wire_type, data_id) && writer.begin_length_delimited(length_position, data_position, len);
968 : : }
969 : :
970 : 5 : bool skip_tlv_value(Reader& reader, uint8_t wire_type, size_t configured_len, size_t end) noexcept {
971 [ + - - - : 5 : switch (wire_type) {
+ + - ]
972 : 1 : case 0U:
973 : 1 : return reader.skip(sizeof(uint8_t), end);
974 : 0 : case 1U:
975 : 0 : return reader.skip(sizeof(uint16_t), end);
976 : 0 : case 2U:
977 : 0 : return reader.skip(sizeof(uint32_t), end);
978 : 0 : case 3U:
979 : 0 : return reader.skip(sizeof(uint64_t), end);
980 : 3 : case 4U: {
981 : 3 : size_t value_end = 0U;
982 : :
983 [ + - + - ]: 6 : return reader.begin_length_delimited(end, value_end, configured_len) &&
984 : 6 : reader.skip(value_end - reader.position(), value_end);
985 : : }
986 : 1 : case 5U:
987 : : case 6U:
988 : : case 7U: {
989 : 1 : const size_t width = size_t{1U} << (wire_type - 5U);
990 : :
991 : 1 : size_t value_end = 0;
992 : :
993 [ + - + - ]: 2 : return reader.begin_length_delimited(end, value_end, width) &&
994 : 2 : reader.skip(value_end - reader.position(), value_end);
995 : : }
996 : 0 : default:
997 : 0 : return false;
998 : : }
999 : : }
1000 : :
1001 : 4 : void report_check_available_failure() noexcept {
1002 : 4 : std::cerr << "SOME/IP serialization rejected by check_available().\n";
1003 : 4 : }
1004 : :
1005 : 67 : bool prepare_destination(Bytes& des, size_t size, uint8_t offset) noexcept {
1006 [ + + + - : 67 : if (des.is_owner() && des.offset() == offset && size <= des.capacity()) {
+ + + + ]
1007 [ - + ]: 7 : if VUNLIKELY (!des.resize(size)) {
1008 : 0 : return false;
1009 : : }
1010 : : } else {
1011 : 60 : des = Bytes::create(size, offset);
1012 : : }
1013 : :
1014 [ + - + - ]: 67 : return size == 0U || des.data() != nullptr;
1015 : : }
1016 : :
1017 : : } // namespace detail
1018 : :
1019 : : } // namespace SomeipSerializer
1020 : :
1021 : : } // namespace vlink
|