1 //! raw font bytes 2 3 use std::ops::{Range, RangeBounds}; 4 5 use types::{BigEndian, FixedSize, Scalar}; 6 7 use crate::array::ComputedArray; 8 use crate::read::{ComputeSize, FontReadWithArgs, FromBytes, ReadError}; 9 use crate::table_ref::TableRef; 10 use crate::FontRead; 11 12 /// A reference to raw binary font data. 13 /// 14 /// This is a wrapper around a byte slice, that provides convenience methods 15 /// for parsing and validating that data. 16 #[derive(Debug, Default, Clone, Copy)] 17 pub struct FontData<'a> { 18 bytes: &'a [u8], 19 } 20 21 /// A cursor for validating bytes during parsing. 22 /// 23 /// This type improves the ergonomics of validation blah blah 24 /// 25 /// # Note 26 /// 27 /// call `finish` when you're done to ensure you're in bounds 28 #[derive(Debug, Default, Clone, Copy)] 29 pub struct Cursor<'a> { 30 pos: usize, 31 data: FontData<'a>, 32 } 33 34 impl<'a> FontData<'a> { 35 /// Create a new `FontData` with these bytes. 36 /// 37 /// You generally don't need to do this? It is handled for you when loading 38 /// data from disk, but may be useful in tests. new(bytes: &'a [u8]) -> Self39 pub const fn new(bytes: &'a [u8]) -> Self { 40 FontData { bytes } 41 } 42 43 /// The length of the data, in bytes len(&self) -> usize44 pub fn len(&self) -> usize { 45 self.bytes.len() 46 } 47 48 /// `true` if the data has a length of zero bytes. is_empty(&self) -> bool49 pub fn is_empty(&self) -> bool { 50 self.bytes.is_empty() 51 } 52 53 /// Returns self[pos..] split_off(&self, pos: usize) -> Option<FontData<'a>>54 pub fn split_off(&self, pos: usize) -> Option<FontData<'a>> { 55 self.bytes.get(pos..).map(|bytes| FontData { bytes }) 56 } 57 58 /// returns self[..pos], and updates self to = self[pos..]; take_up_to(&mut self, pos: usize) -> Option<FontData<'a>>59 pub fn take_up_to(&mut self, pos: usize) -> Option<FontData<'a>> { 60 if pos > self.len() { 61 return None; 62 } 63 let (head, tail) = self.bytes.split_at(pos); 64 self.bytes = tail; 65 Some(FontData { bytes: head }) 66 } 67 slice(&self, range: impl RangeBounds<usize>) -> Option<FontData<'a>>68 pub fn slice(&self, range: impl RangeBounds<usize>) -> Option<FontData<'a>> { 69 let bounds = (range.start_bound().cloned(), range.end_bound().cloned()); 70 self.bytes.get(bounds).map(|bytes| FontData { bytes }) 71 } 72 73 /// Read a scalar at the provided location in the data. read_at<T: Scalar>(&self, offset: usize) -> Result<T, ReadError>74 pub fn read_at<T: Scalar>(&self, offset: usize) -> Result<T, ReadError> { 75 self.bytes 76 .get(offset..offset + T::RAW_BYTE_LEN) 77 .and_then(T::read) 78 .ok_or(ReadError::OutOfBounds) 79 } 80 81 /// Read a big-endian value at the provided location in the data. read_be_at<T: Scalar>(&self, offset: usize) -> Result<BigEndian<T>, ReadError>82 pub fn read_be_at<T: Scalar>(&self, offset: usize) -> Result<BigEndian<T>, ReadError> { 83 self.bytes 84 .get(offset..offset + T::RAW_BYTE_LEN) 85 .and_then(BigEndian::from_slice) 86 .ok_or(ReadError::OutOfBounds) 87 } 88 read_with_args<T>(&self, range: Range<usize>, args: &T::Args) -> Result<T, ReadError> where T: FontReadWithArgs<'a>,89 pub fn read_with_args<T>(&self, range: Range<usize>, args: &T::Args) -> Result<T, ReadError> 90 where 91 T: FontReadWithArgs<'a>, 92 { 93 self.slice(range) 94 .ok_or(ReadError::OutOfBounds) 95 .and_then(|data| T::read_with_args(data, args)) 96 } 97 check_in_bounds(&self, offset: usize) -> Result<(), ReadError>98 fn check_in_bounds(&self, offset: usize) -> Result<(), ReadError> { 99 self.bytes 100 .get(..offset) 101 .ok_or(ReadError::OutOfBounds) 102 .map(|_| ()) 103 } 104 105 /// Interpret the bytes at the provided offset as a reference to `T`. 106 /// 107 /// Returns an error if the slice `offset..` is shorter than `T::RAW_BYTE_LEN`. 108 /// 109 /// This is a wrapper around [`read_ref_unchecked`][], which panics if 110 /// the type does not uphold the required invariants. 111 /// 112 /// # Panics 113 /// 114 /// This function will panic if `T` is zero-sized, has an alignment 115 /// other than one, or has any internal padding. 116 /// 117 /// [`read_ref_unchecked`]: [Self::read_ref_unchecked] read_ref_at<T: FromBytes>(&self, offset: usize) -> Result<&'a T, ReadError>118 pub fn read_ref_at<T: FromBytes>(&self, offset: usize) -> Result<&'a T, ReadError> { 119 assert_ne!(std::mem::size_of::<T>(), 0); 120 // assert we have no padding. 121 // `T::RAW_BYTE_LEN` is computed by recursively taking the raw length of 122 // any fields of `T`; if `size_of::<T>() == T::RAW_BYTE_LEN`` we know that 123 // `T` contains no padding. 124 assert_eq!(std::mem::size_of::<T>(), T::RAW_BYTE_LEN); 125 assert_eq!(std::mem::align_of::<T>(), 1); 126 self.bytes 127 .get(offset..offset + T::RAW_BYTE_LEN) 128 .ok_or(ReadError::OutOfBounds)?; 129 130 // SAFETY: if we have reached this point without hitting an assert or 131 // returning an error, our invariants are met. 132 unsafe { Ok(self.read_ref_unchecked(offset)) } 133 } 134 135 /// Interpret the bytes at `offset` as a reference to some type `T`. 136 /// 137 /// # Safety 138 /// 139 /// `T` must be a struct or scalar that has alignment of 1, a non-zero size, 140 /// and no internal padding, and offset must point to a slice of bytes that 141 /// has length >= `size_of::<T>()`. read_ref_unchecked<T: FromBytes>(&self, offset: usize) -> &'a T142 unsafe fn read_ref_unchecked<T: FromBytes>(&self, offset: usize) -> &'a T { 143 let bytes = self.bytes.get_unchecked(offset..offset + T::RAW_BYTE_LEN); 144 &*(bytes.as_ptr() as *const T) 145 } 146 147 /// Interpret the bytes at the provided offset as a slice of `T`. 148 /// 149 /// Returns an error if `range` is out of bounds for the underlying data, 150 /// or if the length of the range is not a multiple of `T::RAW_BYTE_LEN`. 151 /// 152 /// This is a wrapper around [`read_array_unchecked`][], which panics if 153 /// the type does not uphold the required invariants. 154 /// 155 /// # Panics 156 /// 157 /// This function will panic if `T` is zero-sized, has an alignment 158 /// other than one, or has any internal padding. 159 /// 160 /// [`read_array_unchecked`]: [Self::read_array_unchecked] read_array<T: FromBytes>(&self, range: Range<usize>) -> Result<&'a [T], ReadError>161 pub fn read_array<T: FromBytes>(&self, range: Range<usize>) -> Result<&'a [T], ReadError> { 162 assert_ne!(std::mem::size_of::<T>(), 0); 163 // assert we have no padding. 164 // `T::RAW_BYTE_LEN` is computed by recursively taking the raw length of 165 // any fields of `T`; if `size_of::<T>() == T::RAW_BYTE_LEN`` we know that 166 // `T` contains no padding. 167 assert_eq!(std::mem::size_of::<T>(), T::RAW_BYTE_LEN); 168 assert_eq!(std::mem::align_of::<T>(), 1); 169 let bytes = self 170 .bytes 171 .get(range.clone()) 172 .ok_or(ReadError::OutOfBounds)?; 173 if bytes.len() % std::mem::size_of::<T>() != 0 { 174 return Err(ReadError::InvalidArrayLen); 175 }; 176 // SAFETY: if we have reached this point without hitting an assert or 177 // returning an error, our invariants are met. 178 unsafe { Ok(self.read_array_unchecked(range)) } 179 } 180 181 /// Interpret the bytes at `offset` as a reference to some type `T`. 182 /// 183 /// # Safety 184 /// 185 /// `T` must be a struct or scalar that has alignment of 1, a non-zero size, 186 /// and no internal padding, and `range` must have a length that is non-zero 187 /// and is a multiple of `size_of::<T>()`. read_array_unchecked<T: FromBytes>(&self, range: Range<usize>) -> &'a [T]188 unsafe fn read_array_unchecked<T: FromBytes>(&self, range: Range<usize>) -> &'a [T] { 189 let bytes = self.bytes.get_unchecked(range); 190 let elems = bytes.len() / std::mem::size_of::<T>(); 191 std::slice::from_raw_parts(bytes.as_ptr() as *const _, elems) 192 } 193 cursor(&self) -> Cursor<'a>194 pub(crate) fn cursor(&self) -> Cursor<'a> { 195 Cursor { 196 pos: 0, 197 data: *self, 198 } 199 } 200 201 /// Return the data as a byte slice as_bytes(&self) -> &'a [u8]202 pub fn as_bytes(&self) -> &'a [u8] { 203 self.bytes 204 } 205 } 206 207 impl<'a> Cursor<'a> { advance<T: Scalar>(&mut self)208 pub(crate) fn advance<T: Scalar>(&mut self) { 209 self.pos += T::RAW_BYTE_LEN 210 } 211 advance_by(&mut self, n_bytes: usize)212 pub(crate) fn advance_by(&mut self, n_bytes: usize) { 213 self.pos += n_bytes; 214 } 215 216 /// Read a scalar and advance the cursor. read<T: Scalar>(&mut self) -> Result<T, ReadError>217 pub(crate) fn read<T: Scalar>(&mut self) -> Result<T, ReadError> { 218 let temp = self.data.read_at(self.pos); 219 self.pos += T::RAW_BYTE_LEN; 220 temp 221 } 222 223 /// Read a big-endian value and advance the cursor. read_be<T: Scalar>(&mut self) -> Result<BigEndian<T>, ReadError>224 pub(crate) fn read_be<T: Scalar>(&mut self) -> Result<BigEndian<T>, ReadError> { 225 let temp = self.data.read_be_at(self.pos); 226 self.pos += T::RAW_BYTE_LEN; 227 temp 228 } 229 read_with_args<T>(&mut self, args: &T::Args) -> Result<T, ReadError> where T: FontReadWithArgs<'a> + ComputeSize,230 pub(crate) fn read_with_args<T>(&mut self, args: &T::Args) -> Result<T, ReadError> 231 where 232 T: FontReadWithArgs<'a> + ComputeSize, 233 { 234 let len = T::compute_size(args); 235 let temp = self.data.read_with_args(self.pos..self.pos + len, args); 236 self.pos += len; 237 temp 238 } 239 240 // only used in records that contain arrays :/ read_computed_array<T>( &mut self, len: usize, args: &T::Args, ) -> Result<ComputedArray<'a, T>, ReadError> where T: FontReadWithArgs<'a> + ComputeSize,241 pub(crate) fn read_computed_array<T>( 242 &mut self, 243 len: usize, 244 args: &T::Args, 245 ) -> Result<ComputedArray<'a, T>, ReadError> 246 where 247 T: FontReadWithArgs<'a> + ComputeSize, 248 { 249 let len = len * T::compute_size(args); 250 let temp = self.data.read_with_args(self.pos..self.pos + len, args); 251 self.pos += len; 252 temp 253 } 254 read_array<T: FromBytes>(&mut self, n_elem: usize) -> Result<&'a [T], ReadError>255 pub(crate) fn read_array<T: FromBytes>(&mut self, n_elem: usize) -> Result<&'a [T], ReadError> { 256 let len = n_elem * T::RAW_BYTE_LEN; 257 let temp = self.data.read_array(self.pos..self.pos + len); 258 self.pos += len; 259 temp 260 } 261 262 /// read a value, validating it with the provided function if successful. 263 //pub(crate) fn read_validate<T, F>(&mut self, f: F) -> Result<T, ReadError> 264 //where 265 //T: ReadScalar, 266 //F: FnOnce(&T) -> bool, 267 //{ 268 //let temp = self.read()?; 269 //if f(&temp) { 270 //Ok(temp) 271 //} else { 272 //Err(ReadError::ValidationError) 273 //} 274 //} 275 276 //pub(crate) fn check_array<T: Scalar>(&mut self, len_bytes: usize) -> Result<(), ReadError> { 277 //assert_ne!(std::mem::size_of::<BigEndian<T>>(), 0); 278 //assert_eq!(std::mem::align_of::<BigEndian<T>>(), 1); 279 //if len_bytes % T::SIZE != 0 { 280 //return Err(ReadError::InvalidArrayLen); 281 //} 282 //self.data.check_in_bounds(self.pos + len_bytes) 283 //todo!() 284 //} 285 286 /// return the current position, or an error if we are out of bounds position(&self) -> Result<usize, ReadError>287 pub(crate) fn position(&self) -> Result<usize, ReadError> { 288 self.data.check_in_bounds(self.pos).map(|_| self.pos) 289 } 290 291 // used when handling fields with an implicit length, which must be at the 292 // end of a table. remaining_bytes(&self) -> usize293 pub(crate) fn remaining_bytes(&self) -> usize { 294 self.data.len().saturating_sub(self.pos) 295 } 296 finish<T>(self, shape: T) -> Result<TableRef<'a, T>, ReadError>297 pub(crate) fn finish<T>(self, shape: T) -> Result<TableRef<'a, T>, ReadError> { 298 let data = self.data; 299 data.check_in_bounds(self.pos)?; 300 Ok(TableRef { data, shape }) 301 } 302 } 303 304 // useful so we can have offsets that are just to data 305 impl<'a> FontRead<'a> for FontData<'a> { read(data: FontData<'a>) -> Result<Self, ReadError>306 fn read(data: FontData<'a>) -> Result<Self, ReadError> { 307 Ok(data) 308 } 309 } 310 311 impl AsRef<[u8]> for FontData<'_> { as_ref(&self) -> &[u8]312 fn as_ref(&self) -> &[u8] { 313 self.bytes 314 } 315 } 316 317 impl<'a> From<&'a [u8]> for FontData<'a> { from(src: &'a [u8]) -> FontData<'a>318 fn from(src: &'a [u8]) -> FontData<'a> { 319 FontData::new(src) 320 } 321 } 322 323 //kind of ugly, but makes FontData work with FontBuilder. If FontBuilder stops using 324 //Cow in its API, we can probably get rid of this? 325 #[cfg(feature = "std")] 326 impl<'a> From<FontData<'a>> for std::borrow::Cow<'a, [u8]> { from(src: FontData<'a>) -> Self327 fn from(src: FontData<'a>) -> Self { 328 src.bytes.into() 329 } 330 } 331