/proc/self/cwd/pw_varint/stream.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2021 The Pigweed Authors |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not |
4 | | // use this file except in compliance with the License. You may obtain a copy of |
5 | | // the License at |
6 | | // |
7 | | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
11 | | // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
12 | | // License for the specific language governing permissions and limitations under |
13 | | // the License. |
14 | | |
15 | | #include "pw_varint/stream.h" |
16 | | |
17 | | #include <cstddef> |
18 | | #include <cstdint> |
19 | | |
20 | | #include "pw_span/span.h" |
21 | | #include "pw_status/status_with_size.h" |
22 | | #include "pw_stream/stream.h" |
23 | | #include "pw_varint/varint.h" |
24 | | |
25 | | namespace pw { |
26 | | namespace varint { |
27 | | |
28 | 0 | StatusWithSize Read(stream::Reader& reader, int64_t* output, size_t max_size) { |
29 | 0 | uint64_t value = 0; |
30 | 0 | StatusWithSize count = Read(reader, &value, max_size); |
31 | 0 | if (!count.ok()) { |
32 | 0 | return count; |
33 | 0 | } |
34 | | |
35 | 0 | *output = ZigZagDecode(value); |
36 | 0 | return count; |
37 | 0 | } |
38 | | |
39 | 35.3k | StatusWithSize Read(stream::Reader& reader, uint64_t* output, size_t max_size) { |
40 | 35.3k | uint64_t value = 0; |
41 | 35.3k | size_t count = 0; |
42 | | |
43 | 45.2k | while (true) { |
44 | 45.2k | if (count >= varint::kMaxVarint64SizeBytes) { |
45 | | // Varint can't fit a uint64_t, this likely means we're reading binary |
46 | | // data that is not actually a varint. |
47 | 42 | return StatusWithSize::DataLoss(count); |
48 | 42 | } |
49 | | |
50 | 45.1k | if (count >= max_size) { |
51 | | // Varint didn't fit within the range given; return OutOfRange() if |
52 | | // max_size was 0, but DataLoss if we were reading something we thought |
53 | | // was going to be a varint. |
54 | 304 | return count > 0 ? StatusWithSize::DataLoss(count) |
55 | 304 | : StatusWithSize::OutOfRange(); |
56 | 304 | } |
57 | | |
58 | 44.8k | std::byte b; |
59 | 44.8k | if (auto result = reader.Read(span(&b, 1)); !result.ok()) { |
60 | 245 | if (count > 0 && result.status().IsOutOfRange()) { |
61 | | // Status::OutOfRange on the first byte means we tried to read a varint |
62 | | // when we reached the end of file. But after the first byte it means we |
63 | | // failed to decode a varint we were in the middle of, and that's not |
64 | | // a normal error condition. |
65 | 106 | return StatusWithSize::DataLoss(count); |
66 | 106 | } |
67 | 139 | return StatusWithSize(result.status(), count); |
68 | 245 | } |
69 | | |
70 | 44.6k | value |= static_cast<uint64_t>(b & std::byte(0b01111111)) << (7 * count); |
71 | 44.6k | ++count; |
72 | | |
73 | | // MSB == 0 indicates last byte of the varint. |
74 | 44.6k | if ((b & std::byte(0b10000000)) == std::byte(0)) { |
75 | 34.7k | break; |
76 | 34.7k | } |
77 | 44.6k | } |
78 | | |
79 | 34.7k | *output = value; |
80 | 34.7k | return StatusWithSize(count); |
81 | 35.3k | } |
82 | | |
83 | | } // namespace varint |
84 | | } // namespace pw |