Complete first release candidate audit (#107)
Some checks failed
API and SemVer surface / api-surface (push) Failing after 1m34s
Native code generation / deterministic (push) Has been cancelled
Concurrency and resource soak audit / soak (push) Has been cancelled
Documentation / documentation (push) Has been cancelled
performance evidence / audit (push) Has been cancelled
First release candidate / non-fuzz-release-gate (push) Has been cancelled
Release platform and feature matrix / audit (push) Has been cancelled
Release platform and feature matrix / matrix (false, linux-stable-minimal, x86_64-unknown-linux-gnu, stable) (push) Has been cancelled
Release platform and feature matrix / matrix (false, macos-stable-portable, x86_64-apple-darwin, stable) (push) Has been cancelled
Release platform and feature matrix / matrix (false, windows-stable-portable, x86_64-pc-windows-gnu, stable) (push) Has been cancelled
Release platform and feature matrix / matrix (true, linux-msrv-portable, x86_64-unknown-linux-gnu, 1.96.0) (push) Has been cancelled
Release platform and feature matrix / matrix (true, linux-stable-default, x86_64-unknown-linux-gnu, stable) (push) Has been cancelled
Release platform and feature matrix / matrix (true, linux-stable-features, x86_64-unknown-linux-gnu, stable) (push) Has been cancelled
Release platform and feature matrix / matrix (true, linux-stable-release-surface, x86_64-unknown-linux-gnu, stable) (push) Has been cancelled
Dependency and supply-chain audit / audit (push) Has been cancelled
Native release artifact audit / audit (push) Has been cancelled
Imaging and meshing gate / native (push) Failing after 53s
JPEG 2000 feature / linux (push) Successful in 2m49s
Native Rust workspace compile / compile (push) Failing after 59s
Skia feature / linux (push) Has been cancelled
Some checks failed
API and SemVer surface / api-surface (push) Failing after 1m34s
Native code generation / deterministic (push) Has been cancelled
Concurrency and resource soak audit / soak (push) Has been cancelled
Documentation / documentation (push) Has been cancelled
performance evidence / audit (push) Has been cancelled
First release candidate / non-fuzz-release-gate (push) Has been cancelled
Release platform and feature matrix / audit (push) Has been cancelled
Release platform and feature matrix / matrix (false, linux-stable-minimal, x86_64-unknown-linux-gnu, stable) (push) Has been cancelled
Release platform and feature matrix / matrix (false, macos-stable-portable, x86_64-apple-darwin, stable) (push) Has been cancelled
Release platform and feature matrix / matrix (false, windows-stable-portable, x86_64-pc-windows-gnu, stable) (push) Has been cancelled
Release platform and feature matrix / matrix (true, linux-msrv-portable, x86_64-unknown-linux-gnu, 1.96.0) (push) Has been cancelled
Release platform and feature matrix / matrix (true, linux-stable-default, x86_64-unknown-linux-gnu, stable) (push) Has been cancelled
Release platform and feature matrix / matrix (true, linux-stable-features, x86_64-unknown-linux-gnu, stable) (push) Has been cancelled
Release platform and feature matrix / matrix (true, linux-stable-release-surface, x86_64-unknown-linux-gnu, stable) (push) Has been cancelled
Dependency and supply-chain audit / audit (push) Has been cancelled
Native release artifact audit / audit (push) Has been cancelled
Imaging and meshing gate / native (push) Failing after 53s
JPEG 2000 feature / linux (push) Successful in 2m49s
Native Rust workspace compile / compile (push) Failing after 59s
Skia feature / linux (push) Has been cancelled
This commit is contained in:
164
crates/libremetaverse/src/rendering_binary_reader.rs
Normal file
164
crates/libremetaverse/src/rendering_binary_reader.rs
Normal file
@@ -0,0 +1,164 @@
|
||||
use std::io::Read;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use libremetaverse_types::compat::ReadWrite;
|
||||
|
||||
use crate::Error;
|
||||
use crate::rendering::EndianAwareBinaryReaderSourceFormat as SourceFormat;
|
||||
|
||||
/// A synchronized binary reader whose numeric methods honor the source byte order.
|
||||
pub struct EndianAwareBinaryReader {
|
||||
stream: Mutex<Box<dyn ReadWrite + Send>>,
|
||||
format: SourceFormat,
|
||||
}
|
||||
|
||||
impl EndianAwareBinaryReader {
|
||||
pub fn new_with_stream(stream: Box<dyn ReadWrite + Send>) -> Result<Self, Error> {
|
||||
Self::new_with_stream_source_format(stream, SourceFormat::LittleEndian)
|
||||
}
|
||||
|
||||
pub fn new_with_stream_source_format(
|
||||
stream: Box<dyn ReadWrite + Send>,
|
||||
format: SourceFormat,
|
||||
) -> Result<Self, Error> {
|
||||
Ok(Self {
|
||||
stream: Mutex::new(stream),
|
||||
format,
|
||||
})
|
||||
}
|
||||
|
||||
fn read_exact<const N: usize>(&self) -> Result<[u8; N], Error> {
|
||||
let mut bytes = [0_u8; N];
|
||||
self.stream
|
||||
.lock()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner)
|
||||
.read_exact(&mut bytes)
|
||||
.map_err(|_| Error::IndexOutOfRange)?;
|
||||
Ok(bytes)
|
||||
}
|
||||
|
||||
pub fn read_double(&self) -> Result<f64, Error> {
|
||||
let bytes = self.read_exact()?;
|
||||
Ok(match self.format {
|
||||
SourceFormat::BigEndian => f64::from_be_bytes(bytes),
|
||||
SourceFormat::LittleEndian => f64::from_le_bytes(bytes),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn read_int16(&self) -> Result<i16, Error> {
|
||||
let bytes = self.read_exact()?;
|
||||
Ok(match self.format {
|
||||
SourceFormat::BigEndian => i16::from_be_bytes(bytes),
|
||||
SourceFormat::LittleEndian => i16::from_le_bytes(bytes),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn read_int32(&self) -> Result<i32, Error> {
|
||||
let bytes = self.read_exact()?;
|
||||
Ok(match self.format {
|
||||
SourceFormat::BigEndian => i32::from_be_bytes(bytes),
|
||||
SourceFormat::LittleEndian => i32::from_le_bytes(bytes),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn read_int64(&self) -> Result<i64, Error> {
|
||||
let bytes = self.read_exact()?;
|
||||
Ok(match self.format {
|
||||
SourceFormat::BigEndian => i64::from_be_bytes(bytes),
|
||||
SourceFormat::LittleEndian => i64::from_le_bytes(bytes),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn read_single(&self) -> Result<f32, Error> {
|
||||
let bytes = self.read_exact()?;
|
||||
Ok(match self.format {
|
||||
SourceFormat::BigEndian => f32::from_be_bytes(bytes),
|
||||
SourceFormat::LittleEndian => f32::from_le_bytes(bytes),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn read_u_int32(&self) -> Result<u32, Error> {
|
||||
let bytes = self.read_exact()?;
|
||||
Ok(match self.format {
|
||||
SourceFormat::BigEndian => u32::from_be_bytes(bytes),
|
||||
SourceFormat::LittleEndian => u32::from_le_bytes(bytes),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn read_string_with_method(&self) -> Result<String, Error> {
|
||||
let mut bytes = Vec::new();
|
||||
let mut stream = self
|
||||
.stream
|
||||
.lock()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||
loop {
|
||||
let mut byte = [0_u8; 1];
|
||||
stream
|
||||
.read_exact(&mut byte)
|
||||
.map_err(|_| Error::IndexOutOfRange)?;
|
||||
if byte[0] == 0 {
|
||||
break;
|
||||
}
|
||||
bytes.push(byte[0]);
|
||||
}
|
||||
Ok(String::from_utf8_lossy(&bytes).into_owned())
|
||||
}
|
||||
|
||||
pub fn read_string_with_int32(&self, size: i32) -> Result<String, Error> {
|
||||
let size = usize::try_from(size).map_err(|_| Error::Argument)?;
|
||||
let mut bytes = vec![0_u8; size];
|
||||
let mut stream = self
|
||||
.stream
|
||||
.lock()
|
||||
.unwrap_or_else(std::sync::PoisonError::into_inner);
|
||||
let mut read = 0;
|
||||
while read < size {
|
||||
let count = stream
|
||||
.read(&mut bytes[read..])
|
||||
.map_err(|_| Error::InvalidOperation)?;
|
||||
if count == 0 {
|
||||
break;
|
||||
}
|
||||
read += count;
|
||||
}
|
||||
bytes.truncate(read);
|
||||
Ok(String::from_utf8_lossy(&bytes).trim().to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::io::Cursor;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn reads_both_byte_orders_and_strings() {
|
||||
let mut big = Vec::new();
|
||||
big.extend_from_slice(&(-123_i16).to_be_bytes());
|
||||
big.extend_from_slice(&42.5_f32.to_be_bytes());
|
||||
big.extend_from_slice(b"hello\0 padded ");
|
||||
let reader = EndianAwareBinaryReader::new_with_stream_source_format(
|
||||
Box::new(Cursor::new(big)),
|
||||
SourceFormat::BigEndian,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(reader.read_int16().unwrap(), -123);
|
||||
assert_eq!(reader.read_single().unwrap(), 42.5);
|
||||
assert_eq!(reader.read_string_with_method().unwrap(), "hello");
|
||||
assert_eq!(reader.read_string_with_int32(8).unwrap(), "padded");
|
||||
|
||||
let reader = EndianAwareBinaryReader::new_with_stream(Box::new(Cursor::new(
|
||||
0x1234_5678_u32.to_le_bytes().to_vec(),
|
||||
)))
|
||||
.unwrap();
|
||||
assert_eq!(reader.read_u_int32().unwrap(), 0x1234_5678);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reports_short_numeric_reads() {
|
||||
let reader =
|
||||
EndianAwareBinaryReader::new_with_stream(Box::new(Cursor::new(vec![1, 2]))).unwrap();
|
||||
assert_eq!(reader.read_int32(), Err(Error::IndexOutOfRange));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user