1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// SPDX-License-Identifier: MIT
//! One bounded cursor over the header fields read before segment data.
//!
//! Segment headers and the dictionary and text-region data headers read their
//! fields with this cursor; each locates a [`FieldFault`] in its segment.
use crate::fallible::len_u64;
use crate::{Cancellation, Error, RangedSource};
/// A forward position within `start..end` whose fields are read in requests
/// of at most `request_bytes`.
pub(super) struct FieldCursor {
pub(super) start: u64,
pub(super) at: u64,
pub(super) end: u64,
/// Bytes returned by the source, including any the caller counted first.
pub(super) fetched: u64,
pub(super) request_bytes: usize,
}
/// Why a header field could not be read at the cursor.
pub(super) enum FieldFault {
/// The end of a field of `expected` bytes overflows 64 bits.
Overflow {
expected: u64,
},
/// The field of `expected` bytes would end past the cursor's `end`,
/// with `available` bytes left.
PastEnd {
expected: u64,
available: u64,
},
Cancelled,
Source(Error),
/// The source reported more bytes than requested.
Overread,
/// The source returned no bytes with `expected` bytes of the field
/// left; `cancelled` reports whether cancellation was requested by then.
Ended {
cancelled: bool,
expected: u64,
},
}
impl FieldFault {
/// The unlocated error for this fault while reading `field` at `at`.
pub(super) fn error(self, at: u64, field: &'static str) -> Error {
match self {
Self::Overflow { .. } => Error::malformed(at, "header field offset overflows"),
Self::PastEnd {
expected,
available,
} => Error::truncated(at, expected, available).because(field),
Self::Cancelled
| Self::Ended {
cancelled: true, ..
} => Error::cancelled().at(at),
Self::Ended {
cancelled: false,
expected,
} => Error::truncated(at, expected, 0).because(field),
Self::Source(error) => error,
Self::Overread => Error::malformed(at, "source returned more bytes than requested"),
}
}
}
impl FieldCursor {
/// Check that `additional` more header bytes fit the range.
pub(super) fn check_room(&self, additional: u64) -> Result<(), FieldFault> {
let future = self
.at
.checked_add(additional)
.ok_or(FieldFault::Overflow {
expected: additional,
})?;
if future > self.end {
return Err(FieldFault::PastEnd {
expected: additional,
available: self.end - self.at,
});
}
Ok(())
}
/// Fill `bytes` from the cursor and advance past them. Not generic over
/// the field width, so every field shares one instantiation per source.
pub(super) fn fill<S: RangedSource, C: Cancellation>(
&mut self,
source: &mut S,
cancellation: &C,
bytes: &mut [u8],
) -> Result<(), FieldFault> {
self.check_room(len_u64(bytes.len()))?;
let mut done = 0;
while done < bytes.len() {
if cancellation.is_cancelled() {
return Err(FieldFault::Cancelled);
}
let request = (bytes.len() - done).min(self.request_bytes);
let got = match source.read_at(self.at, &mut bytes[done..done + request]) {
Ok(got) => got,
Err(error) => return Err(FieldFault::Source(error)),
};
if got > request {
return Err(FieldFault::Overread);
}
if got == 0 {
return Err(FieldFault::Ended {
cancelled: cancellation.is_cancelled(),
expected: len_u64(bytes.len() - done),
});
}
// `got <= request`, so `at` stays at or below the checked end.
self.at += len_u64(got);
self.fetched = self.fetched.saturating_add(len_u64(got));
done += got;
}
if cancellation.is_cancelled() {
return Err(FieldFault::Cancelled);
}
Ok(())
}
}