Skip to main content

oaty/
parser.rs

1//! Binary parsing utils.
2//!
3//! This module should not be used directly, unless you're planning to parse
4//! some tables manually.
5
6// This module is adapted from ttf-parser: https://github.com/harfbuzz/ttf-parser/blob/main/src/parser.rs
7// Licensed under MIT and Apache 2.0 licenses. Thanks to Yevhenii Reizner
8
9use crate::tag::Tag;
10use core::convert::TryInto;
11use core::ops::Range;
12
13/// A trait for parsing raw binary data of fixed size.
14///
15/// This is a low-level, internal trait that should not be used directly.
16pub trait TryFromBeBytes: Sized {
17    /// Object's raw data size.
18    ///
19    /// Not always the same as `mem::size_of`.
20    const SIZE: usize;
21
22    /// Parses an object from a raw data.
23    fn try_parse_from_be_bytes(data: &[u8]) -> Option<Self>;
24}
25
26/// A trait for parsing raw binary data of variable size.
27///
28/// This is a low-level, internal trait that should not be used directly.
29pub trait FromSlice<'a>: Sized {
30    /// Parses an object from a raw data.
31    fn parse(data: &'a [u8]) -> Option<Self>;
32}
33
34impl TryFromBeBytes for () {
35    const SIZE: usize = 0;
36
37    #[inline]
38    fn try_parse_from_be_bytes(_: &[u8]) -> Option<Self> {
39        Some(())
40    }
41}
42
43impl TryFromBeBytes for u8 {
44    const SIZE: usize = 1;
45
46    #[inline]
47    fn try_parse_from_be_bytes(data: &[u8]) -> Option<Self> {
48        data.first().copied()
49    }
50}
51
52impl TryFromBeBytes for i8 {
53    const SIZE: usize = 1;
54
55    #[inline]
56    fn try_parse_from_be_bytes(data: &[u8]) -> Option<Self> {
57        data.first().copied().map(|n| n as i8)
58    }
59}
60
61impl TryFromBeBytes for u16 {
62    const SIZE: usize = 2;
63
64    #[inline]
65    fn try_parse_from_be_bytes(data: &[u8]) -> Option<Self> {
66        data.try_into().ok().map(u16::from_be_bytes)
67    }
68}
69
70impl TryFromBeBytes for i16 {
71    const SIZE: usize = 2;
72
73    #[inline]
74    fn try_parse_from_be_bytes(data: &[u8]) -> Option<Self> {
75        data.try_into().ok().map(i16::from_be_bytes)
76    }
77}
78
79impl TryFromBeBytes for u32 {
80    const SIZE: usize = 4;
81
82    #[inline]
83    fn try_parse_from_be_bytes(data: &[u8]) -> Option<Self> {
84        data.try_into().ok().map(u32::from_be_bytes)
85    }
86}
87
88impl TryFromBeBytes for i32 {
89    const SIZE: usize = 4;
90
91    #[inline]
92    fn try_parse_from_be_bytes(data: &[u8]) -> Option<Self> {
93        data.try_into().ok().map(i32::from_be_bytes)
94    }
95}
96
97impl TryFromBeBytes for u64 {
98    const SIZE: usize = 8;
99
100    #[inline]
101    fn try_parse_from_be_bytes(data: &[u8]) -> Option<Self> {
102        data.try_into().ok().map(u64::from_be_bytes)
103    }
104}
105
106impl TryFromBeBytes for i64 {
107    const SIZE: usize = 8;
108
109    #[inline]
110    fn try_parse_from_be_bytes(data: &[u8]) -> Option<Self> {
111        data.try_into().ok().map(i64::from_be_bytes)
112    }
113}
114
115impl TryFromBeBytes for Tag {
116    const SIZE: usize = 4;
117
118    #[inline]
119    fn try_parse_from_be_bytes(data: &[u8]) -> Option<Self> {
120        data.try_into().ok().map(Tag::from_be_bytes)
121    }
122}
123
124/// A slice-like container that converts internal binary data only on access.
125///
126/// Array values are stored in a continuous data chunk.
127pub struct LazyArray16<'a, T> {
128    data: &'a [u8],
129    data_type: core::marker::PhantomData<T>,
130}
131
132impl<T> Clone for LazyArray16<'_, T> {
133    fn clone(&self) -> Self {
134        *self
135    }
136}
137impl<T> Copy for LazyArray16<'_, T> {}
138
139impl<T> Default for LazyArray16<'_, T> {
140    #[inline]
141    fn default() -> Self {
142        LazyArray16 {
143            data: &[],
144            data_type: core::marker::PhantomData,
145        }
146    }
147}
148
149impl<'a, T: TryFromBeBytes> LazyArray16<'a, T> {
150    /// Creates a new `LazyArray`.
151    #[inline]
152    pub fn new(data: &'a [u8]) -> Self {
153        LazyArray16 {
154            data,
155            data_type: core::marker::PhantomData,
156        }
157    }
158
159    pub(crate) fn bytes(&self) -> &[u8] {
160        self.data
161    }
162
163    /// Returns a value at `index`.
164    #[inline]
165    pub fn get(&self, index: u16) -> Option<T> {
166        if index < self.len() {
167            let start = usize::from(index) * T::SIZE;
168            let end = start + T::SIZE;
169            self.data
170                .get(start..end)
171                .and_then(T::try_parse_from_be_bytes)
172        } else {
173            None
174        }
175    }
176
177    /// Returns the last value.
178    #[inline]
179    pub fn last(&self) -> Option<T> {
180        if !self.is_empty() {
181            self.get(self.len() - 1)
182        } else {
183            None
184        }
185    }
186
187    /// Returns sub-array.
188    #[inline]
189    pub fn slice(&self, range: Range<u16>) -> Option<Self> {
190        let start = usize::from(range.start) * T::SIZE;
191        let end = usize::from(range.end) * T::SIZE;
192        Some(LazyArray16 {
193            data: self.data.get(start..end)?,
194            ..LazyArray16::default()
195        })
196    }
197
198    /// Returns array's length.
199    #[inline]
200    pub fn len(&self) -> u16 {
201        (self.data.len() / T::SIZE) as u16
202    }
203
204    /// Checks if array is empty.
205    #[inline]
206    pub fn is_empty(&self) -> bool {
207        self.len() == 0
208    }
209
210    /// Performs a binary search by specified `key`.
211    #[inline]
212    pub fn binary_search(&self, key: &T) -> Option<(u16, T)>
213    where
214        T: Ord,
215    {
216        self.binary_search_by(|p| p.cmp(key))
217    }
218
219    /// Performs a binary search using specified closure.
220    #[inline]
221    pub fn binary_search_by<F>(&self, mut f: F) -> Option<(u16, T)>
222    where
223        F: FnMut(&T) -> core::cmp::Ordering,
224    {
225        // Based on Rust std implementation.
226
227        use core::cmp::Ordering;
228
229        let mut size = self.len();
230        if size == 0 {
231            return None;
232        }
233
234        let mut base = 0;
235        while size > 1 {
236            let half = size / 2;
237            let mid = base + half;
238            // mid is always in [0, size), that means mid is >= 0 and < size.
239            // mid >= 0: by definition
240            // mid < size: mid = size / 2 + size / 4 + size / 8 ...
241            let cmp = f(&self.get(mid)?);
242            base = if cmp == Ordering::Greater { base } else { mid };
243            size -= half;
244        }
245
246        // base is always in [0, size) because base <= mid.
247        let value = self.get(base)?;
248        if f(&value) == Ordering::Equal {
249            Some((base, value))
250        } else {
251            None
252        }
253    }
254}
255
256impl<'a, T: TryFromBeBytes + core::fmt::Debug + Copy> core::fmt::Debug for LazyArray16<'a, T> {
257    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
258        f.debug_list().entries(*self).finish()
259    }
260}
261
262impl<'a, T: TryFromBeBytes> IntoIterator for LazyArray16<'a, T> {
263    type Item = T;
264    type IntoIter = LazyArrayIter16<'a, T>;
265
266    #[inline]
267    fn into_iter(self) -> Self::IntoIter {
268        LazyArrayIter16 {
269            data: self,
270            index: 0,
271        }
272    }
273}
274
275/// An iterator over `LazyArray16`.
276#[derive(Clone, Copy)]
277#[allow(missing_debug_implementations)]
278pub struct LazyArrayIter16<'a, T> {
279    data: LazyArray16<'a, T>,
280    index: u16,
281}
282
283impl<T: TryFromBeBytes> Default for LazyArrayIter16<'_, T> {
284    #[inline]
285    fn default() -> Self {
286        LazyArrayIter16 {
287            data: LazyArray16::new(&[]),
288            index: 0,
289        }
290    }
291}
292
293impl<'a, T: TryFromBeBytes> Iterator for LazyArrayIter16<'a, T> {
294    type Item = T;
295
296    #[inline]
297    fn next(&mut self) -> Option<Self::Item> {
298        self.index += 1; // TODO: check
299        self.data.get(self.index - 1)
300    }
301
302    #[inline]
303    fn count(self) -> usize {
304        usize::from(self.data.len().saturating_sub(self.index))
305    }
306}
307
308/// A slice-like container that converts internal binary data only on access.
309///
310/// This is a low-level, internal structure that should not be used directly.
311#[derive(Clone, Copy)]
312pub struct LazyArray32<'a, T> {
313    data: &'a [u8],
314    data_type: core::marker::PhantomData<T>,
315}
316
317impl<T> Default for LazyArray32<'_, T> {
318    #[inline]
319    fn default() -> Self {
320        LazyArray32 {
321            data: &[],
322            data_type: core::marker::PhantomData,
323        }
324    }
325}
326
327impl<'a, T: TryFromBeBytes> LazyArray32<'a, T> {
328    /// Creates a new `LazyArray`.
329    #[inline]
330    pub fn new(data: &'a [u8]) -> Self {
331        LazyArray32 {
332            data,
333            data_type: core::marker::PhantomData,
334        }
335    }
336
337    /// Returns a value at `index`.
338    #[inline]
339    pub fn get(&self, index: u32) -> Option<T> {
340        if index < self.len() {
341            let start = (index as usize) * T::SIZE;
342            let end = start + T::SIZE;
343            self.data
344                .get(start..end)
345                .and_then(T::try_parse_from_be_bytes)
346        } else {
347            None
348        }
349    }
350
351    /// Returns array's length.
352    #[inline]
353    pub fn len(&self) -> u32 {
354        (self.data.len() / T::SIZE) as u32
355    }
356
357    /// Checks if the array is empty.
358    pub fn is_empty(&self) -> bool {
359        self.len() == 0
360    }
361
362    /// Performs a binary search by specified `key`.
363    #[inline]
364    pub fn binary_search(&self, key: &T) -> Option<(u32, T)>
365    where
366        T: Ord,
367    {
368        self.binary_search_by(|p| p.cmp(key))
369    }
370
371    /// Performs a binary search using specified closure.
372    #[inline]
373    pub fn binary_search_by<F>(&self, mut f: F) -> Option<(u32, T)>
374    where
375        F: FnMut(&T) -> core::cmp::Ordering,
376    {
377        // Based on Rust std implementation.
378
379        use core::cmp::Ordering;
380
381        let mut size = self.len();
382        if size == 0 {
383            return None;
384        }
385
386        let mut base = 0;
387        while size > 1 {
388            let half = size / 2;
389            let mid = base + half;
390            // mid is always in [0, size), that means mid is >= 0 and < size.
391            // mid >= 0: by definition
392            // mid < size: mid = size / 2 + size / 4 + size / 8 ...
393            let cmp = f(&self.get(mid)?);
394            base = if cmp == Ordering::Greater { base } else { mid };
395            size -= half;
396        }
397
398        // base is always in [0, size) because base <= mid.
399        let value = self.get(base)?;
400        if f(&value) == Ordering::Equal {
401            Some((base, value))
402        } else {
403            None
404        }
405    }
406}
407
408impl<'a, T: TryFromBeBytes + core::fmt::Debug + Copy> core::fmt::Debug for LazyArray32<'a, T> {
409    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
410        f.debug_list().entries(*self).finish()
411    }
412}
413
414impl<'a, T: TryFromBeBytes> IntoIterator for LazyArray32<'a, T> {
415    type Item = T;
416    type IntoIter = LazyArrayIter32<'a, T>;
417
418    #[inline]
419    fn into_iter(self) -> Self::IntoIter {
420        LazyArrayIter32 {
421            data: self,
422            index: 0,
423        }
424    }
425}
426
427/// An iterator over `LazyArray32`.
428#[derive(Clone, Copy)]
429#[allow(missing_debug_implementations)]
430pub struct LazyArrayIter32<'a, T> {
431    data: LazyArray32<'a, T>,
432    index: u32,
433}
434
435impl<'a, T: TryFromBeBytes> Iterator for LazyArrayIter32<'a, T> {
436    type Item = T;
437
438    #[inline]
439    fn next(&mut self) -> Option<Self::Item> {
440        self.index += 1; // TODO: check
441        self.data.get(self.index - 1)
442    }
443
444    #[inline]
445    fn count(self) -> usize {
446        self.data.len().saturating_sub(self.index) as usize
447    }
448}
449
450/// A [`LazyArray16`]-like container, but data is accessed by offsets.
451///
452/// Unlike [`LazyArray16`], internal storage is not continuous.
453///
454/// Multiple offsets can point to the same data.
455#[derive(Clone, Copy)]
456pub struct LazyOffsetArray16<'a, T: FromSlice<'a>> {
457    data: &'a [u8],
458    // Zero offsets must be ignored.
459    offsets: LazyArray16<'a, u16>,
460    data_type: core::marker::PhantomData<T>,
461}
462
463impl<'a, T: FromSlice<'a>> LazyOffsetArray16<'a, T> {
464    /// Creates a new `LazyOffsetArray16`.
465    #[allow(dead_code)]
466    pub fn new(data: &'a [u8], offsets: LazyArray16<'a, u16>) -> Self {
467        Self {
468            data,
469            offsets,
470            data_type: core::marker::PhantomData,
471        }
472    }
473
474    /// Parses `LazyOffsetArray16` from raw data.
475    #[allow(dead_code)]
476    pub fn parse(data: &'a [u8]) -> Option<Self> {
477        let mut s = Stream::new(data);
478        let count = s.read::<u16>()?;
479        let offsets = s.read_array16(count)?;
480        Some(Self {
481            data,
482            offsets,
483            data_type: core::marker::PhantomData,
484        })
485    }
486
487    /// Returns a value at `index`.
488    #[inline]
489    pub fn get(&self, index: u16) -> Option<T> {
490        let offset = usize::from(self.offsets.get(index).filter(|offset| *offset != 0)?);
491        self.data.get(offset..).and_then(T::parse)
492    }
493
494    /// Returns array's length.
495    #[inline]
496    pub fn len(&self) -> u16 {
497        self.offsets.len()
498    }
499
500    /// Checks if array is empty.
501    #[inline]
502    #[allow(dead_code)]
503    pub fn is_empty(&self) -> bool {
504        self.len() == 0
505    }
506}
507
508impl<'a, T: FromSlice<'a> + core::fmt::Debug + Copy> core::fmt::Debug for LazyOffsetArray16<'a, T> {
509    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
510        f.debug_list().entries(*self).finish()
511    }
512}
513
514/// An iterator over [`LazyOffsetArray16`] values.
515#[derive(Clone, Copy)]
516#[allow(missing_debug_implementations)]
517pub struct LazyOffsetArrayIter16<'a, T: FromSlice<'a>> {
518    array: LazyOffsetArray16<'a, T>,
519    index: u16,
520}
521
522impl<'a, T: FromSlice<'a>> IntoIterator for LazyOffsetArray16<'a, T> {
523    type Item = T;
524    type IntoIter = LazyOffsetArrayIter16<'a, T>;
525
526    #[inline]
527    fn into_iter(self) -> Self::IntoIter {
528        LazyOffsetArrayIter16 {
529            array: self,
530            index: 0,
531        }
532    }
533}
534
535impl<'a, T: FromSlice<'a>> Iterator for LazyOffsetArrayIter16<'a, T> {
536    type Item = T;
537
538    fn next(&mut self) -> Option<Self::Item> {
539        if self.index < self.array.len() {
540            self.index += 1;
541            self.array.get(self.index - 1)
542        } else {
543            None
544        }
545    }
546
547    #[inline]
548    fn count(self) -> usize {
549        usize::from(self.array.len().saturating_sub(self.index))
550    }
551}
552
553/// A streaming binary parser.
554#[derive(Clone, Default, Debug)]
555pub struct Stream<'a> {
556    data: &'a [u8],
557    offset: usize,
558}
559
560impl<'a> Stream<'a> {
561    /// Creates a new `Stream` parser.
562    #[inline]
563    pub fn new(data: &'a [u8]) -> Self {
564        Stream { data, offset: 0 }
565    }
566
567    /// Creates a new `Stream` parser at offset.
568    ///
569    /// Returns `None` when `offset` is out of bounds.
570    #[inline]
571    pub fn new_at(data: &'a [u8], offset: usize) -> Option<Self> {
572        if offset <= data.len() {
573            Some(Stream { data, offset })
574        } else {
575            None
576        }
577    }
578
579    /// Checks that stream reached the end of the data.
580    #[inline]
581    pub fn at_end(&self) -> bool {
582        self.offset >= self.data.len()
583    }
584
585    /// Jumps to the end of the stream.
586    ///
587    /// Useful to indicate that we parsed all the data.
588    #[inline]
589    pub fn jump_to_end(&mut self) {
590        self.offset = self.data.len();
591    }
592
593    /// Returns the current offset.
594    #[inline]
595    pub fn offset(&self) -> usize {
596        self.offset
597    }
598
599    /// Returns the trailing data.
600    ///
601    /// Returns `None` when `Stream` is reached the end.
602    #[inline]
603    pub fn tail(&self) -> Option<&'a [u8]> {
604        self.data.get(self.offset..)
605    }
606
607    /// Advances by `FromData::SIZE`.
608    ///
609    /// Doesn't check bounds.
610    #[inline]
611    pub fn skip<T: TryFromBeBytes>(&mut self) {
612        self.advance(T::SIZE);
613    }
614
615    /// Advances by the specified `len`.
616    ///
617    /// Doesn't check bounds.
618    #[inline]
619    pub fn advance(&mut self, len: usize) {
620        self.offset += len;
621    }
622
623    /// Advances by the specified `len` and checks for bounds.
624    #[inline]
625    pub fn advance_checked(&mut self, len: usize) -> Option<()> {
626        if self.offset + len <= self.data.len() {
627            self.advance(len);
628            Some(())
629        } else {
630            None
631        }
632    }
633
634    /// Parses the type from the steam.
635    ///
636    /// Returns `None` when there is not enough data left in the stream
637    /// or the type parsing failed.
638    #[inline]
639    pub fn read<T: TryFromBeBytes>(&mut self) -> Option<T> {
640        self.read_bytes(T::SIZE)
641            .and_then(T::try_parse_from_be_bytes)
642    }
643
644    /// Parses the type from the steam at offset.
645    #[inline]
646    pub fn read_at<T: TryFromBeBytes>(data: &[u8], offset: usize) -> Option<T> {
647        data.get(offset..offset + T::SIZE)
648            .and_then(T::try_parse_from_be_bytes)
649    }
650
651    /// Reads N bytes from the stream.
652    #[inline]
653    pub fn read_bytes(&mut self, len: usize) -> Option<&'a [u8]> {
654        // An integer overflow here on 32bit systems is almost guarantee to be caused
655        // by an incorrect parsing logic from the caller side.
656        // Simply using `checked_add` here would silently swallow errors, which is not what we want.
657        debug_assert!(self.offset as u64 + len as u64 <= u32::MAX as u64);
658
659        let v = self.data.get(self.offset..self.offset + len)?;
660        self.advance(len);
661        Some(v)
662    }
663
664    /// Reads the next `count` types as a slice.
665    #[inline]
666    pub fn read_array16<T: TryFromBeBytes>(&mut self, count: u16) -> Option<LazyArray16<'a, T>> {
667        let len = usize::from(count) * T::SIZE;
668        self.read_bytes(len).map(LazyArray16::new)
669    }
670
671    /// Reads the next `count` types as a slice.
672    #[inline]
673    pub fn read_array32<T: TryFromBeBytes>(&mut self, count: u32) -> Option<LazyArray32<'a, T>> {
674        let len = count as usize * T::SIZE;
675        self.read_bytes(len).map(LazyArray32::new)
676    }
677
678    #[allow(dead_code)]
679    #[inline]
680    pub fn read_at_offset16(&mut self, data: &'a [u8]) -> Option<&'a [u8]> {
681        let offset = usize::from(self.read::<u16>()?);
682        data.get(offset..)
683    }
684}
685
686#[inline]
687pub fn i16_bound(min: i16, val: i16, max: i16) -> i16 {
688    use core::cmp;
689    cmp::max(min, cmp::min(max, val))
690}
691
692#[inline]
693pub fn f32_bound(min: f32, val: f32, max: f32) -> f32 {
694    debug_assert!(min.is_finite());
695    debug_assert!(val.is_finite());
696    debug_assert!(max.is_finite());
697
698    if val > max {
699        return max;
700    } else if val < min {
701        return min;
702    }
703
704    val
705}
706
707pub fn round4(value: usize) -> usize {
708    match value.checked_add(3) {
709        Some(value_plus_3) => value_plus_3 & !3,
710        None => value,
711    }
712}