1
//! CFF font handling.
2
//!
3
//! Refer to [Technical Note #5176](http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/font/pdfs/5176.CFF.pdf)
4
//! for more information.
5

            
6
pub mod cff2;
7
pub mod charstring;
8
pub mod outline;
9
mod subset;
10

            
11
use std::io::Write;
12
use std::iter;
13
use std::marker::PhantomData;
14
use std::sync::OnceLock;
15

            
16
use tinyvec::{array_vec, tiny_vec, TinyVec};
17

            
18
use crate::binary::read::{
19
    ReadArray, ReadArrayCow, ReadBinary, ReadBinaryDep, ReadCtxt, ReadFrom, ReadScope,
20
    ReadUnchecked,
21
};
22
use crate::binary::write::{WriteBinary, WriteBinaryDep, WriteBuffer, WriteContext, WriteCounter};
23
use crate::binary::{I16Be, I32Be, U16Be, U24Be, U32Be, U8};
24
use crate::error::{ParseError, WriteError};
25
use crate::tables::variable_fonts::{ItemVariationStore, OwnedTuple};
26
use crate::variations::VariationError;
27
use crate::GlyphId;
28
use crate::TryNumFrom;
29
use cff2::BlendOperand;
30
use charstring::ArgumentsStack;
31
pub use subset::SubsetCFF;
32

            
33
/// Maximum number of operands in Top DICT, Font DICTs, Private DICTs and CharStrings.
34
///
35
/// > An operator may be preceded by up to a maximum of 48 operands.
36
pub const MAX_OPERANDS: usize = 48;
37
const END_OF_FLOAT_FLAG: u8 = 0xf;
38

            
39
const OPERAND_ZERO: [Operand; 1] = [Operand::Integer(0)];
40
const OFFSET_ZERO: [Operand; 1] = [Operand::Offset(0)];
41
const DEFAULT_UNDERLINE_POSITION: [Operand; 1] = [Operand::Integer(-100)];
42
const DEFAULT_UNDERLINE_THICKNESS: [Operand; 1] = [Operand::Integer(50)];
43
const DEFAULT_CHARSTRING_TYPE: [Operand; 1] = [Operand::Integer(2)];
44
const DEFAULT_BBOX: [Operand; 4] = [
45
    Operand::Integer(0),
46
    Operand::Integer(0),
47
    Operand::Integer(0),
48
    Operand::Integer(0),
49
];
50
const DEFAULT_CID_COUNT: [Operand; 1] = [Operand::Integer(8720)];
51
const DEFAULT_BLUE_SHIFT: [Operand; 1] = [Operand::Integer(7)];
52
const DEFAULT_BLUE_FUZZ: [Operand; 1] = [Operand::Integer(1)];
53

            
54
// Operands containing `Real` values can't be const because `Real` wraps a
55
// `TinyVec`, whose construction isn't const. They are computed once on first
56
// access via `OnceLock` and reused thereafter.
57

            
58
pub(crate) fn default_font_matrix() -> &'static [Operand; 6] {
59
    static V: OnceLock<[Operand; 6]> = OnceLock::new();
60
    V.get_or_init(|| {
61
        let real_0_001 = Operand::Real(Real(tiny_vec![0x0a, 0x00, 0x1f])); // 0.001
62
        [
63
            real_0_001.clone(),
64
            Operand::Integer(0),
65
            Operand::Integer(0),
66
            real_0_001,
67
            Operand::Integer(0),
68
            Operand::Integer(0),
69
        ]
70
    })
71
}
72

            
73
pub(crate) fn default_blue_scale() -> &'static [Operand; 1] {
74
    static V: OnceLock<[Operand; 1]> = OnceLock::new();
75
    V.get_or_init(|| [Operand::Real(Real(tiny_vec![0x0a, 0x03, 0x96, 0x25, 0xff]))]) // 0.039625
76
}
77

            
78
pub(crate) fn default_expansion_factor() -> &'static [Operand; 1] {
79
    static V: OnceLock<[Operand; 1]> = OnceLock::new();
80
    V.get_or_init(|| [Operand::Real(Real(tiny_vec![0x0a, 0x06, 0xff]))]) // 0.06
81
}
82

            
83
const ISO_ADOBE_LAST_SID: u16 = 228;
84
const ADOBE: &[u8] = b"Adobe";
85
const IDENTITY: &[u8] = b"Identity";
86

            
87
/// Top level representation of a CFF font file, typically read from a CFF OpenType table.
88
///
89
/// Refer to Technical Note #5176
90
#[derive(Clone)]
91
pub struct CFF<'a> {
92
    pub header: Header,
93
    pub name_index: MaybeOwnedIndex<'a>,
94
    pub string_index: MaybeOwnedIndex<'a>,
95
    pub global_subr_index: MaybeOwnedIndex<'a>,
96
    pub fonts: Vec<Font<'a>>,
97
}
98

            
99
/// CFF Font Header described in Section 6 of Technical Note #5176
100
#[derive(Clone, Debug, PartialEq)]
101
pub struct Header {
102
    pub major: u8,
103
    pub minor: u8,
104
    pub hdr_size: u8,
105
    pub off_size: u8,
106
}
107

            
108
/// Utility type for reading an INDEX with 16-bit offsets
109
pub struct IndexU16;
110

            
111
/// Utility type for reading an INDEX with 32-bit offsets
112
pub struct IndexU32;
113

            
114
/// A CFF INDEX described in Section 5 of Technical Note #5176
115
#[derive(Clone)]
116
pub struct Index<'a> {
117
    pub count: usize,
118
    off_size: u8,
119
    offset_array: &'a [u8],
120
    data_array: &'a [u8],
121
}
122

            
123
/// A single font within a CFF file
124
#[derive(Clone)]
125
pub struct Font<'a> {
126
    pub top_dict: TopDict,
127
    pub char_strings_index: MaybeOwnedIndex<'a>,
128
    pub charset: Charset<'a>,
129
    pub data: CFFVariant<'a>,
130
}
131

            
132
/// A borrowed reference to a [cff::Font](Font) or [cff2::Font].
133
#[derive(Copy, Clone)]
134
pub enum CFFFont<'a, 'data> {
135
    CFF(&'a Font<'data>),
136
    CFF2(&'a cff2::Font<'data>),
137
}
138

            
139
/// A CFF INDEX that can hold borrowed or owned data.
140
#[derive(Clone)]
141
pub enum MaybeOwnedIndex<'a> {
142
    Borrowed(Index<'a>),
143
    Owned(owned::Index),
144
}
145

            
146
/// Iterator for the entries in a `MaybeOwnedIndex`.
147
pub struct MaybeOwnedIndexIterator<'a> {
148
    data: &'a MaybeOwnedIndex<'a>,
149
    index: usize,
150
}
151

            
152
/// A list of errors that can occur when interpreting CFF CharStrings.
153
#[derive(Clone, Eq, PartialEq, Debug)]
154
pub enum CFFError {
155
    ParseError(ParseError),
156
    InvalidOperator,
157
    // Operand was out of range or otherwise unsuitable for the intended use
158
    InvalidOperand,
159
    UnsupportedOperator,
160
    MissingEndChar,
161
    DataAfterEndChar,
162
    NestingLimitReached,
163
    ArgumentsStackLimitReached,
164
    InvalidArgumentsStackLength,
165
    BboxOverflow,
166
    MissingMoveTo,
167
    DuplicateVsIndex,
168
    InvalidSubroutineIndex,
169
    InvalidFontIndex,
170
    NoLocalSubroutines,
171
    InvalidSeacCode,
172
    VsIndexAfterBlend,
173
    MissingVariationStore,
174
}
175

            
176
mod owned {
177
    use super::{U16Be, U32Be, WriteBinary, WriteContext, WriteError, U8};
178

            
179
    pub(super) struct IndexU16;
180
    pub(super) struct IndexU32;
181

            
182
    #[derive(Clone)]
183
    pub struct Index {
184
        pub(super) data: Vec<Vec<u8>>,
185
    }
186

            
187
    impl WriteBinary<&Index> for IndexU16 {
188
        type Output = ();
189

            
190
        fn write<C: WriteContext>(ctxt: &mut C, index: &Index) -> Result<(), WriteError> {
191
            let count = u16::try_from(index.data.len())?;
192
            U16Be::write(ctxt, count)?;
193
            write_index_body(ctxt, index)
194
        }
195
    }
196

            
197
    impl WriteBinary<&Index> for IndexU32 {
198
        type Output = ();
199

            
200
        fn write<C: WriteContext>(ctxt: &mut C, index: &Index) -> Result<(), WriteError> {
201
            let count = u32::try_from(index.data.len())?;
202
            U32Be::write(ctxt, count)?;
203
            write_index_body(ctxt, index)
204
        }
205
    }
206

            
207
    fn write_index_body<C: WriteContext>(ctxt: &mut C, index: &Index) -> Result<(), WriteError> {
208
        if index.data.is_empty() {
209
            return Ok(());
210
        }
211

            
212
        let mut offset = 1; // INDEX offsets start at 1
213
        let mut offsets = Vec::with_capacity(index.data.len() + 1);
214
        for data in &index.data {
215
            offsets.push(offset);
216
            offset += data.len();
217
        }
218
        offsets.push(offset);
219
        let (off_size, offset_array) = super::serialise_offset_array(offsets)?;
220
        U8::write(ctxt, off_size)?;
221
        ctxt.write_bytes(&offset_array)?;
222
        for data in &index.data {
223
            ctxt.write_bytes(data)?;
224
        }
225

            
226
        Ok(())
227
    }
228

            
229
    impl Index {
230
        pub(super) fn read_object(&self, index: usize) -> Option<&[u8]> {
231
            self.data.get(index).map(|data| data.as_slice())
232
        }
233
    }
234
}
235

            
236
#[derive(Clone)]
237
pub enum CFFVariant<'a> {
238
    CID(CIDData<'a>),
239
    Type1(Type1Data<'a>),
240
}
241

            
242
#[derive(Clone)]
243
pub struct CIDData<'a> {
244
    pub font_dict_index: MaybeOwnedIndex<'a>,
245
    pub private_dicts: Vec<PrivateDict>,
246
    /// An optional local subroutine index per Private DICT.
247
    pub local_subr_indices: Vec<Option<MaybeOwnedIndex<'a>>>,
248
    pub fd_select: FDSelect<'a>,
249
}
250

            
251
pub struct CIDDataOffsets {
252
    pub font_dict_index: usize,
253
    pub fd_select: usize,
254
}
255

            
256
#[derive(Clone)]
257
pub struct Type1Data<'a> {
258
    pub encoding: Encoding<'a>,
259
    pub private_dict: PrivateDict,
260
    pub local_subr_index: Option<MaybeOwnedIndex<'a>>,
261
}
262

            
263
pub struct Type1DataOffsets {
264
    pub custom_encoding: Option<usize>,
265
    pub private_dict: usize,
266
    pub private_dict_len: usize,
267
}
268

            
269
// Encoding data is located via the offset operand to the Encoding operator in the Top DICT. Only
270
// one Encoding operator can be specified per font except for CIDFonts which specify no encoding.
271
#[derive(Clone)]
272
pub enum Encoding<'a> {
273
    Standard,
274
    Expert,
275
    Custom(CustomEncoding<'a>),
276
}
277

            
278
#[derive(Clone)]
279
pub enum Charset<'a> {
280
    ISOAdobe,
281
    Expert,
282
    ExpertSubset,
283
    Custom(CustomCharset<'a>),
284
}
285

            
286
#[derive(Clone)]
287
pub enum CustomEncoding<'a> {
288
    Format0 {
289
        codes: ReadArray<'a, U8>,
290
    },
291
    Format1 {
292
        ranges: ReadArray<'a, Range<u8, u8>>,
293
    },
294
}
295

            
296
// A string id in the font
297
type SID = u16;
298

            
299
#[derive(Clone)]
300
pub enum CustomCharset<'a> {
301
    Format0 {
302
        glyphs: ReadArrayCow<'a, U16Be>,
303
    },
304
    Format1 {
305
        ranges: ReadArrayCow<'a, Range<SID, u8>>,
306
    },
307
    Format2 {
308
        ranges: ReadArrayCow<'a, Range<SID, u16>>,
309
    },
310
}
311

            
312
/// A Range from `first` to `first + n_left`
313
#[derive(Copy, Clone, Debug, PartialEq)]
314
pub struct Range<F, N> {
315
    pub first: F,
316
    pub n_left: N,
317
}
318

            
319
/// A CFF DICT described in Section 4 of Technical Note #5176
320
#[derive(Debug, PartialEq, Clone)]
321
pub struct Dict<T>
322
where
323
    T: DictDefault,
324
{
325
    dict: Vec<(Operator, Vec<Operand>)>,
326
    default: PhantomData<T>,
327
}
328

            
329
/// The default values of a DICT
330
pub trait DictDefault {
331
    /// Returns the default operand(s) if any for the supplied `op`.
332
    fn default(op: Operator) -> Option<&'static [Operand]>;
333
}
334

            
335
#[derive(Debug, PartialEq, Clone)]
336
pub struct TopDictDefault;
337

            
338
#[derive(Debug, PartialEq, Clone)]
339
pub struct FontDictDefault;
340

            
341
#[derive(Debug, PartialEq, Clone)]
342
pub struct PrivateDictDefault;
343

            
344
pub type TopDict = Dict<TopDictDefault>;
345

            
346
pub type FontDict = Dict<FontDictDefault>;
347

            
348
pub type PrivateDict = Dict<PrivateDictDefault>;
349

            
350
/// A collection of offset changes to a `Dict`
351
///
352
/// `DictDelta` only accepts Operators with offsets as operands.
353
#[derive(Debug, PartialEq, Clone)]
354
pub struct DictDelta {
355
    // Most entries will have operands of a single offset, so the tiny vec is set to that
356
    dict: Vec<(Operator, TinyVec<[Operand; 1]>)>,
357
}
358

            
359
/// Font DICT select as described in Section 19 of Technical Note #5176
360
#[derive(Clone, Debug)]
361
pub enum FDSelect<'a> {
362
    Format0 {
363
        glyph_font_dict_indices: ReadArrayCow<'a, U8>,
364
    },
365
    // Formats 1 and 2 are not defined
366
    Format3 {
367
        ranges: ReadArrayCow<'a, Range<u16, u8>>,
368
        sentinel: u16,
369
    },
370
    // Format 4 is not yet implemented
371
}
372

            
373
/// CFF DICT operator
374
#[derive(Debug, PartialEq)]
375
enum Op {
376
    Operator(Operator),
377
    Operand(Operand),
378
}
379

            
380
/// CFF operand to an operator
381
#[derive(Debug, PartialEq, Clone)]
382
pub enum Operand {
383
    Integer(i32),
384
    Offset(i32),
385
    Real(Real),
386
}
387

            
388
// On a corpus of 23945 CFF fonts real values were encountered as follows:
389
//     572 2 bytes
390
//     776 3 bytes
391
//    1602 4 bytes
392
//   14037 5 bytes
393
//    3491 6 bytes
394
//      36 7 bytes
395
// Using 7 bytes for the tiny vec covers all these, fits in a register on 64-bit systems,
396
// allows Operand to be 8 bytes on 64-bit systems, and is considerably smaller than the 24 bytes
397
// used by Vec (which Real contained in the past).
398

            
399
/// A real number
400
///
401
/// To parse the value into `f64` use the `TryFrom`/`TryInto` impl.
402
#[derive(Debug, PartialEq, Clone)]
403
pub struct Real(TinyVec<[u8; 7]>);
404

            
405
#[repr(u16)]
406
#[derive(Debug, PartialEq, Copy, Clone)]
407
pub enum Operator {
408
    Version = 0,
409
    Notice = 1,
410
    FullName = 2,
411
    FamilyName = 3,
412
    Weight = 4,
413
    FontBBox = 5,
414
    BlueValues = 6,
415
    OtherBlues = 7,
416
    FamilyBlues = 8,
417
    FamilyOtherBlues = 9,
418
    StdHW = 10,
419
    StdVW = 11,
420
    UniqueID = 13,
421
    XUID = 14,
422
    Charset = 15,
423
    Encoding = 16,
424
    CharStrings = 17,
425
    Private = 18,
426
    Subrs = 19,
427
    DefaultWidthX = 20,
428
    NominalWidthX = 21,
429
    // CFF2
430
    VSIndex = 22,
431
    Blend = 23,
432
    VStore = 24,
433

            
434
    Copyright = op2(0),
435
    IsFixedPitch = op2(1),
436
    ItalicAngle = op2(2),
437
    UnderlinePosition = op2(3),
438
    UnderlineThickness = op2(4),
439
    PaintType = op2(5),
440
    CharstringType = op2(6),
441
    FontMatrix = op2(7),
442
    StrokeWidth = op2(8),
443
    BlueScale = op2(9),
444
    BlueShift = op2(10),
445
    BlueFuzz = op2(11),
446
    StemSnapH = op2(12),
447
    StemSnapV = op2(13),
448
    ForceBold = op2(14),
449
    LanguageGroup = op2(17),
450
    ExpansionFactor = op2(18),
451
    InitialRandomSeed = op2(19),
452
    SyntheticBase = op2(20),
453
    PostScript = op2(21),
454
    BaseFontName = op2(22),
455
    BaseFontBlend = op2(23),
456
    ROS = op2(30),
457
    CIDFontVersion = op2(31),
458
    CIDFontRevision = op2(32),
459
    CIDFontType = op2(33),
460
    CIDCount = op2(34),
461
    UIDBase = op2(35),
462
    FDArray = op2(36),
463
    FDSelect = op2(37),
464
    FontName = op2(38),
465
}
466

            
467
const fn op2(value: u8) -> u16 {
468
    (12 << 8) | (value as u16)
469
}
470

            
471
impl ReadBinary for CFF<'_> {
472
    type HostType<'a> = CFF<'a>;
473

            
474
    fn read<'a>(ctxt: &mut ReadCtxt<'a>) -> Result<Self::HostType<'a>, ParseError> {
475
        // Get a scope that starts at the beginning of the CFF data. This is needed for reading
476
        // data that is specified as an offset from the start of the data later.
477
        let scope = ctxt.scope();
478

            
479
        let header = ctxt.read::<Header>()?;
480
        let name_index = ctxt.read::<IndexU16>()?;
481
        let top_dict_index = ctxt.read::<IndexU16>()?;
482
        let string_index = ctxt.read::<IndexU16>()?;
483
        let global_subr_index = ctxt.read::<IndexU16>().map(MaybeOwnedIndex::Borrowed)?;
484

            
485
        let mut fonts = Vec::with_capacity(name_index.count);
486
        for font_index in 0..name_index.count {
487
            let top_dict = top_dict_index.read::<TopDict>(font_index, MAX_OPERANDS)?;
488

            
489
            // CharStrings index
490
            let offset = top_dict
491
                .get_i32(Operator::CharStrings)
492
                .unwrap_or(Err(ParseError::MissingValue))?;
493
            let char_strings_index = scope.offset(usize::try_from(offset)?).read::<IndexU16>()?;
494

            
495
            // The Top DICT begins with the SyntheticBase and ROS operators
496
            // for synthetic and CIDFonts, respectively. Regular Type 1 fonts
497
            // begin with some other operator.
498
            let data = match top_dict.first_operator() {
499
                Some(Operator::ROS) => {
500
                    let cid_data = read_cid_data(&scope, &top_dict, char_strings_index.count)?;
501
                    CFFVariant::CID(cid_data)
502
                }
503
                Some(Operator::SyntheticBase) => {
504
                    return Err(ParseError::NotImplemented);
505
                }
506
                Some(_) => {
507
                    let (private_dict, private_dict_offset) =
508
                        top_dict.read_private_dict::<PrivateDict>(&scope, MAX_OPERANDS)?;
509
                    let local_subr_index = read_local_subr_index::<_, IndexU16>(
510
                        &scope,
511
                        &private_dict,
512
                        private_dict_offset,
513
                    )?
514
                    .map(MaybeOwnedIndex::Borrowed);
515
                    let encoding = read_encoding(&scope, &top_dict)?;
516

            
517
                    CFFVariant::Type1(Type1Data {
518
                        encoding,
519
                        private_dict,
520
                        local_subr_index,
521
                    })
522
                }
523
                None => return Err(ParseError::MissingValue),
524
            };
525

            
526
            let charset = read_charset(&scope, &top_dict, char_strings_index.count)?;
527

            
528
            fonts.push(Font {
529
                top_dict,
530
                char_strings_index: MaybeOwnedIndex::Borrowed(char_strings_index),
531
                charset,
532
                data,
533
            });
534
        }
535

            
536
        Ok(CFF {
537
            header,
538
            name_index: MaybeOwnedIndex::Borrowed(name_index),
539
            string_index: MaybeOwnedIndex::Borrowed(string_index),
540
            global_subr_index,
541
            fonts,
542
        })
543
    }
544
}
545

            
546
impl<'a> WriteBinary<&Self> for CFF<'a> {
547
    type Output = ();
548

            
549
    fn write<C: WriteContext>(ctxt: &mut C, cff: &CFF<'a>) -> Result<(), WriteError> {
550
        Header::write(ctxt, &cff.header)?;
551
        MaybeOwnedIndex::write16(ctxt, &cff.name_index)?;
552
        let top_dicts = cff.fonts.iter().map(|font| &font.top_dict).collect::<Vec<_>>();
553
        let top_dict_index_length =
554
            Index::calculate_size::<TopDict, _>(top_dicts.as_slice(), DictDelta::new())?;
555
        let top_dict_index_placeholder = ctxt.reserve::<IndexU16, _>(top_dict_index_length)?;
556
        MaybeOwnedIndex::write16(ctxt, &cff.string_index)?;
557
        MaybeOwnedIndex::write16(ctxt, &cff.global_subr_index)?;
558

            
559
        // Collect Top DICT deltas now that we know the offsets to other items in the DICT
560
        let mut top_dict_deltas = vec![DictDelta::new(); cff.fonts.len()];
561
        for (font, top_dict_delta) in cff.fonts.iter().zip(top_dict_deltas.iter_mut()) {
562
            top_dict_delta.push_offset(Operator::CharStrings, i32::try_from(ctxt.bytes_written())?);
563
            MaybeOwnedIndex::write16(ctxt, &font.char_strings_index)?;
564

            
565
            match &font.charset {
566
                Charset::ISOAdobe => top_dict_delta.push_offset(Operator::Charset, 0),
567
                Charset::Expert => top_dict_delta.push_offset(Operator::Charset, 1),
568
                Charset::ExpertSubset => top_dict_delta.push_offset(Operator::Charset, 2),
569
                Charset::Custom(custom) => {
570
                    top_dict_delta
571
                        .push_offset(Operator::Charset, i32::try_from(ctxt.bytes_written())?);
572
                    CustomCharset::write(ctxt, custom)?;
573
                }
574
            }
575
            write_cff_variant(ctxt, &font.data, top_dict_delta)?;
576
        }
577

            
578
        // Write out the Top DICTs with the updated offsets
579
        let mut top_dict_data = WriteBuffer::new();
580
        let mut offsets = Vec::with_capacity(cff.fonts.len());
581
        for (font, top_dict_delta) in cff.fonts.iter().zip(top_dict_deltas.into_iter()) {
582
            offsets.push(top_dict_data.bytes_written() + 1); // +1 because INDEX offsets start at 1
583
            TopDict::write_dep(&mut top_dict_data, &font.top_dict, top_dict_delta)?;
584
        }
585
        offsets.push(top_dict_data.bytes_written() + 1); // Add the extra offset at the end
586
        let (off_size, offset_array) = serialise_offset_array(offsets)?;
587

            
588
        // Fill in the Top DICT INDEX placeholder
589
        let top_dict_index = Index {
590
            count: cff.fonts.len(),
591
            off_size,
592
            offset_array: &offset_array,
593
            data_array: top_dict_data.bytes(),
594
        };
595
        ctxt.write_placeholder(top_dict_index_placeholder, &top_dict_index)?;
596

            
597
        Ok(())
598
    }
599
}
600

            
601
impl CFF<'_> {
602
    /// Read a string with the given SID from the String INDEX
603
    pub fn read_string(&self, sid: SID) -> Result<&str, ParseError> {
604
        read_string_index_string(&self.string_index, sid)
605
    }
606
}
607

            
608
/// Read a string with the given SID from the String INDEX
609
fn read_string_index_string<'idx>(
610
    string_index: &'idx MaybeOwnedIndex<'_>,
611
    sid: SID,
612
) -> Result<&'idx str, ParseError> {
613
    let sid = usize::from(sid);
614
    // When the client needs to determine the string that corresponds to a particular SID it
615
    // performs the following: test if SID is in standard range then fetch from internal table,
616
    // otherwise, fetch string from the String INDEX using a value of (SID – nStdStrings) as
617
    // the index
618
    if let Some(string) = STANDARD_STRINGS.get(sid) {
619
        Ok(string)
620
    } else {
621
        let bytes = string_index
622
            .read_object(sid - STANDARD_STRINGS.len())
623
            .ok_or(ParseError::BadIndex)?;
624

            
625
        std::str::from_utf8(bytes).map_err(|_utf8_err| ParseError::BadValue)
626
    }
627
}
628

            
629
impl ReadBinary for Header {
630
    type HostType<'b> = Self;
631

            
632
    fn read(ctxt: &mut ReadCtxt<'_>) -> Result<Self, ParseError> {
633
        // From section 6 of Technical Note #5176:
634
        // Implementations reading font set files must include code to check version numbers so
635
        // that if and when the format and therefore the version number changes, older
636
        // implementations will reject newer versions gracefully. If the major version number is
637
        // understood by an implementation it can safely proceed with reading the font. The minor
638
        // version number indicates extensions to the format that are undetectable by
639
        // implementations that do not support them although they will be unable to take advantage
640
        // of these extensions.
641
        let major = ctxt.read_u8()?;
642
        ctxt.check(major == 1)?;
643
        let minor = ctxt.read_u8()?;
644
        let hdr_size = ctxt.read_u8()?;
645
        let off_size = ctxt.read_u8()?;
646

            
647
        if hdr_size < 4 {
648
            return Err(ParseError::BadValue);
649
        }
650

            
651
        if off_size < 1 || off_size > 4 {
652
            return Err(ParseError::BadValue);
653
        }
654

            
655
        let _unknown = ctxt.read_slice((hdr_size - 4) as usize)?;
656

            
657
        Ok(Header {
658
            major,
659
            minor,
660
            hdr_size,
661
            off_size,
662
        })
663
    }
664
}
665

            
666
impl WriteBinary<&Self> for Header {
667
    type Output = ();
668

            
669
    fn write<C: WriteContext>(ctxt: &mut C, header: &Header) -> Result<(), WriteError> {
670
        U8::write(ctxt, header.major)?;
671
        U8::write(ctxt, header.minor)?;
672
        // Any data between the header and the Name INDEX will have been discarded.
673
        // So the size will always be 4 bytes.
674
        U8::write(ctxt, 4)?; // hdr_size
675
        U8::write(ctxt, header.off_size)?;
676

            
677
        Ok(())
678
    }
679
}
680

            
681
impl ReadBinary for IndexU16 {
682
    type HostType<'a> = Index<'a>;
683

            
684
    fn read<'a>(ctxt: &mut ReadCtxt<'a>) -> Result<Self::HostType<'a>, ParseError> {
685
        let count = usize::from(ctxt.read_u16be()?);
686
        read_index(ctxt, count)
687
    }
688
}
689

            
690
fn read_index<'a>(ctxt: &mut ReadCtxt<'a>, count: usize) -> Result<Index<'a>, ParseError> {
691
    if count > 0 {
692
        let off_size = ctxt.read_u8()?;
693
        if off_size < 1 || off_size > 4 {
694
            return Err(ParseError::BadValue);
695
        }
696

            
697
        let offset_array_size = (count + 1) * usize::from(off_size);
698
        let offset_array = ctxt.read_slice(offset_array_size)?;
699

            
700
        let last_offset_index = lookup_offset_index(off_size, offset_array, count);
701
        if last_offset_index < 1 {
702
            return Err(ParseError::BadValue);
703
        }
704

            
705
        let data_array_size = last_offset_index - 1;
706
        let data_array = ctxt.read_slice(data_array_size)?;
707

            
708
        Ok(Index {
709
            count,
710
            off_size,
711
            offset_array,
712
            data_array,
713
        })
714
    } else {
715
        // count == 0
716
        Ok(Index {
717
            count,
718
            off_size: 1,
719
            offset_array: &[],
720
            data_array: &[],
721
        })
722
    }
723
}
724

            
725
impl<'a> WriteBinary<&Index<'a>> for IndexU16 {
726
    type Output = ();
727

            
728
    fn write<C: WriteContext>(ctxt: &mut C, index: &Index<'a>) -> Result<(), WriteError> {
729
        U16Be::write(ctxt, u16::try_from(index.count)?)?;
730
        write_index_body(ctxt, index)
731
    }
732
}
733

            
734
fn write_index_body<C: WriteContext>(ctxt: &mut C, index: &Index<'_>) -> Result<(), WriteError> {
735
    if index.count == 0 {
736
        return Ok(());
737
    }
738

            
739
    U8::write(ctxt, index.off_size)?;
740
    ctxt.write_bytes(index.offset_array)?;
741
    ctxt.write_bytes(index.data_array)?;
742

            
743
    Ok(())
744
}
745

            
746
impl<T> ReadBinaryDep for Dict<T>
747
where
748
    T: DictDefault,
749
{
750
    type Args<'a> = usize;
751
    type HostType<'b> = Self;
752

            
753
    fn read_dep<'a>(
754
        ctxt: &mut ReadCtxt<'a>,
755
        max_operands: usize,
756
    ) -> Result<Self::HostType<'a>, ParseError> {
757
        let mut dict = Vec::new();
758
        let mut operands = Vec::new();
759

            
760
        while ctxt.bytes_available() {
761
            match Op::read(ctxt)? {
762
                Op::Operator(operator) => {
763
                    integer_to_offset(operator, &mut operands);
764
                    dict.push((operator, operands.clone()));
765
                    operands.clear();
766
                }
767
                Op::Operand(operand) => {
768
                    operands.push(operand);
769
                    if operands.len() > max_operands {
770
                        return Err(ParseError::LimitExceeded);
771
                    }
772
                }
773
            }
774
        }
775

            
776
        Ok(Dict {
777
            dict,
778
            default: PhantomData,
779
        })
780
    }
781
}
782

            
783
fn offset_size(value: usize) -> Option<u8> {
784
    match value {
785
        0..=0xFF => Some(1),
786
        0x100..=0xFFFF => Some(2),
787
        0x1_0000..=0xFF_FFFF => Some(3),
788
        0x100_0000..=0xFFFF_FFFF => Some(4),
789
        _ => None,
790
    }
791
}
792

            
793
// Special case handling for operands that are offsets. This function swaps them from an
794
// Integer to an Offset. This is later used when writing operands.
795
fn integer_to_offset(operator: Operator, operands: &mut [Operand]) {
796
    match (operator, &operands) {
797
        // Encodings 0..=1 indicate predefined encodings and are not offsets
798
        (Operator::Encoding, [Operand::Integer(offset)]) if *offset > 1 => {
799
            operands[0] = Operand::Offset(*offset);
800
        }
801
        (Operator::Charset, [Operand::Integer(offset)])
802
        | (Operator::CharStrings, [Operand::Integer(offset)])
803
        | (Operator::Subrs, [Operand::Integer(offset)])
804
        | (Operator::FDArray, [Operand::Integer(offset)])
805
        | (Operator::FDSelect, [Operand::Integer(offset)])
806
        | (Operator::VStore, [Operand::Integer(offset)]) => {
807
            operands[0] = Operand::Offset(*offset);
808
        }
809
        (Operator::Private, [Operand::Integer(length), Operand::Integer(offset)]) => {
810
            let offset = *offset; // This is a work around an ownership issue
811
            operands[0] = Operand::Offset(*length);
812
            operands[1] = Operand::Offset(offset);
813
        }
814
        _ => {}
815
    }
816
}
817

            
818
impl<T> WriteBinaryDep<&Self> for Dict<T>
819
where
820
    T: DictDefault,
821
{
822
    type Args = DictDelta;
823
    type Output = usize; // The length of the written Dict
824

            
825
    fn write_dep<C: WriteContext>(
826
        ctxt: &mut C,
827
        dict: &Dict<T>,
828
        delta: DictDelta,
829
    ) -> Result<Self::Output, WriteError> {
830
        let offset = ctxt.bytes_written();
831

            
832
        for (operator, operands) in dict.iter() {
833
            let mut operands = operands.as_slice();
834

            
835
            // Replace operands with delta operands if present otherwise skip if operands match
836
            // default. We never skip operands pulled from the delta DICT as these are offsets and
837
            // always need to be written in order to make the size of the DICT predictable.
838
            if let Some(delta_operands) = delta.get(*operator) {
839
                operands = delta_operands;
840
            } else if T::default(*operator)
841
                .map(|defaults| defaults == operands)
842
                .unwrap_or(false)
843
            {
844
                continue;
845
            }
846

            
847
            for operand in operands {
848
                Operand::write(ctxt, operand)?;
849
            }
850
            Operator::write(ctxt, *operator)?;
851
        }
852

            
853
        Ok(ctxt.bytes_written() - offset)
854
    }
855
}
856

            
857
impl ReadBinary for Op {
858
    type HostType<'b> = Self;
859

            
860
    fn read(ctxt: &mut ReadCtxt<'_>) -> Result<Self, ParseError> {
861
        let b0 = ctxt.read_u8()?;
862

            
863
        match b0 {
864
            0..=11 | 13..=21 => ok_operator(u16::from(b0).try_into().unwrap()), // NOTE(unwrap): Safe due to pattern
865
            // CFF2
866
            22..=24 => ok_operator(u16::from(b0).try_into().unwrap()), // NOTE(unwrap): Safe due to pattern
867
            12 => ok_operator(op2(ctxt.read_u8()?).try_into()?),
868
            28 => {
869
                let num = ctxt.read_i16be()?;
870
                Ok(Op::Operand(Operand::Integer(i32::from(num))))
871
            }
872
            29 => ok_int(ctxt.read_i32be()?),
873
            30 => ok_real(ctxt.read_until_nibble(END_OF_FLOAT_FLAG)?),
874
            32..=246 => ok_int(i32::from(b0) - 139),
875
            247..=250 => {
876
                let b1 = ctxt.read_u8()?;
877
                ok_int((i32::from(b0) - 247) * 256 + i32::from(b1) + 108)
878
            }
879
            251..=254 => {
880
                let b1 = ctxt.read_u8()?;
881
                ok_int(-(i32::from(b0) - 251) * 256 - i32::from(b1) - 108)
882
            }
883
            // reserved
884
            25..=27 | 31 | 255 => Err(ParseError::BadValue),
885
        }
886
    }
887
}
888

            
889
impl WriteBinary<Self> for Operator {
890
    type Output = ();
891

            
892
    fn write<C: WriteContext>(ctxt: &mut C, op: Operator) -> Result<(), WriteError> {
893
        let value = op as u16;
894
        if value > 0xFF {
895
            U16Be::write(ctxt, value)?;
896
        } else {
897
            U8::write(ctxt, value as u8)?;
898
        }
899

            
900
        Ok(())
901
    }
902
}
903

            
904
impl WriteBinary<&Self> for Operand {
905
    type Output = ();
906

            
907
    // Refer to Table 3 Operand Encoding in section 4 of Technical Note #5176 for details on the
908
    // integer encoding scheme.
909
    fn write<C: WriteContext>(ctxt: &mut C, op: &Operand) -> Result<(), WriteError> {
910
        match op {
911
            Operand::Integer(val) => match *val {
912
                // NOTE: Casts are safe due to patterns limiting range
913
                -107..=107 => {
914
                    U8::write(ctxt, (val + 139) as u8)?;
915
                }
916
                108..=1131 => {
917
                    let val = *val - 108;
918
                    U8::write(ctxt, ((val >> 8) + 247) as u8)?;
919
                    U8::write(ctxt, val as u8)?;
920
                }
921
                -1131..=-108 => {
922
                    let val = -*val - 108;
923
                    U8::write(ctxt, ((val >> 8) + 251) as u8)?;
924
                    U8::write(ctxt, val as u8)?;
925
                }
926
                -32768..=32767 => {
927
                    U8::write(ctxt, 28)?;
928
                    I16Be::write(ctxt, *val as i16)?
929
                }
930
                _ => {
931
                    U8::write(ctxt, 29)?;
932
                    I32Be::write(ctxt, *val)?
933
                }
934
            },
935
            Operand::Offset(val) => {
936
                U8::write(ctxt, 29)?;
937
                // Offsets are always encoded using the i32 representation to make their size
938
                // predictable.
939
                I32Be::write(ctxt, *val)?;
940
            }
941
            Operand::Real(Real(val)) => {
942
                U8::write(ctxt, 30)?;
943
                ctxt.write_bytes(val)?;
944
            }
945
        }
946

            
947
        Ok(())
948
    }
949
}
950

            
951
fn ok_operator(op: Operator) -> Result<Op, ParseError> {
952
    Ok(Op::Operator(op))
953
}
954

            
955
fn ok_int(num: i32) -> Result<Op, ParseError> {
956
    Ok(Op::Operand(Operand::Integer(num)))
957
}
958

            
959
fn ok_real(slice: &[u8]) -> Result<Op, ParseError> {
960
    Ok(Op::Operand(Operand::Real(Real(TinyVec::from(slice)))))
961
}
962

            
963
const FLOAT_BUF_LEN: usize = 64;
964

            
965
// Portions of this try_from impl derived from ttf-parser, licenced under Apache-2.0.
966
// https://github.com/RazrFalcon/ttf-parser/blob/ba2d9c8b9a207951b7b07e9481bc74688762bd21/src/tables/cff/dict.rs#L188
967
impl TryFrom<&Real> for f64 {
968
    type Error = ParseError;
969

            
970
    /// Try to parse this `Real` into an `f64`.
971
    fn try_from(real: &Real) -> Result<Self, Self::Error> {
972
        let mut buf = [0u8; FLOAT_BUF_LEN];
973
        let mut used = 0;
974

            
975
        for byte in real.0.iter().copied() {
976
            let nibble1 = byte >> 4;
977
            let nibble2 = byte & 0xF;
978

            
979
            if nibble1 == END_OF_FLOAT_FLAG {
980
                break;
981
            }
982
            parse_float_nibble(nibble1, &mut used, &mut buf)?;
983
            if nibble2 == END_OF_FLOAT_FLAG {
984
                break;
985
            }
986
            parse_float_nibble(nibble2, &mut used, &mut buf)?;
987
        }
988

            
989
        // NOTE(unwrap): Safe as we have constructed the string from only ASCII characters in
990
        // parse_float_nibble.
991
        let s = core::str::from_utf8(&buf[..used]).unwrap();
992
        s.parse().map_err(|_| ParseError::BadValue)
993
    }
994
}
995

            
996
// Adobe Technical Note #5176, Table 5 Nibble Definitions
997
fn parse_float_nibble(nibble: u8, idx: &mut usize, data: &mut [u8]) -> Result<(), ParseError> {
998
    if *idx == FLOAT_BUF_LEN {
999
        return Err(ParseError::LimitExceeded);
    }
    match nibble {
        0..=9 => {
            data[*idx] = b'0' + nibble;
        }
        10 => {
            data[*idx] = b'.';
        }
        11 => {
            data[*idx] = b'E';
        }
        12 => {
            if *idx + 1 == FLOAT_BUF_LEN {
                return Err(ParseError::LimitExceeded);
            }
            data[*idx] = b'E';
            *idx += 1;
            data[*idx] = b'-';
        }
        13 => return Err(ParseError::BadValue),
        14 => {
            data[*idx] = b'-';
        }
        _ => return Err(ParseError::BadValue),
    }
    *idx += 1;
    Ok(())
}
impl ReadFrom for Range<u8, u8> {
    type ReadType = (U8, U8);
    fn read_from((first, n_left): (u8, u8)) -> Self {
        Range { first, n_left }
    }
}
impl WriteBinary for Range<u8, u8> {
    type Output = ();
    fn write<C: WriteContext>(ctxt: &mut C, range: Self) -> Result<(), WriteError> {
        U8::write(ctxt, range.first)?;
        U8::write(ctxt, range.n_left)?;
        Ok(())
    }
}
impl ReadFrom for Range<SID, u8> {
    type ReadType = (U16Be, U8);
    fn read_from((first, n_left): (SID, u8)) -> Self {
        Range { first, n_left }
    }
}
impl WriteBinary for Range<SID, u8> {
    type Output = ();
    fn write<C: WriteContext>(ctxt: &mut C, range: Self) -> Result<(), WriteError> {
        U16Be::write(ctxt, range.first)?;
        U8::write(ctxt, range.n_left)?;
        Ok(())
    }
}
impl ReadFrom for Range<SID, u16> {
    type ReadType = (U16Be, U16Be);
    fn read_from((first, n_left): (SID, u16)) -> Self {
        Range { first, n_left }
    }
}
impl WriteBinary for Range<SID, u16> {
    type Output = ();
    fn write<C: WriteContext>(ctxt: &mut C, range: Self) -> Result<(), WriteError> {
        U16Be::write(ctxt, range.first)?;
        U16Be::write(ctxt, range.n_left)?;
        Ok(())
    }
}
impl<F, N> Range<F, N>
where
    N: Copy,
    usize: From<N>,
{
    pub fn len(&self) -> usize {
        usize::from(self.n_left) + 1
    }
}
// TODO: Make these generic. Requires Rust stabilisation of the Step trait or its replacement.
// https://doc.rust-lang.org/core/iter/trait.Step.html
impl Range<SID, u8> {
    pub fn iter(&self) -> impl Iterator<Item = SID> {
        let last = self.first + SID::from(self.n_left);
        self.first..=last
    }
}
impl Range<SID, u16> {
    pub fn iter(&self) -> impl Iterator<Item = SID> {
        let last = self.first + self.n_left;
        self.first..=last
    }
}
impl ReadBinary for CustomEncoding<'_> {
    type HostType<'a> = CustomEncoding<'a>;
    fn read<'a>(ctxt: &mut ReadCtxt<'a>) -> Result<Self::HostType<'a>, ParseError> {
        // First byte indicates the format of the encoding data
        match ctxt.read::<U8>()? {
            0 => {
                let ncodes = ctxt.read::<U8>()?;
                let codes = ctxt.read_array::<U8>(usize::from(ncodes))?;
                Ok(CustomEncoding::Format0 { codes })
            }
            1 => {
                let nranges = ctxt.read::<U8>()?;
                let ranges = ctxt.read_array::<Range<u8, u8>>(usize::from(nranges))?;
                Ok(CustomEncoding::Format1 { ranges })
            }
            // The CFF spec notes:
            // A few fonts have multiply-encoded glyphs which are not supported directly by any of
            // the above formats. This situation is indicated by setting the high-order bit in the
            // format byte and supplementing the encoding.
            //
            // This is not handed as it is not expected that these will be encountered in CFF in
            // OTF files.
            format if format & 0x80 == 0x80 => Err(ParseError::NotImplemented),
            _ => Err(ParseError::BadValue),
        }
    }
}
impl WriteBinary<&Self> for CustomEncoding<'_> {
    type Output = ();
    fn write<C: WriteContext>(ctxt: &mut C, encoding: &Self) -> Result<(), WriteError> {
        match encoding {
            CustomEncoding::Format0 { codes } => {
                U8::write(ctxt, 0)?; // format
                U8::write(ctxt, u8::try_from(codes.len())?)?;
                <&ReadArray<'_, _>>::write(ctxt, codes)?;
            }
            CustomEncoding::Format1 { ranges } => {
                U8::write(ctxt, 1)?; // format
                U8::write(ctxt, u8::try_from(ranges.len())?)?;
                <&ReadArray<'_, _>>::write(ctxt, ranges)?;
            }
        }
        Ok(())
    }
}
impl Charset<'_> {
    /// Returns the id of the SID (Type 1 font) or CID (CID keyed font) of the name of the supplied glyph
    pub fn id_for_glyph(&self, glyph_id: u16) -> Option<u16> {
        match self {
            // In ISOAdobe glyph ID maps to SID
            Charset::ISOAdobe => {
                if glyph_id <= ISO_ADOBE_LAST_SID {
                    Some(glyph_id)
                } else {
                    None
                }
            }
            Charset::Expert => EXPERT_CHARSET.get(usize::from(glyph_id)).copied(),
            Charset::ExpertSubset => EXPERT_SUBSET_CHARSET.get(usize::from(glyph_id)).copied(),
            Charset::Custom(custom) => custom.id_for_glyph(glyph_id),
        }
    }
    /// Returns the glyph id of the supplied string id.
    pub fn sid_to_gid(&self, sid: SID) -> Option<u16> {
        if sid == 0 {
            return Some(0);
        }
        match self {
            Charset::ISOAdobe | Charset::Expert | Charset::ExpertSubset => None,
            Charset::Custom(custom) => custom.sid_to_gid(sid),
        }
    }
}
impl ReadBinaryDep for CustomCharset<'_> {
    type Args<'a> = usize;
    type HostType<'a> = CustomCharset<'a>;
    fn read_dep<'a>(
        ctxt: &mut ReadCtxt<'a>,
        n_glyphs: usize,
    ) -> Result<Self::HostType<'a>, ParseError> {
        // (There is one less element in the charset than nGlyphs because the .notdef glyph name is omitted.)
        let n_glyphs = n_glyphs.checked_sub(1).ok_or(ParseError::BadValue)?;
        match ctxt.read::<U8>()? {
            0 => {
                // The number of glyphs (nGlyphs) is the value of the count field in the
                // CharStrings INDEX.
                let glyphs = ctxt.read_array::<U16Be>(n_glyphs)?;
                Ok(CustomCharset::Format0 {
                    glyphs: ReadArrayCow::Borrowed(glyphs),
                })
            }
            1 => {
                let ranges = read_range_array(ctxt, n_glyphs)?;
                Ok(CustomCharset::Format1 {
                    ranges: ReadArrayCow::Borrowed(ranges),
                })
            }
            2 => {
                let ranges = read_range_array(ctxt, n_glyphs)?;
                Ok(CustomCharset::Format2 {
                    ranges: ReadArrayCow::Borrowed(ranges),
                })
            }
            _ => Err(ParseError::BadValue),
        }
    }
}
impl WriteBinary<&Self> for CustomCharset<'_> {
    type Output = ();
    fn write<C: WriteContext>(ctxt: &mut C, charset: &Self) -> Result<(), WriteError> {
        match charset {
            CustomCharset::Format0 { glyphs } => {
                U8::write(ctxt, 0)?; // format
                ReadArrayCow::write(ctxt, glyphs)?;
            }
            CustomCharset::Format1 { ranges } => {
                U8::write(ctxt, 1)?; // format
                ReadArrayCow::write(ctxt, ranges)?;
            }
            CustomCharset::Format2 { ranges } => {
                U8::write(ctxt, 2)?; // format
                ReadArrayCow::write(ctxt, ranges)?;
            }
        }
        Ok(())
    }
}
impl<'a> CustomCharset<'a> {
    pub fn iter(&'a self) -> Box<dyn Iterator<Item = u16> + 'a> {
        let notdef = iter::once(0);
        match &self {
            CustomCharset::Format0 { glyphs } => Box::new(notdef.chain(glyphs.iter())),
            CustomCharset::Format1 { ranges } => {
                Box::new(notdef.chain(ranges.iter().flat_map(|range| range.iter())))
            }
            CustomCharset::Format2 { ranges } => {
                Box::new(notdef.chain(ranges.iter().flat_map(|range| range.iter())))
            }
        }
    }
    /// Returns the SID (Type 1 font) or CID (CID keyed font) of the name of the supplied glyph
    pub fn id_for_glyph(&self, glyph_id: u16) -> Option<u16> {
        // Section 11 of Technical Note #5176:
        // By definition the first glyph (GID 0) is “.notdef” and must be present in all fonts.
        // Since this is always the case, it is not necessary to represent either the encoding
        // (unencoded) or name (.notdef) for GID 0. Consequently, taking advantage of this
        // optimization, the encoding and charset arrays always begin with GID 1.
        if glyph_id == 0 {
            return Some(0);
        }
        match self {
            CustomCharset::Format0 { glyphs } => {
                let index = usize::from(glyph_id - 1);
                glyphs.get_item(index)
            }
            CustomCharset::Format1 { ranges } => Self::id_for_glyph_in_ranges(ranges, glyph_id),
            CustomCharset::Format2 { ranges } => Self::id_for_glyph_in_ranges(ranges, glyph_id),
        }
    }
    pub fn sid_to_gid(&self, sid: SID) -> Option<u16> {
        match self {
            CustomCharset::Format0 { glyphs: array } => {
                // First glyph is omitted, so we have to add 1.
                array
                    .into_iter()
                    .position(|n| n == sid)
                    .and_then(|n| u16::try_from(n + 1).ok())
            }
            CustomCharset::Format1 { ranges } => Self::glyph_id_for_sid_in_ranges(ranges, sid),
            CustomCharset::Format2 { ranges } => Self::glyph_id_for_sid_in_ranges(ranges, sid),
        }
    }
    fn glyph_id_for_sid_in_ranges<F, N>(
        ranges: &ReadArrayCow<'a, Range<F, N>>,
        sid: SID,
    ) -> Option<u16>
    where
        F: Copy,
        N: Copy,
        u32: From<N> + From<F>,
        u16: From<N> + From<F>,
        Range<F, N>: ReadFrom,
    {
        let mut glyph_id = 1;
        for range in ranges.iter() {
            let last = u32::from(range.first) + u32::from(range.n_left);
            if u16::from(range.first) <= sid && u32::from(sid) <= last {
                glyph_id += sid - u16::from(range.first);
                return Some(glyph_id);
            }
            glyph_id += u16::from(range.n_left) + 1;
        }
        None
    }
    fn id_for_glyph_in_ranges<F, N>(
        ranges: &ReadArrayCow<'a, Range<F, N>>,
        glyph_id: u16,
    ) -> Option<u16>
    where
        F: Copy,
        N: Copy,
        usize: From<N> + From<F>,
        Range<F, N>: ReadFrom,
        <Range<F, N> as ReadUnchecked>::HostType: Copy,
    {
        let glyph_id = usize::from(glyph_id);
        ranges
            .iter()
            .scan(0usize, |glyphs_covered, range| {
                *glyphs_covered += range.len();
                Some((*glyphs_covered, range))
            })
            .find(|(glyphs_covered, _range)| glyph_id <= *glyphs_covered)
            .and_then(|(glyphs_covered, range)| {
                (usize::from(range.first) + (glyph_id - (glyphs_covered - range.len()) - 1))
                    .try_into()
                    .ok()
            })
    }
}
impl ReadBinaryDep for FDSelect<'_> {
    type Args<'a> = usize;
    type HostType<'a> = FDSelect<'a>;
    fn read_dep<'a>(
        ctxt: &mut ReadCtxt<'a>,
        n_glyphs: usize,
    ) -> Result<Self::HostType<'a>, ParseError> {
        match ctxt.read::<U8>()? {
            0 => {
                let glyph_font_dict_indices = ctxt.read_array::<U8>(n_glyphs)?;
                Ok(FDSelect::Format0 {
                    glyph_font_dict_indices: ReadArrayCow::Borrowed(glyph_font_dict_indices),
                })
            }
            3 => {
                let nranges = usize::from(ctxt.read::<U16Be>()?);
                let ranges = ctxt.read_array(nranges)?;
                let sentinel = ctxt.read::<U16Be>()?;
                Ok(FDSelect::Format3 {
                    ranges: ReadArrayCow::Borrowed(ranges),
                    sentinel,
                })
            }
            // Format4 was added in CFF2, it allows GIDs greater than u16::MAX but the
            // rest of the OpenType format does not accommodate this yet, so it's not
            // implemented.
            4 => Err(ParseError::NotImplemented),
            _ => Err(ParseError::BadValue),
        }
    }
}
impl WriteBinary<&Self> for FDSelect<'_> {
    type Output = ();
    fn write<C: WriteContext>(ctxt: &mut C, fd_select: &Self) -> Result<(), WriteError> {
        match fd_select {
            FDSelect::Format0 {
                glyph_font_dict_indices,
            } => {
                U8::write(ctxt, 0)?; // format
                ReadArrayCow::write(ctxt, glyph_font_dict_indices)?;
            }
            FDSelect::Format3 { ranges, sentinel } => {
                U8::write(ctxt, 3)?; // format
                U16Be::write(ctxt, u16::try_from(ranges.len())?)?;
                ReadArrayCow::write(ctxt, ranges)?;
                U16Be::write(ctxt, *sentinel)?;
            }
        }
        Ok(())
    }
}
impl PartialEq for FDSelect<'_> {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (
                FDSelect::Format0 {
                    glyph_font_dict_indices: self_glyph_font_dict_indices,
                },
                FDSelect::Format0 {
                    glyph_font_dict_indices: other_glyph_font_dict_indices,
                },
            ) => {
                self_glyph_font_dict_indices.len() == other_glyph_font_dict_indices.len()
                    && self_glyph_font_dict_indices
                        .iter()
                        .zip(other_glyph_font_dict_indices.iter())
                        .all(|(left, right)| left == right)
            }
            (
                FDSelect::Format3 {
                    ranges: self_ranges,
                    sentinel: self_sentinel,
                },
                FDSelect::Format3 {
                    ranges: other_ranges,
                    sentinel: other_sentinel,
                },
            ) => {
                self_ranges.len() == other_ranges.len()
                    && self_sentinel == other_sentinel
                    && self_ranges
                        .iter()
                        .zip(other_ranges.iter())
                        .all(|(left, right)| left == right)
            }
            _ => false,
        }
    }
}
impl FDSelect<'_> {
    /// Returns the index of the Font DICT for the supplied `glyph_id`
    pub fn font_dict_index(&self, glyph_id: u16) -> Option<u8> {
        let index = usize::from(glyph_id);
        match self {
            FDSelect::Format0 {
                glyph_font_dict_indices,
            } => glyph_font_dict_indices.get_item(index),
            FDSelect::Format3 { ranges, sentinel } => {
                let mut iter = ranges
                    .iter()
                    .map(|Range { first, n_left }| (first, Some(n_left)))
                    .chain(iter::once((*sentinel, None)))
                    .peekable();
                while let Some((first, fd_index)) = iter.next() {
                    let &(last, _) = match iter.peek() {
                        Some(next) => next,
                        None => break,
                    };
                    if glyph_id >= first && glyph_id < last {
                        return fd_index;
                    }
                }
                None
            }
        }
    }
}
impl<'a> Index<'a> {
    fn read_object(&self, index: usize) -> Option<&[u8]> {
        if index < self.count {
            let start_index = lookup_offset_index(self.off_size, self.offset_array, index) - 1;
            let end_index = lookup_offset_index(self.off_size, self.offset_array, index + 1) - 1;
            Some(&self.data_array[start_index..end_index])
        } else {
            None
        }
    }
    pub fn read<T: ReadBinaryDep>(
        &'a self,
        index: usize,
        args: T::Args<'a>,
    ) -> Result<T::HostType<'a>, ParseError> {
        let data = self.read_object(index).ok_or(ParseError::BadIndex)?;
        ReadScope::new(data).read_dep::<T>(args)
    }
    pub fn iter(&self) -> impl Iterator<Item = &[u8]> {
        // NOTE(unwrap): Safe since we're iterating over valid indices
        (0..self.count).map(move |i| self.read_object(i).unwrap())
    }
    /// Returns the length required to write `objects`.
    pub fn calculate_size<'b, T, HostType>(
        objects: &'b [&HostType],
        args: T::Args,
    ) -> Result<usize, WriteError>
    where
        T: WriteBinaryDep<&'b HostType>,
        T::Args: Clone,
    {
        let mut counter = WriteCounter::new();
        U16Be::write(&mut counter, u16::try_from(objects.len())?)?;
        let off_size = if !objects.is_empty() {
            let start = counter.bytes_written();
            for obj in objects {
                T::write_dep(&mut counter, obj, args.clone())?;
            }
            let last_offset = counter.bytes_written() - start + 1; // +1 because index offsets start at 1
            let off_size = offset_size(last_offset).ok_or(WriteError::BadValue)?;
            U8::write(&mut counter, off_size)?;
            off_size
        } else {
            0
        };
        let offset_array_size = usize::from(off_size) * (objects.len() + 1);
        Ok(counter.bytes_written() + offset_array_size)
    }
    /// Returns the size of the data held by this INDEX.
    pub fn data_len(&self) -> usize {
        self.data_array.len()
    }
}
impl<'a> MaybeOwnedIndex<'a> {
    pub fn iter(&'a self) -> MaybeOwnedIndexIterator<'a> {
        MaybeOwnedIndexIterator {
            data: self,
            index: 0,
        }
    }
    pub fn read_object(&self, index: usize) -> Option<&[u8]> {
        match self {
            MaybeOwnedIndex::Borrowed(idx) => idx.read_object(index),
            MaybeOwnedIndex::Owned(idx) => idx.read_object(index),
        }
    }
    /// Returns the number of items in self.
    pub fn len(&self) -> usize {
        match self {
            MaybeOwnedIndex::Borrowed(index) => index.count,
            MaybeOwnedIndex::Owned(index) => index.data.len(),
        }
    }
    /// Returns the index of `object` in self if found.
    fn index(&self, object: &[u8]) -> Option<usize> {
        self.iter().position(|obj| obj == object)
    }
    /// Push an object onto this `MaybeOwnedIndex`. Returns the index of the object in self.
    ///
    /// If self is `Borrowed` then it is converted to the `Owned` variant first.
    fn push(&mut self, object: Vec<u8>) -> usize {
        match self {
            MaybeOwnedIndex::Borrowed(_) => {
                self.to_owned();
                self.push(object);
            }
            MaybeOwnedIndex::Owned(index) => {
                index.data.push(object);
            }
        }
        self.len() - 1
    }
    /// Replace the object at `idx` with `object`.
    ///
    /// If self is `Borrowed` then it is converted to the `Owned` variant first.
    ///
    /// **Panics**
    ///
    /// Panics if `idx` is out of bounds.
    pub fn replace(&mut self, idx: usize, object: Vec<u8>) {
        match self {
            MaybeOwnedIndex::Borrowed(_) => {
                self.to_owned();
                self.replace(idx, object);
            }
            MaybeOwnedIndex::Owned(index) => index.data[idx] = object,
        }
    }
    /// If self is the `Borrowed` variant, convert to the `Owned` variant.
    fn to_owned(&mut self) {
        match self {
            MaybeOwnedIndex::Borrowed(data) => {
                let data = data.iter().map(|obj| obj.to_owned()).collect();
                *self = MaybeOwnedIndex::Owned(owned::Index { data })
            }
            MaybeOwnedIndex::Owned(_) => {}
        }
    }
    pub fn data_len(&self) -> usize {
        match self {
            MaybeOwnedIndex::Borrowed(index) => index.data_len(),
            MaybeOwnedIndex::Owned(index) => index.data.iter().map(|data| data.len()).sum(),
        }
    }
    pub(crate) fn write32<C: WriteContext>(
        ctxt: &mut C,
        index: &MaybeOwnedIndex<'_>,
    ) -> Result<(), WriteError> {
        match index {
            MaybeOwnedIndex::Borrowed(index) => IndexU32::write(ctxt, index),
            MaybeOwnedIndex::Owned(index) => owned::IndexU32::write(ctxt, index),
        }
    }
    pub(crate) fn write16<C: WriteContext>(
        ctxt: &mut C,
        index: &MaybeOwnedIndex<'_>,
    ) -> Result<(), WriteError> {
        match index {
            MaybeOwnedIndex::Borrowed(index) => IndexU16::write(ctxt, index),
            MaybeOwnedIndex::Owned(index) => owned::IndexU16::write(ctxt, index),
        }
    }
}
impl<'a> Iterator for MaybeOwnedIndexIterator<'a> {
    type Item = &'a [u8];
    fn next(&mut self) -> Option<Self::Item> {
        if self.index < self.data.len() {
            let index = self.index;
            self.index += 1;
            self.data.read_object(index)
        } else {
            None
        }
    }
    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = self.data.len();
        (len, Some(len))
    }
}
impl DictDefault for TopDictDefault {
    fn default(op: Operator) -> Option<&'static [Operand]> {
        match op {
            Operator::IsFixedPitch => Some(&OPERAND_ZERO),
            Operator::ItalicAngle => Some(&OPERAND_ZERO),
            Operator::UnderlinePosition => Some(&DEFAULT_UNDERLINE_POSITION),
            Operator::UnderlineThickness => Some(&DEFAULT_UNDERLINE_THICKNESS),
            Operator::PaintType => Some(&OPERAND_ZERO),
            Operator::CharstringType => Some(&DEFAULT_CHARSTRING_TYPE),
            Operator::FontMatrix => Some(default_font_matrix().as_ref()),
            Operator::FontBBox => Some(&DEFAULT_BBOX),
            Operator::StrokeWidth => Some(&OPERAND_ZERO),
            Operator::Charset => Some(&OFFSET_ZERO),
            Operator::Encoding => Some(&OFFSET_ZERO),
            Operator::CIDFontVersion => Some(&OPERAND_ZERO),
            Operator::CIDFontRevision => Some(&OPERAND_ZERO),
            Operator::CIDFontType => Some(&OPERAND_ZERO),
            Operator::CIDCount => Some(&DEFAULT_CID_COUNT),
            _ => None,
        }
    }
}
impl DictDefault for FontDictDefault {
    fn default(_op: Operator) -> Option<&'static [Operand]> {
        None
    }
}
impl DictDefault for PrivateDictDefault {
    fn default(op: Operator) -> Option<&'static [Operand]> {
        match op {
            Operator::BlueScale => Some(default_blue_scale().as_ref()),
            Operator::BlueShift => Some(&DEFAULT_BLUE_SHIFT),
            Operator::BlueFuzz => Some(&DEFAULT_BLUE_FUZZ),
            Operator::ForceBold => Some(&OPERAND_ZERO),
            Operator::LanguageGroup => Some(&OPERAND_ZERO),
            Operator::ExpansionFactor => Some(default_expansion_factor().as_ref()),
            Operator::InitialRandomSeed => Some(&OPERAND_ZERO),
            Operator::StrokeWidth => Some(&OPERAND_ZERO),
            Operator::DefaultWidthX => Some(&OPERAND_ZERO),
            Operator::NominalWidthX => Some(&OPERAND_ZERO),
            _ => None,
        }
    }
}
impl<'a, T> Dict<T>
where
    T: DictDefault,
{
    pub fn new() -> Self {
        Dict {
            dict: Vec::new(),
            default: PhantomData,
        }
    }
    pub fn get_with_default(&self, key: Operator) -> Option<&[Operand]> {
        self.get(key).or_else(|| T::default(key))
    }
    pub fn get(&self, key: Operator) -> Option<&[Operand]> {
        self.dict.iter().find_map(|(op, args)| {
            if *op == key {
                Some(args.as_slice())
            } else {
                None
            }
        })
    }
    /// Returns the i32 value of this operator if the operands hold a single Integer.
    pub fn get_i32(&self, key: Operator) -> Option<Result<i32, ParseError>> {
        self.get_with_default(key).map(|operands| match operands {
            [Operand::Integer(number)] => Ok(*number),
            [Operand::Offset(number)] => Ok(*number),
            _ => Err(ParseError::BadValue),
        })
    }
    pub fn iter(&self) -> impl Iterator<Item = &(Operator, Vec<Operand>)> {
        self.dict.iter()
    }
    /// Returns the first operator of this DICT or `None` if the DICT is empty.
    pub fn first_operator(&self) -> Option<Operator> {
        self.iter().next().map(|(operator, _)| *operator)
    }
    /// Read a PrivateDict from this Dict returning it and its offset within `scope` on success.
    ///
    /// A Private DICT is required, but may be specified as having a length of 0 if there are no
    /// non-default values to be stored.
    pub fn read_private_dict<D: ReadBinaryDep<Args<'a> = usize>>(
        &self,
        scope: &ReadScope<'a>,
        max_operands: usize,
    ) -> Result<(D::HostType<'a>, usize), ParseError> {
        let (private_dict_offset, private_dict_length) =
            match self.get_with_default(Operator::Private) {
                Some([Operand::Offset(length), Operand::Offset(offset)]) => {
                    Ok((usize::try_from(*offset)?, usize::try_from(*length)?))
                }
                Some(_) => Err(ParseError::BadValue),
                None => Err(ParseError::MissingValue),
            }?;
        scope
            .offset_length(private_dict_offset, private_dict_length)?
            .read_dep::<D>(max_operands)
            .map(|dict| (dict, private_dict_offset))
    }
    pub fn len(&self) -> usize {
        self.dict.len()
    }
    fn inner_mut(&mut self) -> &mut Vec<(Operator, Vec<Operand>)> {
        &mut self.dict
    }
    fn remove(&mut self, operator: Operator) {
        if let Some(index) = self.dict.iter().position(|(op, _)| *op == operator) {
            self.dict.remove(index);
        }
    }
    /// Replace the entry in the DICT for `operator` with `operands`.
    ///
    /// If `operator` is not found then append it to the DICT.
    fn replace(&mut self, operator: Operator, operands: Vec<Operand>) {
        match self.dict.iter().position(|(op, _)| *op == operator) {
            Some(index) => self.dict[index] = (operator, operands),
            None => self.dict.push((operator, operands)),
        }
    }
    /// Apply variation data to this Dict according to `instance` to produce a new Dict.
    ///
    /// The new Dict is no longer variable and does not contain any vsindex or blend operators.
    fn instance(
        &self,
        instance: &OwnedTuple,
        vstore: &ItemVariationStore<'_>,
    ) -> Result<Self, VariationError> {
        let mut dict = Vec::new();
        let mut vsindex = 0;
        let mut stack = ArgumentsStack {
            data: &mut [0.0; cff2::MAX_OPERANDS],
            len: 0,
            max_len: cff2::MAX_OPERANDS,
        };
        for (op, operands) in self.iter() {
            match op {
                Operator::VSIndex => match operands.as_slice() {
                    [Operand::Integer(variation_index)] => vsindex = *variation_index,
                    _ => return Err(ParseError::BadValue.into()),
                },
                Operator::Blend => {
                    // do the blend, generating new operands for the following op to inherit
                    operands
                        .iter()
                        .try_for_each(|operand| stack.push(f32::try_from(operand)?))?;
                    let scalars = cff2::scalars(
                        u16::try_from(vsindex).map_err(ParseError::from)?,
                        vstore,
                        instance,
                    )?;
                    cff2::blend(&scalars, &mut stack)?;
                }
                _ if !stack.is_empty() => {
                    // The operator needs to operate on any blended operands on the stack in
                    // addition to any that were supplied to it. All operators except `blend` clear
                    // the stack:
                    //
                    // "In well-formed CFF2 data, the number of operands preceding a DICT key
                    // operator must be exactly the number required for that operator; hence, the
                    // stack will be empty after the operator is processed."
                    // Take all the operands, clearing out the stack at the same time
                    let mut new_operands = stack
                        .pop_all()
                        .iter()
                        .copied()
                        .map(Operand::from)
                        .collect::<Vec<_>>();
                    new_operands.extend(operands.iter().cloned());
                    dict.push((*op, new_operands));
                }
                _ => dict.push((*op, operands.clone())),
            }
        }
        Ok(Dict {
            dict,
            default: PhantomData,
        })
    }
}
impl BlendOperand for f32 {
    fn try_as_i32(self) -> Option<i32> {
        i32::try_num_from(self)
    }
    fn try_as_u16(self) -> Option<u16> {
        if self.fract() == 0.0 {
            u16::try_from(self as i32).ok()
        } else {
            None
        }
    }
    fn try_as_u8(self) -> Option<u8> {
        u8::try_num_from(self)
    }
}
impl DictDelta {
    pub fn new() -> Self {
        DictDelta { dict: Vec::new() }
    }
    pub fn get(&self, key: Operator) -> Option<&[Operand]> {
        self.dict
            .iter()
            .filter_map(|(op, args)| {
                if *op == key {
                    Some(args.as_slice())
                } else {
                    None
                }
            })
            .next()
    }
    /// Push `operator` on this Dict as an Offset Operand
    pub fn push_offset(&mut self, operator: Operator, offset: i32) {
        self.dict
            .push((operator, tiny_vec!([Operand; 1] => Operand::Offset(offset))))
    }
    /// Push `operands` onto this Dict
    ///
    /// Panics if all `operands` are not `Operand::Offsets`
    pub fn push(&mut self, operator: Operator, operands: TinyVec<[Operand; 1]>) {
        assert!(operands.iter().all(Operand::is_offset));
        self.dict.push((operator, operands))
    }
}
impl CIDData<'_> {
    pub fn font_dict(&self, index: usize) -> Result<FontDict, ParseError> {
        let data = self
            .font_dict_index
            .read_object(index)
            .ok_or(ParseError::BadIndex)?;
        ReadScope::new(data).read_dep::<FontDict>(MAX_OPERANDS)
    }
}
impl TryFrom<u16> for Operator {
    type Error = ParseError;
    fn try_from(value: u16) -> Result<Self, Self::Error> {
        if (value & 0xFF00) == (12 << 8) {
            match value as u8 {
                0 => Ok(Operator::Copyright),
                1 => Ok(Operator::IsFixedPitch),
                2 => Ok(Operator::ItalicAngle),
                3 => Ok(Operator::UnderlinePosition),
                4 => Ok(Operator::UnderlineThickness),
                5 => Ok(Operator::PaintType),
                6 => Ok(Operator::CharstringType),
                7 => Ok(Operator::FontMatrix),
                8 => Ok(Operator::StrokeWidth),
                9 => Ok(Operator::BlueScale),
                10 => Ok(Operator::BlueShift),
                11 => Ok(Operator::BlueFuzz),
                12 => Ok(Operator::StemSnapH),
                13 => Ok(Operator::StemSnapV),
                14 => Ok(Operator::ForceBold),
                17 => Ok(Operator::LanguageGroup),
                18 => Ok(Operator::ExpansionFactor),
                19 => Ok(Operator::InitialRandomSeed),
                20 => Ok(Operator::SyntheticBase),
                21 => Ok(Operator::PostScript),
                22 => Ok(Operator::BaseFontName),
                23 => Ok(Operator::BaseFontBlend),
                30 => Ok(Operator::ROS),
                31 => Ok(Operator::CIDFontVersion),
                32 => Ok(Operator::CIDFontRevision),
                33 => Ok(Operator::CIDFontType),
                34 => Ok(Operator::CIDCount),
                35 => Ok(Operator::UIDBase),
                36 => Ok(Operator::FDArray),
                37 => Ok(Operator::FDSelect),
                38 => Ok(Operator::FontName),
                _ => Err(ParseError::BadValue),
            }
        } else {
            match value {
                0 => Ok(Operator::Version),
                1 => Ok(Operator::Notice),
                2 => Ok(Operator::FullName),
                3 => Ok(Operator::FamilyName),
                4 => Ok(Operator::Weight),
                5 => Ok(Operator::FontBBox),
                6 => Ok(Operator::BlueValues),
                7 => Ok(Operator::OtherBlues),
                8 => Ok(Operator::FamilyBlues),
                9 => Ok(Operator::FamilyOtherBlues),
                10 => Ok(Operator::StdHW),
                11 => Ok(Operator::StdVW),
                13 => Ok(Operator::UniqueID),
                14 => Ok(Operator::XUID),
                15 => Ok(Operator::Charset),
                16 => Ok(Operator::Encoding),
                17 => Ok(Operator::CharStrings),
                18 => Ok(Operator::Private),
                19 => Ok(Operator::Subrs),
                20 => Ok(Operator::DefaultWidthX),
                21 => Ok(Operator::NominalWidthX),
                // CFF2
                22 => Ok(Operator::VSIndex),
                23 => Ok(Operator::Blend),
                24 => Ok(Operator::VStore),
                _ => Err(ParseError::BadValue),
            }
        }
    }
}
impl Operand {
    pub fn is_offset(&self) -> bool {
        matches!(self, Operand::Offset(_))
    }
    fn bcd_encode(buf: &mut TinyVec<[u8; 32]>, val: f32) -> Operand {
        if val == 0.0 {
            Operand::Integer(0)
        } else if val.fract() == 0.0 {
            Operand::Integer(val as i32)
        } else {
            // encode Real
            // https://learn.microsoft.com/en-us/typography/opentype/otspec191alpha/cff2#binary-coded-decimal
            buf.clear();
            // NOTE(unwrap): write into string won't return an error
            write!(buf, "{:E}", val).unwrap();
            // The formatter will always include an exponent. Drop it if it's "E0"
            if buf.ends_with(b"E0") {
                buf.truncate(buf.len() - 2);
            }
            let mut chars = buf.iter().peekable();
            let mut bcd = tiny_vec!([u8; 7]);
            let mut pair = array_vec!([u8; 2]);
            while let Some(c) = chars.next() {
                let nibble = match c {
                    b'0'..=b'9' => c - b'0',
                    b'.' => 0xA,
                    b'E' if chars.peek() == Some(&&b'-') => {
                        let _ = chars.next(); // discard '-'
                        0xC
                    }
                    b'E' => 0xB,
                    b'-' => 0xE,
                    _ => unreachable!(),
                };
                pair.push(nibble);
                if let [high, low] = pair.as_slice() {
                    bcd.push((high << 4) | low);
                    pair.clear();
                }
            }
            // Add the end of number sentinel
            match pair.as_slice() {
                // "If the terminating 0xf nibble is the first nibble of a byte, then an additional
                // 0xf nibble must be appended (hence, the byte is 0xff) so that the encoded
                // representation is always a whole number of bytes."
                [] => bcd.push(0xFF),
                [high] => bcd.push((high << 4) | 0xF),
                _ => unreachable!(),
            }
            Operand::Real(Real(bcd))
        }
    }
}
impl TryFrom<&Operand> for f32 {
    type Error = ParseError;
    fn try_from(operand: &Operand) -> Result<f32, Self::Error> {
        const MAX: i32 = 1 << f32::MANTISSA_DIGITS;
        const MIN: i32 = -MAX;
        match operand {
            Operand::Integer(int) | Operand::Offset(int) => (MIN..=MAX)
                .contains(int)
                .then_some(*int as f32)
                .ok_or(ParseError::LimitExceeded),
            Operand::Real(r) => f64::try_from(r).and_then(|val| {
                (f32::MIN as f64..=f32::MAX as f64)
                    .contains(&val)
                    .then_some(val as f32)
                    .ok_or(ParseError::LimitExceeded)
            }),
        }
    }
}
impl From<f32> for Operand {
    fn from(val: f32) -> Self {
        let mut buf = tiny_vec!([u8; 32]);
        Operand::bcd_encode(&mut buf, val)
    }
}
// This exists so that Operand can be used in a TinyVec
impl Default for Operand {
    fn default() -> Self {
        Operand::Offset(0)
    }
}
impl Font<'_> {
    pub fn is_cid_keyed(&self) -> bool {
        match self.data {
            CFFVariant::CID(_) => true,
            CFFVariant::Type1(_) => false,
        }
    }
    // seac = standard encoding accented character, makes an accented character from two other
    // characters.
    pub(crate) fn seac_code_to_glyph_id(&self, code: u8) -> Option<GlyphId> {
        let sid = STANDARD_ENCODING[usize::from(code)];
        match self.charset {
            Charset::ISOAdobe => {
                // ISO Adobe charset only defines string ids up to 228 (zcaron)
                if code <= 228 {
                    Some(u16::from(sid))
                } else {
                    None
                }
            }
            Charset::Expert | Charset::ExpertSubset => None,
            Charset::Custom(_) => self.charset.sid_to_gid(u16::from(sid)),
        }
    }
}
fn lookup_offset_index(off_size: u8, offset_array: &[u8], index: usize) -> usize {
    let buf = &offset_array[index * usize::from(off_size)..];
    match off_size {
        1 => buf[0] as usize,
        2 => u16::from_be_bytes([buf[0], buf[1]]) as usize,
        3 => u32::from_be_bytes([0, buf[0], buf[1], buf[2]]) as usize,
        4 => u32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]) as usize,
        _ => panic!("unexpected off_size"),
    }
}
fn read_range_array<'a, F, N>(
    ctxt: &mut ReadCtxt<'a>,
    n_glyphs: usize,
) -> Result<ReadArray<'a, Range<F, N>>, ParseError>
where
    Range<F, N>: ReadFrom,
    usize: From<N>,
    N: Copy,
{
    let mut peek = ctxt.scope().ctxt();
    let mut range_count = 0;
    let mut glyphs_covered = 0;
    while glyphs_covered < n_glyphs {
        let range = peek.read::<Range<F, N>>()?;
        range_count += 1;
        glyphs_covered += range.len();
    }
    ctxt.read_array::<Range<F, N>>(range_count)
}
fn write_cff_variant<C: WriteContext>(
    ctxt: &mut C,
    variant: &CFFVariant<'_>,
    top_dict_delta: &mut DictDelta,
) -> Result<(), WriteError> {
    match variant {
        CFFVariant::CID(cid_data) => {
            let offsets = CIDData::write(ctxt, cid_data)?;
            top_dict_delta.push_offset(Operator::FDArray, i32::try_from(offsets.font_dict_index)?);
            top_dict_delta.push_offset(Operator::FDSelect, i32::try_from(offsets.fd_select)?);
        }
        CFFVariant::Type1(type1_data) => {
            let offsets = Type1Data::write(ctxt, type1_data)?;
            if let Some(custom_encoding_offset) = offsets.custom_encoding {
                top_dict_delta
                    .push_offset(Operator::Encoding, i32::try_from(custom_encoding_offset)?);
            }
            top_dict_delta.push(
                Operator::Private,
                tiny_vec!([Operand; 1] =>
                    Operand::Offset(i32::try_from(offsets.private_dict_len)?),
                    Operand::Offset(i32::try_from(offsets.private_dict)?)),
            );
        }
    }
    Ok(())
}
// NOTE: Ideally the following read_* functions would ReadBinary or ReadBinaryDep impls.
// However we need to be able to indicate that the borrowed TopDict has a different lifetime
// to the other aspects, which is not currently possible.
// This post sums up the issue fairly well:
// https://lukaskalbertodt.github.io/2018/08/03/solving-the-generalized-streaming-iterator-problem-without-gats.html
// Rust tracking issue: https://github.com/rust-lang/rust/issues/44265
fn read_cid_data<'a>(
    scope: &ReadScope<'a>,
    top_dict: &TopDict,
    n_glyphs: usize,
) -> Result<CIDData<'a>, ParseError> {
    // The Top DICT begins with ROS operator
    // which specifies the Registry-Ordering-Supplement for the font.
    // This will indicate to a CFF parser that special CID processing
    // should be applied to this font. Specifically:
    //
    // • The FDArray operator is expected to be present, with a single
    //   argument specifying an offset to the Font DICT INDEX. Each
    //   Font DICT in this array specifies information unique to a
    //   particular group of glyphs in the font.
    let offset = top_dict
        .get_i32(Operator::FDArray)
        .ok_or(ParseError::MissingValue)??;
    let font_dict_index = scope.offset(usize::try_from(offset)?).read::<IndexU16>()?;
    let offset = top_dict
        .get_i32(Operator::FDSelect)
        .ok_or(ParseError::MissingValue)??;
    let fd_select = scope
        .offset(usize::try_from(offset)?)
        .read_dep::<FDSelect<'a>>(n_glyphs)?;
    let mut private_dicts = Vec::with_capacity(font_dict_index.count);
    let mut local_subr_indices = Vec::with_capacity(font_dict_index.count);
    for object in font_dict_index.iter() {
        let font_dict = ReadScope::new(object).read_dep::<FontDict>(MAX_OPERANDS)?;
        let (private_dict, private_dict_offset) =
            font_dict.read_private_dict::<PrivateDict>(scope, MAX_OPERANDS)?;
        let local_subr_index =
            read_local_subr_index::<_, IndexU16>(scope, &private_dict, private_dict_offset)?
                .map(MaybeOwnedIndex::Borrowed);
        private_dicts.push(private_dict);
        local_subr_indices.push(local_subr_index);
    }
    Ok(CIDData {
        font_dict_index: MaybeOwnedIndex::Borrowed(font_dict_index),
        private_dicts,
        local_subr_indices,
        fd_select,
    })
}
impl WriteBinary<&Self> for CIDData<'_> {
    type Output = CIDDataOffsets;
    fn write<C: WriteContext>(ctxt: &mut C, data: &Self) -> Result<Self::Output, WriteError> {
        // Private DICTs and Local subroutines
        let mut private_dict_offset_lengths = Vec::with_capacity(data.private_dicts.len());
        for (private_dict, local_subr_index) in data
            .private_dicts
            .iter()
            .zip(data.local_subr_indices.iter())
        {
            let offset = ctxt.bytes_written();
            let written_length =
                write_private_dict_and_local_subr_index(ctxt, private_dict, local_subr_index)?;
            private_dict_offset_lengths.push((offset, written_length));
        }
        // Font DICT INDEX
        let mut font_dict_data = WriteBuffer::new();
        let mut font_dict_offsets = Vec::with_capacity(data.font_dict_index.len());
        for (object, (offset, length)) in data
            .font_dict_index
            .iter()
            .zip(private_dict_offset_lengths.into_iter())
        {
            let font_dict = ReadScope::new(object)
                .read_dep::<FontDict>(MAX_OPERANDS)
                .map_err(|_err| WriteError::BadValue)?;
            let mut font_dict_delta = DictDelta::new();
            font_dict_delta.push(
                Operator::Private,
                tiny_vec!([Operand; 1] =>
                    Operand::Offset(i32::try_from(length)?),
                    Operand::Offset(i32::try_from(offset)?)),
            );
            font_dict_offsets.push(font_dict_data.bytes_written() + 1); // +1 INDEXes start at offset 1
            FontDict::write_dep(&mut font_dict_data, &font_dict, font_dict_delta)?;
        }
        let last_font_dict_offset = font_dict_data.bytes_written() + 1;
        font_dict_offsets.push(last_font_dict_offset);
        let (off_size, offset_array) = serialise_offset_array(font_dict_offsets)?;
        let font_dict_index = Index {
            count: data.font_dict_index.len(),
            off_size,
            offset_array: &offset_array,
            data_array: font_dict_data.bytes(),
        };
        let font_dict_index_offset = ctxt.bytes_written();
        IndexU16::write(ctxt, &font_dict_index)?;
        let fd_select_offset = ctxt.bytes_written();
        FDSelect::write(ctxt, &data.fd_select)?;
        Ok(CIDDataOffsets {
            font_dict_index: font_dict_index_offset,
            fd_select: fd_select_offset,
        })
    }
}
impl WriteBinary<&Self> for Type1Data<'_> {
    type Output = Type1DataOffsets;
    fn write<C: WriteContext>(ctxt: &mut C, data: &Self) -> Result<Self::Output, WriteError> {
        let mut offsets = Type1DataOffsets {
            custom_encoding: None,
            private_dict: ctxt.bytes_written(),
            private_dict_len: 0,
        };
        offsets.private_dict_len = write_private_dict_and_local_subr_index(
            ctxt,
            &data.private_dict,
            &data.local_subr_index,
        )?;
        if let Type1Data {
            encoding: Encoding::Custom(ref custom_encoding),
            ..
        } = data
        {
            offsets.custom_encoding = Some(ctxt.bytes_written());
            CustomEncoding::write(ctxt, custom_encoding)?;
        }
        Ok(offsets)
    }
}
/// Write the Private DICT and local subrs if present, returns the length of the Private DICT
fn write_private_dict_and_local_subr_index<C: WriteContext>(
    ctxt: &mut C,
    private_dict: &PrivateDict,
    local_subr_index: &Option<MaybeOwnedIndex<'_>>,
) -> Result<usize, WriteError> {
    // Determine how big the Private DICT will be
    let private_dict_length =
        PrivateDict::write_dep(&mut WriteCounter::new(), private_dict, DictDelta::new())?;
    // Write Private DICT with updated offset to Local subroutines if present
    let mut private_dict_delta = DictDelta::new();
    if local_subr_index.is_some() {
        // This offset is relative to the start of the Private DICT
        private_dict_delta.push_offset(Operator::Subrs, i32::try_from(private_dict_length)?);
    }
    let written_length = PrivateDict::write_dep(ctxt, private_dict, private_dict_delta)?;
    assert_eq!(written_length, private_dict_length);
    if let Some(local_subr_index) = local_subr_index {
        MaybeOwnedIndex::write16(ctxt, local_subr_index)?;
    }
    Ok(written_length)
}
fn read_encoding<'a>(
    scope: &ReadScope<'a>,
    top_dict: &TopDict,
) -> Result<Encoding<'a>, ParseError> {
    let offset = top_dict
        .get_i32(Operator::Encoding)
        .ok_or(ParseError::MissingValue)??;
    let encoding = match offset {
        0 => Encoding::Standard,
        1 => Encoding::Expert,
        _ => Encoding::Custom(
            scope
                .offset(usize::try_from(offset)?)
                .read::<CustomEncoding<'_>>()?,
        ),
    };
    Ok(encoding)
}
fn read_charset<'a>(
    scope: &ReadScope<'a>,
    top_dict: &TopDict,
    char_strings_count: usize,
) -> Result<Charset<'a>, ParseError> {
    let offset = top_dict
        .get_i32(Operator::Charset)
        .ok_or(ParseError::MissingValue)??;
    let charset = match offset {
        0 => Charset::ISOAdobe,
        1 => Charset::Expert,
        2 => Charset::ExpertSubset,
        _ => Charset::Custom(
            scope
                .offset(usize::try_from(offset)?)
                .read_dep::<CustomCharset<'_>>(char_strings_count)?,
        ),
    };
    Ok(charset)
}
fn read_local_subr_index<'a, T, Idx>(
    scope: &ReadScope<'a>,
    private_dict: &Dict<T>,
    private_dict_offset: usize,
) -> Result<Option<Index<'a>>, ParseError>
where
    T: DictDefault,
    Idx: ReadBinary<HostType<'a> = Index<'a>>,
{
    // Local subrs are stored in an INDEX structure which is located via the offset operand
    // of the Subrs operator in the Private DICT. A font without local subrs has no Subrs
    // operator in the Private DICT. The local subrs offset is relative to the beginning of
    // the Private DICT data.
    private_dict
        .get_i32(Operator::Subrs)
        .transpose()?
        .map(|offset| {
            let offset = usize::try_from(offset)?;
            scope.offset(private_dict_offset + offset).read::<Idx>()
        })
        .transpose()
}
/// Serialise the offsets using an optimal `off_size`, returning that and the serialised data.
fn serialise_offset_array(offsets: Vec<usize>) -> Result<(u8, Vec<u8>), WriteError> {
    if offsets.is_empty() {
        return Ok((1, Vec::new()));
    }
    // NOTE(unwrap): Safe due to is_empty check
    let off_size = offset_size(*offsets.last().unwrap()).ok_or(WriteError::BadValue)?;
    let mut offset_array = WriteBuffer::new();
    match off_size {
        1 => offset_array.write_iter::<U8, _>(offsets.into_iter().map(|offset| offset as u8))?,
        2 => {
            offset_array.write_iter::<U16Be, _>(offsets.into_iter().map(|offset| offset as u16))?
        }
        3 => {
            offset_array.write_iter::<U24Be, _>(offsets.into_iter().map(|offset| offset as u32))?
        }
        4 => {
            offset_array.write_iter::<U32Be, _>(offsets.into_iter().map(|offset| offset as u32))?
        }
        _ => unreachable!(), // offset_size only returns 1..=4
    }
    Ok((off_size, offset_array.into_inner()))
}
impl CFFFont<'_, '_> {
    pub fn is_cff(&self) -> bool {
        matches!(self, CFFFont::CFF(_))
    }
    pub fn is_cff2(&self) -> bool {
        matches!(self, CFFFont::CFF2(_))
    }
}
const STANDARD_STRINGS: [&str; 391] = [
    ".notdef",
    "space",
    "exclam",
    "quotedbl",
    "numbersign",
    "dollar",
    "percent",
    "ampersand",
    "quoteright",
    "parenleft",
    "parenright",
    "asterisk",
    "plus",
    "comma",
    "hyphen",
    "period",
    "slash",
    "zero",
    "one",
    "two",
    "three",
    "four",
    "five",
    "six",
    "seven",
    "eight",
    "nine",
    "colon",
    "semicolon",
    "less",
    "equal",
    "greater",
    "question",
    "at",
    "A",
    "B",
    "C",
    "D",
    "E",
    "F",
    "G",
    "H",
    "I",
    "J",
    "K",
    "L",
    "M",
    "N",
    "O",
    "P",
    "Q",
    "R",
    "S",
    "T",
    "U",
    "V",
    "W",
    "X",
    "Y",
    "Z",
    "bracketleft",
    "backslash",
    "bracketright",
    "asciicircum",
    "underscore",
    "quoteleft",
    "a",
    "b",
    "c",
    "d",
    "e",
    "f",
    "g",
    "h",
    "i",
    "j",
    "k",
    "l",
    "m",
    "n",
    "o",
    "p",
    "q",
    "r",
    "s",
    "t",
    "u",
    "v",
    "w",
    "x",
    "y",
    "z",
    "braceleft",
    "bar",
    "braceright",
    "asciitilde",
    "exclamdown",
    "cent",
    "sterling",
    "fraction",
    "yen",
    "florin",
    "section",
    "currency",
    "quotesingle",
    "quotedblleft",
    "guillemotleft",
    "guilsinglleft",
    "guilsinglright",
    "fi",
    "fl",
    "endash",
    "dagger",
    "daggerdbl",
    "periodcentered",
    "paragraph",
    "bullet",
    "quotesinglbase",
    "quotedblbase",
    "quotedblright",
    "guillemotright",
    "ellipsis",
    "perthousand",
    "questiondown",
    "grave",
    "acute",
    "circumflex",
    "tilde",
    "macron",
    "breve",
    "dotaccent",
    "dieresis",
    "ring",
    "cedilla",
    "hungarumlaut",
    "ogonek",
    "caron",
    "emdash",
    "AE",
    "ordfeminine",
    "Lslash",
    "Oslash",
    "OE",
    "ordmasculine",
    "ae",
    "dotlessi",
    "lslash",
    "oslash",
    "oe",
    "germandbls",
    "onesuperior",
    "logicalnot",
    "mu",
    "trademark",
    "Eth",
    "onehalf",
    "plusminus",
    "Thorn",
    "onequarter",
    "divide",
    "brokenbar",
    "degree",
    "thorn",
    "threequarters",
    "twosuperior",
    "registered",
    "minus",
    "eth",
    "multiply",
    "threesuperior",
    "copyright",
    "Aacute",
    "Acircumflex",
    "Adieresis",
    "Agrave",
    "Aring",
    "Atilde",
    "Ccedilla",
    "Eacute",
    "Ecircumflex",
    "Edieresis",
    "Egrave",
    "Iacute",
    "Icircumflex",
    "Idieresis",
    "Igrave",
    "Ntilde",
    "Oacute",
    "Ocircumflex",
    "Odieresis",
    "Ograve",
    "Otilde",
    "Scaron",
    "Uacute",
    "Ucircumflex",
    "Udieresis",
    "Ugrave",
    "Yacute",
    "Ydieresis",
    "Zcaron",
    "aacute",
    "acircumflex",
    "adieresis",
    "agrave",
    "aring",
    "atilde",
    "ccedilla",
    "eacute",
    "ecircumflex",
    "edieresis",
    "egrave",
    "iacute",
    "icircumflex",
    "idieresis",
    "igrave",
    "ntilde",
    "oacute",
    "ocircumflex",
    "odieresis",
    "ograve",
    "otilde",
    "scaron",
    "uacute",
    "ucircumflex",
    "udieresis",
    "ugrave",
    "yacute",
    "ydieresis",
    "zcaron",
    "exclamsmall",
    "Hungarumlautsmall",
    "dollaroldstyle",
    "dollarsuperior",
    "ampersandsmall",
    "Acutesmall",
    "parenleftsuperior",
    "parenrightsuperior",
    "twodotenleader",
    "onedotenleader",
    "zerooldstyle",
    "oneoldstyle",
    "twooldstyle",
    "threeoldstyle",
    "fouroldstyle",
    "fiveoldstyle",
    "sixoldstyle",
    "sevenoldstyle",
    "eightoldstyle",
    "nineoldstyle",
    "commasuperior",
    "threequartersemdash",
    "periodsuperior",
    "questionsmall",
    "asuperior",
    "bsuperior",
    "centsuperior",
    "dsuperior",
    "esuperior",
    "isuperior",
    "lsuperior",
    "msuperior",
    "nsuperior",
    "osuperior",
    "rsuperior",
    "ssuperior",
    "tsuperior",
    "ff",
    "ffi",
    "ffl",
    "parenleftinferior",
    "parenrightinferior",
    "Circumflexsmall",
    "hyphensuperior",
    "Gravesmall",
    "Asmall",
    "Bsmall",
    "Csmall",
    "Dsmall",
    "Esmall",
    "Fsmall",
    "Gsmall",
    "Hsmall",
    "Ismall",
    "Jsmall",
    "Ksmall",
    "Lsmall",
    "Msmall",
    "Nsmall",
    "Osmall",
    "Psmall",
    "Qsmall",
    "Rsmall",
    "Ssmall",
    "Tsmall",
    "Usmall",
    "Vsmall",
    "Wsmall",
    "Xsmall",
    "Ysmall",
    "Zsmall",
    "colonmonetary",
    "onefitted",
    "rupiah",
    "Tildesmall",
    "exclamdownsmall",
    "centoldstyle",
    "Lslashsmall",
    "Scaronsmall",
    "Zcaronsmall",
    "Dieresissmall",
    "Brevesmall",
    "Caronsmall",
    "Dotaccentsmall",
    "Macronsmall",
    "figuredash",
    "hypheninferior",
    "Ogoneksmall",
    "Ringsmall",
    "Cedillasmall",
    "questiondownsmall",
    "oneeighth",
    "threeeighths",
    "fiveeighths",
    "seveneighths",
    "onethird",
    "twothirds",
    "zerosuperior",
    "foursuperior",
    "fivesuperior",
    "sixsuperior",
    "sevensuperior",
    "eightsuperior",
    "ninesuperior",
    "zeroinferior",
    "oneinferior",
    "twoinferior",
    "threeinferior",
    "fourinferior",
    "fiveinferior",
    "sixinferior",
    "seveninferior",
    "eightinferior",
    "nineinferior",
    "centinferior",
    "dollarinferior",
    "periodinferior",
    "commainferior",
    "Agravesmall",
    "Aacutesmall",
    "Acircumflexsmall",
    "Atildesmall",
    "Adieresissmall",
    "Aringsmall",
    "AEsmall",
    "Ccedillasmall",
    "Egravesmall",
    "Eacutesmall",
    "Ecircumflexsmall",
    "Edieresissmall",
    "Igravesmall",
    "Iacutesmall",
    "Icircumflexsmall",
    "Idieresissmall",
    "Ethsmall",
    "Ntildesmall",
    "Ogravesmall",
    "Oacutesmall",
    "Ocircumflexsmall",
    "Otildesmall",
    "Odieresissmall",
    "OEsmall",
    "Oslashsmall",
    "Ugravesmall",
    "Uacutesmall",
    "Ucircumflexsmall",
    "Udieresissmall",
    "Yacutesmall",
    "Thornsmall",
    "Ydieresissmall",
    "001.000",
    "001.001",
    "001.002",
    "001.003",
    "Black",
    "Bold",
    "Book",
    "Light",
    "Medium",
    "Regular",
    "Roman",
    "Semibold",
];
#[allow(dead_code)]
const STANDARD_ENCODING: [u8; 256] = [
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    1,   // space
    2,   // exclam
    3,   // quotedbl
    4,   // numbersign
    5,   // dollar
    6,   // percent
    7,   // ampersand
    8,   // quoteright
    9,   // parenleft
    10,  // parenright
    11,  // asterisk
    12,  // plus
    13,  // comma
    14,  // hyphen
    15,  // period
    16,  // slash
    17,  // zero
    18,  // one
    19,  // two
    20,  // three
    21,  // four
    22,  // five
    23,  // six
    24,  // seven
    25,  // eight
    26,  // nine
    27,  // colon
    28,  // semicolon
    29,  // less
    30,  // equal
    31,  // greater
    32,  // question
    33,  // at
    34,  // A
    35,  // B
    36,  // C
    37,  // D
    38,  // E
    39,  // F
    40,  // G
    41,  // H
    42,  // I
    43,  // J
    44,  // K
    45,  // L
    46,  // M
    47,  // N
    48,  // O
    49,  // P
    50,  // Q
    51,  // R
    52,  // S
    53,  // T
    54,  // U
    55,  // V
    56,  // W
    57,  // X
    58,  // Y
    59,  // Z
    60,  // bracketleft
    61,  // backslash
    62,  // bracketright
    63,  // asciicircum
    64,  // underscore
    65,  // quoteleft
    66,  // a
    67,  // b
    68,  // c
    69,  // d
    70,  // e
    71,  // f
    72,  // g
    73,  // h
    74,  // i
    75,  // j
    76,  // k
    77,  // l
    78,  // m
    79,  // n
    80,  // o
    81,  // p
    82,  // q
    83,  // r
    84,  // s
    85,  // t
    86,  // u
    87,  // v
    88,  // w
    89,  // x
    90,  // y
    91,  // z
    92,  // braceleft
    93,  // bar
    94,  // braceright
    95,  // asciitilde
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    96,  // exclamdown
    97,  // cent
    98,  // sterling
    99,  // fraction
    100, // yen
    101, // florin
    102, // section
    103, // currency
    104, // quotesingle
    105, // quotedblleft
    106, // guillemotleft
    107, // guilsinglleft
    108, // guilsinglright
    109, // fi
    110, // fl
    0,   // .notdef
    111, // endash
    112, // dagger
    113, // daggerdbl
    114, // periodcentered
    0,   // .notdef
    115, // paragraph
    116, // bullet
    117, // quotesinglbase
    118, // quotedblbase
    119, // quotedblright
    120, // guillemotright
    121, // ellipsis
    122, // perthousand
    0,   // .notdef
    123, // questiondown
    0,   // .notdef
    124, // grave
    125, // acute
    126, // circumflex
    127, // tilde
    128, // macron
    129, // breve
    130, // dotaccent
    131, // dieresis
    0,   // .notdef
    132, // ring
    133, // cedilla
    0,   // .notdef
    134, // hungarumlaut
    135, // ogonek
    136, // caron
    137, // emdash
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    138, // AE
    0,   // .notdef
    139, // ordfeminine
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    140, // Lslash
    141, // Oslash
    142, // OE
    143, // ordmasculine
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    144, // ae
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    145, // dotlessi
    0,   // .notdef
    0,   // .notdef
    146, // lslash
    147, // oslash
    148, // oe
    149, // germandbls
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
    0,   // .notdef
];
const EXPERT_CHARSET: [u16; 166] = [
    0,   // .notdef
    1,   // space
    229, // exclamsmall
    230, // Hungarumlautsmall
    231, // dollaroldstyle
    232, // dollarsuperior
    233, // ampersandsmall
    234, // Acutesmall
    235, // parenleftsuperior
    236, // parenrightsuperior
    237, // twodotenleader
    238, // onedotenleader
    13,  // comma
    14,  // hyphen
    15,  // period
    99,  // fraction
    239, // zerooldstyle
    240, // oneoldstyle
    241, // twooldstyle
    242, // threeoldstyle
    243, // fouroldstyle
    244, // fiveoldstyle
    245, // sixoldstyle
    246, // sevenoldstyle
    247, // eightoldstyle
    248, // nineoldstyle
    27,  // colon
    28,  // semicolon
    249, // commasuperior
    250, // threequartersemdash
    251, // periodsuperior
    252, // questionsmall
    253, // asuperior
    254, // bsuperior
    255, // centsuperior
    256, // dsuperior
    257, // esuperior
    258, // isuperior
    259, // lsuperior
    260, // msuperior
    261, // nsuperior
    262, // osuperior
    263, // rsuperior
    264, // ssuperior
    265, // tsuperior
    266, // ff
    109, // fi
    110, // fl
    267, // ffi
    268, // ffl
    269, // parenleftinferior
    270, // parenrightinferior
    271, // Circumflexsmall
    272, // hyphensuperior
    273, // Gravesmall
    274, // Asmall
    275, // Bsmall
    276, // Csmall
    277, // Dsmall
    278, // Esmall
    279, // Fsmall
    280, // Gsmall
    281, // Hsmall
    282, // Ismall
    283, // Jsmall
    284, // Ksmall
    285, // Lsmall
    286, // Msmall
    287, // Nsmall
    288, // Osmall
    289, // Psmall
    290, // Qsmall
    291, // Rsmall
    292, // Ssmall
    293, // Tsmall
    294, // Usmall
    295, // Vsmall
    296, // Wsmall
    297, // Xsmall
    298, // Ysmall
    299, // Zsmall
    300, // colonmonetary
    301, // onefitted
    302, // rupiah
    303, // Tildesmall
    304, // exclamdownsmall
    305, // centoldstyle
    306, // Lslashsmall
    307, // Scaronsmall
    308, // Zcaronsmall
    309, // Dieresissmall
    310, // Brevesmall
    311, // Caronsmall
    312, // Dotaccentsmall
    313, // Macronsmall
    314, // figuredash
    315, // hypheninferior
    316, // Ogoneksmall
    317, // Ringsmall
    318, // Cedillasmall
    158, // onequarter
    155, // onehalf
    163, // threequarters
    319, // questiondownsmall
    320, // oneeighth
    321, // threeeighths
    322, // fiveeighths
    323, // seveneighths
    324, // onethird
    325, // twothirds
    326, // zerosuperior
    150, // onesuperior
    164, // twosuperior
    169, // threesuperior
    327, // foursuperior
    328, // fivesuperior
    329, // sixsuperior
    330, // sevensuperior
    331, // eightsuperior
    332, // ninesuperior
    333, // zeroinferior
    334, // oneinferior
    335, // twoinferior
    336, // threeinferior
    337, // fourinferior
    338, // fiveinferior
    339, // sixinferior
    340, // seveninferior
    341, // eightinferior
    342, // nineinferior
    343, // centinferior
    344, // dollarinferior
    345, // periodinferior
    346, // commainferior
    347, // Agravesmall
    348, // Aacutesmall
    349, // Acircumflexsmall
    350, // Atildesmall
    351, // Adieresissmall
    352, // Aringsmall
    353, // AEsmall
    354, // Ccedillasmall
    355, // Egravesmall
    356, // Eacutesmall
    357, // Ecircumflexsmall
    358, // Edieresissmall
    359, // Igravesmall
    360, // Iacutesmall
    361, // Icircumflexsmall
    362, // Idieresissmall
    363, // Ethsmall
    364, // Ntildesmall
    365, // Ogravesmall
    366, // Oacutesmall
    367, // Ocircumflexsmall
    368, // Otildesmall
    369, // Odieresissmall
    370, // OEsmall
    371, // Oslashsmall
    372, // Ugravesmall
    373, // Uacutesmall
    374, // Ucircumflexsmall
    375, // Udieresissmall
    376, // Yacutesmall
    377, // Thornsmall
    378, // Ydieresissmall
];
const EXPERT_SUBSET_CHARSET: [u16; 87] = [
    0,   // .notdef
    1,   // space
    231, // dollaroldstyle
    232, // dollarsuperior
    235, // parenleftsuperior
    236, // parenrightsuperior
    237, // twodotenleader
    238, // onedotenleader
    13,  // comma
    14,  // hyphen
    15,  // period
    99,  // fraction
    239, // zerooldstyle
    240, // oneoldstyle
    241, // twooldstyle
    242, // threeoldstyle
    243, // fouroldstyle
    244, // fiveoldstyle
    245, // sixoldstyle
    246, // sevenoldstyle
    247, // eightoldstyle
    248, // nineoldstyle
    27,  // colon
    28,  // semicolon
    249, // commasuperior
    250, // threequartersemdash
    251, // periodsuperior
    253, // asuperior
    254, // bsuperior
    255, // centsuperior
    256, // dsuperior
    257, // esuperior
    258, // isuperior
    259, // lsuperior
    260, // msuperior
    261, // nsuperior
    262, // osuperior
    263, // rsuperior
    264, // ssuperior
    265, // tsuperior
    266, // ff
    109, // fi
    110, // fl
    267, // ffi
    268, // ffl
    269, // parenleftinferior
    270, // parenrightinferior
    272, // hyphensuperior
    300, // colonmonetary
    301, // onefitted
    302, // rupiah
    305, // centoldstyle
    314, // figuredash
    315, // hypheninferior
    158, // onequarter
    155, // onehalf
    163, // threequarters
    320, // oneeighth
    321, // threeeighths
    322, // fiveeighths
    323, // seveneighths
    324, // onethird
    325, // twothirds
    326, // zerosuperior
    150, // onesuperior
    164, // twosuperior
    169, // threesuperior
    327, // foursuperior
    328, // fivesuperior
    329, // sixsuperior
    330, // sevensuperior
    331, // eightsuperior
    332, // ninesuperior
    333, // zeroinferior
    334, // oneinferior
    335, // twoinferior
    336, // threeinferior
    337, // fourinferior
    338, // fiveinferior
    339, // sixinferior
    340, // seveninferior
    341, // eightinferior
    342, // nineinferior
    343, // centinferior
    344, // dollarinferior
    345, // periodinferior
    346, // commainferior
];
#[cfg(test)]
mod tests {
    use super::*;
    use crate::binary::read::ReadScope;
    fn assert_close(actual: f64, expected: f64) {
        assert!(
            (actual - expected).abs() < f64::EPSILON,
            "{:?} != {:?} ± {}",
            actual,
            expected,
            f64::EPSILON
        );
    }
    #[test]
    fn test_iter_index() {
        let offset_array = [1, 2, 3];
        let data_array = [4, 5];
        let index = Index {
            count: 2,
            off_size: 1,
            offset_array: &offset_array,
            data_array: &data_array,
        };
        assert_eq!(index.iter().collect::<Vec<_>>(), vec![[4], [5]]);
    }
    #[test]
    fn test_read_op1() {
        let mut ctxt = ReadScope::new(&[0, 0]).ctxt();
        assert_eq!(
            Op::read(&mut ctxt).unwrap(),
            Op::Operator(Operator::Version)
        );
    }
    #[test]
    fn test_fail_op1() {
        let mut ctxt = ReadScope::new(&[]).ctxt();
        assert!(Op::read(&mut ctxt).is_err());
    }
    #[test]
    fn test_read_op2() {
        let mut ctxt = ReadScope::new(&[12, 1]).ctxt();
        assert_eq!(
            Op::read(&mut ctxt).unwrap(),
            Op::Operator(Operator::IsFixedPitch)
        );
    }
    #[test]
    fn test_fail_op2() {
        let mut ctxt = ReadScope::new(&[12]).ctxt();
        assert!(Op::read(&mut ctxt).is_err());
    }
    #[test]
    fn test_read_i8() {
        let mut ctxt = ReadScope::new(&[0x8b]).ctxt();
        assert_eq!(
            Op::read(&mut ctxt).unwrap(),
            Op::Operand(Operand::Integer(0))
        );
    }
    #[test]
    fn test_read_i16() {
        //                             _____-10000______  ______10000_____  100   -100
        let mut ctxt = ReadScope::new(&[0x1c, 0xd8, 0xf0, 0x1c, 0x27, 0x10, 0xef, 0x27]).ctxt();
        assert_eq!(
            Op::read(&mut ctxt).unwrap(),
            Op::Operand(Operand::Integer(-10000))
        );
        assert_eq!(
            Op::read(&mut ctxt).unwrap(),
            Op::Operand(Operand::Integer(10000))
        );
        assert_eq!(
            Op::read(&mut ctxt).unwrap(),
            Op::Operand(Operand::Integer(100))
        );
        assert_eq!(
            Op::read(&mut ctxt).unwrap(),
            Op::Operand(Operand::Integer(-100))
        );
    }
    #[test]
    fn test_read_i32() {
        //                   __________-100000___________  ____________100000__________
        let mut ctxt =
            ReadScope::new(&[0x1d, 0xff, 0xfe, 0x79, 0x60, 0x1d, 0x00, 0x01, 0x86, 0xa0]).ctxt();
        assert_eq!(
            Op::read(&mut ctxt).unwrap(),
            Op::Operand(Operand::Integer(-100000))
        );
        assert_eq!(
            Op::read(&mut ctxt).unwrap(),
            Op::Operand(Operand::Integer(100000))
        );
    }
    #[test]
    fn test_read_real() {
        // From the spec:
        // Thus, the value –2.25 is encoded by the byte sequence (1e e2 a2 5f) and the value
        // 0.140541E–3 by the sequence (1e 0a 14 05 41 c3 ff).
        let mut ctxt = ReadScope::new(&[
            // ______-2.25________  _______________0.140541E–3______________
            0x1e, 0xe2, 0xa2, 0x5f, 0x1e, 0x0a, 0x14, 0x05, 0x41, 0xc3, 0xff,
        ])
        .ctxt();
        let op = Op::read(&mut ctxt).unwrap();
        assert_eq!(
            op,
            Op::Operand(Operand::Real(Real(tiny_vec![0xe2, 0xa2, 0x5f])))
        );
        let Op::Operand(Operand::Real(real)) = op else {
            panic!("op didn't match Real")
        };
        assert_close(f64::try_from(&real).unwrap(), -2.25);
        let op = Op::read(&mut ctxt).unwrap();
        assert_eq!(
            op,
            Op::Operand(Operand::Real(Real(tiny_vec![
                0x0a, 0x14, 0x05, 0x41, 0xc3, 0xff
            ])))
        );
        let Op::Operand(Operand::Real(real)) = op else {
            panic!("op didn't match Real")
        };
        assert_close(f64::try_from(&real).unwrap(), 0.000140541);
    }
    #[test]
    fn test_read_top_dict() {
        let expected = TopDict {
            dict: vec![
                (Operator::IsFixedPitch, vec![Operand::Integer(1)]),
                (Operator::Notice, vec![Operand::Integer(123)]),
            ],
            default: PhantomData,
        };
        // IsFixedPitch (12 1) is true (1)
        // Notice (1) SID is 123
        //                              _1__         __123__
        let mut ctxt = ReadScope::new(&[0x8c, 12, 1, 247, 15, 1]).ctxt();
        assert_eq!(
            TopDict::read_dep(&mut ctxt, MAX_OPERANDS).unwrap(),
            expected
        );
    }
    #[test]
    fn test_write_top_dict() {
        let dict = TopDict {
            dict: vec![
                (Operator::IsFixedPitch, vec![Operand::Integer(1)]),
                (Operator::Notice, vec![Operand::Integer(123)]),
                // This one is omitted in the output because it is the default for this operator
                (Operator::PaintType, vec![Operand::Integer(0)]),
            ],
            default: PhantomData,
        };
        // IsFixedPitch Op2(1) is true (1)
        // Notice Op1(1) SID is 123
        //              _1__  Op2(1) __123__  Op1(1)
        let expected = [0x8c, 12, 1, 247, 15, 1];
        let mut ctxt = WriteBuffer::new();
        TopDict::write_dep(&mut ctxt, &dict, DictDelta::new()).unwrap();
        assert_eq!(ctxt.bytes(), &expected);
    }
    #[test]
    fn test_write_top_dict_delta() {
        let dict = TopDict {
            dict: vec![(Operator::CharStrings, vec![Operand::Offset(123)])],
            default: PhantomData,
        };
        let mut delta = DictDelta::new();
        delta.push(
            Operator::CharStrings,
            tiny_vec!([Operand; 1] => Operand::Offset(1000)),
        );
        // CharStrings is operator 17 and takes an offset (number as operand)
        // Offsets are always written out using the 5 byte representation
        //              _______1000_________
        let expected = [29, 0, 0, 0x03, 0xE8, 17];
        let mut ctxt = WriteBuffer::new();
        TopDict::write_dep(&mut ctxt, &dict, delta).unwrap();
        // It's expected that the delta value is used instead of the dict value
        assert_eq!(ctxt.bytes(), &expected);
    }
    #[test]
    fn test_write_top_dict_size() {
        let dict = TopDict {
            dict: vec![
                (Operator::IsFixedPitch, vec![Operand::Integer(1)]),
                (Operator::Notice, vec![Operand::Integer(123)]),
                // This one is omitted in the output because it is the default for this operator
                (Operator::PaintType, vec![Operand::Integer(0)]),
            ],
            default: PhantomData,
        };
        let mut counter = WriteCounter::new();
        TopDict::write_dep(&mut counter, &dict, DictDelta::new()).unwrap();
        assert_eq!(counter.bytes_written(), 6);
    }
    #[test]
    fn test_read_top_dict_operand_limit() {
        let mut ctxt = ReadScope::new(&[0x8c; 2]).ctxt();
        match TopDict::read_dep(&mut ctxt, 1) {
            Err(ParseError::LimitExceeded) => {}
            _ => panic!("expected Err(ParseError::LimitExceeded) got something else"),
        }
    }
    #[test]
    fn test_read_empty_private_dict() {
        // A Private DICT is required, but may be specified as having a length of 0 if there are
        // no non-default values to be stored.
        let dict = ReadScope::new(&[]).read_dep::<PrivateDict>(MAX_OPERANDS);
        assert!(dict.is_ok());
    }
    #[test]
    fn test_read_custom_encoding_format0() {
        let data_format0 = [0, 3, 4, 5, 6];
        let mut ctxt = ReadScope::new(&data_format0).ctxt();
        let format0_encoding = ctxt.read::<CustomEncoding<'_>>().unwrap();
        match format0_encoding {
            CustomEncoding::Format0 { codes } => {
                assert_eq!(codes.iter().collect::<Vec<_>>(), vec![4, 5, 6])
            }
            _ => panic!("expected CustomEncoding::Format0 got something else"),
        }
    }
    #[test]
    fn test_read_custom_encoding_format1() {
        let data_format1 = [1, 2, 4, 5, 6, 7];
        let mut ctxt = ReadScope::new(&data_format1).ctxt();
        let format1_encoding = ctxt.read::<CustomEncoding<'_>>().unwrap();
        match format1_encoding {
            CustomEncoding::Format1 { ranges } => assert_eq!(
                ranges.iter().collect::<Vec<_>>(),
                vec![
                    Range {
                        first: 4,
                        n_left: 5
                    },
                    Range {
                        first: 6,
                        n_left: 7
                    }
                ]
            ),
            _ => panic!("expected CustomEncoding::Format1 got something else"),
        }
    }
    #[test]
    fn test_read_custom_charset_format0() {
        let n_glyphs = 2;
        let data_format0 = [0, 0xAA, 0xBB];
        let mut ctxt = ReadScope::new(&data_format0).ctxt();
        let format0_charset = ctxt.read_dep::<CustomCharset<'_>>(n_glyphs).unwrap();
        match format0_charset {
            CustomCharset::Format0 { glyphs } => {
                assert_eq!(glyphs.iter().collect::<Vec<_>>(), vec![0xAABB])
            }
            _ => panic!("expected CustomCharset::Format0 got something else"),
        }
    }
    #[test]
    fn test_read_custom_charset_format1() {
        let n_glyphs = 5;
        let data_format1 = [1, 0, 1, 3];
        let mut ctxt = ReadScope::new(&data_format1).ctxt();
        let format1_charset = ctxt.read_dep::<CustomCharset<'_>>(n_glyphs).unwrap();
        match format1_charset {
            CustomCharset::Format1 { ranges } => assert_eq!(
                ranges.iter().collect::<Vec<_>>(),
                vec![Range {
                    first: 1,
                    n_left: 3
                },]
            ),
            _ => panic!("expected CustomCharset::Format1 got something else"),
        }
    }
    #[test]
    fn test_read_custom_charset_format2() {
        let n_glyphs = 5;
        let data_format2 = [2, 0, 1, 0, 3];
        let mut ctxt = ReadScope::new(&data_format2).ctxt();
        let format2_charset = ctxt.read_dep::<CustomCharset<'_>>(n_glyphs).unwrap();
        match format2_charset {
            CustomCharset::Format2 { ranges } => assert_eq!(
                ranges.iter().collect::<Vec<_>>(),
                vec![Range {
                    first: 1,
                    n_left: 3
                },]
            ),
            _ => panic!("expected CustomCharset::Format2 got something else"),
        }
    }
    #[test]
    fn test_read_write_index() {
        let mut count = vec![0, 1];
        let off_size = 3;
        let mut offset0 = vec![0, 0, 1];
        let mut offset1 = vec![0, 0, 2];
        let object = 5;
        // The data is built up like so it's easier to see what each value represents
        let mut data = Vec::new();
        data.append(&mut count);
        data.push(off_size);
        data.append(&mut offset0);
        data.append(&mut offset1);
        data.push(object);
        // Read
        let mut ctxt = ReadScope::new(&data).ctxt();
        let index = ctxt.read::<IndexU16>().unwrap();
        let actual: Vec<_> = index.iter().collect();
        assert_eq!(actual, &[&[5]]);
        // Write
        let mut ctxt = WriteBuffer::new();
        IndexU16::write(&mut ctxt, &index).unwrap();
        assert_eq!(ctxt.bytes(), &[0, 1, 3, 0, 0, 1, 0, 0, 2, 5]);
    }
    #[test]
    fn test_write_int_operand() {
        assert_eq!(write_int_operand(0), &[0x8b]);
        assert_eq!(write_int_operand(100), &[0xef]);
        assert_eq!(write_int_operand(-100), &[0x27]);
        assert_eq!(write_int_operand(1000), &[0xfa, 0x7c]);
        assert_eq!(write_int_operand(-1000), &[0xfe, 0x7c]);
        assert_eq!(write_int_operand(10000), &[0x1c, 0x27, 0x10]);
        assert_eq!(write_int_operand(-10000), &[0x1c, 0xd8, 0xf0]);
        assert_eq!(write_int_operand(100000), &[0x1d, 0x00, 0x01, 0x86, 0xa0]);
        assert_eq!(write_int_operand(-100000), &[0x1d, 0xff, 0xfe, 0x79, 0x60]);
    }
    #[test]
    fn test_write_int_operand_round_trip() {
        int_operand_round_trip(0);
        int_operand_round_trip(100);
        int_operand_round_trip(540);
        int_operand_round_trip(-100);
        int_operand_round_trip(-267);
        int_operand_round_trip(1000);
        int_operand_round_trip(-1000);
        int_operand_round_trip(10000);
        int_operand_round_trip(-10000);
        int_operand_round_trip(100000);
        int_operand_round_trip(-100000);
    }
    fn int_operand_round_trip(val: i32) {
        let int = write_int_operand(val);
        match ReadScope::new(&int).read::<Op>().unwrap() {
            Op::Operand(Operand::Integer(actual)) => assert_eq!(actual, val),
            _ => unreachable!(),
        }
    }
    fn write_int_operand(val: i32) -> Vec<u8> {
        let mut ctxt = WriteBuffer::new();
        Operand::write(&mut ctxt, &Operand::Integer(val)).unwrap();
        ctxt.into_inner()
    }
    #[test]
    fn test_fd_select_font_dict_index_format0() {
        let glyph_font_dict_indices = ReadArrayCow::Owned(vec![1, 2, 3]);
        let fd_select = FDSelect::Format0 {
            glyph_font_dict_indices,
        };
        assert_eq!(fd_select.font_dict_index(2), Some(3));
        assert_eq!(fd_select.font_dict_index(3), None);
    }
    #[test]
    fn test_fd_select_font_dict_index_format3() {
        // Set up 3 ranges:
        //  0..10 -> Font DICT index 2
        // 10..17 -> Font DICT index 1
        // 17..33 -> Font DICT index 0
        let ranges: Vec<Range<u16, u8>> = vec![
            Range {
                first: 0,
                n_left: 2,
            },
            Range {
                first: 10,
                n_left: 1,
            },
            Range {
                first: 17,
                n_left: 0,
            },
        ];
        let fd_select = FDSelect::Format3 {
            ranges: ReadArrayCow::Owned(ranges),
            sentinel: 33,
        };
        assert_eq!(fd_select.font_dict_index(2), Some(2));
        assert_eq!(fd_select.font_dict_index(10), Some(1));
        assert_eq!(fd_select.font_dict_index(32), Some(0));
        assert_eq!(fd_select.font_dict_index(33), None);
    }
    #[test]
    fn test_charset_id_for_glyph_pre_defined_charsets() {
        assert_eq!(Charset::ISOAdobe.id_for_glyph(2), Some(2));
        assert_eq!(Charset::ISOAdobe.id_for_glyph(300), None);
        assert_eq!(Charset::Expert.id_for_glyph(2), Some(229));
        assert_eq!(Charset::Expert.id_for_glyph(300), None);
        assert_eq!(Charset::ExpertSubset.id_for_glyph(2), Some(231));
        assert_eq!(Charset::ExpertSubset.id_for_glyph(300), None);
    }
    #[test]
    fn test_custom_charset_id_for_glyph_format0() {
        let glyph_sids = ReadArrayCow::Owned(vec![1, 2, 3]);
        let charset = CustomCharset::Format0 { glyphs: glyph_sids };
        // glyph id 0 is .notdef and is implicitly encoded
        assert_eq!(charset.id_for_glyph(0), Some(0));
        assert_eq!(charset.id_for_glyph(1), Some(1));
        assert_eq!(charset.id_for_glyph(4), None);
    }
    #[test]
    fn test_custom_charset_id_for_glyph_format1() {
        let ranges = ReadArrayCow::Owned(vec![Range {
            first: 34,
            n_left: 5,
        }]);
        let charset = CustomCharset::Format1 { ranges };
        // glyph id 0 is .notdef and is implicitly encoded
        assert_eq!(charset.id_for_glyph(0), Some(0));
        assert_eq!(charset.id_for_glyph(1), Some(34));
        assert_eq!(charset.id_for_glyph(6), Some(39));
        assert_eq!(charset.id_for_glyph(7), None);
    }
    #[test]
    fn test_custom_charset_id_for_glyph_format2() {
        let ranges = ReadArrayCow::Owned(vec![Range {
            first: 34,
            n_left: 5,
        }]);
        let charset = CustomCharset::Format2 { ranges };
        // glyph id 0 is .notdef and is implicitly encoded
        assert_eq!(charset.id_for_glyph(0), Some(0));
        assert_eq!(charset.id_for_glyph(1), Some(34));
        assert_eq!(charset.id_for_glyph(6), Some(39));
        assert_eq!(charset.id_for_glyph(7), None);
    }
    #[test]
    fn test_arno_custom_charset_ranges() {
        // These ranges are from the ArnoPro-Regular font and are in the same order they are in the
        // font.
        #[rustfmt::skip]
        let ranges = ReadArrayCow::Owned(vec![
            Range { first: 1, n_left: 107, },
            Range { first: 111, n_left: 38, },
            Range { first: 151, n_left: 12, },
            Range { first: 165, n_left: 3, },
            Range { first: 170, n_left: 58, },
            Range { first: 237, n_left: 1, },
            Range { first: 391, n_left: 0, },
            Range { first: 393, n_left: 0, },
            Range { first: 300, n_left: 0, },
            Range { first: 392, n_left: 0, },
            Range { first: 314, n_left: 0, },
            Range { first: 324, n_left: 1, },
            Range { first: 320, n_left: 3, },
            Range { first: 394, n_left: 2577, },
            Range { first: 109, n_left: 1, },
            Range { first: 2972, n_left: 28, },
            Range { first: 2846, n_left: 768, },
        ]);
        let charset = CustomCharset::Format2 { ranges };
        // glyph id 0 is .notdef and is implicitly encoded
        assert_eq!(charset.id_for_glyph(134), Some(136));
        assert_eq!(charset.id_for_glyph(265), Some(422));
        assert_eq!(charset.id_for_glyph(279), Some(436));
    }
    #[test]
    fn test_custom_charset_iter() {
        // These ranges are from the ArnoPro-Regular font and are in the same order they are in the
        // font.
        #[rustfmt::skip]
            let ranges = ReadArrayCow::Owned(vec![
            Range { first: 111, n_left: 4, },
            Range { first: 1, n_left: 3, },
            Range { first: 2972, n_left: 2, },
        ]);
        let charset = CustomCharset::Format2 { ranges };
        let actual = charset.iter().collect::<Vec<_>>();
        let expected = vec![0, 111, 112, 113, 114, 115, 1, 2, 3, 4, 2972, 2973, 2974];
        assert_eq!(actual, expected);
    }
    #[test]
    fn test_read_standard_string() {
        let data = b"Ferris";
        let offsets = [1, (data.len() + 1) as u8];
        let string_index = MaybeOwnedIndex::Borrowed(Index {
            count: 1,
            off_size: 1,
            offset_array: &offsets,
            data_array: data,
        });
        assert_eq!(
            read_string_index_string(&string_index, 7).unwrap(),
            "ampersand"
        );
        assert_eq!(
            read_string_index_string(&string_index, 390).unwrap(),
            "Semibold"
        );
    }
    #[test]
    fn test_read_custom_string() {
        let data = b"Ferris";
        let offsets = [1, (data.len() + 1) as u8];
        let string_index = MaybeOwnedIndex::Borrowed(Index {
            count: 1,
            off_size: 1,
            offset_array: &offsets,
            data_array: data,
        });
        assert_eq!(
            read_string_index_string(&string_index, 391).unwrap(),
            "Ferris"
        );
        assert!(read_string_index_string(&string_index, 392).is_err());
    }
    #[test]
    fn bcd_encode() {
        let mut buf = tiny_vec!([u8; 32]);
        assert_eq!(Operand::bcd_encode(&mut buf, 0.0), Operand::Integer(0));
        assert_eq!(Operand::bcd_encode(&mut buf, 1.0), Operand::Integer(1));
        assert_eq!(Operand::bcd_encode(&mut buf, -1.0), Operand::Integer(-1));
        assert_eq!(
            Operand::bcd_encode(&mut buf, -2.25),
            Operand::Real(Real(tiny_vec![0xe2, 0xa2, 0x5f]))
        );
        assert_eq!(
            Operand::bcd_encode(&mut buf, 1.140541E-3),
            Operand::Real(Real(tiny_vec![0x1a, 0x14, 0x05, 0x41, 0xc3, 0xff]))
        );
    }
}