use std::io::BufRead;
use std::io::Error;
use std::io::ErrorKind;
use std::io::Read;
use std::io::Result;
use std::string::FromUtf8Error;
use crate::traits::validate_read_count;
use crate::util::SliceRange;
use crate::util::UncheckedSlice;
use crate::util::allocation_error;
use crate::util::try_reserve_string;
use crate::util::try_reserve_vec;
pub(crate) const READ_TO_END_BUFFER_SIZE: usize = 8 * 1024;
pub(crate) fn read_exact_or_eof(reader: &mut dyn Read, buffer: &mut [u8]) -> Result<usize> {
let mut total = 0;
while total < buffer.len() {
match reader.read(&mut buffer[total..]) {
Ok(0) => break,
Ok(count) => {
validate_read_count(count, buffer.len() - total)?;
total += count;
}
Err(error) => {
if error.kind() == ErrorKind::Interrupted {
continue;
}
return Err(error);
}
}
}
Ok(total)
}
pub(crate) fn read_exact_vec_limited_into(
reader: &mut dyn Read,
output: &mut Vec<u8>,
len: usize,
max_len: usize,
) -> Result<()> {
validate_exact_read_len(len, max_len)?;
let original_len = output.len();
let new_len = match original_len.checked_add(len) {
Some(value) => value,
None => {
return Err(Error::new(
ErrorKind::InvalidInput,
format!("length {original_len} plus {len} overflows usize"),
));
}
};
try_reserve_vec(output, len).map_err(allocation_error)?;
output.resize(new_len, 0);
match reader.read_exact(&mut output[original_len..]) {
Ok(()) => Ok(()),
Err(error) => {
output.truncate(original_len);
Err(error)
}
}
}
#[inline]
pub(crate) fn validate_exact_read_len(len: usize, max_len: usize) -> Result<()> {
if len > max_len {
return Err(Error::new(
ErrorKind::InvalidData,
format!("requested length {len} exceeds maximum length {max_len}"),
));
}
Ok(())
}
#[inline]
pub(crate) fn read_to_end_limited(reader: &mut dyn Read, max_len: usize) -> Result<Vec<u8>> {
let mut output = Vec::new();
try_reserve_vec(&mut output, max_len.min(READ_TO_END_BUFFER_SIZE)).map_err(allocation_error)?;
read_to_end_limited_into(reader, &mut output, max_len)?;
Ok(output)
}
pub(crate) fn read_to_end_limited_into(reader: &mut dyn Read, output: &mut Vec<u8>, max_len: usize) -> Result<usize> {
let original_len = output.len();
let mut buffer = [0; READ_TO_END_BUFFER_SIZE];
let mut appended = 0;
loop {
let remaining = max_len.saturating_sub(appended);
let requested = remaining.saturating_add(1).min(READ_TO_END_BUFFER_SIZE);
match reader.read(&mut buffer[..requested]) {
Ok(count) => {
if let Err(error) = validate_read_count(count, requested) {
output.truncate(original_len);
return Err(error);
}
if count == 0 {
return Ok(appended);
} else if count <= remaining {
if let Err(error) = try_reserve_vec(output, count) {
output.truncate(original_len);
return Err(allocation_error(error));
}
output.extend_from_slice(&buffer[..count]);
appended += count;
} else {
output.truncate(original_len);
return Err(Error::new(
ErrorKind::InvalidData,
format!("input exceeds maximum length of {max_len} bytes"),
));
}
}
Err(error) => {
if error.kind() == ErrorKind::Interrupted {
continue;
}
output.truncate(original_len);
return Err(error);
}
}
}
}
#[inline(always)]
#[must_use]
pub(crate) fn invalid_utf8_error(error: FromUtf8Error) -> Error {
Error::new(
ErrorKind::InvalidData,
format!("limited input is not valid UTF-8: {error}"),
)
}
#[inline]
pub(crate) fn read_until_limited_into<T>(
reader: &mut T,
delimiter: u8,
output: &mut Vec<u8>,
max_len: usize,
) -> Result<usize>
where
T: BufRead + ?Sized,
{
let original_len = output.len();
match read_until_limited_into_inner(reader, delimiter, output, max_len) {
Ok(count) => Ok(count),
Err(error) => {
output.truncate(original_len);
Err(error)
}
}
}
fn read_until_limited_into_inner<T>(
reader: &mut T,
delimiter: u8,
output: &mut Vec<u8>,
max_len: usize,
) -> Result<usize>
where
T: BufRead + ?Sized,
{
let mut appended = 0;
loop {
let available = match reader.fill_buf() {
Ok(available) => available,
Err(error) if error.kind() == ErrorKind::Interrupted => continue,
Err(error) => return Err(error),
};
if available.is_empty() {
return Ok(appended);
}
let remaining = max_len.saturating_sub(appended);
let search_len = available.len().min(remaining);
let delimiter_position = available[..search_len].iter().position(|byte| *byte == delimiter);
let requested = delimiter_position.map_or(available.len(), |position| position + 1);
if requested > remaining {
if remaining > 0 {
reader.consume(remaining);
}
return Err(limit_exceeded_error(max_len, delimiter));
}
try_reserve_vec(output, requested).map_err(allocation_error)?;
output.extend_from_slice(&available[..requested]);
reader.consume(requested);
appended += requested;
if delimiter_position.is_some() {
return Ok(appended);
}
}
}
#[inline]
#[must_use]
fn limit_exceeded_error(max_len: usize, delimiter: u8) -> Error {
Error::new(
ErrorKind::InvalidData,
format!("input exceeds maximum length of {max_len} bytes before delimiter {delimiter}"),
)
}
const DISCARD_BUFFER_SIZE: usize = 8 * 1024;
pub(in crate::std_io::ext) unsafe fn read_exact_or_eof_unchecked_impl(
reader: &mut dyn Read,
buffer: &mut [u8],
start_index: usize,
count: usize,
) -> Result<usize> {
debug_assert!(
SliceRange::range_fits(buffer.len(), start_index, count),
"unchecked read range exceeds buffer"
);
let mut total = 0;
while total < count {
let target = unsafe { UncheckedSlice::subslice_mut(buffer, start_index + total, count - total) };
let requested = count - total;
match reader.read(target) {
Ok(0) => break,
Ok(read) => {
validate_read_count(read, requested)?;
total += read;
}
Err(error) => {
if error.kind() == ErrorKind::Interrupted {
continue;
}
return Err(error);
}
}
}
Ok(total)
}
#[inline]
pub(in crate::std_io::ext) fn read_exact_array_impl<const N: usize>(reader: &mut dyn Read) -> Result<[u8; N]> {
let mut buffer = [0; N];
reader.read_exact(&mut buffer)?;
Ok(buffer)
}
#[inline]
pub(in crate::std_io::ext) fn read_exact_vec_limited_impl(
reader: &mut dyn Read,
len: usize,
max_len: usize,
) -> Result<Vec<u8>> {
let mut output = Vec::new();
read_exact_vec_limited_into(reader, &mut output, len, max_len)?;
Ok(output)
}
pub(in crate::std_io::ext) fn discard_exact_or_eof_impl(reader: &mut dyn Read, bytes: u64) -> Result<u64> {
let mut buffer = [0; DISCARD_BUFFER_SIZE];
let mut remaining = bytes;
let mut discarded = 0;
while remaining > 0 {
let requested = remaining.min(DISCARD_BUFFER_SIZE as u64) as usize;
match reader.read(&mut buffer[..requested]) {
Ok(0) => break,
Ok(count) => {
validate_read_count(count, requested)?;
let count = count as u64;
remaining -= count;
discarded += count;
}
Err(error) => {
if error.kind() == ErrorKind::Interrupted {
continue;
}
return Err(error);
}
}
}
Ok(discarded)
}
#[inline]
pub(in crate::std_io::ext) fn read_to_string_limited_impl(reader: &mut dyn Read, max_len: usize) -> Result<String> {
let bytes = read_to_end_limited(reader, max_len)?;
String::from_utf8(bytes).map_err(invalid_utf8_error)
}
#[inline]
pub(in crate::std_io::ext) fn read_to_string_limited_into_impl(
reader: &mut dyn Read,
output: &mut String,
max_len: usize,
) -> Result<usize> {
let bytes = read_to_end_limited(reader, max_len)?;
let text = String::from_utf8(bytes).map_err(invalid_utf8_error)?;
let count = text.len();
try_reserve_string(output, count).map_err(allocation_error)?;
output.push_str(&text);
Ok(count)
}