1#![allow(dead_code, non_camel_case_types, non_snake_case, non_upper_case_globals)]
6
7pub(crate) type integer = i32;
8pub(crate) type size_t = usize;
9pub(crate) type int32_t = i32;
10pub(crate) type uint32_t = u32;
11pub(crate) type real = f64;
12pub(crate) type glueratio = f64;
13pub(crate) type boolean = i32;
14pub(crate) type schar = i8;
15pub(crate) type ASCIIcode = integer;
16pub(crate) type eightbits = integer;
17pub(crate) type poolpointer = integer;
18pub(crate) type strnumber = integer;
19pub(crate) type savepointer = integer;
20pub(crate) type packedASCIIcode = u16;
21pub(crate) type packedUTF16code = u16;
22pub(crate) type scaled = integer;
23pub(crate) type nonnegativeinteger = integer;
24pub(crate) type smallnumber = integer;
25pub(crate) type quarterword = integer;
26pub(crate) type halfword = integer;
27pub(crate) type glueord = integer;
28pub(crate) type groupcode = integer;
29pub(crate) type internalfontnumber = integer;
30pub(crate) type fontindex = integer;
31pub(crate) type ninebits = integer;
32pub(crate) type triepointer = integer;
33pub(crate) type trieopcode = integer;
34pub(crate) type hyphpointer = integer;
35pub(crate) type UTF16code = u16;
36pub(crate) type UnicodeScalar = integer;
37pub(crate) type uint16_t = u16;
38pub(crate) type UTF8code = integer;
39pub(crate) type voidpointer = *mut ();
40pub(crate) type address = voidpointer;
41pub(crate) type string = *mut i8;
42pub(crate) type const_string = *const i8;
43pub(crate) type Fixed = int32_t;
44pub(crate) struct PortableFileHandle {
45 name: String,
46 kind: ResourceKind,
47 package: Option<String>,
48 format: integer,
49 bytes: Vec<u8>,
50 cursor: usize,
51 eof_after_failed_read: bool,
52 encoding: InputEncoding,
57 saved_char: Option<u32>,
59}
60
61#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
66pub enum InputEncoding {
67 #[default]
69 Bytes,
70 Utf8,
72 Utf16Be,
74 Utf16Le,
76}
77pub(crate) type bytefile = NativeFileHandle;
78pub(crate) type unicodefile = NativeFileHandle;
79pub(crate) type ResourceSearchHandle = *mut ResourceSearchState;
80pub type PortableFontHandle = usize;
81pub(crate) type FontHandle = PortableFontHandle;
82pub(crate) type CFDictionaryRef = voidpointer;
83pub(crate) type NativeFileHandle = *mut PortableFileHandle;
84pub(crate) type alphafile = NativeFileHandle;
85pub(crate) type UFILE = PortableFileHandle;
86
87pub(crate) const true_0: boolean = 1;
88pub(crate) const false_0: boolean = 0;
89pub(crate) const firstmathfontdimen: integer = 10;
90pub(crate) const native_node_size: integer = 6;
91
92#[derive(Debug)]
93pub(crate) struct EngineAbort {
94 status: integer,
95}
96
97#[derive(Debug)]
103pub(crate) struct EngineError {
104 pub(crate) message: String,
105}
106
107#[derive(Debug)]
113pub(crate) enum EngineBreak {
114 Abort(EngineAbort),
115 Error(EngineError),
116}
117
118impl From<EngineAbort> for EngineBreak {
119 fn from(abort: EngineAbort) -> Self {
120 EngineBreak::Abort(abort)
121 }
122}
123
124fn collapse_doubled_line(line: &str) -> Option<String> {
132 let chars: Vec<char> = line.chars().collect();
133 if chars.len() < 2 || chars.len() % 2 != 0 {
134 return None;
135 }
136 if chars.chunks_exact(2).all(|pair| pair[0] == pair[1]) {
137 Some(chars.iter().step_by(2).collect())
138 } else {
139 None
140 }
141}
142
143pub(crate) const SANDBOX_OP_BUDGET: u64 = 2_000_000;
147
148pub(crate) type EngineFlow<T> = core::result::Result<T, EngineBreak>;
157pub(crate) const nullptr: voidpointer = core::ptr::null_mut::<()>();
158pub(crate) const nil: voidpointer = core::ptr::null_mut::<()>();
159pub(crate) const maxint: integer = i32::MAX;
160pub(crate) const mintrieop: integer = 0;
161pub(crate) const trieopsize: i64 = 35111;
162pub(crate) const negtrieopsize: i64 = -35111;
163pub(crate) const maxtrieop: i64 = 65535;
164pub(crate) const hashoffset: integer = 514;
165pub(crate) const xetex_hash_top: halfword = 1_205_763;
166pub(crate) const xetex_eqtb_top: halfword = 9_006_997;
167pub(crate) const DIR_SEP: integer = b'/' as integer;
168pub(crate) const resource_format_tex_input: integer = 26;
169pub(crate) const resource_format_tfm: integer = 3;
170pub(crate) const resource_format_format_image: integer = 10;
171pub(crate) const resource_format_config: integer = 8;
172pub(crate) const resource_format_font_map: integer = 11;
173pub(crate) const resource_format_encoding: integer = 44;
174pub(crate) const resource_format_font: integer = 47;
175pub(crate) const FOPEN_RBIN_MODE: [i8; 3] = [b'r' as i8, b'b' as i8, 0];
176
177#[derive(Clone, Debug, PartialEq, Eq)]
178pub struct PortableSourceSpan {
179 pub name: String,
180 pub start: u32,
181 pub end: u32,
182 pub role: u8,
186}
187
188pub(crate) type SrcId = u32;
192
193#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
199pub(crate) struct RawSpan {
200 pub name: strnumber,
201 pub start: u32,
202 pub end: u32,
203 pub role: u8,
204}
205
206fn node_src_default(_i: usize) -> u32 {
208 0
209}
210
211fn node_src_sig(_i: usize) -> (usize, usize) {
213 (0, 4)
214}
215
216#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
226pub(crate) struct SrcStackCell {
227 pub span: SrcId,
229 pub parent: u32,
231 pub start: u32,
233 pub name: strnumber,
235 pub pending: bool,
237}
238
239fn node_stack_default(_i: usize) -> u32 {
242 0
243}
244
245fn node_stack_sig(_i: usize) -> (usize, usize) {
247 (0, 4)
248}
249
250#[derive(Clone, Debug, PartialEq, Eq)]
251pub struct PortableNodeSourceSpan {
252 pub node: i32,
253 pub size: i32,
254 pub source: PortableSourceSpan,
255}
256
257#[derive(Clone, Copy, Debug, PartialEq, Eq)]
258pub enum ResourceKind {
259 TexInput,
260 Package,
261 Class,
262 FontDefinition,
263 PackageSupport,
264 Font,
265 Encoding,
266 Map,
267 Config,
268 FormatImage,
269 Asset,
270 Other(integer),
271}
272
273#[derive(Clone, Debug, PartialEq, Eq)]
274pub struct ResourceRequest<'a> {
275 pub name: &'a str,
276 pub kind: ResourceKind,
277 pub package: Option<&'a str>,
278 pub format: integer,
279 pub mode: &'a str,
280 pub source: Option<PortableSourceSpan>,
281}
282
283#[derive(Clone, Debug, PartialEq, Eq)]
284pub struct PortableResourceRequestRecord {
285 pub name: String,
286 pub kind: ResourceKind,
287 pub package: Option<String>,
288 pub format: integer,
289 pub mode: String,
290 pub source: Option<PortableSourceSpan>,
291 pub byte_len: Option<u32>,
292}
293
294#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
295pub struct PortableFontMetrics {
296 pub ascent: i32,
297 pub descent: i32,
298 pub xheight: i32,
299 pub capheight: i32,
300 pub slant: i32,
301}
302
303#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
304pub struct PortableNativeGlyph {
305 pub glyph_id: u16,
306 pub x: i32,
307 pub y: i32,
308 pub advance: i32,
309 pub cluster_start: u32,
310 pub cluster_end: u32,
311 pub src_start: u32,
317 pub src_end: u32,
318}
319
320#[derive(Clone, Debug, Default, PartialEq, Eq)]
321pub struct PortableNativeTextMetrics {
322 pub width: i32,
323 pub height: i32,
324 pub depth: i32,
325 pub glyphs: Vec<PortableNativeGlyph>,
326}
327
328#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
329pub struct PortableNativeGlyphMetrics {
330 pub width: i32,
331 pub height: i32,
332 pub depth: i32,
333}
334
335#[derive(Clone, Debug, Default, PartialEq, Eq)]
336struct PortableNativeGlyphInfo {
337 glyphs: Vec<PortableNativeGlyph>,
338}
339
340#[derive(Clone, Copy, Debug, PartialEq, Eq)]
343pub struct PortableMathVariant {
344 pub glyph: i32,
345 pub advance: i32,
346}
347
348#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
351pub struct PortableMathAssemblyPart {
352 pub glyph: i32,
353 pub start_connector: i32,
354 pub end_connector: i32,
355 pub full_advance: i32,
356 pub extender: bool,
357}
358
359#[derive(Clone, Copy, Debug, PartialEq, Eq)]
361pub enum PortableMathKernCorner {
362 TopRight,
363 TopLeft,
364 BottomRight,
365 BottomLeft,
366}
367
368#[derive(Clone, Debug, Default, PartialEq, Eq)]
376pub struct GlyphAssembly {
377 pub parts: Vec<PortableMathAssemblyPart>,
378}
379
380pub trait FontPlatform {
381 fn resolve_font_handle(&mut self, _name: &[i32], _size: i32) -> Option<PortableFontHandle> {
382 None
383 }
384
385 fn release_font_handle(&mut self, _font: PortableFontHandle, _type_flag: i32) {}
386
387 fn font_table(&self) -> Vec<(PortableFontHandle, String, i32)> {
392 Vec::new()
393 }
394
395 fn restore_font_table(&mut self, _table: &[(PortableFontHandle, String, i32)]) -> bool {
400 true
401 }
402
403 fn font_metrics(&mut self, _font: PortableFontHandle) -> PortableFontMetrics {
404 PortableFontMetrics::default()
405 }
406
407 fn opentype_font_metrics(&mut self, font: PortableFontHandle) -> PortableFontMetrics {
408 self.font_metrics(font)
409 }
410
411 fn is_opentype_math_font(&mut self, _font: PortableFontHandle) -> bool {
412 false
413 }
414
415 fn using_opentype(&mut self, _font: PortableFontHandle) -> bool {
420 false
421 }
422
423 fn math_symbol_parameter(&mut self, _font: PortableFontHandle, _parameter: i32) -> i32 {
424 0
425 }
426
427 fn math_extension_parameter(&mut self, _font: PortableFontHandle, _parameter: i32) -> i32 {
428 0
429 }
430
431 fn opentype_math_constant(&mut self, _font: PortableFontHandle, _constant: i32) -> i32 {
432 0
433 }
434
435 fn opentype_math_accent_position(&mut self, _font: PortableFontHandle, _glyph: i32) -> i32 {
436 0
437 }
438
439 fn math_glyph_italic_correction(&mut self, _font: PortableFontHandle, _glyph: i32) -> i32 {
441 0
442 }
443
444 fn math_glyph_variant(
448 &mut self,
449 _font: PortableFontHandle,
450 _glyph: i32,
451 _index: u16,
452 _horizontal: bool,
453 ) -> Option<PortableMathVariant> {
454 None
455 }
456
457 fn math_glyph_assembly(
460 &mut self,
461 _font: PortableFontHandle,
462 _glyph: i32,
463 _horizontal: bool,
464 ) -> Vec<PortableMathAssemblyPart> {
465 Vec::new()
466 }
467
468 fn math_min_connector_overlap(&mut self, _font: PortableFontHandle) -> i32 {
470 0
471 }
472
473 fn math_kern_at(
476 &mut self,
477 _font: PortableFontHandle,
478 _glyph: i32,
479 _corner: PortableMathKernCorner,
480 _correction_height: i32,
481 ) -> i32 {
482 0
483 }
484
485 fn math_points_to_units(&mut self, _font: PortableFontHandle, _points: f32) -> f32 {
488 0.0
489 }
490
491 fn math_units_to_scaled(&mut self, _font: PortableFontHandle, _units: i32) -> i32 {
494 0
495 }
496
497 fn math_point_size(&mut self, _font: PortableFontHandle) -> f32 {
499 0.0
500 }
501
502 fn map_char_to_glyph(&mut self, _font: PortableFontHandle, _codepoint: i32) -> i32 {
503 0
504 }
505
506 fn map_glyph_to_index(&mut self, _font: PortableFontHandle, _name: &str) -> i32 {
507 0
508 }
509
510 fn ot_font_get(
516 &mut self,
517 _font: PortableFontHandle,
518 _what: i32,
519 _param1: i32,
520 _param2: i32,
521 _param3: i32,
522 ) -> i32 {
523 0
524 }
525
526 fn font_spec(&self, _font: PortableFontHandle) -> Option<String> {
530 None
531 }
532
533 fn shape_native_text(
534 &mut self,
535 _font: PortableFontHandle,
536 _text: &[u16],
537 _use_glyph_metrics: bool,
538 ) -> PortableNativeTextMetrics {
539 PortableNativeTextMetrics::default()
540 }
541
542 fn measure_native_glyph(
543 &mut self,
544 _font: PortableFontHandle,
545 _glyph: u16,
546 _use_glyph_metrics: bool,
547 ) -> PortableNativeGlyphMetrics {
548 PortableNativeGlyphMetrics::default()
549 }
550}
551
552#[derive(Default)]
553pub struct EmptyFontPlatform;
554
555impl FontPlatform for EmptyFontPlatform {}
556
557pub trait ResourceProvider {
558 fn read(&mut self, request: ResourceRequest<'_>) -> Option<Vec<u8>>;
559}
560
561#[derive(Default)]
562pub struct EmptyResourceProvider;
563
564impl ResourceProvider for EmptyResourceProvider {
565 fn read(&mut self, _request: ResourceRequest<'_>) -> Option<Vec<u8>> {
566 None
567 }
568}
569
570#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
571pub struct PortableClock {
572 pub seconds: integer,
573 pub micros: integer,
574}
575
576#[derive(Clone, Copy, Debug, PartialEq, Eq)]
577pub struct PortableLinebreakRequest<'a> {
578 pub font: integer,
579 pub locale: integer,
580 pub text: &'a [uint16_t],
581}
582
583pub trait PortablePlatform {
584 fn clock(&mut self) -> PortableClock {
585 PortableClock::default()
586 }
587
588 fn linebreak_start(&mut self, _request: PortableLinebreakRequest<'_>) {}
589
590 fn linebreak_next(&mut self) -> Option<integer> {
591 None
592 }
593}
594
595#[derive(Default)]
596pub struct EmptyPlatform;
597
598impl PortablePlatform for EmptyPlatform {}
599
600impl PortableFileHandle {
601 fn new(
602 name: String,
603 kind: ResourceKind,
604 package: Option<String>,
605 format: integer,
606 bytes: Vec<u8>,
607 ) -> Self {
608 Self {
609 name,
610 kind,
611 package,
612 format,
613 bytes,
614 cursor: 0,
615 eof_after_failed_read: false,
616 encoding: InputEncoding::Bytes,
617 saved_char: None,
618 }
619 }
620
621 fn read_byte(&mut self) -> Option<u8> {
622 let Some(byte) = self.bytes.get(self.cursor).copied() else {
623 self.eof_after_failed_read = true;
624 return None;
625 };
626 self.cursor += 1;
627 Some(byte)
628 }
629
630 fn has_remaining(&self) -> bool {
631 self.cursor < self.bytes.len()
632 }
633
634 fn is_eof(&self) -> bool {
635 self.eof_after_failed_read
636 }
637
638 fn resolve_text_encoding_auto(&mut self) {
651 let b1 = self.bytes.first().copied();
652 let b2 = self.bytes.get(1).copied();
653 match (b1, b2) {
654 (Some(0xFE), Some(0xFF)) => {
655 self.encoding = InputEncoding::Utf16Be;
656 self.cursor = 2;
657 }
658 (Some(0xFF), Some(0xFE)) => {
659 self.encoding = InputEncoding::Utf16Le;
660 self.cursor = 2;
661 }
662 (Some(0x00), Some(b2)) if b2 != 0 => {
663 self.encoding = InputEncoding::Utf16Be;
664 }
666 (Some(b1), Some(0x00)) if b1 != 0 => {
667 self.encoding = InputEncoding::Utf16Le;
668 }
669 (Some(0xEF), Some(0xBB)) if self.bytes.get(2).copied() == Some(0xBF) => {
670 self.encoding = InputEncoding::Utf8;
671 self.cursor = 3;
672 }
673 _ => {
674 self.encoding = InputEncoding::Utf8;
675 }
676 }
677 }
678
679 fn next_input_scalar(&mut self) -> Option<u32> {
684 if let Some(saved) = self.saved_char.take() {
686 return Some(saved);
687 }
688 match self.encoding {
689 InputEncoding::Bytes => self.read_byte().map(u32::from),
690 InputEncoding::Utf8 => self.next_utf8_scalar(),
691 InputEncoding::Utf16Be => self.next_utf16_scalar(true),
692 InputEncoding::Utf16Le => self.next_utf16_scalar(false),
693 }
694 }
695
696 fn next_utf8_scalar(&mut self) -> Option<u32> {
701 const OFFSETS: [u32; 6] = [
703 0x0000_0000,
704 0x0000_3080,
705 0x000E_2080,
706 0x03C8_2080,
707 0xFA08_2080,
708 0x8208_2080,
709 ];
710 let lead = self.read_byte()?;
711 let extra: usize = match lead {
713 0x00..=0xBF => 0,
714 0xC0..=0xDF => 1,
715 0xE0..=0xEF => 2,
716 0xF0..=0xF7 => 3,
717 0xF8..=0xFB => 4,
718 0xFC..=0xFF => 5,
719 };
720 let mut rval: i64 = i64::from(lead);
722 if extra >= 4 {
725 return Some(0xFFFD);
728 }
729 for _ in 0..extra {
730 match self.read_byte() {
731 Some(c) if (0x80..0xC0).contains(&c) => {
732 rval = (rval << 6) + i64::from(c);
733 }
734 Some(c) => {
735 self.cursor -= 1;
737 let _ = c;
738 return Some(0xFFFD);
739 }
740 None => {
741 return Some(0xFFFD);
743 }
744 }
745 }
746 rval -= i64::from(OFFSETS[extra]);
747 if rval < 0 || rval > 0x10_FFFF {
748 return Some(0xFFFD);
749 }
750 Some(rval as u32)
751 }
752
753 fn next_utf16_scalar(&mut self, big_endian: bool) -> Option<u32> {
758 let unit = self.read_utf16_unit(big_endian)?;
759 if (0xD800..=0xDBFF).contains(&unit) {
760 match self.read_utf16_unit(big_endian) {
762 Some(lo) if (0xDC00..=0xDFFF).contains(&lo) => {
763 Some(0x10000 + (unit - 0xD800) * 0x400 + (lo - 0xDC00))
764 }
765 Some(lo) => {
766 self.saved_char = Some(lo);
767 Some(0xFFFD)
768 }
769 None => Some(0xFFFD),
770 }
771 } else if (0xDC00..=0xDFFF).contains(&unit) {
772 Some(0xFFFD)
774 } else {
775 Some(unit)
776 }
777 }
778
779 fn read_utf16_unit(&mut self, big_endian: bool) -> Option<u32> {
783 let first = self.read_byte()?;
784 let second = self.read_byte().unwrap_or(0);
785 let unit = if big_endian {
786 (u32::from(first) << 8) + u32::from(second)
787 } else {
788 u32::from(first) + (u32::from(second) << 8)
789 };
790 Some(unit)
791 }
792}
793
794pub(crate) trait StatePtrCompat<T> {
795 fn as_mut_ptr(self) -> *mut T;
796 fn is_empty(self) -> bool;
797}
798
799impl<T> StatePtrCompat<T> for *mut T {
800 fn as_mut_ptr(self) -> *mut T {
801 self
802 }
803
804 fn is_empty(self) -> bool {
805 self.is_null()
806 }
807}
808
809#[derive(Copy, Clone)]
810#[repr(C)]
811pub(crate) union twohalves {
812 pub v: TwoHalvesPair,
813 pub u: TwoHalvesBytes,
814}
815
816impl Default for twohalves {
817 fn default() -> Self {
818 Self {
819 v: TwoHalvesPair::default(),
820 }
821 }
822}
823
824#[derive(Copy, Clone, Default)]
825#[repr(C)]
826pub(crate) struct TwoHalvesBytes {
827 pub B1: i16,
828 pub B0: i16,
829}
830
831#[derive(Copy, Clone, Default)]
832#[repr(C)]
833pub(crate) struct TwoHalvesPair {
834 pub LH: halfword,
835 pub RH: halfword,
836}
837
838#[derive(Copy, Clone)]
839#[repr(C)]
840pub(crate) struct fourquarters {
841 pub u: FourQuarterBytes,
842}
843
844impl Default for fourquarters {
845 fn default() -> Self {
846 Self {
847 u: FourQuarterBytes::default(),
848 }
849 }
850}
851
852#[derive(Copy, Clone, Default)]
863#[repr(C)]
864pub(crate) struct FourQuarterBytes {
865 pub B3: u16,
866 pub B2: u16,
867 pub B1: u16,
868 pub B0: u16,
869}
870
871pub(crate) type C2RustUnnamed_2 = FourQuarterBytes;
872
873#[derive(Copy, Clone)]
874#[repr(C)]
875pub(crate) union memoryword {
876 pub gr: glueratio,
877 pub hh: twohalves,
878 pub u: MemoryInt,
879 pub v: MemoryQuarters,
880 pub ptr: voidpointer,
881}
882
883impl Default for memoryword {
884 fn default() -> Self {
885 Self {
886 u: MemoryInt::default(),
887 }
888 }
889}
890
891#[derive(Copy, Clone, Default)]
898#[repr(C)]
899pub(crate) struct MemoryQuarters {
900 pub QQQQ: fourquarters,
901}
902
903#[derive(Copy, Clone, Default)]
904#[repr(C)]
905pub(crate) struct MemoryInt {
906 pub CINT: integer,
907}
908
909#[derive(Copy, Clone)]
910#[repr(C)]
911pub(crate) union fmemoryword {
912 pub u: FontMemoryInt,
913 pub v: FontMemoryQuarters,
914}
915
916impl Default for fmemoryword {
917 fn default() -> Self {
918 Self {
919 u: FontMemoryInt::default(),
920 }
921 }
922}
923
924#[derive(Copy, Clone, Default)]
925#[repr(C)]
926pub(crate) struct FontMemoryQuarters {
927 pub QQQQ: fourquarters,
928}
929
930#[derive(Copy, Clone, Default)]
931#[repr(C)]
932pub(crate) struct FontMemoryInt {
933 pub CINT: integer,
934}
935
936#[derive(Copy, Clone, Default)]
937#[repr(C)]
938pub(crate) struct liststaterecord {
939 pub modefield: i16,
940 pub headfield: halfword,
941 pub tailfield: halfword,
942 pub eTeXauxfield: halfword,
943 pub pgfield: integer,
944 pub mlfield: integer,
945 pub auxfield: memoryword,
946}
947
948#[derive(Copy, Clone, Default)]
949#[repr(C)]
950pub(crate) struct instaterecord {
951 pub statefield: quarterword,
952 pub indexfield: quarterword,
953 pub startfield: halfword,
954 pub locfield: halfword,
955 pub limitfield: halfword,
956 pub namefield: halfword,
957 pub spanfield: SrcId,
963}
964
965#[derive(Copy, Clone, Default)]
966#[repr(C)]
967pub(crate) struct transform {
968 pub a: f64,
969 pub b: f64,
970 pub c: f64,
971 pub d: f64,
972 pub x: f64,
973 pub y: f64,
974}
975
976#[derive(Copy, Clone, Default)]
977#[repr(C)]
978pub(crate) struct realpoint {
979 pub x: f32,
980 pub y: f32,
981}
982
983#[derive(Copy, Clone, Default)]
984#[repr(C)]
985pub(crate) struct realrect {
986 pub x: f32,
987 pub y: f32,
988 pub wd: f32,
989 pub ht: f32,
990}
991
992#[derive(Copy, Clone, Default)]
993#[repr(C)]
994pub(crate) struct ResourceSearchState {
995 pub make_tex_discard_errors: boolean,
996}
997
998const CODEPOINT_LO: usize = 1_207_592; const PAGE_BITS: usize = 12;
1017const PAGE_LEN: usize = 1 << PAGE_BITS;
1018fn eqtb_sig_range(i: usize) -> (usize, usize) {
1024 if (7_892_264..=9_006_997).contains(&i) {
1025 (0, 4) } else {
1027 (0, 8)
1028 }
1029}
1030
1031fn hash_sig_range(_i: usize) -> (usize, usize) {
1033 (0, 8)
1034}
1035
1036fn paged_bytes_eq<T>(a: &T, b: &T, off: usize, len: usize) -> bool {
1044 unsafe {
1046 let pa = (a as *const T as *const u8).add(off);
1047 let pb = (b as *const T as *const u8).add(off);
1048 core::slice::from_raw_parts(pa, len) == core::slice::from_raw_parts(pb, len)
1049 }
1050}
1051
1052pub(crate) struct PagedArray<T: Copy + Default> {
1053 base: usize, lo: usize, end: usize, low: Vec<T>, pages: Vec<Option<Box<[T]>>>, default_fn: fn(usize) -> T, sig_range: fn(usize) -> (usize, usize), }
1061
1062impl<T: Copy + Default> PagedArray<T> {
1063 fn new(
1064 base: usize,
1065 end: usize,
1066 default_fn: fn(usize) -> T,
1067 sig_range: fn(usize) -> (usize, usize),
1068 ) -> Self {
1069 let lo = base;
1074 let npages = (end - lo).div_ceil(PAGE_LEN);
1075 PagedArray {
1076 base,
1077 lo,
1078 end,
1079 low: vec![T::default(); lo - base],
1080 pages: (0..npages).map(|_| None).collect(),
1081 default_fn,
1082 sig_range,
1083 }
1084 }
1085
1086 #[inline]
1087 fn ptr(&mut self, abs: usize) -> *mut T {
1088 if abs < self.lo {
1089 return unsafe { self.low.as_mut_ptr().add(abs - self.base) };
1091 }
1092 let rel = abs - self.lo;
1093 let pg = rel >> PAGE_BITS;
1094 let off = rel & (PAGE_LEN - 1);
1095 if self.pages[pg].is_none() {
1096 let page_base = self.lo + pg * PAGE_LEN;
1097 let f = self.default_fn;
1098 let mut page: Vec<T> = Vec::with_capacity(PAGE_LEN);
1099 for j in 0..PAGE_LEN {
1100 page.push(f(page_base + j));
1101 }
1102 self.pages[pg] = Some(page.into_boxed_slice());
1103 }
1104 unsafe {
1106 self.pages[pg]
1107 .as_mut()
1108 .unwrap_unchecked()
1109 .as_mut_ptr()
1110 .add(off)
1111 }
1112 }
1113
1114 fn compact(&mut self) {
1118 let f = self.default_fn;
1119 for pg in 0..self.pages.len() {
1120 let page_base = self.lo + pg * PAGE_LEN;
1121 let is_default = match &self.pages[pg] {
1122 None => continue,
1123 Some(page) => (0..PAGE_LEN).all(|j| {
1124 let (off, len) = (self.sig_range)(page_base + j);
1125 paged_bytes_eq(&page[j], &f(page_base + j), off, len)
1126 }),
1127 };
1128 if is_default {
1129 self.pages[pg] = None;
1130 }
1131 }
1132 }
1133
1134 fn resident_bytes(&self) -> usize {
1135 let elt = core::mem::size_of::<T>();
1136 self.low.capacity() * elt
1137 + self.pages.iter().filter(|p| p.is_some()).count() * PAGE_LEN * elt
1138 + self.pages.capacity() * core::mem::size_of::<Option<Box<[T]>>>()
1139 }
1140
1141 #[inline]
1145 fn set(&mut self, abs: usize, v: T) {
1146 if abs < self.base || abs >= self.end {
1147 return;
1148 }
1149 unsafe {
1151 *self.ptr(abs) = v;
1152 }
1153 }
1154
1155 #[inline]
1159 fn get_copy(&self, abs: usize) -> T {
1160 if abs < self.base || abs >= self.end {
1161 return (self.default_fn)(abs);
1162 }
1163 if abs < self.lo {
1164 return self.low[abs - self.base];
1165 }
1166 let rel = abs - self.lo;
1167 let pg = rel >> PAGE_BITS;
1168 let off = rel & (PAGE_LEN - 1);
1169 match self.pages.get(pg).and_then(|p| p.as_ref()) {
1170 Some(page) => page[off],
1171 None => (self.default_fn)(abs),
1172 }
1173 }
1174}
1175
1176impl<T: Copy + Default> Clone for PagedArray<T> {
1177 fn clone(&self) -> Self {
1178 PagedArray {
1179 base: self.base,
1180 lo: self.lo,
1181 end: self.end,
1182 low: self.low.clone(),
1183 pages: self.pages.clone(),
1184 default_fn: self.default_fn,
1185 sig_range: self.sig_range,
1186 }
1187 }
1188}
1189
1190pub(crate) struct PagedView<T: Copy + Default>(*mut PagedArray<T>);
1198
1199impl<T: Copy + Default> Clone for PagedView<T> {
1200 fn clone(&self) -> Self {
1201 *self
1202 }
1203}
1204impl<T: Copy + Default> Copy for PagedView<T> {}
1205
1206impl<T: Copy + Default> PagedView<T> {
1207 pub(crate) fn new(arr: &mut PagedArray<T>) -> Self {
1208 PagedView(arr as *mut PagedArray<T>)
1209 }
1210 #[allow(dead_code)]
1211 pub(crate) fn null() -> Self {
1212 PagedView(core::ptr::null_mut())
1213 }
1214 #[inline]
1215 pub(crate) fn as_mut_ptr(self) -> Self {
1216 self
1217 }
1218 #[inline]
1219 pub(crate) fn is_null(self) -> bool {
1220 self.0.is_null()
1221 }
1222 #[inline]
1223 pub(crate) fn offset(self, count: isize) -> *mut T {
1224 unsafe { (*self.0).ptr(count as usize) }
1228 }
1229}
1230
1231fn eqtb_codepoint_default(i: usize) -> memoryword {
1234 let mut w: memoryword = unsafe { core::mem::zeroed() };
1239 if (1_207_592..=7_892_263).contains(&i) {
1240 let rh: i32 = if (1_207_592..=2_321_703).contains(&i) {
1242 12 } else if (4_549_928..=5_664_039).contains(&i) {
1244 1000 } else if (5_664_040..=6_778_151).contains(&i) {
1246 (i - 5_664_040) as i32 } else {
1248 0 };
1250 w.hh.u.B0 = 123;
1252 w.hh.u.B1 = 1;
1253 w.hh.v.RH = rh;
1254 } else if (7_892_607..=9_006_718).contains(&i) {
1255 w.u.CINT = -1;
1257 } else if i < CODEPOINT_LO || i > xetex_eqtb_top as usize {
1258 w.hh.u.B0 = 104;
1265 w.hh.v.RH = -(268435455 as i32);
1266 }
1267 w
1270}
1271
1272fn hash_codepoint_default(_i: usize) -> twohalves {
1275 twohalves::default()
1276}
1277
1278pub(crate) struct PortableTexState {
1279 pub mem: Vec<memoryword>,
1280 buffer_storage: Vec<UnicodeScalar>,
1281 nest_storage: Vec<liststaterecord>,
1282 savestack_storage: Vec<memoryword>,
1283 inputstack_storage: Vec<instaterecord>,
1284 inputfile_storage: Vec<unicodefile>,
1285 eofseen_storage: Vec<boolean>,
1286 linestack_storage: Vec<integer>,
1287 grpstack_storage: Vec<savepointer>,
1288 ifstack_storage: Vec<halfword>,
1289 sourcefilenamestack_storage: Vec<strnumber>,
1290 fullsourcefilenamestack_storage: Vec<strnumber>,
1291 paramstack_storage: Vec<halfword>,
1292 hyphword_storage: Vec<strnumber>,
1293 hyphlist_storage: Vec<halfword>,
1294 hyphlink_storage: Vec<hyphpointer>,
1295 hash_paged: PagedArray<twohalves>,
1296 eqtb_paged: PagedArray<memoryword>,
1297 strstart_storage: Vec<poolpointer>,
1298 strpool_storage: Vec<packedUTF16code>,
1299 fontinfo_storage: Vec<fmemoryword>,
1300 bcharlabel_storage: Vec<fontindex>,
1301 charbase_storage: Vec<integer>,
1302 widthbase_storage: Vec<integer>,
1303 heightbase_storage: Vec<integer>,
1304 depthbase_storage: Vec<integer>,
1305 italicbase_storage: Vec<integer>,
1306 ligkernbase_storage: Vec<integer>,
1307 kernbase_storage: Vec<integer>,
1308 extenbase_storage: Vec<integer>,
1309 parambase_storage: Vec<integer>,
1310 fontarea_storage: Vec<strnumber>,
1311 fontname_storage: Vec<strnumber>,
1312 fontbc_storage: Vec<UTF16code>,
1313 fontec_storage: Vec<UTF16code>,
1314 fontbchar_storage: Vec<ninebits>,
1315 fontfalsebchar_storage: Vec<ninebits>,
1316 fontcheck_storage: Vec<fourquarters>,
1317 fontdsize_storage: Vec<scaled>,
1318 fontsize_storage: Vec<scaled>,
1319 fontflags_storage: Vec<i8>,
1320 fontglue_storage: Vec<halfword>,
1321 fontlayoutengine_storage: Vec<voidpointer>,
1322 fontletterspace_storage: Vec<scaled>,
1323 fontmapping_storage: Vec<voidpointer>,
1324 fontparams_storage: Vec<fontindex>,
1325 fontused_storage: Vec<boolean>,
1326 nativetext_storage: Vec<UTF16code>,
1327 hyphenchar_storage: Vec<integer>,
1328 skewchar_storage: Vec<integer>,
1329 triec_storage: Vec<packedUTF16code>,
1330 triehash_storage: Vec<triepointer>,
1331 triel_storage: Vec<triepointer>,
1332 trieo_storage: Vec<trieopcode>,
1333 trier_storage: Vec<triepointer>,
1334 trietaken_storage: Vec<boolean>,
1335 trietrc_storage: Vec<quarterword>,
1336 trietrl_storage: Vec<triepointer>,
1337 trietro_storage: Vec<triepointer>,
1338 source_tracking: bool,
1345 cmd_span: SrcId,
1348 pending_call_span: SrcId,
1351 src_token_start: integer,
1354 src_line_base: u32,
1357 src_line_buf_start: integer,
1361 src_prev_line_len: u32,
1364 src_line_initialized: bool,
1367 src_primary_name: strnumber,
1370 src_call_start: u32,
1372 src_call_name: strnumber,
1374 src_call_state: integer,
1376 src_call_index: integer,
1382 src_call_span: SrcId,
1384 src_call_argspan: SrcId,
1389 src_user_cmd_span: SrcId,
1398 src_anchor_cmd: SrcId,
1408 src_call_user_span: SrcId,
1414 src_tok_span: SrcId,
1420 src_spans: Vec<RawSpan>,
1422 src_dedup: std::collections::HashMap<RawSpan, SrcId>,
1424 node_src: PagedArray<u32>,
1428 src_native_offsets: Vec<SrcId>,
1435 src_stack_cells: Vec<SrcStackCell>,
1439 cur_stack_head: u32,
1442 src_grp_stack: Vec<SrcId>,
1450 src_grp_closing: SrcId,
1454 node_stack: PagedArray<u32>,
1458 pub LRproblems: integer,
1459 pub LRptr: halfword,
1460 pub OKtointerrupt: boolean,
1461 pub terminal_output: NativeFileHandle,
1462 pub activenodesize: smallnumber,
1463 pub activewidth: [scaled; 7],
1464 pub actuallooseness: integer,
1465 pub adjusttail: halfword,
1466 pub aftertoken: halfword,
1467 pub alignptr: halfword,
1468 pub alignstate: integer,
1469 pub areadelimiter: poolpointer,
1470 pub aritherror: boolean,
1471 pub avail: halfword,
1472 pub background: [scaled; 7],
1473 pub baseptr: integer,
1474 pub bchar: halfword,
1475 pub bcharlabel: *mut fontindex,
1476 pub bestbet: halfword,
1477 pub bestheightplusdepth: scaled,
1478 pub bestline: halfword,
1479 pub bestplace: [halfword; 4],
1480 pub bestplglue: [scaled; 4],
1481 pub bestplline: [halfword; 4],
1482 pub bestplshort: [scaled; 4],
1483 pub breadthmax: integer,
1484 pub breakwidth: [scaled; 7],
1485 pub buffer: *mut UnicodeScalar,
1486 pub bufsize: integer,
1487 pub c: quarterword,
1488 pub cancelboundary: boolean,
1489 pub charbase: *mut integer,
1490 pub condptr: halfword,
1491 pub cscount: integer,
1492 pub curactivewidth: [scaled; 7],
1493 pub curalign: halfword,
1494 pub curarea: strnumber,
1495 pub curboundary: integer,
1496 pub curbox: halfword,
1497 pub curc: integer,
1498 pub curchr: halfword,
1499 pub curcmd: eightbits,
1500 pub curcs: halfword,
1501 pub curdir: smallnumber,
1502 pub curext: strnumber,
1503 pub curf: internalfontnumber,
1504 pub curgroup: groupcode,
1505 pub curhead: halfword,
1506 pub curi: fourquarters,
1507 pub curif: smallnumber,
1508 pub curinput: instaterecord,
1509 pub curl: halfword,
1510 pub curlang: eightbits,
1511 pub curlevel: quarterword,
1512 pub curlist: liststaterecord,
1513 pub curloop: halfword,
1514 pub curmark: [halfword; 5],
1515 pub curmlist: halfword,
1516 pub curmu: scaled,
1517 pub curname: strnumber,
1518 pub curorder: glueord,
1519 pub curp: halfword,
1520 pub curprehead: halfword,
1521 pub curpretail: halfword,
1522 pub curptr: halfword,
1523 pub curq: halfword,
1524 pub curr: halfword,
1525 pub curs: integer,
1526 pub cursize: integer,
1527 pub curspan: halfword,
1528 pub curstyle: smallnumber,
1529 pub curtail: halfword,
1530 pub curtok: halfword,
1531 pub curval: integer,
1532 pub curval1: integer,
1533 pub curvallevel: eightbits,
1534 pub deadcycles: integer,
1535 pub defref: halfword,
1536 pub deletionsallowed: boolean,
1537 pub depthbase: *mut integer,
1538 pub depththreshold: integer,
1539 pub dig: [eightbits; 23],
1540 pub discptr: [halfword; 4],
1541 pub discwidth: scaled,
1542 pub doingleaders: boolean,
1543 pub doingspecial: boolean,
1544 pub dolastlinefit: boolean,
1545 pub downptr: halfword,
1546 pub dvibufsize: integer,
1547 pub dvigone: integer,
1548 pub dvilimit: integer,
1549 pub dvioffset: integer,
1550 pub dviptr: integer,
1551 pub dynused: integer,
1552 pub eTeXmode: eightbits,
1553 pub easyline: halfword,
1554 pub editline: integer,
1555 pub editnamelength: integer,
1556 pub editnamestart: poolpointer,
1557 pub eightbitp: i32,
1558 pub emptyfield: twohalves,
1559 pub eofseen: *mut boolean,
1560 pub epochseconds: integer,
1561 pub eqtbtop: halfword,
1562 pub errorcount: schar,
1563 pub errorline: integer,
1564 pub expanddepth: integer,
1565 pub expanddepthcount: integer,
1566 pub extdelimiter: poolpointer,
1567 pub extenbase: *mut integer,
1568 pub f: internalfontnumber,
1569 pub falsebchar: halfword,
1570 pub fewestdemerits: integer,
1571 pub filelineerrorstylep: i32,
1572 pub filenamequotechar: UTF16code,
1573 pub fileoffset: integer,
1574 pub fillwidth: [scaled; 3],
1575 pub finalpass: boolean,
1576 pub first: integer,
1577 pub firstcount: integer,
1578 pub firstindent: scaled,
1579 pub firstp: halfword,
1580 pub firstwidth: scaled,
1581 pub fmemptr: fontindex,
1582 pub fontarea: *mut strnumber,
1583 pub fontbc: *mut UTF16code,
1584 pub fontbchar: *mut ninebits,
1585 pub fontcheck: *mut fourquarters,
1586 pub fontdsize: *mut scaled,
1587 pub fontec: *mut UTF16code,
1588 pub fontfalsebchar: *mut ninebits,
1589 pub fontflags: *mut i8,
1590 pub fontglue: *mut halfword,
1591 pub fontinfo: *mut fmemoryword,
1592 pub fontinshortdisplay: integer,
1593 pub fontlayoutengine: *mut voidpointer,
1594 pub fontletterspace: *mut scaled,
1595 pub fontmapping: *mut voidpointer,
1596 pub fontmax: integer,
1597 pub fontmemsize: integer,
1598 pub fontname: *mut strnumber,
1599 pub fontparams: *mut fontindex,
1600 pub fontptr: internalfontnumber,
1601 pub fontsize: *mut scaled,
1602 pub fontused: *mut boolean,
1603 pub forceeof: boolean,
1604 pub formatident: strnumber,
1605 pub fullsourcefilenamestack: *mut strnumber,
1606 pub g: halfword,
1607 pub globalprevp: halfword,
1608 pub grpstack: *mut savepointer,
1609 pub ha: halfword,
1610 pub halfbuf: integer,
1611 pub halferrorline: integer,
1612 pub haltingonerrorp: boolean,
1613 pub haltonerrorp: i32,
1614 pub hash: PagedView<twohalves>,
1615 pub hashextra: halfword,
1616 pub hashhigh: halfword,
1617 pub hashused: halfword,
1618 pub hb: halfword,
1619 pub hc: [integer; 4099],
1620 pub heightbase: *mut integer,
1621 pub helpline: [strnumber; 6],
1622 pub helpptr: eightbits,
1623 pub hf: internalfontnumber,
1624 pub himemmin: halfword,
1625 pub history: eightbits,
1626 pub hliststack: [halfword; 513],
1627 pub hliststacklevel: i16,
1628 pub hn: smallnumber,
1629 pub hu: [integer; 4097],
1630 pub hyf: [eightbits; 4097],
1631 pub hyfbchar: halfword,
1632 pub hyfchar: integer,
1633 pub hyfdistance: [smallnumber; 35112],
1634 pub hyfnext: [trieopcode; 35112],
1635 pub hyfnum: [smallnumber; 35112],
1636 pub hyphcount: integer,
1637 pub hyphenchar: *mut integer,
1638 pub hyphenpassed: smallnumber,
1639 pub hyphindex: triepointer,
1640 pub hyphlink: *mut hyphpointer,
1641 pub hyphlist: *mut halfword,
1642 pub hyphnext: integer,
1643 pub hyphsize: integer,
1644 pub hyphstart: triepointer,
1645 pub hyphword: *mut strnumber,
1646 pub iflimit: eightbits,
1647 pub ifline: integer,
1648 pub ifstack: *mut halfword,
1649 pub initcurlang: eightbits,
1650 pub initlft: boolean,
1651 pub initlhyf: integer,
1652 pub initlig: boolean,
1653 pub initlist: halfword,
1654 pub initpoolptr: poolpointer,
1655 pub initrhyf: integer,
1656 pub initstrptr: strnumber,
1657 pub iniversion: boolean,
1658 pub inopen: integer,
1659 pub inputfile: *mut unicodefile,
1660 pub inputptr: integer,
1661 pub inputstack: *mut instaterecord,
1662 pub insdisc: boolean,
1663 pub insertpenalties: integer,
1664 pub insertsrcspecialauto: boolean,
1665 pub insertsrcspecialeverymath: boolean,
1666 pub insertsrcspecialeverypar: boolean,
1667 pub insertsrcspecialeveryvbox: boolean,
1668 pub interaction: eightbits,
1669 pub interactionoption: eightbits,
1670 pub interrupt: integer,
1671 pub ishyph: boolean,
1672 pub isincsname: boolean,
1673 pub italicbase: *mut integer,
1674 pub jobname: strnumber,
1675 pub jrandom: eightbits,
1676 pub justbox: halfword,
1677 pub kernbase: *mut integer,
1678 pub resource_search_state: ResourceSearchState,
1679 pub l: eightbits,
1680 pub last: integer,
1681 pub lastbadness: integer,
1682 pub lastbop: integer,
1683 pub lastglue: halfword,
1684 pub lastkern: scaled,
1685 pub lastleftmostchar: halfword,
1686 pub lastlinefill: halfword,
1687 pub lastnodetype: integer,
1688 pub lastpenalty: integer,
1689 pub lastrightmostchar: halfword,
1690 pub lastspecialline: halfword,
1691 pub lfthit: boolean,
1692 pub lhyf: integer,
1693 pub ligaturepresent: boolean,
1694 pub ligkernbase: *mut integer,
1695 pub ligstack: halfword,
1696 pub line: integer,
1697 pub linediff: integer,
1698 pub linestack: *mut integer,
1699 pub loadedfontdesignsize: scaled,
1700 pub loadedfontflags: i8,
1701 pub loadedfontletterspace: scaled,
1702 pub loadedfontmapping: voidpointer,
1703 pub logfile: alphafile,
1704 pub logopened: boolean,
1705 pub lomemmax: halfword,
1706 pub longhelpseen: boolean,
1707 pub longstate: eightbits,
1708 pub magicoffset: integer,
1709 pub magset: integer,
1710 pub mainf: internalfontnumber,
1711 pub mainh: halfword,
1712 pub maini: fourquarters,
1713 pub mainj: fourquarters,
1714 pub maink: fontindex,
1715 pub mainp: halfword,
1716 pub mainpp: halfword,
1717 pub mainppp: halfword,
1718 pub mains: integer,
1719 pub mappedtext: *mut UTF16code,
1720 pub maxbufstack: integer,
1721 pub maxh: scaled,
1722 pub maxhyphchar: integer,
1723 pub maxinopen: integer,
1724 pub maxinstack: integer,
1725 pub maxneststack: integer,
1726 pub maxopused: trieopcode,
1727 pub maxparamstack: integer,
1728 pub maxprintline: integer,
1729 pub maxpush: integer,
1730 pub maxreghelpline: strnumber,
1731 pub maxregnum: halfword,
1732 pub maxsavestack: integer,
1733 pub maxstrings: integer,
1734 pub maxv: scaled,
1735 pub membot: integer,
1736 pub memend: halfword,
1737 pub memmax: integer,
1738 pub memmin: integer,
1739 pub memtop: integer,
1740 pub microseconds: integer,
1741 pub minimaldemerits: [integer; 4],
1742 pub minimumdemerits: integer,
1743 pub mlistpenalties: boolean,
1744 pub mltexenabledp: boolean,
1745 pub mltexp: boolean,
1746 pub mubytecswrite: [halfword; 128],
1747 pub mubytekeep: integer,
1748 pub mubyteprefix: integer,
1749 pub mubyteread: [halfword; 256],
1750 pub mubyteskip: integer,
1751 pub mubytestart: boolean,
1752 pub mubytestoken: halfword,
1753 pub mubytetoken: halfword,
1754 pub nameinprogress: boolean,
1755 pub namelength: integer,
1756 pub nameoffile: *mut UTF8code,
1757 pub nativefonttypeflag: integer,
1758 pub nativelen: integer,
1759 pub nativetext: *mut UTF16code,
1760 pub nativetextsize: integer,
1761 pub nest: *mut liststaterecord,
1762 pub nestptr: integer,
1763 pub nestsize: integer,
1764 pub nonewcontrolsequence: boolean,
1765 pub noshrinkerroryet: boolean,
1766 pub nullcharacter: fourquarters,
1767 pub nulldelimiter: fourquarters,
1768 pub oldselectorignorederr: eightbits,
1769 pub oldsetting: eightbits,
1770 pub openparens: integer,
1771 pub opstart: [integer; 256],
1772 pub outputactive: boolean,
1773 pub outputcanend: boolean,
1774 pub packbeginline: integer,
1775 pub pagecontents: eightbits,
1776 pub pagemaxdepth: scaled,
1777 pub pagesofar: [scaled; 8],
1778 pub pagetail: halfword,
1779 pub parambase: *mut integer,
1780 pub paramptr: integer,
1781 pub paramsize: integer,
1782 pub paramstack: *mut halfword,
1783 pub parloc: halfword,
1784 pub partoken: halfword,
1785 pub passive: halfword,
1786 pub passnumber: halfword,
1787 pub pdflastxpos: integer,
1788 pub pdflastypos: integer,
1789 pub poolptr: poolpointer,
1790 pub poolsize: integer,
1791 pub preadjusttail: halfword,
1792 pub prevclass: integer,
1793 pub prim: [twohalves; 2101],
1794 pub primused: halfword,
1795 pub printednode: halfword,
1796 pub pseudofiles: halfword,
1797 pub pstack: [halfword; 9],
1798 pub quotedfilename: boolean,
1799 pub radix: smallnumber,
1800 pub randoms: [integer; 55],
1801 pub randomseed: scaled,
1802 pub readfile: [unicodefile; 16],
1803 pub readopen: [eightbits; 17],
1804 pub readyalready: integer,
1805 pub restrictedshell: i32,
1806 pub rhyf: integer,
1807 pub rightptr: halfword,
1808 pub rover: halfword,
1809 pub rthit: boolean,
1810 pub sachain: halfword,
1811 pub salevel: quarterword,
1812 pub sanull: memoryword,
1813 pub saroot: [halfword; 8],
1814 pub savearitherror: boolean,
1815 pub savenativelen: integer,
1816 pub saveptr: integer,
1817 pub savesize: integer,
1818 pub savestack: *mut memoryword,
1819 pub scannerstatus: eightbits,
1820 pub secondindent: scaled,
1821 pub secondpass: boolean,
1822 pub secondwidth: scaled,
1823 pub selector: eightbits,
1824 pub setboxallowed: boolean,
1825 pub shellenabledp: i32,
1826 pub shownmode: i16,
1827 pub skewchar: *mut integer,
1828 pub skipline: integer,
1829 pub sourcefilenamestack: *mut strnumber,
1830 pub spaceclass: integer,
1831 pub speclog: [integer; 29],
1832 pub stacksize: integer,
1833 pub stopatspace: boolean,
1834 pub stringvacancies: integer,
1835 pub strpool: *mut packedUTF16code,
1836 pub strptr: strnumber,
1837 pub strstart: *mut poolpointer,
1838 pub tally: integer,
1839 pub tempptr: halfword,
1840 pub termin: unicodefile,
1841 pub termoffset: integer,
1842 pub texinputtype: i32,
1843 pub texremainder: scaled,
1844 pub tfmfile: bytefile,
1845 pub tfmtemp: i32,
1846 pub threshold: integer,
1847 pub totalpages: integer,
1848 pub totalshrink: [scaled; 4],
1849 pub totalstretch: [scaled; 4],
1850 pub trickbuf: [UnicodeScalar; 256],
1851 pub trickcount: integer,
1852 pub triec: *mut packedUTF16code,
1853 pub triehash: *mut triepointer,
1854 pub triel: *mut triepointer,
1855 pub triemax: triepointer,
1856 pub triemin: [triepointer; 65536],
1857 pub trienotready: boolean,
1858 pub trieo: *mut trieopcode,
1859 pub trieoplang: [eightbits; 35112],
1860 pub trieopptr: integer,
1861 pub trieopval: [trieopcode; 35112],
1862 pub trieptr: triepointer,
1863 pub trier: *mut triepointer,
1864 pub triesize: integer,
1865 pub trietaken: *mut boolean,
1866 pub trietrc: *mut quarterword,
1867 pub trietrl: *mut triepointer,
1868 pub trietro: *mut triepointer,
1869 pub trieused: [trieopcode; 256],
1870 pub twotothe: [integer; 31],
1871 pub useerrhelp: boolean,
1872 pub varused: integer,
1873 pub warningindex: halfword,
1874 pub widthbase: *mut integer,
1875 pub writefile: [alphafile; 16],
1876 pub writeloc: halfword,
1877 pub writeopen: [boolean; 18],
1878 pub xchr: [ASCIIcode; 256],
1879 pub xtxligaturepresent: boolean,
1880 pub zeqtb: PagedView<memoryword>,
1881 pub zmem: *mut memoryword,
1882 pub zzzaa: [quarterword; 1114734],
1883 pub zzzab: [integer; 70223],
1884}
1885
1886const PORTABLE_FORMAT_MAGIC: [u8; 8] = *b"MTXfmt\x04\x00";
1889
1890macro_rules! portable_owning_vecs {
1895 ($cb:ident) => {
1896 $cb!(buffer_storage, UnicodeScalar);
1897 $cb!(nest_storage, liststaterecord);
1898 $cb!(savestack_storage, memoryword);
1899 $cb!(inputstack_storage, instaterecord);
1900 $cb!(inputfile_storage, unicodefile);
1901 $cb!(eofseen_storage, boolean);
1902 $cb!(linestack_storage, integer);
1903 $cb!(grpstack_storage, savepointer);
1904 $cb!(ifstack_storage, halfword);
1905 $cb!(sourcefilenamestack_storage, strnumber);
1906 $cb!(fullsourcefilenamestack_storage, strnumber);
1907 $cb!(paramstack_storage, halfword);
1908 $cb!(hyphword_storage, strnumber);
1909 $cb!(hyphlist_storage, halfword);
1910 $cb!(hyphlink_storage, hyphpointer);
1911 $cb!(strstart_storage, poolpointer);
1912 $cb!(strpool_storage, packedUTF16code);
1913 $cb!(fontinfo_storage, fmemoryword);
1914 $cb!(bcharlabel_storage, fontindex);
1915 $cb!(charbase_storage, integer);
1916 $cb!(widthbase_storage, integer);
1917 $cb!(heightbase_storage, integer);
1918 $cb!(depthbase_storage, integer);
1919 $cb!(italicbase_storage, integer);
1920 $cb!(ligkernbase_storage, integer);
1921 $cb!(kernbase_storage, integer);
1922 $cb!(extenbase_storage, integer);
1923 $cb!(parambase_storage, integer);
1924 $cb!(fontarea_storage, strnumber);
1925 $cb!(fontname_storage, strnumber);
1926 $cb!(fontbc_storage, UTF16code);
1927 $cb!(fontec_storage, UTF16code);
1928 $cb!(fontbchar_storage, ninebits);
1929 $cb!(fontfalsebchar_storage, ninebits);
1930 $cb!(fontcheck_storage, fourquarters);
1931 $cb!(fontdsize_storage, scaled);
1932 $cb!(fontsize_storage, scaled);
1933 $cb!(fontflags_storage, i8);
1934 $cb!(fontglue_storage, halfword);
1935 $cb!(fontlayoutengine_storage, voidpointer);
1936 $cb!(fontletterspace_storage, scaled);
1937 $cb!(fontmapping_storage, voidpointer);
1938 $cb!(fontparams_storage, fontindex);
1939 $cb!(fontused_storage, boolean);
1940 $cb!(nativetext_storage, UTF16code);
1941 $cb!(hyphenchar_storage, integer);
1942 $cb!(skewchar_storage, integer);
1943 $cb!(triec_storage, packedUTF16code);
1944 $cb!(triehash_storage, triepointer);
1945 $cb!(triel_storage, triepointer);
1946 $cb!(trieo_storage, trieopcode);
1947 $cb!(trier_storage, triepointer);
1948 $cb!(trietaken_storage, boolean);
1949 $cb!(trietrc_storage, quarterword);
1950 $cb!(trietrl_storage, triepointer);
1951 $cb!(trietro_storage, triepointer);
1952 };
1953}
1954
1955fn portable_write_vec_ranges<T: Copy>(out: &mut Vec<u8>, v: &[T], ranges: &[(usize, usize)]) {
1960 let elt = core::mem::size_of::<T>();
1961 out.extend_from_slice(&(v.len() as u64).to_le_bytes());
1962 out.extend_from_slice(&(ranges.len() as u32).to_le_bytes());
1963 for &(start, len) in ranges {
1964 out.extend_from_slice(&(start as u64).to_le_bytes());
1965 out.extend_from_slice(&(len as u64).to_le_bytes());
1966 let bytes =
1968 unsafe { core::slice::from_raw_parts(v.as_ptr().add(start) as *const u8, len * elt) };
1969 out.extend_from_slice(bytes);
1970 }
1971}
1972
1973fn portable_read_vec_ranges<T: Copy>(bytes: &[u8], cursor: &mut usize) -> Option<Vec<T>> {
1977 let elt = core::mem::size_of::<T>();
1978 let full = u64::from_le_bytes(bytes.get(*cursor..*cursor + 8)?.try_into().ok()?) as usize;
1979 *cursor += 8;
1980 let nranges = u32::from_le_bytes(bytes.get(*cursor..*cursor + 4)?.try_into().ok()?) as usize;
1981 *cursor += 4;
1982 let total = full.checked_mul(elt)?;
1983 let mut v = Vec::<T>::with_capacity(full);
1984 unsafe {
1987 core::ptr::write_bytes(v.as_mut_ptr() as *mut u8, 0, total);
1988 for _ in 0..nranges {
1989 let start = u64::from_le_bytes(bytes.get(*cursor..*cursor + 8)?.try_into().ok()?) as usize;
1990 *cursor += 8;
1991 let len = u64::from_le_bytes(bytes.get(*cursor..*cursor + 8)?.try_into().ok()?) as usize;
1992 *cursor += 8;
1993 if start.checked_add(len)? > full {
1994 return None;
1995 }
1996 let nbytes = len.checked_mul(elt)?;
1997 let src = bytes.get(*cursor..*cursor + nbytes)?;
1998 *cursor += nbytes;
1999 core::ptr::copy_nonoverlapping(
2000 src.as_ptr(),
2001 (v.as_mut_ptr() as *mut u8).add(start * elt),
2002 nbytes,
2003 );
2004 }
2005 v.set_len(full);
2006 }
2007 Some(v)
2008}
2009
2010fn portable_used_prefix_len<T>(v: &[T]) -> usize {
2014 let bytes =
2015 unsafe { core::slice::from_raw_parts(v.as_ptr() as *const u8, core::mem::size_of_val(v)) };
2016 match bytes.iter().rposition(|&b| b != 0) {
2017 Some(last) => last / core::mem::size_of::<T>() + 1,
2018 None => 0,
2019 }
2020}
2021
2022fn portable_write_paged<T: Copy + Default>(out: &mut Vec<u8>, arr: &PagedArray<T>) {
2026 let elt = core::mem::size_of::<T>();
2027 out.extend_from_slice(&(arr.base as u64).to_le_bytes());
2028 out.extend_from_slice(&(arr.lo as u64).to_le_bytes());
2029 out.extend_from_slice(&(arr.end as u64).to_le_bytes());
2030 let used = portable_used_prefix_len(arr.low.as_slice());
2031 let ranges: &[(usize, usize)] = if used == 0 { &[] } else { &[(0, used)] };
2032 portable_write_vec_ranges::<T>(out, arr.low.as_slice(), ranges);
2033 let present: Vec<usize> = arr
2034 .pages
2035 .iter()
2036 .enumerate()
2037 .filter_map(|(i, p)| p.as_ref().map(|_| i))
2038 .collect();
2039 out.extend_from_slice(&(arr.pages.len() as u64).to_le_bytes());
2040 out.extend_from_slice(&(present.len() as u32).to_le_bytes());
2041 for pg in present {
2042 out.extend_from_slice(&(pg as u64).to_le_bytes());
2043 let page = arr.pages[pg].as_ref().unwrap();
2044 let pbytes =
2046 unsafe { core::slice::from_raw_parts(page.as_ptr() as *const u8, PAGE_LEN * elt) };
2047 out.extend_from_slice(pbytes);
2048 }
2049}
2050
2051fn portable_read_paged<T: Copy + Default>(
2054 bytes: &[u8],
2055 cursor: &mut usize,
2056 default_fn: fn(usize) -> T,
2057 sig_range: fn(usize) -> (usize, usize),
2058) -> Option<PagedArray<T>> {
2059 let elt = core::mem::size_of::<T>();
2060 let read_u64 = |cursor: &mut usize| -> Option<usize> {
2061 let v = u64::from_le_bytes(bytes.get(*cursor..*cursor + 8)?.try_into().ok()?) as usize;
2062 *cursor += 8;
2063 Some(v)
2064 };
2065 let base = read_u64(cursor)?;
2066 let lo = read_u64(cursor)?;
2067 let end = read_u64(cursor)?;
2068 let low: Vec<T> = portable_read_vec_ranges(bytes, cursor)?;
2069 let npages = read_u64(cursor)?;
2070 let npresent = u32::from_le_bytes(bytes.get(*cursor..*cursor + 4)?.try_into().ok()?) as usize;
2071 *cursor += 4;
2072 let mut pages: Vec<Option<Box<[T]>>> = (0..npages).map(|_| None).collect();
2073 for _ in 0..npresent {
2074 let pg = read_u64(cursor)?;
2075 if pg >= npages {
2076 return None;
2077 }
2078 let nbytes = PAGE_LEN.checked_mul(elt)?;
2079 let src = bytes.get(*cursor..*cursor + nbytes)?;
2080 *cursor += nbytes;
2081 let mut page: Vec<T> = Vec::with_capacity(PAGE_LEN);
2082 unsafe {
2084 core::ptr::copy_nonoverlapping(src.as_ptr(), page.as_mut_ptr() as *mut u8, nbytes);
2085 page.set_len(PAGE_LEN);
2086 }
2087 pages[pg] = Some(page.into_boxed_slice());
2088 }
2089 Some(PagedArray {
2090 base,
2091 lo,
2092 end,
2093 low,
2094 pages,
2095 default_fn,
2096 sig_range,
2097 })
2098}
2099
2100impl PortableTexState {
2101 fn new_boxed_default() -> Box<Self> {
2102 let mut state = Box::<Self>::new_uninit();
2103 let state_ptr = state.as_mut_ptr();
2104 unsafe {
2105 core::ptr::write_bytes(state_ptr, 0, 1);
2106 core::ptr::addr_of_mut!((*state_ptr).mem).write(Vec::new());
2107 core::ptr::addr_of_mut!((*state_ptr).buffer_storage).write(Vec::new());
2108 core::ptr::addr_of_mut!((*state_ptr).nest_storage).write(Vec::new());
2109 core::ptr::addr_of_mut!((*state_ptr).savestack_storage).write(Vec::new());
2110 core::ptr::addr_of_mut!((*state_ptr).inputstack_storage).write(Vec::new());
2111 core::ptr::addr_of_mut!((*state_ptr).inputfile_storage).write(Vec::new());
2112 core::ptr::addr_of_mut!((*state_ptr).eofseen_storage).write(Vec::new());
2113 core::ptr::addr_of_mut!((*state_ptr).linestack_storage).write(Vec::new());
2114 core::ptr::addr_of_mut!((*state_ptr).grpstack_storage).write(Vec::new());
2115 core::ptr::addr_of_mut!((*state_ptr).ifstack_storage).write(Vec::new());
2116 core::ptr::addr_of_mut!((*state_ptr).sourcefilenamestack_storage).write(Vec::new());
2117 core::ptr::addr_of_mut!((*state_ptr).fullsourcefilenamestack_storage).write(Vec::new());
2118 core::ptr::addr_of_mut!((*state_ptr).paramstack_storage).write(Vec::new());
2119 core::ptr::addr_of_mut!((*state_ptr).hyphword_storage).write(Vec::new());
2120 core::ptr::addr_of_mut!((*state_ptr).hyphlist_storage).write(Vec::new());
2121 core::ptr::addr_of_mut!((*state_ptr).hyphlink_storage).write(Vec::new());
2122 core::ptr::addr_of_mut!((*state_ptr).hash_paged)
2123 .write(PagedArray::new(0, 0, hash_codepoint_default, hash_sig_range));
2124 core::ptr::addr_of_mut!((*state_ptr).eqtb_paged)
2125 .write(PagedArray::new(0, 0, eqtb_codepoint_default, eqtb_sig_range));
2126 core::ptr::addr_of_mut!((*state_ptr).strstart_storage).write(Vec::new());
2127 core::ptr::addr_of_mut!((*state_ptr).strpool_storage).write(Vec::new());
2128 core::ptr::addr_of_mut!((*state_ptr).fontinfo_storage).write(Vec::new());
2129 core::ptr::addr_of_mut!((*state_ptr).bcharlabel_storage).write(Vec::new());
2130 core::ptr::addr_of_mut!((*state_ptr).charbase_storage).write(Vec::new());
2131 core::ptr::addr_of_mut!((*state_ptr).widthbase_storage).write(Vec::new());
2132 core::ptr::addr_of_mut!((*state_ptr).heightbase_storage).write(Vec::new());
2133 core::ptr::addr_of_mut!((*state_ptr).depthbase_storage).write(Vec::new());
2134 core::ptr::addr_of_mut!((*state_ptr).italicbase_storage).write(Vec::new());
2135 core::ptr::addr_of_mut!((*state_ptr).ligkernbase_storage).write(Vec::new());
2136 core::ptr::addr_of_mut!((*state_ptr).kernbase_storage).write(Vec::new());
2137 core::ptr::addr_of_mut!((*state_ptr).extenbase_storage).write(Vec::new());
2138 core::ptr::addr_of_mut!((*state_ptr).parambase_storage).write(Vec::new());
2139 core::ptr::addr_of_mut!((*state_ptr).fontarea_storage).write(Vec::new());
2140 core::ptr::addr_of_mut!((*state_ptr).fontname_storage).write(Vec::new());
2141 core::ptr::addr_of_mut!((*state_ptr).fontbc_storage).write(Vec::new());
2142 core::ptr::addr_of_mut!((*state_ptr).fontec_storage).write(Vec::new());
2143 core::ptr::addr_of_mut!((*state_ptr).fontbchar_storage).write(Vec::new());
2144 core::ptr::addr_of_mut!((*state_ptr).fontfalsebchar_storage).write(Vec::new());
2145 core::ptr::addr_of_mut!((*state_ptr).fontcheck_storage).write(Vec::new());
2146 core::ptr::addr_of_mut!((*state_ptr).fontdsize_storage).write(Vec::new());
2147 core::ptr::addr_of_mut!((*state_ptr).fontsize_storage).write(Vec::new());
2148 core::ptr::addr_of_mut!((*state_ptr).fontflags_storage).write(Vec::new());
2149 core::ptr::addr_of_mut!((*state_ptr).fontglue_storage).write(Vec::new());
2150 core::ptr::addr_of_mut!((*state_ptr).fontlayoutengine_storage).write(Vec::new());
2151 core::ptr::addr_of_mut!((*state_ptr).fontletterspace_storage).write(Vec::new());
2152 core::ptr::addr_of_mut!((*state_ptr).fontmapping_storage).write(Vec::new());
2153 core::ptr::addr_of_mut!((*state_ptr).fontparams_storage).write(Vec::new());
2154 core::ptr::addr_of_mut!((*state_ptr).fontused_storage).write(Vec::new());
2155 core::ptr::addr_of_mut!((*state_ptr).nativetext_storage).write(Vec::new());
2156 core::ptr::addr_of_mut!((*state_ptr).hyphenchar_storage).write(Vec::new());
2157 core::ptr::addr_of_mut!((*state_ptr).skewchar_storage).write(Vec::new());
2158 core::ptr::addr_of_mut!((*state_ptr).triec_storage).write(Vec::new());
2159 core::ptr::addr_of_mut!((*state_ptr).triehash_storage).write(Vec::new());
2160 core::ptr::addr_of_mut!((*state_ptr).triel_storage).write(Vec::new());
2161 core::ptr::addr_of_mut!((*state_ptr).trieo_storage).write(Vec::new());
2162 core::ptr::addr_of_mut!((*state_ptr).trier_storage).write(Vec::new());
2163 core::ptr::addr_of_mut!((*state_ptr).trietaken_storage).write(Vec::new());
2164 core::ptr::addr_of_mut!((*state_ptr).trietrc_storage).write(Vec::new());
2165 core::ptr::addr_of_mut!((*state_ptr).trietrl_storage).write(Vec::new());
2166 core::ptr::addr_of_mut!((*state_ptr).trietro_storage).write(Vec::new());
2167 core::ptr::addr_of_mut!((*state_ptr).src_spans).write(Vec::new());
2168 core::ptr::addr_of_mut!((*state_ptr).src_dedup)
2169 .write(std::collections::HashMap::new());
2170 core::ptr::addr_of_mut!((*state_ptr).node_src)
2171 .write(PagedArray::new(0, 0, node_src_default, node_src_sig));
2172 core::ptr::addr_of_mut!((*state_ptr).src_native_offsets).write(Vec::new());
2173 core::ptr::addr_of_mut!((*state_ptr).src_stack_cells).write(Vec::new());
2174 core::ptr::addr_of_mut!((*state_ptr).cur_stack_head).write(0);
2175 core::ptr::addr_of_mut!((*state_ptr).node_stack)
2176 .write(PagedArray::new(0, 0, node_stack_default, node_stack_sig));
2177 state.assume_init()
2178 }
2179 }
2180
2181 fn clone_boxed(&self) -> Box<Self> {
2182 let mem = self.mem.clone();
2183 let buffer_storage = self.buffer_storage.clone();
2184 let nest_storage = self.nest_storage.clone();
2185 let savestack_storage = self.savestack_storage.clone();
2186 let inputstack_storage = self.inputstack_storage.clone();
2187 let inputfile_storage = self.inputfile_storage.clone();
2188 let eofseen_storage = self.eofseen_storage.clone();
2189 let linestack_storage = self.linestack_storage.clone();
2190 let grpstack_storage = self.grpstack_storage.clone();
2191 let ifstack_storage = self.ifstack_storage.clone();
2192 let sourcefilenamestack_storage = self.sourcefilenamestack_storage.clone();
2193 let fullsourcefilenamestack_storage = self.fullsourcefilenamestack_storage.clone();
2194 let paramstack_storage = self.paramstack_storage.clone();
2195 let hyphword_storage = self.hyphword_storage.clone();
2196 let hyphlist_storage = self.hyphlist_storage.clone();
2197 let hyphlink_storage = self.hyphlink_storage.clone();
2198 let hash_paged = self.hash_paged.clone();
2199 let eqtb_paged = self.eqtb_paged.clone();
2200 let strstart_storage = self.strstart_storage.clone();
2201 let strpool_storage = self.strpool_storage.clone();
2202 let fontinfo_storage = self.fontinfo_storage.clone();
2203 let bcharlabel_storage = self.bcharlabel_storage.clone();
2204 let charbase_storage = self.charbase_storage.clone();
2205 let widthbase_storage = self.widthbase_storage.clone();
2206 let heightbase_storage = self.heightbase_storage.clone();
2207 let depthbase_storage = self.depthbase_storage.clone();
2208 let italicbase_storage = self.italicbase_storage.clone();
2209 let ligkernbase_storage = self.ligkernbase_storage.clone();
2210 let kernbase_storage = self.kernbase_storage.clone();
2211 let extenbase_storage = self.extenbase_storage.clone();
2212 let parambase_storage = self.parambase_storage.clone();
2213 let fontarea_storage = self.fontarea_storage.clone();
2214 let fontname_storage = self.fontname_storage.clone();
2215 let fontbc_storage = self.fontbc_storage.clone();
2216 let fontec_storage = self.fontec_storage.clone();
2217 let fontbchar_storage = self.fontbchar_storage.clone();
2218 let fontfalsebchar_storage = self.fontfalsebchar_storage.clone();
2219 let fontcheck_storage = self.fontcheck_storage.clone();
2220 let fontdsize_storage = self.fontdsize_storage.clone();
2221 let fontsize_storage = self.fontsize_storage.clone();
2222 let fontflags_storage = self.fontflags_storage.clone();
2223 let fontglue_storage = self.fontglue_storage.clone();
2224 let fontlayoutengine_storage = self.fontlayoutengine_storage.clone();
2225 let fontletterspace_storage = self.fontletterspace_storage.clone();
2226 let fontmapping_storage = self.fontmapping_storage.clone();
2227 let fontparams_storage = self.fontparams_storage.clone();
2228 let fontused_storage = self.fontused_storage.clone();
2229 let nativetext_storage = self.nativetext_storage.clone();
2230 let hyphenchar_storage = self.hyphenchar_storage.clone();
2231 let skewchar_storage = self.skewchar_storage.clone();
2232 let triec_storage = self.triec_storage.clone();
2233 let triehash_storage = self.triehash_storage.clone();
2234 let triel_storage = self.triel_storage.clone();
2235 let trieo_storage = self.trieo_storage.clone();
2236 let trier_storage = self.trier_storage.clone();
2237 let trietaken_storage = self.trietaken_storage.clone();
2238 let trietrc_storage = self.trietrc_storage.clone();
2239 let trietrl_storage = self.trietrl_storage.clone();
2240 let trietro_storage = self.trietro_storage.clone();
2241 let src_spans = self.src_spans.clone();
2242 let src_dedup = self.src_dedup.clone();
2243 let node_src = self.node_src.clone();
2244 let src_native_offsets = self.src_native_offsets.clone();
2245 let src_stack_cells = self.src_stack_cells.clone();
2246 let node_stack = self.node_stack.clone();
2247 let mut state = Box::<Self>::new_uninit();
2248 let state_ptr = state.as_mut_ptr();
2249 unsafe {
2250 core::ptr::copy_nonoverlapping(self as *const Self, state_ptr, 1);
2251 core::ptr::addr_of_mut!((*state_ptr).mem).write(mem);
2252 core::ptr::addr_of_mut!((*state_ptr).buffer_storage).write(buffer_storage);
2253 core::ptr::addr_of_mut!((*state_ptr).nest_storage).write(nest_storage);
2254 core::ptr::addr_of_mut!((*state_ptr).savestack_storage).write(savestack_storage);
2255 core::ptr::addr_of_mut!((*state_ptr).inputstack_storage).write(inputstack_storage);
2256 core::ptr::addr_of_mut!((*state_ptr).inputfile_storage).write(inputfile_storage);
2257 core::ptr::addr_of_mut!((*state_ptr).eofseen_storage).write(eofseen_storage);
2258 core::ptr::addr_of_mut!((*state_ptr).linestack_storage).write(linestack_storage);
2259 core::ptr::addr_of_mut!((*state_ptr).grpstack_storage).write(grpstack_storage);
2260 core::ptr::addr_of_mut!((*state_ptr).ifstack_storage).write(ifstack_storage);
2261 core::ptr::addr_of_mut!((*state_ptr).sourcefilenamestack_storage)
2262 .write(sourcefilenamestack_storage);
2263 core::ptr::addr_of_mut!((*state_ptr).fullsourcefilenamestack_storage)
2264 .write(fullsourcefilenamestack_storage);
2265 core::ptr::addr_of_mut!((*state_ptr).paramstack_storage).write(paramstack_storage);
2266 core::ptr::addr_of_mut!((*state_ptr).hyphword_storage).write(hyphword_storage);
2267 core::ptr::addr_of_mut!((*state_ptr).hyphlist_storage).write(hyphlist_storage);
2268 core::ptr::addr_of_mut!((*state_ptr).hyphlink_storage).write(hyphlink_storage);
2269 core::ptr::addr_of_mut!((*state_ptr).hash_paged).write(hash_paged);
2270 core::ptr::addr_of_mut!((*state_ptr).eqtb_paged).write(eqtb_paged);
2271 core::ptr::addr_of_mut!((*state_ptr).strstart_storage).write(strstart_storage);
2272 core::ptr::addr_of_mut!((*state_ptr).strpool_storage).write(strpool_storage);
2273 core::ptr::addr_of_mut!((*state_ptr).fontinfo_storage).write(fontinfo_storage);
2274 core::ptr::addr_of_mut!((*state_ptr).bcharlabel_storage).write(bcharlabel_storage);
2275 core::ptr::addr_of_mut!((*state_ptr).charbase_storage).write(charbase_storage);
2276 core::ptr::addr_of_mut!((*state_ptr).widthbase_storage).write(widthbase_storage);
2277 core::ptr::addr_of_mut!((*state_ptr).heightbase_storage).write(heightbase_storage);
2278 core::ptr::addr_of_mut!((*state_ptr).depthbase_storage).write(depthbase_storage);
2279 core::ptr::addr_of_mut!((*state_ptr).italicbase_storage).write(italicbase_storage);
2280 core::ptr::addr_of_mut!((*state_ptr).ligkernbase_storage).write(ligkernbase_storage);
2281 core::ptr::addr_of_mut!((*state_ptr).kernbase_storage).write(kernbase_storage);
2282 core::ptr::addr_of_mut!((*state_ptr).extenbase_storage).write(extenbase_storage);
2283 core::ptr::addr_of_mut!((*state_ptr).parambase_storage).write(parambase_storage);
2284 core::ptr::addr_of_mut!((*state_ptr).fontarea_storage).write(fontarea_storage);
2285 core::ptr::addr_of_mut!((*state_ptr).fontname_storage).write(fontname_storage);
2286 core::ptr::addr_of_mut!((*state_ptr).fontbc_storage).write(fontbc_storage);
2287 core::ptr::addr_of_mut!((*state_ptr).fontec_storage).write(fontec_storage);
2288 core::ptr::addr_of_mut!((*state_ptr).fontbchar_storage).write(fontbchar_storage);
2289 core::ptr::addr_of_mut!((*state_ptr).fontfalsebchar_storage).write(fontfalsebchar_storage);
2290 core::ptr::addr_of_mut!((*state_ptr).fontcheck_storage).write(fontcheck_storage);
2291 core::ptr::addr_of_mut!((*state_ptr).fontdsize_storage).write(fontdsize_storage);
2292 core::ptr::addr_of_mut!((*state_ptr).fontsize_storage).write(fontsize_storage);
2293 core::ptr::addr_of_mut!((*state_ptr).fontflags_storage).write(fontflags_storage);
2294 core::ptr::addr_of_mut!((*state_ptr).fontglue_storage).write(fontglue_storage);
2295 core::ptr::addr_of_mut!((*state_ptr).fontlayoutengine_storage).write(fontlayoutengine_storage);
2296 core::ptr::addr_of_mut!((*state_ptr).fontletterspace_storage).write(fontletterspace_storage);
2297 core::ptr::addr_of_mut!((*state_ptr).fontmapping_storage).write(fontmapping_storage);
2298 core::ptr::addr_of_mut!((*state_ptr).fontparams_storage).write(fontparams_storage);
2299 core::ptr::addr_of_mut!((*state_ptr).fontused_storage).write(fontused_storage);
2300 core::ptr::addr_of_mut!((*state_ptr).nativetext_storage).write(nativetext_storage);
2301 core::ptr::addr_of_mut!((*state_ptr).hyphenchar_storage).write(hyphenchar_storage);
2302 core::ptr::addr_of_mut!((*state_ptr).skewchar_storage).write(skewchar_storage);
2303 core::ptr::addr_of_mut!((*state_ptr).triec_storage).write(triec_storage);
2304 core::ptr::addr_of_mut!((*state_ptr).triehash_storage).write(triehash_storage);
2305 core::ptr::addr_of_mut!((*state_ptr).triel_storage).write(triel_storage);
2306 core::ptr::addr_of_mut!((*state_ptr).trieo_storage).write(trieo_storage);
2307 core::ptr::addr_of_mut!((*state_ptr).trier_storage).write(trier_storage);
2308 core::ptr::addr_of_mut!((*state_ptr).trietaken_storage).write(trietaken_storage);
2309 core::ptr::addr_of_mut!((*state_ptr).trietrc_storage).write(trietrc_storage);
2310 core::ptr::addr_of_mut!((*state_ptr).trietrl_storage).write(trietrl_storage);
2311 core::ptr::addr_of_mut!((*state_ptr).trietro_storage).write(trietro_storage);
2312 core::ptr::addr_of_mut!((*state_ptr).src_spans).write(src_spans);
2313 core::ptr::addr_of_mut!((*state_ptr).src_dedup).write(src_dedup);
2314 core::ptr::addr_of_mut!((*state_ptr).node_src).write(node_src);
2315 core::ptr::addr_of_mut!((*state_ptr).src_native_offsets).write(src_native_offsets);
2316 core::ptr::addr_of_mut!((*state_ptr).src_stack_cells).write(src_stack_cells);
2317 core::ptr::addr_of_mut!((*state_ptr).node_stack).write(node_stack);
2318 let mut state = state.assume_init();
2319 state.refresh_runtime_pointers();
2320 state
2321 }
2322 }
2323
2324 fn refresh_runtime_pointers(&mut self) {
2325 self.zmem = pointer_or_null(&mut self.mem).wrapping_offset(-(self.memmin as isize));
2326 self.buffer = pointer_or_null(&mut self.buffer_storage);
2327 self.nest = pointer_or_null(&mut self.nest_storage);
2328 self.savestack = pointer_or_null(&mut self.savestack_storage);
2329 self.inputstack = pointer_or_null(&mut self.inputstack_storage);
2330 self.inputfile = pointer_or_null(&mut self.inputfile_storage);
2331 self.eofseen = pointer_or_null(&mut self.eofseen_storage);
2332 self.linestack = pointer_or_null(&mut self.linestack_storage);
2333 self.grpstack = pointer_or_null(&mut self.grpstack_storage);
2334 self.ifstack = pointer_or_null(&mut self.ifstack_storage);
2335 self.sourcefilenamestack = pointer_or_null(&mut self.sourcefilenamestack_storage);
2336 self.fullsourcefilenamestack =
2337 pointer_or_null(&mut self.fullsourcefilenamestack_storage);
2338 self.paramstack = pointer_or_null(&mut self.paramstack_storage);
2339 self.hyphword = pointer_or_null(&mut self.hyphword_storage);
2340 self.hyphlist = pointer_or_null(&mut self.hyphlist_storage);
2341 self.hyphlink = pointer_or_null(&mut self.hyphlink_storage);
2342 self.hash = PagedView::new(&mut self.hash_paged);
2343 self.zeqtb = PagedView::new(&mut self.eqtb_paged);
2344 self.strstart = pointer_or_null(&mut self.strstart_storage);
2345 self.strpool = pointer_or_null(&mut self.strpool_storage);
2346 self.fontinfo = pointer_or_null(&mut self.fontinfo_storage);
2347 self.bcharlabel = pointer_or_null(&mut self.bcharlabel_storage);
2348 self.charbase = pointer_or_null(&mut self.charbase_storage);
2349 self.widthbase = pointer_or_null(&mut self.widthbase_storage);
2350 self.heightbase = pointer_or_null(&mut self.heightbase_storage);
2351 self.depthbase = pointer_or_null(&mut self.depthbase_storage);
2352 self.italicbase = pointer_or_null(&mut self.italicbase_storage);
2353 self.ligkernbase = pointer_or_null(&mut self.ligkernbase_storage);
2354 self.kernbase = pointer_or_null(&mut self.kernbase_storage);
2355 self.extenbase = pointer_or_null(&mut self.extenbase_storage);
2356 self.parambase = pointer_or_null(&mut self.parambase_storage);
2357 self.fontarea = pointer_or_null(&mut self.fontarea_storage);
2358 self.fontname = pointer_or_null(&mut self.fontname_storage);
2359 self.fontbc = pointer_or_null(&mut self.fontbc_storage);
2360 self.fontec = pointer_or_null(&mut self.fontec_storage);
2361 self.fontbchar = pointer_or_null(&mut self.fontbchar_storage);
2362 self.fontfalsebchar = pointer_or_null(&mut self.fontfalsebchar_storage);
2363 self.fontcheck = pointer_or_null(&mut self.fontcheck_storage);
2364 self.fontdsize = pointer_or_null(&mut self.fontdsize_storage);
2365 self.fontsize = pointer_or_null(&mut self.fontsize_storage);
2366 self.fontflags = pointer_or_null(&mut self.fontflags_storage);
2367 self.fontglue = pointer_or_null(&mut self.fontglue_storage);
2368 self.fontlayoutengine = pointer_or_null(&mut self.fontlayoutengine_storage);
2369 self.fontletterspace = pointer_or_null(&mut self.fontletterspace_storage);
2370 self.fontmapping = pointer_or_null(&mut self.fontmapping_storage);
2371 self.fontparams = pointer_or_null(&mut self.fontparams_storage);
2372 self.fontused = pointer_or_null(&mut self.fontused_storage);
2373 self.nativetext = pointer_or_null(&mut self.nativetext_storage);
2374 self.hyphenchar = pointer_or_null(&mut self.hyphenchar_storage);
2375 self.skewchar = pointer_or_null(&mut self.skewchar_storage);
2376 self.triec = pointer_or_null(&mut self.triec_storage);
2377 self.triehash = pointer_or_null(&mut self.triehash_storage);
2378 self.triel = pointer_or_null(&mut self.triel_storage);
2379 self.trieo = pointer_or_null(&mut self.trieo_storage);
2380 self.trier = pointer_or_null(&mut self.trier_storage);
2381 self.trietaken = pointer_or_null(&mut self.trietaken_storage);
2382 self.trietrc = pointer_or_null(&mut self.trietrc_storage);
2383 self.trietrl = pointer_or_null(&mut self.trietrl_storage);
2384 self.trietro = pointer_or_null(&mut self.trietro_storage);
2385 }
2386
2387 fn seal_as_format_snapshot(&mut self) {
2388 self.curinput = instaterecord::default();
2389 self.inputptr = 0;
2390 self.inopen = 0;
2391 self.baseptr = 0;
2392 self.scannerstatus = 0;
2393 self.warningindex = 0;
2394 self.defref = -(268435455 as i64) as halfword;
2395 self.paramptr = 0;
2396 self.alignstate = 1000000 as integer;
2397 self.first = 0;
2398 self.last = 0;
2399 self.line = 0;
2400 self.openparens = 0;
2401 self.inputstack_storage.fill(instaterecord::default());
2402 self.inputfile_storage.fill(core::ptr::null_mut());
2403 self.eofseen_storage.fill(false_0);
2404 self.linestack_storage.fill(0);
2405 self.grpstack_storage.fill(-(268435455 as i64) as halfword);
2406 self.ifstack_storage.fill(-(268435455 as i64) as halfword);
2407 self.sourcefilenamestack_storage.fill(0);
2408 self.fullsourcefilenamestack_storage.fill(0);
2409 self.paramstack_storage.fill(0);
2410 self.eqtb_paged.compact();
2414 self.hash_paged.compact();
2415 if self.trienotready == false_0 {
2422 self.triehash_storage = Vec::new();
2423 self.triel_storage = Vec::new();
2424 self.trier_storage = Vec::new();
2425 self.trieo_storage = Vec::new();
2426 self.triec_storage = Vec::new();
2427 self.trietaken_storage = Vec::new();
2428 }
2429 self.refresh_runtime_pointers();
2430 }
2431
2432 pub(crate) fn to_portable_bytes(&self) -> Vec<u8> {
2445 let mut out = Vec::new();
2446 out.extend_from_slice(&PORTABLE_FORMAT_MAGIC);
2447 out.push(core::mem::size_of::<usize>() as u8);
2448 out.extend_from_slice(&(core::mem::size_of::<PortableTexState>() as u64).to_le_bytes());
2449 let image = unsafe {
2452 core::slice::from_raw_parts(
2453 self as *const Self as *const u8,
2454 core::mem::size_of::<Self>(),
2455 )
2456 };
2457 out.extend_from_slice(image);
2458 let lo_len = (self.lomemmax - self.memmin + 1).max(0) as usize;
2462 let hi_start = (self.himemmin - self.memmin).max(0) as usize;
2463 let hi_len = (self.memend - self.himemmin + 1).max(0) as usize;
2464 portable_write_vec_ranges::<memoryword>(
2465 &mut out,
2466 self.mem.as_slice(),
2467 &[(0, lo_len), (hi_start, hi_len)],
2468 );
2469 macro_rules! write_field {
2471 ($name:ident, $ty:ty) => {{
2472 let slice = self.$name.as_slice();
2473 let used = portable_used_prefix_len(slice);
2474 let ranges: &[(usize, usize)] = if used == 0 { &[] } else { &[(0, used)] };
2475 portable_write_vec_ranges::<$ty>(&mut out, slice, ranges);
2476 }};
2477 }
2478 portable_owning_vecs!(write_field);
2479 portable_write_paged(&mut out, &self.eqtb_paged);
2481 portable_write_paged(&mut out, &self.hash_paged);
2482 out
2483 }
2484
2485 pub(crate) fn from_portable_bytes(bytes: &[u8]) -> Option<Box<Self>> {
2494 let mut cursor = 0usize;
2495 if bytes.get(cursor..cursor + PORTABLE_FORMAT_MAGIC.len())? != &PORTABLE_FORMAT_MAGIC[..] {
2496 return None;
2497 }
2498 cursor += PORTABLE_FORMAT_MAGIC.len();
2499 if *bytes.get(cursor)? as usize != core::mem::size_of::<usize>() {
2500 return None;
2501 }
2502 cursor += 1;
2503 let struct_size =
2504 u64::from_le_bytes(bytes.get(cursor..cursor + 8)?.try_into().ok()?) as usize;
2505 cursor += 8;
2506 if struct_size != core::mem::size_of::<Self>() {
2507 return None;
2508 }
2509 let image = bytes.get(cursor..cursor + core::mem::size_of::<Self>())?;
2510 cursor += core::mem::size_of::<Self>();
2511
2512 let mut state = Box::<Self>::new_uninit();
2513 let state_ptr = state.as_mut_ptr();
2514 let state = unsafe {
2519 core::ptr::copy_nonoverlapping(
2520 image.as_ptr(),
2521 state_ptr as *mut u8,
2522 core::mem::size_of::<Self>(),
2523 );
2524 let decoded_mem: Vec<memoryword> = portable_read_vec_ranges(bytes, &mut cursor)?;
2525 core::ptr::addr_of_mut!((*state_ptr).mem).write(decoded_mem);
2526 macro_rules! read_field {
2527 ($name:ident, $ty:ty) => {
2528 let decoded: Vec<$ty> = portable_read_vec_ranges(bytes, &mut cursor)?;
2529 core::ptr::addr_of_mut!((*state_ptr).$name).write(decoded);
2530 };
2531 }
2532 portable_owning_vecs!(read_field);
2533 let eqtb_paged =
2534 portable_read_paged(bytes, &mut cursor, eqtb_codepoint_default, eqtb_sig_range)?;
2535 core::ptr::addr_of_mut!((*state_ptr).eqtb_paged).write(eqtb_paged);
2536 let hash_paged =
2537 portable_read_paged(bytes, &mut cursor, hash_codepoint_default, hash_sig_range)?;
2538 core::ptr::addr_of_mut!((*state_ptr).hash_paged).write(hash_paged);
2539 core::ptr::addr_of_mut!((*state_ptr).src_spans).write(Vec::new());
2545 core::ptr::addr_of_mut!((*state_ptr).src_dedup)
2546 .write(std::collections::HashMap::new());
2547 core::ptr::addr_of_mut!((*state_ptr).node_src)
2548 .write(PagedArray::new(0, 0, node_src_default, node_src_sig));
2549 core::ptr::addr_of_mut!((*state_ptr).src_native_offsets).write(Vec::new());
2550 core::ptr::addr_of_mut!((*state_ptr).src_stack_cells).write(Vec::new());
2551 core::ptr::addr_of_mut!((*state_ptr).cur_stack_head).write(0);
2552 core::ptr::addr_of_mut!((*state_ptr).node_stack)
2553 .write(PagedArray::new(0, 0, node_stack_default, node_stack_sig));
2554 for slot in (*state_ptr).inputfile_storage.iter_mut() {
2558 *slot = core::ptr::null_mut();
2559 }
2560 let mut state = state.assume_init();
2561 state.refresh_runtime_pointers();
2562 state
2563 };
2564 Some(state)
2565 }
2566
2567 pub(crate) fn state_array_bytes(&self) -> usize {
2571 let mut total = self.mem.capacity() * core::mem::size_of::<memoryword>();
2572 macro_rules! accumulate {
2573 ($name:ident, $ty:ty) => {
2574 total += self.$name.capacity() * core::mem::size_of::<$ty>();
2575 };
2576 }
2577 portable_owning_vecs!(accumulate);
2578 total += self.eqtb_paged.resident_bytes() + self.hash_paged.resident_bytes();
2579 total
2580 }
2581
2582 fn allocate_initial_arrays(&mut self) {
2583 self.iniversion = true_0;
2584 self.membot = 0;
2585 self.memmin = self.membot;
2586 self.memtop = 999_999;
2591 self.memmax = self.memtop;
2592 self.hashextra = 600_000;
2593 self.eqtbtop = xetex_eqtb_top + self.hashextra;
2594 self.bufsize = 200_000;
2595 self.nestsize = 1_000;
2596 self.maxinopen = 15;
2597 self.paramsize = 20_000;
2598 self.savesize = 200_000;
2599 self.stacksize = 10_000;
2600 self.dvibufsize = 16_384;
2601 self.poolsize = 6_250_000;
2602 self.maxstrings = 500_000;
2603 self.fontmemsize = 1_000_000;
2604 self.fontmax = 500;
2605 self.triesize = 1_100_000;
2611 self.hyphsize = 8_191;
2612 self.primused = 2_100;
2613 self.errorline = 79;
2614 self.halferrorline = 50;
2615 self.maxprintline = 79;
2616 self.expanddepth = 10_000;
2617
2618 self.mem = zeroed_vec((self.memtop - self.memmin + 1) as usize);
2619 self.buffer_storage = zeroed_vec((self.bufsize + 1) as usize);
2627 self.nest_storage = zeroed_vec((self.nestsize + 1) as usize);
2628 self.savestack_storage = zeroed_vec((self.savesize + 1) as usize);
2629 self.inputstack_storage = zeroed_vec((self.stacksize + 1) as usize);
2630 self.inputfile_storage = zeroed_vec((self.maxinopen + 1) as usize);
2631 self.eofseen_storage = zeroed_vec((self.maxinopen + 1) as usize);
2632 self.linestack_storage = zeroed_vec((self.maxinopen + 1) as usize);
2633 self.grpstack_storage = zeroed_vec((self.maxinopen + 1) as usize);
2634 self.ifstack_storage = zeroed_vec((self.maxinopen + 1) as usize);
2635 self.sourcefilenamestack_storage = zeroed_vec((self.maxinopen + 1) as usize);
2636 self.fullsourcefilenamestack_storage = zeroed_vec((self.maxinopen + 1) as usize);
2637 self.paramstack_storage = zeroed_vec((self.paramsize + 1) as usize);
2638 self.hyphword_storage = zeroed_vec((self.hyphsize + 1) as usize);
2639 self.hyphlist_storage = zeroed_vec((self.hyphsize + 1) as usize);
2640 self.hyphlink_storage = zeroed_vec((self.hyphsize + 1) as usize);
2641 self.eqtb_paged = PagedArray::new(
2645 0,
2646 (self.eqtbtop + 1) as usize,
2647 eqtb_codepoint_default,
2648 eqtb_sig_range,
2649 );
2650 self.hash_paged = PagedArray::new(
2651 hashoffset as usize,
2652 (self.eqtbtop + 1) as usize,
2653 hash_codepoint_default,
2654 hash_sig_range,
2655 );
2656 self.strstart_storage = zeroed_vec((self.maxstrings + 1) as usize);
2657 self.strpool_storage = zeroed_vec((self.poolsize + 1) as usize);
2658 self.fontinfo_storage = zeroed_vec((self.fontmemsize + 1) as usize);
2659 let font_slots = (self.fontmax + 1) as usize;
2660 self.bcharlabel_storage = zeroed_vec(font_slots);
2661 self.charbase_storage = zeroed_vec(font_slots);
2662 self.widthbase_storage = zeroed_vec(font_slots);
2663 self.heightbase_storage = zeroed_vec(font_slots);
2664 self.depthbase_storage = zeroed_vec(font_slots);
2665 self.italicbase_storage = zeroed_vec(font_slots);
2666 self.ligkernbase_storage = zeroed_vec(font_slots);
2667 self.kernbase_storage = zeroed_vec(font_slots);
2668 self.extenbase_storage = zeroed_vec(font_slots);
2669 self.parambase_storage = zeroed_vec(font_slots);
2670 self.fontarea_storage = zeroed_vec(font_slots);
2671 self.fontname_storage = zeroed_vec(font_slots);
2672 self.fontbc_storage = zeroed_vec(font_slots);
2673 self.fontec_storage = zeroed_vec(font_slots);
2674 self.fontbchar_storage = zeroed_vec(font_slots);
2675 self.fontfalsebchar_storage = zeroed_vec(font_slots);
2676 self.fontcheck_storage = zeroed_vec(font_slots);
2677 self.fontdsize_storage = zeroed_vec(font_slots);
2678 self.fontsize_storage = zeroed_vec(font_slots);
2679 self.fontflags_storage = zeroed_vec(font_slots);
2680 self.fontglue_storage = zeroed_vec(font_slots);
2681 self.fontlayoutengine_storage = zeroed_vec(font_slots);
2682 self.fontletterspace_storage = zeroed_vec(font_slots);
2683 self.fontmapping_storage = zeroed_vec(font_slots);
2684 self.fontparams_storage = zeroed_vec(font_slots);
2685 self.fontused_storage = zeroed_vec(font_slots);
2686 self.nativetext_storage = Vec::new();
2687 self.hyphenchar_storage = zeroed_vec(font_slots);
2688 self.skewchar_storage = zeroed_vec(font_slots);
2689 let trie_slots = (self.triesize + 1) as usize;
2690 self.triec_storage = zeroed_vec(trie_slots);
2691 self.triehash_storage = zeroed_vec(trie_slots);
2692 self.triel_storage = zeroed_vec(trie_slots);
2693 self.trieo_storage = zeroed_vec(trie_slots);
2694 self.trier_storage = zeroed_vec(trie_slots);
2695 self.trietaken_storage = zeroed_vec(trie_slots);
2696 self.trietrc_storage = zeroed_vec(trie_slots);
2697 self.trietrl_storage = zeroed_vec(trie_slots);
2698 self.trietro_storage = zeroed_vec(trie_slots);
2699 self.refresh_runtime_pointers();
2700 }
2701}
2702
2703fn zeroed_vec<T>(len: usize) -> Vec<T>
2704where
2705 T: Clone + Default,
2706{
2707 vec![T::default(); len]
2708}
2709
2710fn pointer_or_null<T>(storage: &mut Vec<T>) -> *mut T {
2711 if storage.is_empty() {
2712 core::ptr::null_mut()
2713 } else {
2714 storage.as_mut_ptr()
2715 }
2716}
2717
2718#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2719pub enum EngineProfileKind {
2720 Tex,
2721 Etex,
2722 Xetex,
2723}
2724
2725#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2726pub struct EngineProfile {
2727 pub id: &'static str,
2728 pub kind: EngineProfileKind,
2729 pub etex: bool,
2730 pub xetex: bool,
2731 pub unicode_scalars: bool,
2732 pub unicode_math: bool,
2733 pub native_fonts: bool,
2734}
2735
2736#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2737struct WriteTokenConstants {
2738 open_group_token: halfword,
2739 end_write_token: halfword,
2740 close_group_token: halfword,
2741}
2742
2743impl EngineProfile {
2744 pub const fn tex() -> Self {
2745 Self {
2746 id: "tex",
2747 kind: EngineProfileKind::Tex,
2748 etex: false,
2749 xetex: false,
2750 unicode_scalars: false,
2751 unicode_math: false,
2752 native_fonts: false,
2753 }
2754 }
2755
2756 pub const fn etex() -> Self {
2757 Self {
2758 id: "etex",
2759 kind: EngineProfileKind::Etex,
2760 etex: true,
2761 xetex: false,
2762 unicode_scalars: false,
2763 unicode_math: false,
2764 native_fonts: false,
2765 }
2766 }
2767
2768 pub const fn xetex() -> Self {
2769 Self {
2770 id: "xetex",
2771 kind: EngineProfileKind::Xetex,
2772 etex: true,
2773 xetex: true,
2774 unicode_scalars: true,
2775 unicode_math: true,
2776 native_fonts: false,
2777 }
2778 }
2779
2780 const fn write_token_constants(self) -> WriteTokenConstants {
2781 match self.kind {
2782 EngineProfileKind::Tex | EngineProfileKind::Etex => WriteTokenConstants {
2783 open_group_token: 637,
2784 end_write_token: 19617,
2785 close_group_token: 379,
2786 },
2787 EngineProfileKind::Xetex => WriteTokenConstants {
2788 open_group_token: 4_194_429,
2789 end_write_token: 34_749_089,
2790 close_group_token: 2_097_275,
2791 },
2792 }
2793 }
2794}
2795
2796pub struct PortableFormatImage {
2797 state: Box<PortableTexState>,
2798}
2799
2800#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2801pub struct PortableNodeHandle(pub i32);
2802
2803#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2804pub enum PortableNodeKind {
2805 HorizontalBox,
2806 VerticalBox,
2807 Rule,
2808 Insertion,
2809 Mark,
2810 Adjustment,
2811 Ligature,
2812 Discretionary,
2813 OutputWhatsit,
2814 Whatsit,
2815 Math,
2816 Glue,
2817 Kern,
2818 Penalty,
2819 UnsetBox,
2820 Noad,
2821 Style,
2822 Choice,
2823 Character,
2824 NativeWord,
2825 NativeGlyph,
2826 Unknown(i32),
2827}
2828
2829#[derive(Clone, Debug, PartialEq)]
2830pub struct PortableNodeSnapshot {
2831 pub handle: PortableNodeHandle,
2832 pub kind: PortableNodeKind,
2833 pub subtype: i32,
2834 pub source: Option<PortableSourceSpan>,
2835 pub link: Option<PortableNodeHandle>,
2836 pub font: i32,
2837 pub character: i32,
2838 pub width: i32,
2839 pub height: i32,
2840 pub depth: i32,
2841 pub shift: i32,
2842 pub list: Option<PortableNodeHandle>,
2843 pub native_glyphs: Vec<PortableNativeGlyph>,
2844 pub glue_set: f64,
2846 pub glue_sign: i32,
2848 pub glue_order: i32,
2850 pub glue_stretch: i32,
2852 pub glue_shrink: i32,
2854 pub glue_stretch_order: i32,
2856 pub glue_shrink_order: i32,
2858}
2859
2860impl Clone for PortableFormatImage {
2861 fn clone(&self) -> Self {
2862 Self {
2863 state: self.state.clone_boxed(),
2864 }
2865 }
2866}
2867
2868impl PortableFormatImage {
2869 pub fn empty() -> Self {
2870 Self {
2871 state: PortableTexState::new_boxed_default(),
2872 }
2873 }
2874
2875 fn from_engine_state(state: &PortableTexState) -> Self {
2876 let mut state = state.clone_boxed();
2877 state.seal_as_format_snapshot();
2878 Self {
2879 state,
2880 }
2881 }
2882
2883 fn from_sealed_state(state: Box<PortableTexState>) -> Self {
2886 Self { state }
2887 }
2888
2889 #[must_use]
2893 pub fn to_bytes(&self) -> Vec<u8> {
2894 self.state.to_portable_bytes()
2895 }
2896
2897 #[must_use]
2900 pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
2901 Some(Self {
2902 state: PortableTexState::from_portable_bytes(bytes)?,
2903 })
2904 }
2905
2906 #[must_use]
2909 pub fn state_array_bytes(&self) -> usize {
2910 self.state.state_array_bytes()
2911 }
2912
2913}
2914
2915#[must_use]
2919pub fn memory_word_bytes() -> usize {
2920 core::mem::size_of::<memoryword>()
2921}
2922
2923pub struct PortableTexEngine<'resources> {
2924 pub(crate) state: Box<PortableTexState>,
2925 pub(crate) profile: EngineProfile,
2926 pub(crate) resources: Box<dyn ResourceProvider + 'resources>,
2927 pub(crate) fonts: Box<dyn FontPlatform + 'resources>,
2928 pub(crate) platform: Box<dyn PortablePlatform + 'resources>,
2929 pub(crate) nameoffile_storage: Vec<UTF8code>,
2930 native_glyph_infos: std::collections::BTreeMap<i32, PortableNativeGlyphInfo>,
2931 character_protrusions: std::collections::BTreeMap<(integer, u32, integer), integer>,
2932 pub(crate) resource_requests: usize,
2933 pub(crate) resource_request_records: Vec<PortableResourceRequestRecord>,
2934 pub(crate) virtual_files: std::collections::BTreeMap<String, Vec<u8>>,
2935 pub(crate) transcript_bytes: Vec<u8>,
2936 pub(crate) current_input_package_owner: Option<String>,
2937 pub(crate) stripped_page_builds: usize,
2938 pub(crate) stripped_shipouts: usize,
2939 pub(crate) stripped_special_outputs: usize,
2940 pub(crate) stripped_picture_loads: usize,
2941 pub(crate) stripped_source_specials: usize,
2942 pub(crate) stripped_write_whatsit_diagnostics: usize,
2943 pub(crate) stripped_pdf_extensions: usize,
2944 pub(crate) stripped_page_top_prunes: usize,
2945 pub(crate) last_stripped_shipout_box: Option<PortableNodeHandle>,
2946 pub(crate) fragment_capture_enabled: bool,
2947 pub(crate) format_initialization: bool,
2948 pub(crate) captured_fragment_root: Option<PortableNodeHandle>,
2949 pub(crate) last_abort_status: Option<integer>,
2950 pub(crate) last_error_message: Option<String>,
2954 pub(crate) sandbox: bool,
2960 pub(crate) sandbox_math_depth: i32,
2967 pub(crate) sandbox_math_opened: bool,
2971 pub(crate) sandbox_ops: u64,
2974}
2975
2976pub(crate) fn zround(value: real) -> integer {
2977 value.round() as integer
2978}
2979
2980impl<'resources> PortableTexEngine<'resources> {
2981 pub fn from_format<R>(
2982 profile: EngineProfile,
2983 format: &PortableFormatImage,
2984 resources: R,
2985 ) -> Self
2986 where
2987 R: ResourceProvider + 'resources,
2988 {
2989 Self {
2990 state: format.state.clone_boxed(),
2991 profile,
2992 resources: Box::new(resources),
2993 fonts: Box::<EmptyFontPlatform>::default(),
2994 platform: Box::<EmptyPlatform>::default(),
2995 nameoffile_storage: Vec::new(),
2996 native_glyph_infos: std::collections::BTreeMap::new(),
2997 character_protrusions: std::collections::BTreeMap::new(),
2998 resource_requests: 0,
2999 resource_request_records: Vec::new(),
3000 virtual_files: std::collections::BTreeMap::new(),
3001 transcript_bytes: Vec::new(),
3002 current_input_package_owner: None,
3003 stripped_page_builds: 0,
3004 stripped_shipouts: 0,
3005 stripped_special_outputs: 0,
3006 stripped_picture_loads: 0,
3007 stripped_source_specials: 0,
3008 stripped_write_whatsit_diagnostics: 0,
3009 stripped_pdf_extensions: 0,
3010 stripped_page_top_prunes: 0,
3011 last_stripped_shipout_box: None,
3012 fragment_capture_enabled: false,
3013 format_initialization: false,
3014 captured_fragment_root: None,
3015 last_abort_status: None,
3016 last_error_message: None,
3017 sandbox: false,
3018 sandbox_math_depth: 0,
3019 sandbox_math_opened: false,
3020 sandbox_ops: 0,
3021 }
3022 }
3023
3024 pub fn with_font_platform<F>(mut self, fonts: F) -> Self
3025 where
3026 F: FontPlatform + 'resources,
3027 {
3028 self.fonts = Box::new(fonts);
3029 self
3030 }
3031
3032 pub fn with_platform<P>(mut self, platform: P) -> Self
3033 where
3034 P: PortablePlatform + 'resources,
3035 {
3036 self.platform = Box::new(platform);
3037 self
3038 }
3039
3040 pub fn profile(&self) -> EngineProfile {
3041 self.profile
3042 }
3043
3044 pub fn initialize_format_state(self: &mut Self) -> bool {
3045 self.catch_engine_abort(|engine| unsafe {
3046 let this = engine as *mut PortableTexEngine<'_>;
3047 engine.state.allocate_initial_arrays();
3048 engine.initialize();
3049 if engine.supports_etex() {
3050 engine.state.eTeXmode = 1 as eightbits;
3051 }
3052 if engine.getstringsstarted()? == 0 {
3057 Self::abort_engine(this, 1 as integer)?;
3058 }
3059 engine.initprim()?;
3060 engine.init_etex_startup_primitives()?;
3061 engine.init_xetex_startup_primitives()?;
3062 engine.state.initstrptr = engine.state.strptr;
3063 engine.state.initpoolptr = engine.state.poolptr;
3064 engine.state.magicoffset =
3073 (*engine.state.strstart.offset(784) as integer - 9 * 16) as integer;
3074 engine.state.alignstate = 1000000 as integer;
3075 Ok(())
3076 })
3077 }
3078
3079 pub(crate) fn ensure_nativetext_capacity(
3080 engine: &mut PortableTexEngine<'_>,
3081 required: integer,
3082 ) {
3083 let required = required.max(0) as usize;
3084 if engine.state.nativetext_storage.len() < required {
3085 engine.state.nativetext_storage.resize(required, UTF16code::default());
3086 }
3087 engine.state.nativetext = pointer_or_null(&mut engine.state.nativetext_storage);
3088 }
3089
3090 unsafe fn init_etex_startup_primitives(&mut self) -> EngineFlow<()> {
3091 if !self.supports_etex() || self.is_xetex() {
3092 return Ok(());
3093 }
3094 self.state.nonewcontrolsequence = false_0 as boolean;
3095 (&mut *(self as *mut PortableTexEngine<'_>))
3096 .zprimitive(1360 as i32, 70 as i32 as quarterword, 3 as i32)?;
3097 (&mut *(self as *mut PortableTexEngine<'_>))
3098 .zprimitive(1361 as i32, 70 as i32 as quarterword, 6 as i32)?;
3099 (&mut *(self as *mut PortableTexEngine<'_>))
3100 .zprimitive(765 as i32, 108 as i32 as quarterword, 5 as i32)?;
3101 (&mut *(self as *mut PortableTexEngine<'_>))
3102 .zprimitive(1363 as i32, 72 as i32 as quarterword, 25067 as i32)?;
3103 (&mut *(self as *mut PortableTexEngine<'_>))
3104 .zprimitive(1364 as i32, 73 as i32 as quarterword, 27234 as i32)?;
3105 (&mut *(self as *mut PortableTexEngine<'_>))
3106 .zprimitive(1365 as i32, 73 as i32 as quarterword, 27235 as i32)?;
3107 (&mut *(self as *mut PortableTexEngine<'_>))
3108 .zprimitive(1366 as i32, 73 as i32 as quarterword, 27236 as i32)?;
3109 (&mut *(self as *mut PortableTexEngine<'_>))
3110 .zprimitive(1367 as i32, 73 as i32 as quarterword, 27237 as i32)?;
3111 (&mut *(self as *mut PortableTexEngine<'_>))
3112 .zprimitive(1368 as i32, 73 as i32 as quarterword, 27238 as i32)?;
3113 (&mut *(self as *mut PortableTexEngine<'_>))
3114 .zprimitive(1369 as i32, 73 as i32 as quarterword, 27239 as i32)?;
3115 (&mut *(self as *mut PortableTexEngine<'_>))
3116 .zprimitive(1370 as i32, 73 as i32 as quarterword, 27240 as i32)?;
3117 (&mut *(self as *mut PortableTexEngine<'_>))
3118 .zprimitive(1371 as i32, 73 as i32 as quarterword, 27241 as i32)?;
3119 (&mut *(self as *mut PortableTexEngine<'_>))
3120 .zprimitive(1372 as i32, 73 as i32 as quarterword, 27242 as i32)?;
3121 (&mut *(self as *mut PortableTexEngine<'_>))
3122 .zprimitive(1387 as i32, 70 as i32 as quarterword, 7 as i32)?;
3123 (&mut *(self as *mut PortableTexEngine<'_>))
3124 .zprimitive(1388 as i32, 70 as i32 as quarterword, 8 as i32)?;
3125 (&mut *(self as *mut PortableTexEngine<'_>))
3126 .zprimitive(1389 as i32, 70 as i32 as quarterword, 9 as i32)?;
3127 (&mut *(self as *mut PortableTexEngine<'_>))
3128 .zprimitive(1390 as i32, 70 as i32 as quarterword, 10 as i32)?;
3129 (&mut *(self as *mut PortableTexEngine<'_>))
3130 .zprimitive(1391 as i32, 70 as i32 as quarterword, 11 as i32)?;
3131 (&mut *(self as *mut PortableTexEngine<'_>))
3132 .zprimitive(1392 as i32, 70 as i32 as quarterword, 14 as i32)?;
3133 (&mut *(self as *mut PortableTexEngine<'_>))
3134 .zprimitive(1393 as i32, 70 as i32 as quarterword, 15 as i32)?;
3135 (&mut *(self as *mut PortableTexEngine<'_>))
3136 .zprimitive(1394 as i32, 70 as i32 as quarterword, 16 as i32)?;
3137 (&mut *(self as *mut PortableTexEngine<'_>))
3138 .zprimitive(1395 as i32, 70 as i32 as quarterword, 17 as i32)?;
3139 (&mut *(self as *mut PortableTexEngine<'_>))
3140 .zprimitive(1396 as i32, 70 as i32 as quarterword, 18 as i32)?;
3141 (&mut *(self as *mut PortableTexEngine<'_>))
3142 .zprimitive(1397 as i32, 70 as i32 as quarterword, 19 as i32)?;
3143 (&mut *(self as *mut PortableTexEngine<'_>))
3144 .zprimitive(1398 as i32, 70 as i32 as quarterword, 20 as i32)?;
3145 (&mut *(self as *mut PortableTexEngine<'_>))
3146 .zprimitive(1399 as i32, 19 as i32 as quarterword, 4 as i32)?;
3147 (&mut *(self as *mut PortableTexEngine<'_>))
3148 .zprimitive(1401 as i32, 19 as i32 as quarterword, 5 as i32)?;
3149 (&mut *(self as *mut PortableTexEngine<'_>))
3150 .zprimitive(1402 as i32, 109 as i32 as quarterword, 1 as i32)?;
3151 (&mut *(self as *mut PortableTexEngine<'_>))
3152 .zprimitive(1403 as i32, 109 as i32 as quarterword, 5 as i32)?;
3153 (&mut *(self as *mut PortableTexEngine<'_>))
3154 .zprimitive(1404 as i32, 19 as i32 as quarterword, 6 as i32)?;
3155 (&mut *(self as *mut PortableTexEngine<'_>))
3156 .zprimitive(1408 as i32, 82 as i32 as quarterword, 2 as i32)?;
3157 (&mut *(self as *mut PortableTexEngine<'_>))
3158 .zprimitive(908 as i32, 49 as i32 as quarterword, 1 as i32)?;
3159 (&mut *(self as *mut PortableTexEngine<'_>))
3160 .zprimitive(1412 as i32, 73 as i32 as quarterword, 27243 as i32)?;
3161 (&mut *(self as *mut PortableTexEngine<'_>))
3162 .zprimitive(1413 as i32, 33 as i32 as quarterword, 6 as i32)?;
3163 (&mut *(self as *mut PortableTexEngine<'_>))
3164 .zprimitive(1414 as i32, 33 as i32 as quarterword, 7 as i32)?;
3165 (&mut *(self as *mut PortableTexEngine<'_>))
3166 .zprimitive(1415 as i32, 33 as i32 as quarterword, 10 as i32)?;
3167 (&mut *(self as *mut PortableTexEngine<'_>))
3168 .zprimitive(1416 as i32, 33 as i32 as quarterword, 11 as i32)?;
3169 (&mut *(self as *mut PortableTexEngine<'_>))
3170 .zprimitive(1425 as i32, 104 as i32 as quarterword, 2 as i32)?;
3171 (&mut *(self as *mut PortableTexEngine<'_>))
3172 .zprimitive(1427 as i32, 96 as i32 as quarterword, 1 as i32)?;
3173 (&mut *(self as *mut PortableTexEngine<'_>))
3174 .zprimitive(799 as i32, 102 as i32 as quarterword, 1 as i32)?;
3175 (&mut *(self as *mut PortableTexEngine<'_>))
3176 .zprimitive(1428 as i32, 105 as i32 as quarterword, 17 as i32)?;
3177 (&mut *(self as *mut PortableTexEngine<'_>))
3178 .zprimitive(1429 as i32, 105 as i32 as quarterword, 18 as i32)?;
3179 (&mut *(self as *mut PortableTexEngine<'_>))
3180 .zprimitive(1430 as i32, 105 as i32 as quarterword, 19 as i32)?;
3181 (&mut *(self as *mut PortableTexEngine<'_>))
3182 .zprimitive(1217 as i32, 93 as i32 as quarterword, 8 as i32)?;
3183 (&mut *(self as *mut PortableTexEngine<'_>))
3184 .zprimitive(1436 as i32, 70 as i32 as quarterword, 25 as i32)?;
3185 (&mut *(self as *mut PortableTexEngine<'_>))
3186 .zprimitive(1437 as i32, 70 as i32 as quarterword, 26 as i32)?;
3187 (&mut *(self as *mut PortableTexEngine<'_>))
3188 .zprimitive(1438 as i32, 70 as i32 as quarterword, 27 as i32)?;
3189 (&mut *(self as *mut PortableTexEngine<'_>))
3190 .zprimitive(1439 as i32, 70 as i32 as quarterword, 28 as i32)?;
3191 (&mut *(self as *mut PortableTexEngine<'_>))
3192 .zprimitive(1443 as i32, 70 as i32 as quarterword, 12 as i32)?;
3193 (&mut *(self as *mut PortableTexEngine<'_>))
3194 .zprimitive(1444 as i32, 70 as i32 as quarterword, 13 as i32)?;
3195 (&mut *(self as *mut PortableTexEngine<'_>))
3196 .zprimitive(1445 as i32, 70 as i32 as quarterword, 21 as i32)?;
3197 (&mut *(self as *mut PortableTexEngine<'_>))
3198 .zprimitive(1446 as i32, 70 as i32 as quarterword, 22 as i32)?;
3199 (&mut *(self as *mut PortableTexEngine<'_>))
3200 .zprimitive(1447 as i32, 70 as i32 as quarterword, 23 as i32)?;
3201 (&mut *(self as *mut PortableTexEngine<'_>))
3202 .zprimitive(1448 as i32, 70 as i32 as quarterword, 24 as i32)?;
3203 (&mut *(self as *mut PortableTexEngine<'_>))
3204 .zprimitive(1449 as i32, 18 as i32 as quarterword, 5 as i32)?;
3205 (&mut *(self as *mut PortableTexEngine<'_>))
3206 .zprimitive(1450 as i32, 110 as i32 as quarterword, 5 as i32)?;
3207 (&mut *(self as *mut PortableTexEngine<'_>))
3208 .zprimitive(1451 as i32, 110 as i32 as quarterword, 6 as i32)?;
3209 (&mut *(self as *mut PortableTexEngine<'_>))
3210 .zprimitive(1452 as i32, 110 as i32 as quarterword, 7 as i32)?;
3211 (&mut *(self as *mut PortableTexEngine<'_>))
3212 .zprimitive(1453 as i32, 110 as i32 as quarterword, 8 as i32)?;
3213 (&mut *(self as *mut PortableTexEngine<'_>))
3214 .zprimitive(1454 as i32, 110 as i32 as quarterword, 9 as i32)?;
3215 (&mut *(self as *mut PortableTexEngine<'_>))
3216 .zprimitive(1458 as i32, 24 as i32 as quarterword, 2 as i32)?;
3217 (&mut *(self as *mut PortableTexEngine<'_>))
3218 .zprimitive(1459 as i32, 24 as i32 as quarterword, 3 as i32)?;
3219 (&mut *(self as *mut PortableTexEngine<'_>))
3220 .zprimitive(1460 as i32, 84 as i32 as quarterword, 25324 as i32)?;
3221 (&mut *(self as *mut PortableTexEngine<'_>))
3222 .zprimitive(1461 as i32, 84 as i32 as quarterword, 25325 as i32)?;
3223 (&mut *(self as *mut PortableTexEngine<'_>))
3224 .zprimitive(1462 as i32, 84 as i32 as quarterword, 25326 as i32)?;
3225 (&mut *(self as *mut PortableTexEngine<'_>))
3226 .zprimitive(1463 as i32, 84 as i32 as quarterword, 25327 as i32)?;
3227 self.state.eTeXmode = 1 as eightbits;
3228 Ok(())
3229 }
3230 unsafe fn init_xetex_startup_primitives(&mut self) -> EngineFlow<()> {
3231 if !self.is_xetex() {
3232 return Ok(());
3233 }
3234 self.state.nonewcontrolsequence = false_0 as boolean;
3235 (&mut *(self as *mut PortableTexEngine<'_>))
3236 .zprimitive(66755 as i64 as strnumber, 59 as i32 as quarterword, 41 as i32)?;
3237 (&mut *(self as *mut PortableTexEngine<'_>))
3238 .zprimitive(66756 as i64 as strnumber, 59 as i32 as quarterword, 42 as i32)?;
3239 (&mut *(self as *mut PortableTexEngine<'_>))
3240 .zprimitive(66757 as i64 as strnumber, 59 as i32 as quarterword, 43 as i32)?;
3241 (&mut *(self as *mut PortableTexEngine<'_>))
3242 .zprimitive(66758 as i64 as strnumber, 59 as i32 as quarterword, 46 as i32)?;
3243 (&mut *(self as *mut PortableTexEngine<'_>))
3244 .zprimitive(
3245 66759 as i64 as strnumber,
3246 73 as i32 as quarterword,
3247 1206306 as i64 as halfword,
3248 )?;
3249 (&mut *(self as *mut PortableTexEngine<'_>))
3250 .zprimitive(66760 as i64 as strnumber, 59 as i32 as quarterword, 23 as i32)?;
3251 (&mut *(self as *mut PortableTexEngine<'_>))
3252 .zprimitive(66816 as i64 as strnumber, 71 as i32 as quarterword, 3 as i32)?;
3253 (&mut *(self as *mut PortableTexEngine<'_>))
3254 .zprimitive(66817 as i64 as strnumber, 71 as i32 as quarterword, 19 as i32)?;
3255 (&mut *(self as *mut PortableTexEngine<'_>))
3256 .zprimitive(66115 as i64 as strnumber, 111 as i32 as quarterword, 5 as i32)?;
3257 (&mut *(self as *mut PortableTexEngine<'_>))
3258 .zprimitive(66818 as i64 as strnumber, 71 as i32 as quarterword, 27 as i32)?;
3259 (&mut *(self as *mut PortableTexEngine<'_>))
3260 .zprimitive(
3261 66819 as i64 as strnumber,
3262 111 as i32 as quarterword,
3263 33 as i32,
3264 )?;
3265 (&mut *(self as *mut PortableTexEngine<'_>))
3266 .zprimitive(66820 as i64 as strnumber, 71 as i32 as quarterword, 28 as i32)?;
3267 (&mut *(self as *mut PortableTexEngine<'_>))
3268 .zprimitive(66821 as i64 as strnumber, 71 as i32 as quarterword, 29 as i32)?;
3269 (&mut *(self as *mut PortableTexEngine<'_>))
3270 .zprimitive(66822 as i64 as strnumber, 71 as i32 as quarterword, 30 as i32)?;
3271 (&mut *(self as *mut PortableTexEngine<'_>))
3272 .zprimitive(66823 as i64 as strnumber, 71 as i32 as quarterword, 31 as i32)?;
3273 (&mut *(self as *mut PortableTexEngine<'_>))
3274 .zprimitive(66824 as i64 as strnumber, 71 as i32 as quarterword, 32 as i32)?;
3275 (&mut *(self as *mut PortableTexEngine<'_>))
3276 .zprimitive(66825 as i64 as strnumber, 71 as i32 as quarterword, 33 as i32)?;
3277 (&mut *(self as *mut PortableTexEngine<'_>))
3278 .zprimitive(66826 as i64 as strnumber, 71 as i32 as quarterword, 34 as i32)?;
3279 (&mut *(self as *mut PortableTexEngine<'_>))
3280 .zprimitive(66827 as i64 as strnumber, 71 as i32 as quarterword, 35 as i32)?;
3281 (&mut *(self as *mut PortableTexEngine<'_>))
3282 .zprimitive(66828 as i64 as strnumber, 71 as i32 as quarterword, 36 as i32)?;
3283 (&mut *(self as *mut PortableTexEngine<'_>))
3284 .zprimitive(66829 as i64 as strnumber, 71 as i32 as quarterword, 37 as i32)?;
3285 (&mut *(self as *mut PortableTexEngine<'_>))
3286 .zprimitive(66830 as i64 as strnumber, 71 as i32 as quarterword, 38 as i32)?;
3287 (&mut *(self as *mut PortableTexEngine<'_>))
3288 .zprimitive(66831 as i64 as strnumber, 71 as i32 as quarterword, 39 as i32)?;
3289 (&mut *(self as *mut PortableTexEngine<'_>))
3290 .zprimitive(66832 as i64 as strnumber, 71 as i32 as quarterword, 40 as i32)?;
3291 (&mut *(self as *mut PortableTexEngine<'_>))
3292 .zprimitive(66833 as i64 as strnumber, 71 as i32 as quarterword, 41 as i32)?;
3293 (&mut *(self as *mut PortableTexEngine<'_>))
3294 .zprimitive(66834 as i64 as strnumber, 71 as i32 as quarterword, 42 as i32)?;
3295 (&mut *(self as *mut PortableTexEngine<'_>))
3296 .zprimitive(
3297 66835 as i64 as strnumber,
3298 111 as i32 as quarterword,
3299 34 as i32,
3300 )?;
3301 (&mut *(self as *mut PortableTexEngine<'_>))
3302 .zprimitive(
3303 66836 as i64 as strnumber,
3304 111 as i32 as quarterword,
3305 35 as i32,
3306 )?;
3307 (&mut *(self as *mut PortableTexEngine<'_>))
3308 .zprimitive(
3309 66837 as i64 as strnumber,
3310 111 as i32 as quarterword,
3311 36 as i32,
3312 )?;
3313 (&mut *(self as *mut PortableTexEngine<'_>))
3314 .zprimitive(66838 as i64 as strnumber, 71 as i32 as quarterword, 43 as i32)?;
3315 (&mut *(self as *mut PortableTexEngine<'_>))
3316 .zprimitive(66839 as i64 as strnumber, 71 as i32 as quarterword, 44 as i32)?;
3317 (&mut *(self as *mut PortableTexEngine<'_>))
3318 .zprimitive(66840 as i64 as strnumber, 71 as i32 as quarterword, 45 as i32)?;
3319 (&mut *(self as *mut PortableTexEngine<'_>))
3320 .zprimitive(66841 as i64 as strnumber, 71 as i32 as quarterword, 46 as i32)?;
3321 (&mut *(self as *mut PortableTexEngine<'_>))
3322 .zprimitive(66842 as i64 as strnumber, 71 as i32 as quarterword, 47 as i32)?;
3323 (&mut *(self as *mut PortableTexEngine<'_>))
3324 .zprimitive(66843 as i64 as strnumber, 71 as i32 as quarterword, 48 as i32)?;
3325 (&mut *(self as *mut PortableTexEngine<'_>))
3326 .zprimitive(66844 as i64 as strnumber, 71 as i32 as quarterword, 49 as i32)?;
3327 (&mut *(self as *mut PortableTexEngine<'_>))
3328 .zprimitive(66845 as i64 as strnumber, 71 as i32 as quarterword, 50 as i32)?;
3329 (&mut *(self as *mut PortableTexEngine<'_>))
3330 .zprimitive(66846 as i64 as strnumber, 71 as i32 as quarterword, 55 as i32)?;
3331 (&mut *(self as *mut PortableTexEngine<'_>))
3332 .zprimitive(
3333 66847 as i64 as strnumber,
3334 111 as i32 as quarterword,
3335 37 as i32,
3336 )?;
3337 (&mut *(self as *mut PortableTexEngine<'_>))
3338 .zprimitive(66848 as i64 as strnumber, 71 as i32 as quarterword, 51 as i32)?;
3339 (&mut *(self as *mut PortableTexEngine<'_>))
3340 .zprimitive(66849 as i64 as strnumber, 71 as i32 as quarterword, 52 as i32)?;
3341 (&mut *(self as *mut PortableTexEngine<'_>))
3342 .zprimitive(66850 as i64 as strnumber, 71 as i32 as quarterword, 53 as i32)?;
3343 (&mut *(self as *mut PortableTexEngine<'_>))
3344 .zprimitive(66851 as i64 as strnumber, 71 as i32 as quarterword, 54 as i32)?;
3345 (&mut *(self as *mut PortableTexEngine<'_>))
3346 .zprimitive(
3347 66861 as i64 as strnumber,
3348 73 as i32 as quarterword,
3349 1206305 as i64 as halfword,
3350 )?;
3351 (&mut *(self as *mut PortableTexEngine<'_>))
3352 .zprimitive(
3353 66862 as i64 as strnumber,
3354 74 as i32 as quarterword,
3355 7892325 as i64 as halfword,
3356 )?;
3357 (&mut *(self as *mut PortableTexEngine<'_>))
3358 .zprimitive(
3359 66863 as i64 as strnumber,
3360 74 as i32 as quarterword,
3361 7892326 as i64 as halfword,
3362 )?;
3363 (&mut *(self as *mut PortableTexEngine<'_>))
3364 .zprimitive(
3365 66864 as i64 as strnumber,
3366 74 as i32 as quarterword,
3367 7892327 as i64 as halfword,
3368 )?;
3369 (&mut *(self as *mut PortableTexEngine<'_>))
3370 .zprimitive(
3371 66865 as i64 as strnumber,
3372 74 as i32 as quarterword,
3373 7892328 as i64 as halfword,
3374 )?;
3375 (&mut *(self as *mut PortableTexEngine<'_>))
3376 .zprimitive(
3377 66866 as i64 as strnumber,
3378 74 as i32 as quarterword,
3379 7892329 as i64 as halfword,
3380 )?;
3381 (&mut *(self as *mut PortableTexEngine<'_>))
3382 .zprimitive(
3383 66867 as i64 as strnumber,
3384 74 as i32 as quarterword,
3385 7892330 as i64 as halfword,
3386 )?;
3387 (&mut *(self as *mut PortableTexEngine<'_>))
3388 .zprimitive(
3389 66868 as i64 as strnumber,
3390 74 as i32 as quarterword,
3391 7892331 as i64 as halfword,
3392 )?;
3393 (&mut *(self as *mut PortableTexEngine<'_>))
3394 .zprimitive(
3395 66869 as i64 as strnumber,
3396 74 as i32 as quarterword,
3397 7892332 as i64 as halfword,
3398 )?;
3399 (&mut *(self as *mut PortableTexEngine<'_>))
3400 .zprimitive(
3401 66870 as i64 as strnumber,
3402 74 as i32 as quarterword,
3403 7892333 as i64 as halfword,
3404 )?;
3405 (&mut *(self as *mut PortableTexEngine<'_>))
3406 .zprimitive(
3407 66871 as i64 as strnumber,
3408 74 as i32 as quarterword,
3409 7892335 as i64 as halfword,
3410 )?;
3411 (&mut *(self as *mut PortableTexEngine<'_>))
3412 .zprimitive(66885 as i64 as strnumber, 71 as i32 as quarterword, 20 as i32)?;
3413 (&mut *(self as *mut PortableTexEngine<'_>))
3414 .zprimitive(66886 as i64 as strnumber, 71 as i32 as quarterword, 21 as i32)?;
3415 (&mut *(self as *mut PortableTexEngine<'_>))
3416 .zprimitive(66887 as i64 as strnumber, 71 as i32 as quarterword, 22 as i32)?;
3417 (&mut *(self as *mut PortableTexEngine<'_>))
3418 .zprimitive(66888 as i64 as strnumber, 71 as i32 as quarterword, 23 as i32)?;
3419 (&mut *(self as *mut PortableTexEngine<'_>))
3420 .zprimitive(66889 as i64 as strnumber, 71 as i32 as quarterword, 24 as i32)?;
3421 (&mut *(self as *mut PortableTexEngine<'_>))
3422 .zprimitive(66890 as i64 as strnumber, 71 as i32 as quarterword, 56 as i32)?;
3423 (&mut *(self as *mut PortableTexEngine<'_>))
3424 .zprimitive(66891 as i64 as strnumber, 71 as i32 as quarterword, 57 as i32)?;
3425 (&mut *(self as *mut PortableTexEngine<'_>))
3426 .zprimitive(66892 as i64 as strnumber, 71 as i32 as quarterword, 58 as i32)?;
3427 (&mut *(self as *mut PortableTexEngine<'_>))
3428 .zprimitive(66893 as i64 as strnumber, 71 as i32 as quarterword, 59 as i32)?;
3429 (&mut *(self as *mut PortableTexEngine<'_>))
3430 .zprimitive(66894 as i64 as strnumber, 71 as i32 as quarterword, 60 as i32)?;
3431 (&mut *(self as *mut PortableTexEngine<'_>))
3432 .zprimitive(66895 as i64 as strnumber, 71 as i32 as quarterword, 61 as i32)?;
3433 (&mut *(self as *mut PortableTexEngine<'_>))
3434 .zprimitive(66896 as i64 as strnumber, 71 as i32 as quarterword, 62 as i32)?;
3435 (&mut *(self as *mut PortableTexEngine<'_>))
3436 .zprimitive(66897 as i64 as strnumber, 19 as i32 as quarterword, 4 as i32)?;
3437 (&mut *(self as *mut PortableTexEngine<'_>))
3438 .zprimitive(66899 as i64 as strnumber, 19 as i32 as quarterword, 5 as i32)?;
3439 (&mut *(self as *mut PortableTexEngine<'_>))
3440 .zprimitive(66900 as i64 as strnumber, 112 as i32 as quarterword, 1 as i32)?;
3441 (&mut *(self as *mut PortableTexEngine<'_>))
3442 .zprimitive(66901 as i64 as strnumber, 112 as i32 as quarterword, 5 as i32)?;
3443 (&mut *(self as *mut PortableTexEngine<'_>))
3444 .zprimitive(66902 as i64 as strnumber, 19 as i32 as quarterword, 6 as i32)?;
3445 (&mut *(self as *mut PortableTexEngine<'_>))
3446 .zprimitive(66906 as i64 as strnumber, 83 as i32 as quarterword, 2 as i32)?;
3447 (&mut *(self as *mut PortableTexEngine<'_>))
3448 .zprimitive(66288 as i64 as strnumber, 49 as i32 as quarterword, 1 as i32)?;
3449 (&mut *(self as *mut PortableTexEngine<'_>))
3450 .zprimitive(
3451 66910 as i64 as strnumber,
3452 74 as i32 as quarterword,
3453 7892334 as i64 as halfword,
3454 )?;
3455 (&mut *(self as *mut PortableTexEngine<'_>))
3456 .zprimitive(
3457 66911 as i64 as strnumber,
3458 74 as i32 as quarterword,
3459 7892339 as i64 as halfword,
3460 )?;
3461 (&mut *(self as *mut PortableTexEngine<'_>))
3462 .zprimitive(
3463 66912 as i64 as strnumber,
3464 74 as i32 as quarterword,
3465 7892341 as i64 as halfword,
3466 )?;
3467 (&mut *(self as *mut PortableTexEngine<'_>))
3468 .zprimitive(
3469 66913 as i64 as strnumber,
3470 74 as i32 as quarterword,
3471 7892342 as i64 as halfword,
3472 )?;
3473 (&mut *(self as *mut PortableTexEngine<'_>))
3474 .zprimitive(
3475 66914 as i64 as strnumber,
3476 74 as i32 as quarterword,
3477 7892343 as i64 as halfword,
3478 )?;
3479 (&mut *(self as *mut PortableTexEngine<'_>))
3480 .zprimitive(
3481 66915 as i64 as strnumber,
3482 74 as i32 as quarterword,
3483 7892340 as i64 as halfword,
3484 )?;
3485 (&mut *(self as *mut PortableTexEngine<'_>))
3486 .zprimitive(
3487 66916 as i64 as strnumber,
3488 74 as i32 as quarterword,
3489 7892344 as i64 as halfword,
3490 )?;
3491 (&mut *(self as *mut PortableTexEngine<'_>))
3492 .zprimitive(
3493 66917 as i64 as strnumber,
3494 74 as i32 as quarterword,
3495 7892347 as i64 as halfword,
3496 )?;
3497 (&mut *(self as *mut PortableTexEngine<'_>))
3498 .zprimitive(
3499 66918 as i64 as strnumber,
3500 74 as i32 as quarterword,
3501 7892348 as i64 as halfword,
3502 )?;
3503 (&mut *(self as *mut PortableTexEngine<'_>))
3504 .zprimitive(
3505 66919 as i64 as strnumber,
3506 74 as i32 as quarterword,
3507 7892349 as i64 as halfword,
3508 )?;
3509 (&mut *(self as *mut PortableTexEngine<'_>))
3510 .zprimitive(
3511 66920 as i64 as strnumber,
3512 74 as i32 as quarterword,
3513 7892350 as i64 as halfword,
3514 )?;
3515 (&mut *(self as *mut PortableTexEngine<'_>))
3516 .zprimitive(66761 as i64 as strnumber, 59 as i32 as quarterword, 44 as i32)?;
3517 (&mut *(self as *mut PortableTexEngine<'_>))
3518 .zprimitive(66762 as i64 as strnumber, 59 as i32 as quarterword, 45 as i32)?;
3519 (&mut *(self as *mut PortableTexEngine<'_>))
3520 .zprimitive(66921 as i64 as strnumber, 33 as i32 as quarterword, 6 as i32)?;
3521 (&mut *(self as *mut PortableTexEngine<'_>))
3522 .zprimitive(66922 as i64 as strnumber, 33 as i32 as quarterword, 7 as i32)?;
3523 (&mut *(self as *mut PortableTexEngine<'_>))
3524 .zprimitive(66923 as i64 as strnumber, 33 as i32 as quarterword, 10 as i32)?;
3525 (&mut *(self as *mut PortableTexEngine<'_>))
3526 .zprimitive(66924 as i64 as strnumber, 33 as i32 as quarterword, 11 as i32)?;
3527 (&mut *(self as *mut PortableTexEngine<'_>))
3528 .zprimitive(66933 as i64 as strnumber, 107 as i32 as quarterword, 2 as i32)?;
3529 (&mut *(self as *mut PortableTexEngine<'_>))
3530 .zprimitive(66935 as i64 as strnumber, 98 as i32 as quarterword, 1 as i32)?;
3531 (&mut *(self as *mut PortableTexEngine<'_>))
3532 .zprimitive(66164 as i64 as strnumber, 105 as i32 as quarterword, 1 as i32)?;
3533 (&mut *(self as *mut PortableTexEngine<'_>))
3534 .zprimitive(
3535 66936 as i64 as strnumber,
3536 108 as i32 as quarterword,
3537 17 as i32,
3538 )?;
3539 (&mut *(self as *mut PortableTexEngine<'_>))
3540 .zprimitive(
3541 66937 as i64 as strnumber,
3542 108 as i32 as quarterword,
3543 18 as i32,
3544 )?;
3545 (&mut *(self as *mut PortableTexEngine<'_>))
3546 .zprimitive(
3547 66938 as i64 as strnumber,
3548 108 as i32 as quarterword,
3549 19 as i32,
3550 )?;
3551 (&mut *(self as *mut PortableTexEngine<'_>))
3552 .zprimitive(
3553 66939 as i64 as strnumber,
3554 108 as i32 as quarterword,
3555 20 as i32,
3556 )?;
3557 (&mut *(self as *mut PortableTexEngine<'_>))
3558 .zprimitive(66623 as i64 as strnumber, 95 as i32 as quarterword, 8 as i32)?;
3559 (&mut *(self as *mut PortableTexEngine<'_>))
3560 .zprimitive(66945 as i64 as strnumber, 71 as i32 as quarterword, 67 as i32)?;
3561 (&mut *(self as *mut PortableTexEngine<'_>))
3562 .zprimitive(66946 as i64 as strnumber, 71 as i32 as quarterword, 68 as i32)?;
3563 (&mut *(self as *mut PortableTexEngine<'_>))
3564 .zprimitive(66947 as i64 as strnumber, 71 as i32 as quarterword, 69 as i32)?;
3565 (&mut *(self as *mut PortableTexEngine<'_>))
3566 .zprimitive(66948 as i64 as strnumber, 71 as i32 as quarterword, 70 as i32)?;
3567 (&mut *(self as *mut PortableTexEngine<'_>))
3568 .zprimitive(66952 as i64 as strnumber, 71 as i32 as quarterword, 25 as i32)?;
3569 (&mut *(self as *mut PortableTexEngine<'_>))
3570 .zprimitive(66953 as i64 as strnumber, 71 as i32 as quarterword, 26 as i32)?;
3571 (&mut *(self as *mut PortableTexEngine<'_>))
3572 .zprimitive(66954 as i64 as strnumber, 71 as i32 as quarterword, 63 as i32)?;
3573 (&mut *(self as *mut PortableTexEngine<'_>))
3574 .zprimitive(66955 as i64 as strnumber, 71 as i32 as quarterword, 64 as i32)?;
3575 (&mut *(self as *mut PortableTexEngine<'_>))
3576 .zprimitive(66956 as i64 as strnumber, 71 as i32 as quarterword, 65 as i32)?;
3577 (&mut *(self as *mut PortableTexEngine<'_>))
3578 .zprimitive(66957 as i64 as strnumber, 71 as i32 as quarterword, 66 as i32)?;
3579 (&mut *(self as *mut PortableTexEngine<'_>))
3580 .zprimitive(66958 as i64 as strnumber, 18 as i32 as quarterword, 5 as i32)?;
3581 (&mut *(self as *mut PortableTexEngine<'_>))
3582 .zprimitive(66959 as i64 as strnumber, 113 as i32 as quarterword, 5 as i32)?;
3583 (&mut *(self as *mut PortableTexEngine<'_>))
3584 .zprimitive(66960 as i64 as strnumber, 113 as i32 as quarterword, 6 as i32)?;
3585 (&mut *(self as *mut PortableTexEngine<'_>))
3586 .zprimitive(66961 as i64 as strnumber, 113 as i32 as quarterword, 7 as i32)?;
3587 (&mut *(self as *mut PortableTexEngine<'_>))
3588 .zprimitive(66962 as i64 as strnumber, 113 as i32 as quarterword, 8 as i32)?;
3589 (&mut *(self as *mut PortableTexEngine<'_>))
3590 .zprimitive(66963 as i64 as strnumber, 113 as i32 as quarterword, 9 as i32)?;
3591 (&mut *(self as *mut PortableTexEngine<'_>))
3592 .zprimitive(66968 as i64 as strnumber, 24 as i32 as quarterword, 2 as i32)?;
3593 (&mut *(self as *mut PortableTexEngine<'_>))
3594 .zprimitive(66969 as i64 as strnumber, 24 as i32 as quarterword, 3 as i32)?;
3595 (&mut *(self as *mut PortableTexEngine<'_>))
3596 .zprimitive(
3597 66970 as i64 as strnumber,
3598 85 as i32 as quarterword,
3599 1206563 as i64 as halfword,
3600 )?;
3601 (&mut *(self as *mut PortableTexEngine<'_>))
3602 .zprimitive(
3603 66971 as i64 as strnumber,
3604 85 as i32 as quarterword,
3605 1206564 as i64 as halfword,
3606 )?;
3607 (&mut *(self as *mut PortableTexEngine<'_>))
3608 .zprimitive(
3609 66972 as i64 as strnumber,
3610 85 as i32 as quarterword,
3611 1206565 as i64 as halfword,
3612 )?;
3613 (&mut *(self as *mut PortableTexEngine<'_>))
3614 .zprimitive(
3615 66973 as i64 as strnumber,
3616 85 as i32 as quarterword,
3617 1206566 as i64 as halfword,
3618 )?;
3619 if *self.state.buffer.offset(self.state.curinput.locfield as isize) == 42 as i32
3620 {
3621 self.state.curinput.locfield += 1;
3622 }
3623 self.state.eTeXmode = 1 as eightbits;
3624 self.state.maxregnum = 32767 as i32 as halfword;
3625 self.state.maxreghelpline = 66965 as i64 as strnumber;
3626 Ok(())
3627 }
3628
3629 pub fn begin_primary_input(self: &mut Self, name: &str, bytes: Vec<u8>) -> bool {
3630 self.last_abort_status = None;
3635 self.last_error_message = None;
3636 match unsafe { self.begin_primary_input_raw(name, bytes) } {
3637 Ok(started) => started != 0,
3638 Err(EngineBreak::Abort(EngineAbort { status })) => {
3639 self.last_abort_status = Some(status);
3640 false
3641 }
3642 Err(EngineBreak::Error(error)) => {
3643 self.last_error_message = Some(error.message);
3644 false
3645 }
3646 }
3647 }
3648
3649 pub fn run_main_control(self: &mut Self) -> bool {
3650 self.catch_engine_abort(|engine| unsafe { engine.maincontrol() })
3651 }
3652
3653 pub fn run_format_initialization(self: &mut Self) -> bool {
3654 self.format_initialization = true;
3655 let completed = self.catch_engine_abort(|engine| unsafe { engine.maincontrol() });
3656 self.format_initialization = false;
3657 completed
3658 }
3659
3660 pub fn begin_fragment_capture(self: &mut Self) {
3661 self.fragment_capture_enabled = true;
3662 self.captured_fragment_root = None;
3663 }
3664
3665 pub fn end_fragment_capture(self: &mut Self) {
3666 self.fragment_capture_enabled = false;
3667 }
3668
3669 fn catch_engine_abort<F>(self: &mut Self, run: F) -> bool
3670 where
3671 F: FnOnce(&mut Self) -> EngineFlow<()>,
3672 {
3673 self.last_abort_status = None;
3679 self.last_error_message = None;
3680 match run(self) {
3681 Ok(()) => self.last_abort_status.is_none(),
3682 Err(EngineBreak::Abort(EngineAbort { status: 0 })) => {
3683 self.last_abort_status = None;
3684 true
3685 }
3686 Err(EngineBreak::Abort(EngineAbort { status })) => {
3687 self.last_abort_status = Some(status);
3688 false
3689 }
3690 Err(EngineBreak::Error(error)) => {
3693 self.last_error_message = Some(error.message);
3694 false
3695 }
3696 }
3697 }
3698
3699 pub fn snapshot_format(&self) -> PortableFormatImage {
3700 PortableFormatImage::from_engine_state(self.state.as_ref())
3701 }
3702
3703 #[must_use]
3712 pub fn into_format(self) -> PortableFormatImage {
3713 let mut state = self.state;
3719 state.seal_as_format_snapshot();
3720 PortableFormatImage::from_sealed_state(state)
3721 }
3722
3723 pub fn finalize_trie(self: &mut Self) {
3731 if self.state.trienotready != 0 && !self.state.triehash.is_null() {
3733 let saved = self.format_initialization;
3734 self.format_initialization = false;
3735 let _ = unsafe { self.inittrie() };
3736 self.format_initialization = saved;
3737 }
3738 }
3739
3740 pub fn resource_request_count(&self) -> usize {
3741 self.resource_requests
3742 }
3743
3744 pub fn resource_request_records(&self) -> &[PortableResourceRequestRecord] {
3745 self.resource_request_records.as_slice()
3746 }
3747
3748 pub fn transcript_bytes(&self) -> &[u8] {
3749 self.transcript_bytes.as_slice()
3750 }
3751
3752 pub fn primary_input_source_span(&self) -> Option<PortableSourceSpan> {
3755 if !self.state.source_tracking {
3756 return None;
3757 }
3758 let primary = self.state.src_primary_name;
3759 let raw = self
3760 .state
3761 .src_spans
3762 .iter()
3763 .find(|raw| raw.name == primary)?;
3764 let name = unsafe { self.pool_string(raw.name) }?;
3765 Some(PortableSourceSpan {
3766 name,
3767 start: raw.start,
3768 end: raw.end,
3769 role: raw.role,
3770 })
3771 }
3772
3773 pub fn node_source_spans(&self) -> &[PortableNodeSourceSpan] {
3778 &[]
3779 }
3780
3781 pub fn stripped_page_build_count(&self) -> usize {
3782 self.stripped_page_builds
3783 }
3784
3785 pub fn stripped_shipout_count(&self) -> usize {
3786 self.stripped_shipouts
3787 }
3788
3789 pub fn stripped_special_output_count(&self) -> usize {
3790 self.stripped_special_outputs
3791 }
3792
3793 pub fn stripped_picture_load_count(&self) -> usize {
3794 self.stripped_picture_loads
3795 }
3796
3797 pub fn stripped_source_special_count(&self) -> usize {
3798 self.stripped_source_specials
3799 }
3800
3801 pub fn stripped_write_whatsit_diagnostic_count(&self) -> usize {
3802 self.stripped_write_whatsit_diagnostics
3803 }
3804
3805 pub fn stripped_pdf_extension_count(&self) -> usize {
3806 self.stripped_pdf_extensions
3807 }
3808
3809 pub fn stripped_page_top_prune_count(&self) -> usize {
3810 self.stripped_page_top_prunes
3811 }
3812
3813 pub fn last_stripped_shipout_box(&self) -> Option<PortableNodeHandle> {
3814 self.last_stripped_shipout_box
3815 }
3816
3817 pub fn captured_fragment_root(&self) -> Option<PortableNodeHandle> {
3818 self.captured_fragment_root
3819 }
3820
3821 pub fn font_at_size(&self, font: integer) -> integer {
3824 if font < 0 {
3825 return 0;
3826 }
3827 self.state
3828 .fontsize_storage
3829 .get(font as usize)
3830 .copied()
3831 .unwrap_or(0)
3832 }
3833
3834 pub fn font_name(&self, font: integer) -> Option<String> {
3840 if font < 0 {
3841 return None;
3842 }
3843 let name = self.state.fontname_storage.get(font as usize).copied()?;
3844 unsafe { self.pool_string(name) }
3847 }
3848
3849 pub fn native_font_spec(&self, font: integer) -> Option<String> {
3853 let handle = Self::font_handle_for_number(self, font)?;
3854 self.fonts.font_spec(handle)
3855 }
3856
3857 pub fn native_font_table(&self) -> Vec<(PortableFontHandle, String, i32)> {
3860 self.fonts.font_table()
3861 }
3862
3863 pub fn restore_native_font_table(
3868 self: &mut Self,
3869 table: &[(PortableFontHandle, String, i32)],
3870 ) -> bool {
3871 self.fonts.restore_font_table(table)
3872 }
3873
3874 pub fn last_abort_status(&self) -> Option<integer> {
3875 self.last_abort_status
3876 }
3877
3878 pub fn last_error_message(&self) -> Option<&str> {
3882 self.last_error_message.as_deref()
3883 }
3884
3885 pub fn set_sandbox(self: &mut Self, on: bool) {
3890 self.sandbox = on;
3891 self.sandbox_math_depth = 0;
3892 self.sandbox_math_opened = false;
3893 self.sandbox_ops = 0;
3894 }
3895
3896 pub(crate) fn capture_last_error_message(&self) -> String {
3903 let transcript = core::str::from_utf8(&self.transcript_bytes).unwrap_or("");
3904 for raw in transcript.lines().rev() {
3905 let collapsed = collapse_doubled_line(raw.trim());
3906 let line = collapsed.as_deref().unwrap_or(raw).trim();
3907 if let Some(rest) = line.strip_prefix("! ") {
3908 return rest.trim_end_matches('.').trim().into();
3909 }
3910 }
3911 "TeX error".into()
3912 }
3913
3914 pub fn snapshot_node(&self, handle: PortableNodeHandle) -> Option<PortableNodeSnapshot> {
3915 let node = handle.0 as halfword;
3916 let word = self.node_word(node, 0)?;
3917 let raw_kind = unsafe { word.hh.u.B0 as i32 };
3918 let subtype = unsafe { word.hh.u.B1 as i32 };
3919 let kind = self.node_kind(raw_kind, node, subtype);
3920 let link = self.node_link(node);
3921 let is_character = node >= self.state.himemmin;
3922 let native_word4 = if matches!(kind, PortableNodeKind::NativeWord | PortableNodeKind::NativeGlyph) {
3923 self.node_word(node, 4)
3924 } else {
3925 None
3926 };
3927 let font = if is_character {
3928 raw_kind
3929 } else {
3930 native_word4.map_or(0, |word| unsafe { word.v.QQQQ.u.B1 as i32 })
3931 };
3932 let character = if is_character {
3933 subtype
3934 } else {
3935 native_word4.map_or(0, |word| unsafe { word.v.QQQQ.u.B2 as i32 })
3936 };
3937 let (width, height, depth, shift, list) = match raw_kind {
3938 _ if is_character => (
3939 self.character_width(font, character).unwrap_or_default(),
3940 0,
3941 0,
3942 0,
3943 None,
3944 ),
3945 0 | 1 | 13 => (
3946 self.node_scaled(node, 1).unwrap_or_default(),
3947 self.node_scaled(node, 3).unwrap_or_default(),
3948 self.node_scaled(node, 2).unwrap_or_default(),
3949 self.node_scaled(node, 4).unwrap_or_default(),
3950 self.node_field_link(node, 5),
3951 ),
3952 2 => (
3953 self.node_scaled(node, 1).unwrap_or_default(),
3954 self.node_scaled(node, 3).unwrap_or_default(),
3955 self.node_scaled(node, 2).unwrap_or_default(),
3956 0,
3957 None,
3958 ),
3959 10 => (
3960 self.glue_amount(node).unwrap_or_default(),
3961 0,
3962 0,
3963 0,
3964 None,
3965 ),
3966 11 => (
3967 self.node_scaled(node, 1).unwrap_or_default(),
3968 0,
3969 0,
3970 0,
3971 None,
3972 ),
3973 8 if matches!(kind, PortableNodeKind::NativeWord | PortableNodeKind::NativeGlyph) => (
3974 self.node_scaled(node, 1).unwrap_or_default(),
3975 self.node_scaled(node, 3).unwrap_or_default(),
3976 self.node_scaled(node, 2).unwrap_or_default(),
3977 0,
3978 None,
3979 ),
3980 _ => (0, 0, 0, 0, None),
3981 };
3982 let native_glyphs = if matches!(kind, PortableNodeKind::NativeWord | PortableNodeKind::NativeGlyph) {
3983 self.native_glyph_infos
3984 .get(&node)
3985 .map(|info| info.glyphs.clone())
3986 .unwrap_or_default()
3987 } else {
3988 Vec::new()
3989 };
3990
3991 let (glue_set, glue_sign, glue_order) = match raw_kind {
3996 0 | 1 | 13 => (
3997 self.node_word(node, 6).map_or(0.0, |word| unsafe { word.gr }),
3998 self.node_word(node, 5)
3999 .map_or(0, |word| unsafe { word.hh.u.B0 as i32 }),
4000 self.node_word(node, 5)
4001 .map_or(0, |word| unsafe { word.hh.u.B1 as i32 }),
4002 ),
4003 _ => (0.0, 0, 0),
4004 };
4005 let (glue_stretch, glue_shrink, glue_stretch_order, glue_shrink_order) = if raw_kind == 10 {
4007 match self.node_word(node, 1).map(|word| unsafe { word.hh.v.LH }) {
4008 Some(spec) => (
4009 self.node_scaled(spec, 2).unwrap_or_default(),
4010 self.node_scaled(spec, 3).unwrap_or_default(),
4011 self.node_word(spec, 0)
4012 .map_or(0, |word| unsafe { word.hh.u.B0 as i32 }),
4013 self.node_word(spec, 0)
4014 .map_or(0, |word| unsafe { word.hh.u.B1 as i32 }),
4015 ),
4016 None => (0, 0, 0, 0),
4017 }
4018 } else {
4019 (0, 0, 0, 0)
4020 };
4021
4022 Some(PortableNodeSnapshot {
4023 handle,
4024 kind,
4025 subtype,
4026 source: self.resolve_node_src(node),
4027 link,
4028 font,
4029 character,
4030 width,
4031 height,
4032 depth,
4033 shift,
4034 list,
4035 native_glyphs,
4036 glue_set,
4037 glue_sign,
4038 glue_order,
4039 glue_stretch,
4040 glue_shrink,
4041 glue_stretch_order,
4042 glue_shrink_order,
4043 })
4044 }
4045
4046 fn node_kind(&self, raw_kind: i32, node: halfword, subtype: i32) -> PortableNodeKind {
4047 if node >= self.state.himemmin {
4048 return PortableNodeKind::Character;
4049 }
4050
4051 match raw_kind {
4052 0 => PortableNodeKind::HorizontalBox,
4053 1 => PortableNodeKind::VerticalBox,
4054 2 => PortableNodeKind::Rule,
4055 3 => PortableNodeKind::Insertion,
4056 4 => PortableNodeKind::Mark,
4057 5 => PortableNodeKind::Adjustment,
4058 6 => PortableNodeKind::Ligature,
4059 7 => PortableNodeKind::Discretionary,
4060 8 if matches!(subtype, 40 | 41) => PortableNodeKind::NativeWord,
4061 8 if subtype == 42 => PortableNodeKind::NativeGlyph,
4062 8 if matches!(subtype, 0 | 1 | 2 | 3) => PortableNodeKind::OutputWhatsit,
4063 8 => PortableNodeKind::Whatsit,
4064 9 => PortableNodeKind::Math,
4065 10 => PortableNodeKind::Glue,
4066 11 => PortableNodeKind::Kern,
4067 12 => PortableNodeKind::Penalty,
4068 13 => PortableNodeKind::UnsetBox,
4069 16 => PortableNodeKind::Noad,
4070 14 => PortableNodeKind::Style,
4071 15 => PortableNodeKind::Choice,
4072 other => PortableNodeKind::Unknown(other),
4073 }
4074 }
4075
4076 pub(crate) fn copy_native_glyph_info(
4077 this: &mut Self,
4078 src: halfword,
4079 dest: halfword,
4080 ) -> quarterword {
4081 if let Some(info) = this.native_glyph_infos.get(&src).cloned() {
4082 let glyph_count = info.glyphs.len().min(i32::MAX as usize) as quarterword;
4083 this.native_glyph_infos.insert(dest, info);
4084 glyph_count
4085 } else {
4086 this.native_glyph_infos.remove(&dest);
4087 0
4088 }
4089 }
4090
4091 fn font_handle_for_number(this: &Self, font: integer) -> Option<FontHandle> {
4092 if font < 0 || this.state.fontlayoutengine.is_null() {
4093 return None;
4094 }
4095 let handle = unsafe { *this.state.fontlayoutengine.offset(font as isize) as FontHandle };
4096 (handle != 0).then_some(handle)
4097 }
4098
4099 unsafe fn node_index_for_pointer(
4100 engine: &PortableTexEngine<'_>,
4101 node: voidpointer,
4102 ) -> Option<halfword> {
4103 if node.is_null() || engine.state.zmem.is_null() {
4104 return None;
4105 }
4106 let base = engine.state.zmem as isize;
4107 let address = node as isize;
4108 let word_size = core::mem::size_of::<memoryword>() as isize;
4109 if word_size == 0 || address < base {
4110 return None;
4111 }
4112 let bytes = address - base;
4113 if bytes % word_size != 0 {
4114 return None;
4115 }
4116 let index = (bytes / word_size) as halfword;
4117 if index < engine.state.memmin || index > engine.state.memmax {
4118 None
4119 } else {
4120 Some(index)
4121 }
4122 }
4123
4124 unsafe fn native_node_font(mem: *mut memoryword, node: halfword) -> integer {
4125 (*mem.offset((node + 4) as isize)).v.QQQQ.u.B1 as integer
4126 }
4127
4128 unsafe fn native_node_text<'a>(mem: *mut memoryword, node: halfword) -> &'a [u16] {
4129 let len = (*mem.offset((node + 4) as isize)).v.QQQQ.u.B2.max(0) as usize;
4130 if len == 0 {
4131 return &[];
4132 }
4133 core::slice::from_raw_parts(
4134 mem.offset((node + native_node_size) as isize) as *const memoryword as *const u16,
4135 len,
4136 )
4137 }
4138
4139 unsafe fn write_native_node_metrics(
4140 mem: *mut memoryword,
4141 node: halfword,
4142 width: i32,
4143 height: i32,
4144 depth: i32,
4145 ) {
4146 (*mem.offset((node + 1) as isize)).u.CINT = width;
4147 (*mem.offset((node + 2) as isize)).u.CINT = depth;
4148 (*mem.offset((node + 3) as isize)).u.CINT = height;
4149 }
4150
4151 fn node_word(&self, node: halfword, offset: halfword) -> Option<memoryword> {
4152 let index = node.checked_add(offset)?;
4153 if node as i64 == -(268435455 as i64) {
4154 return None;
4155 }
4156 if self.state.zmem.is_null() || index < self.state.memmin || index > self.state.memmax {
4157 return None;
4158 }
4159 unsafe { Some(*self.state.zmem.offset(index as isize)) }
4160 }
4161
4162 fn node_link(&self, node: halfword) -> Option<PortableNodeHandle> {
4163 let word = self.node_word(node, 0)?;
4164 let link = unsafe { word.hh.v.RH };
4165 Self::node_handle_from_raw(link)
4166 }
4167
4168 fn node_field_link(&self, node: halfword, offset: halfword) -> Option<PortableNodeHandle> {
4169 let word = self.node_word(node, offset)?;
4170 let link = unsafe { word.hh.v.RH };
4171 Self::node_handle_from_raw(link)
4172 }
4173
4174 fn node_scaled(&self, node: halfword, offset: halfword) -> Option<i32> {
4175 let word = self.node_word(node, offset)?;
4176 Some(unsafe { word.u.CINT })
4177 }
4178
4179 fn glue_amount(&self, node: halfword) -> Option<i32> {
4180 let word = self.node_word(node, 1)?;
4181 let glue_spec = unsafe { word.hh.v.LH };
4182 self.node_scaled(glue_spec, 1)
4183 }
4184
4185 fn character_width(&self, font: i32, character: i32) -> Option<i32> {
4186 if font < 0
4187 || character < 0
4188 || self.state.fontinfo.is_null()
4189 || self.state.charbase.is_null()
4190 || self.state.widthbase.is_null()
4191 {
4192 return None;
4193 }
4194 let char_info_index = unsafe {
4195 *self.state.charbase.offset(font as isize) + character
4196 };
4197 let char_info = unsafe {
4198 (*self.state.fontinfo.offset(char_info_index as isize)).v.QQQQ
4199 };
4200 let width_index = unsafe {
4201 *self.state.widthbase.offset(font as isize) as i32 + char_info.u.B0 as i32
4202 };
4203 Some(unsafe { (*self.state.fontinfo.offset(width_index as isize)).u.CINT })
4204 }
4205
4206 fn node_handle_from_raw(raw: halfword) -> Option<PortableNodeHandle> {
4207 if raw as i64 == -(268435455 as i64) {
4208 None
4209 } else {
4210 Some(PortableNodeHandle(raw))
4211 }
4212 }
4213
4214
4215 pub(crate) fn is_xetex(&self) -> bool {
4216 self.profile.xetex
4217 }
4218
4219 pub(crate) fn supports_etex(&self) -> bool {
4220 self.profile.etex
4221 }
4222
4223 pub(crate) fn supports_unicode_scalars(&self) -> bool {
4224 self.profile.unicode_scalars
4225 }
4226
4227 pub(crate) fn supports_unicode_math(&self) -> bool {
4228 self.profile.unicode_math
4229 }
4230
4231 pub(crate) fn supports_native_fonts(&self) -> bool {
4232 self.profile.native_fonts
4233 }
4234
4235 pub(crate) unsafe fn getinputnormalizationstate(&self) -> integer {
4236 if !self.is_xetex() {
4237 return 0;
4238 }
4239 let eqtb = self.state.zeqtb.as_mut_ptr();
4240 if eqtb.is_null() {
4241 return 0;
4242 }
4243 (*eqtb.offset(7892344 as i64 as isize)).u.CINT
4244 }
4245
4246 pub(crate) unsafe fn gettracingfontsstate(&self) -> integer {
4247 if !self.is_xetex() {
4248 return 0;
4249 }
4250 let eqtb = self.state.zeqtb.as_mut_ptr();
4251 if eqtb.is_null() {
4252 return 0;
4253 }
4254 (*eqtb.offset(7892347 as i64 as isize)).u.CINT
4255 }
4256
4257 unsafe fn current_resource_name(engine: *mut PortableTexEngine<'_>) -> Option<String> {
4258 let engine = engine.as_ref()?;
4259 if engine.state.nameoffile.is_null() || engine.state.namelength <= 0 {
4260 return None;
4261 }
4262
4263 let mut bytes = Vec::with_capacity(engine.state.namelength as usize);
4264 for index in 1..=engine.state.namelength {
4265 let value = *engine.state.nameoffile.offset(index as isize);
4266 if value <= 0 {
4267 continue;
4268 }
4269 bytes.push(value as u8);
4270 }
4271 Some(String::from_utf8_lossy(bytes.as_slice()).into_owned())
4272 }
4273
4274 pub(crate) unsafe fn get_encoding_mode_and_info(
4280 engine: *mut PortableTexEngine<'_>,
4281 info: *mut integer,
4282 ) -> integer {
4283 if !info.is_null() {
4284 *info = 0;
4285 }
4286 let name = Self::current_resource_name(engine).unwrap_or_default();
4287 let lowered = name.trim().to_ascii_lowercase();
4288 match lowered.as_str() {
4289 "auto" => 0, "utf8" | "utf-8" => 1, "utf16" | "utf-16" | "utf16be" | "utf-16be" => 2, "utf16le" | "utf-16le" => 3, "bytes" => 4, _ => 4,
4297 }
4298 }
4299
4300 unsafe fn mode_string(mode: const_string) -> String {
4301 if mode.is_null() {
4302 return String::new();
4303 }
4304
4305 let mut bytes = Vec::new();
4306 let mut cursor = mode;
4307 while *cursor != 0 {
4308 bytes.push(*cursor as u8);
4309 cursor = cursor.add(1);
4310 }
4311 String::from_utf8_lossy(bytes.as_slice()).into_owned()
4312 }
4313
4314 unsafe fn pool_string(&self, string: strnumber) -> Option<String> {
4315 if string < 0 || self.state.strstart.is_null() || self.state.strpool.is_null() {
4316 return None;
4317 }
4318 let index = Self::pool_string_index(string)?;
4319 let start = *self.state.strstart.offset(index);
4320 let end = *self.state.strstart.offset(index + 1);
4321 if start < 0 || end < start {
4322 return None;
4323 }
4324
4325 let len = usize::try_from(end - start).ok()?;
4326 let mut units = Vec::with_capacity(len);
4327 for offset in 0..len {
4328 units.push(*self.state.strpool.offset((start as usize + offset) as isize));
4329 }
4330 Some(
4331 char::decode_utf16(units)
4332 .map(|codepoint| codepoint.unwrap_or(char::REPLACEMENT_CHARACTER))
4333 .collect(),
4334 )
4335 }
4336
4337 pub(crate) fn pool_string_index(string: strnumber) -> Option<isize> {
4338 if string < 0 {
4339 return None;
4340 }
4341 let index = if string >= 65536 { string - 65536 } else { string };
4342 isize::try_from(index).ok()
4343 }
4344
4345 fn resource_kind(name: &str, format: integer) -> ResourceKind {
4346 match format {
4347 resource_format_tex_input | 0 => Self::tex_resource_kind(name),
4348 resource_format_tfm | resource_format_font => ResourceKind::Font,
4349 resource_format_encoding => ResourceKind::Encoding,
4350 resource_format_font_map => ResourceKind::Map,
4351 resource_format_config => ResourceKind::Config,
4352 resource_format_format_image => ResourceKind::FormatImage,
4353 other => ResourceKind::Other(other),
4354 }
4355 }
4356
4357 fn tex_resource_kind(name: &str) -> ResourceKind {
4358 let name = name.rsplit(['/', '\\']).next().unwrap_or(name);
4359 let name = name.to_ascii_lowercase();
4360 if name.ends_with(".sty") {
4361 return ResourceKind::Package;
4362 }
4363 if name.ends_with(".cls") {
4364 return ResourceKind::Class;
4365 }
4366 if name.ends_with(".fd") {
4367 return ResourceKind::FontDefinition;
4368 }
4369 if name.ends_with(".clo")
4370 || name.ends_with(".def")
4371 || name.ends_with(".ldf")
4372 || name.ends_with(".cfg")
4373 {
4374 return ResourceKind::PackageSupport;
4375 }
4376 ResourceKind::TexInput
4377 }
4378
4379 fn resource_kind_for_open(
4380 engine: &PortableTexEngine<'_>,
4381 name: &str,
4382 format: integer,
4383 ) -> ResourceKind {
4384 let kind = Self::resource_kind(name, format);
4385 if kind == ResourceKind::TexInput
4386 && Self::active_package_owner(engine).is_some()
4387 && Self::looks_like_package_asset(name)
4388 {
4389 ResourceKind::Asset
4390 } else {
4391 kind
4392 }
4393 }
4394
4395 fn resource_package_owner(
4396 engine: &PortableTexEngine<'_>,
4397 name: &str,
4398 kind: ResourceKind,
4399 ) -> Option<String> {
4400 match kind {
4401 ResourceKind::Package | ResourceKind::Class => Self::resource_stem(name),
4402 ResourceKind::PackageSupport | ResourceKind::FontDefinition | ResourceKind::Asset => {
4403 Self::active_package_owner(engine)
4404 }
4405 _ => None,
4406 }
4407 }
4408
4409 fn active_package_owner(engine: &PortableTexEngine<'_>) -> Option<String> {
4410 engine.current_input_package_owner.clone()
4411 }
4412
4413 fn looks_like_package_asset(name: &str) -> bool {
4414 let name = name.rsplit(['/', '\\']).next().unwrap_or(name);
4415 let name = name.to_ascii_lowercase();
4416 !(name.ends_with(".tex")
4417 || name.ends_with(".ltx")
4418 || name.ends_with(".sty")
4419 || name.ends_with(".cls")
4420 || name.ends_with(".fd")
4421 || name.ends_with(".clo")
4422 || name.ends_with(".def")
4423 || name.ends_with(".ldf")
4424 || name.ends_with(".cfg"))
4425 }
4426
4427 fn resource_stem(name: &str) -> Option<String> {
4428 let name = name.rsplit(['/', '\\']).next().unwrap_or(name);
4429 let stem = name.rsplit_once('.').map_or(name, |(stem, _)| stem);
4430 if stem.is_empty() {
4431 None
4432 } else {
4433 Some(stem.to_string())
4434 }
4435 }
4436
4437 fn source_index(value: usize) -> u32 {
4438 value.min(u32::MAX as usize) as u32
4439 }
4440
4441 fn virtual_file_key(name: &str) -> String {
4442 let mut name = name;
4443 while let Some(stripped) = name.strip_prefix("./") {
4444 name = stripped;
4445 }
4446 name.to_string()
4447 }
4448
4449 fn normalized_runtime_resource_name(mut name: &str) -> &str {
4450 while let Some(stripped) = name.strip_prefix("./") {
4451 name = stripped;
4452 }
4453 name
4454 }
4455
4456 unsafe fn intern_static_pool_string(
4463 engine: &mut PortableTexEngine<'_>,
4464 text: &str,
4465 ) -> EngineFlow<Option<strnumber>> {
4466 if engine.state.strpool.is_null() || engine.state.strstart.is_null() {
4467 return Ok(None);
4468 }
4469
4470 let Ok(needed) = integer::try_from(text.encode_utf16().count()) else {
4471 return Ok(None);
4472 };
4473 let Some(next_pool) = engine.state.poolptr.checked_add(needed) else {
4474 return Ok(None);
4475 };
4476 if next_pool > engine.state.poolsize {
4477 return Ok(None);
4478 }
4479
4480 for unit in text.encode_utf16() {
4481 *engine.state.strpool.offset(engine.state.poolptr as isize) = unit as packedUTF16code;
4482 engine.state.poolptr += 1;
4483 }
4484
4485 Ok(Some(engine.makestring()?))
4486 }
4487
4488 unsafe fn append_text_to_pool(engine: &mut PortableTexEngine<'_>, text: &str) -> boolean {
4489 if engine.state.strpool.is_null() {
4490 return false_0;
4491 }
4492 let needed = match integer::try_from(text.encode_utf16().count()) {
4493 Ok(needed) => needed,
4494 Err(_) => return false_0,
4495 };
4496 let Some(next_pool) = engine.state.poolptr.checked_add(needed) else {
4497 return false_0;
4498 };
4499 if next_pool > engine.state.poolsize {
4500 return false_0;
4501 }
4502 for unit in text.encode_utf16() {
4503 *engine.state.strpool.offset(engine.state.poolptr as isize) = unit as packedUTF16code;
4504 engine.state.poolptr += 1;
4505 }
4506 true_0
4507 }
4508
4509 unsafe fn resource_bytes_for_name(
4510 engine: &mut PortableTexEngine<'_>,
4511 name: &str,
4512 ) -> Option<Vec<u8>> {
4513 let name = Self::normalized_runtime_resource_name(name);
4514 let kind = Self::resource_kind_for_open(engine, name, resource_format_tex_input);
4515 let package = Self::resource_package_owner(engine, name, kind);
4516 let request = ResourceRequest {
4517 name,
4518 kind,
4519 package: package.as_deref(),
4520 format: resource_format_tex_input,
4521 mode: "rb",
4522 source: None,
4523 };
4524 let virtual_key = Self::virtual_file_key(name);
4525 if let Some(bytes) = engine.virtual_files.get(&virtual_key) {
4526 Some(bytes.clone())
4527 } else {
4528 engine.resources.read(request)
4529 }
4530 }
4531
4532 pub(crate) unsafe fn boundary_get_file_size(
4533 engine: *mut PortableTexEngine<'_>,
4534 string: integer,
4535 ) {
4536 let Some(engine) = engine.as_mut() else {
4537 return;
4538 };
4539 let Some(name) = engine.pool_string(string as strnumber) else {
4540 return;
4541 };
4542 const PLACEHOLDER_FILE_SIZE: usize = 4096;
4552 let size = Self::resource_bytes_for_name(engine, name.as_str())
4553 .map_or(PLACEHOLDER_FILE_SIZE, |bytes| bytes.len());
4554 Self::append_text_to_pool(engine, size.to_string().as_str());
4555 }
4556
4557 pub(crate) unsafe fn load_pool_strings(
4558 engine: &mut PortableTexEngine<'_>,
4559 spare_size: integer,
4560 ) -> EngineFlow<integer> {
4561 if engine.state.strpool.is_null() || engine.state.strstart.is_null()
4562 || spare_size <= 0
4563 {
4564 return Ok(0);
4565 }
4566 let mut used = 0_i32;
4567 let mut last = 0_i32;
4568 for line in include_str!("../pool/xetex.pool").lines() {
4569 if line.starts_with('*') {
4570 break;
4571 }
4572 let bytes = line.as_bytes();
4573 let text = if bytes.len() >= 2 && bytes[0].is_ascii_digit()
4574 && bytes[1].is_ascii_digit()
4575 {
4576 &line[2..]
4577 } else {
4578 line
4579 };
4580 let units = text.encode_utf16().count().min(i32::MAX as usize) as integer;
4581 used = used.saturating_add(units);
4582 if used >= spare_size
4583 || engine.state.poolptr.saturating_add(units) > engine.state.poolsize
4584 {
4585 return Ok(0);
4586 }
4587 for unit in text.encode_utf16() {
4588 *engine.state.strpool.offset(engine.state.poolptr as isize) = unit
4589 as packedUTF16code;
4590 engine.state.poolptr += 1;
4591 }
4592 last = engine.makestring()?;
4593 }
4594 Ok(last)
4595 }
4596
4597 pub(crate) unsafe fn boundary_open_log_file(
4598 engine: *mut PortableTexEngine<'_>,
4599 ) -> EngineFlow<()> {
4600 let Some(engine) = engine.as_mut() else {
4601 return Ok(());
4602 };
4603 let old_setting = engine.state.selector;
4604 if engine.state.jobname == 0 {
4605 if let Some(jobname) = Self::intern_static_pool_string(engine, "texput")? {
4606 engine.state.jobname = jobname;
4607 }
4608 }
4609 engine.state.logopened = true_0 as boolean;
4610 engine.state.selector = (old_setting as i32 + 2).clamp(0, 21) as eightbits;
4611 Ok(())
4612 }
4613
4614 pub(crate) unsafe fn boundary_jump_out(
4615 engine: *mut PortableTexEngine<'_>,
4616 ) -> EngineFlow<core::convert::Infallible> {
4617 let status = if let Some(engine) = engine.as_ref() {
4622 if engine.state.history as i32 <= 1 {
4623 0 as integer
4624 } else {
4625 1 as integer
4626 }
4627 } else {
4628 1 as integer
4629 };
4630 Self::abort_engine(engine, status)
4631 }
4632
4633 pub(crate) unsafe fn boundary_shipout(
4634 engine: *mut PortableTexEngine<'_>,
4635 box_node: halfword,
4636 ) {
4637 if let Some(engine) = engine.as_mut() {
4638 engine.stripped_shipouts = engine.stripped_shipouts.saturating_add(1);
4639 engine.last_stripped_shipout_box = Some(PortableNodeHandle(box_node));
4640 }
4641 }
4642
4643 pub(crate) unsafe fn boundary_capture_fragment_box(
4644 engine: *mut PortableTexEngine<'_>,
4645 box_node: halfword,
4646 mode: integer,
4647 boxcontext: integer,
4648 ) -> boolean {
4649 if let Some(engine) = engine.as_mut() {
4650 if engine.fragment_capture_enabled {
4651 engine.captured_fragment_root = Some(PortableNodeHandle(box_node));
4652 let absolute_mode = if mode >= 0 { mode } else { -mode };
4653 if absolute_mode == 1 && boxcontext < 1_073_741_824 {
4654 return true_0;
4655 }
4656 }
4657 }
4658 false_0
4659 }
4660
4661 pub(crate) unsafe fn boundary_build_page(
4662 engine: *mut PortableTexEngine<'_>,
4663 ) -> EngineFlow<()> {
4664 if let Some(engine) = engine.as_mut() {
4665 if engine.format_initialization
4666 && engine.state.curcmd as i32 == 15
4667 && engine.state.curchr == 1
4668 {
4669 Self::abort_engine(engine as *mut PortableTexEngine<'_>, 0 as integer)?;
4673 }
4674 engine.stripped_page_builds = engine.stripped_page_builds.saturating_add(1);
4675 }
4676 Ok(())
4677 }
4678
4679 pub(crate) unsafe fn boundary_prune_page_top(
4680 engine: *mut PortableTexEngine<'_>,
4681 node: halfword,
4682 _saving: boolean,
4683 ) -> halfword {
4684 if let Some(engine) = engine.as_mut() {
4685 engine.stripped_page_top_prunes =
4686 engine.stripped_page_top_prunes.saturating_add(1);
4687 }
4688 node
4689 }
4690
4691 pub(crate) unsafe fn boundary_special_out(
4692 engine: *mut PortableTexEngine<'_>,
4693 node: halfword,
4694 ) -> EngineFlow<()> {
4695 let Some(engine) = engine.as_mut() else {
4696 return Ok(());
4697 };
4698 if node < engine.state.memmin || node > engine.state.memend {
4699 engine.stripped_special_outputs = engine
4700 .stripped_special_outputs
4701 .saturating_add(1);
4702 return Ok(());
4703 }
4704 let mem = engine.state.zmem.as_mut_ptr();
4705 if (*mem.offset(node as isize)).hh.u.B0 as i32 == 8 {
4706 match (*mem.offset(node as isize)).hh.u.B1 as i32 {
4707 0 => {
4708 Self::boundary_open_write_whatsit(engine, node);
4709 return Ok(());
4710 }
4711 1 => {
4712 Self::boundary_write_whatsit(engine, node)?;
4713 return Ok(());
4714 }
4715 2 => {
4716 Self::boundary_close_write_whatsit(engine, node);
4717 return Ok(());
4718 }
4719 _ => {}
4720 }
4721 }
4722 engine.stripped_special_outputs = engine
4723 .stripped_special_outputs
4724 .saturating_add(1);
4725 Ok(())
4726 }
4727
4728 unsafe fn boundary_open_write_whatsit(engine: &mut PortableTexEngine<'_>, node: halfword) {
4729 let mem = engine.state.zmem.as_mut_ptr();
4730 let stream = (*mem.offset((node + 1) as isize)).hh.v.LH as usize;
4731 if stream >= 16 {
4732 return;
4733 }
4734
4735 if engine.state.writeopen[stream] != 0 {
4736 Self::boundary_close_write_stream(engine, stream);
4737 }
4738
4739 engine.state.curname = (*mem.offset((node + 1) as isize)).hh.v.RH as strnumber;
4740 engine.state.curarea = (*mem.offset((node + 2) as isize)).hh.v.LH as strnumber;
4741 engine.state.curext = (*mem.offset((node + 2) as isize)).hh.v.RH as strnumber;
4742 if engine.state.curext == 335 {
4743 engine.state.curext = 799;
4744 }
4745 engine.zpackfilename(engine.state.curname, engine.state.curarea, engine.state.curext);
4746 let Some(name) = Self::current_resource_name(engine as *mut PortableTexEngine<'_>) else {
4747 return;
4748 };
4749 let handle = Box::new(PortableFileHandle::new(
4750 name,
4751 ResourceKind::TexInput,
4752 None,
4753 resource_format_tex_input,
4754 Vec::new(),
4755 ));
4756 engine.state.writefile[stream] = Box::into_raw(handle);
4757 engine.state.writeopen[stream] = true_0;
4758 }
4759
4760 unsafe fn boundary_write_whatsit(
4761 engine: &mut PortableTexEngine<'_>,
4762 node: halfword,
4763 ) -> EngineFlow<()> {
4764 let mem = engine.state.zmem.as_mut_ptr();
4765 let stream = (*mem.offset((node + 1) as isize)).hh.v.LH as usize;
4766 if stream >= 16 || engine.state.writeopen[stream] == 0 {
4767 return Ok(());
4768 }
4769 let write_tokens = engine.profile.write_token_constants();
4770 let q = engine.getavail()?;
4771 (*mem.offset(q as isize)).hh.v.LH = write_tokens.open_group_token;
4772 let r = engine.getavail()?;
4773 (*mem.offset(q as isize)).hh.v.RH = r;
4774 (*mem.offset(r as isize)).hh.v.LH = write_tokens.end_write_token;
4775 engine.zbegintokenlist(q, 4)?;
4776 engine.zbegintokenlist((*mem.offset((node + 1) as isize)).hh.v.RH, 15)?;
4777 let q = engine.getavail()?;
4778 (*mem.offset(q as isize)).hh.v.LH = write_tokens.close_group_token;
4779 engine.zbegintokenlist(q, 4)?;
4780 let old_mode = engine.state.curlist.modefield;
4781 engine.state.curlist.modefield = 0;
4782 engine.state.curcs = engine.state.writeloc;
4783 engine.zscantoks(false_0, true_0)?;
4784 engine.state.curlist.modefield = old_mode;
4785 engine.gettoken()?;
4786 if engine.state.curtok != write_tokens.end_write_token {
4787 while engine.state.curtok != write_tokens.end_write_token {
4788 engine.gettoken()?;
4789 }
4790 }
4791 engine.endtokenlist()?;
4792 let old_setting = engine.state.selector;
4793 engine.state.selector = stream as eightbits;
4794 engine.ztokenshow(engine.state.defref);
4795 engine.println();
4796 engine.state.selector = old_setting;
4797 engine.zflushlist(engine.state.defref);
4798 Ok(())
4799 }
4800
4801 unsafe fn boundary_close_write_whatsit(engine: &mut PortableTexEngine<'_>, node: halfword) {
4802 let mem = engine.state.zmem.as_mut_ptr();
4803 let stream = (*mem.offset((node + 1) as isize)).hh.v.LH as usize;
4804 if stream < 16 {
4805 Self::boundary_close_write_stream(engine, stream);
4806 }
4807 }
4808
4809 unsafe fn boundary_close_write_stream(engine: &mut PortableTexEngine<'_>, stream: usize) {
4810 if stream >= 16 || engine.state.writeopen[stream] == 0 {
4811 return;
4812 }
4813 let file = engine.state.writefile[stream];
4814 engine.state.writefile[stream] = core::ptr::null_mut();
4815 engine.state.writeopen[stream] = false_0;
4816 if file.is_null() {
4817 return;
4818 }
4819 let handle = Box::from_raw(file);
4820 let key = Self::virtual_file_key(handle.name.as_str());
4821 engine.virtual_files.insert(key, handle.bytes);
4822 }
4823
4824 pub(crate) unsafe fn boundary_load_picture(
4825 engine: *mut PortableTexEngine<'_>,
4826 _is_pdf: boolean,
4827 ) {
4828 if let Some(engine) = engine.as_mut() {
4829 engine.stripped_picture_loads = engine.stripped_picture_loads.saturating_add(1);
4830 }
4831 }
4832
4833 pub(crate) fn record_stripped_source_special(engine: *mut PortableTexEngine<'_>) {
4834 if let Some(engine) = unsafe { engine.as_mut() } {
4835 engine.stripped_source_specials = engine.stripped_source_specials.saturating_add(1);
4836 }
4837 }
4838
4839 pub(crate) fn record_stripped_write_whatsit_diagnostic(engine: *mut PortableTexEngine<'_>) {
4840 if let Some(engine) = unsafe { engine.as_mut() } {
4841 engine.stripped_write_whatsit_diagnostics =
4842 engine.stripped_write_whatsit_diagnostics.saturating_add(1);
4843 }
4844 }
4845
4846 pub(crate) fn record_stripped_pdf_extension(engine: *mut PortableTexEngine<'_>) {
4847 if let Some(engine) = unsafe { engine.as_mut() } {
4848 engine.stripped_pdf_extensions = engine.stripped_pdf_extensions.saturating_add(1);
4849 }
4850 }
4851
4852 fn resolve_input_encoding(engine: &PortableTexEngine<'_>, handle: &mut PortableFileHandle) {
4862 let is_text = handle.format == resource_format_tex_input || handle.format == 0;
4863 if engine.is_xetex() && is_text {
4864 handle.resolve_text_encoding_auto();
4865 } else {
4866 handle.encoding = InputEncoding::Bytes;
4867 }
4868 }
4869
4870 pub(crate) unsafe fn boundary_open_input(
4871 engine: *mut PortableTexEngine<'_>,
4872 file: *mut NativeFileHandle,
4873 format: integer,
4874 mode: const_string,
4875 ) -> boolean {
4876 let Some(engine) = engine.as_mut() else {
4877 if !file.is_null() {
4878 *file = core::ptr::null_mut();
4879 }
4880 return false_0;
4881 };
4882 let Some(name) = Self::current_resource_name(engine as *mut PortableTexEngine<'_>) else {
4883 if !file.is_null() {
4884 *file = core::ptr::null_mut();
4885 }
4886 return false_0;
4887 };
4888 let mode = Self::mode_string(mode);
4889 let request_kind = Self::resource_kind_for_open(engine, name.as_str(), format);
4890 let request_package = Self::resource_package_owner(engine, name.as_str(), request_kind);
4891 let source: Option<PortableSourceSpan> = None;
4892 let request = ResourceRequest {
4893 name: name.as_str(),
4894 kind: request_kind,
4895 package: request_package.as_deref(),
4896 format,
4897 mode: mode.as_str(),
4898 source: source.clone(),
4899 };
4900 engine.resource_requests = engine.resource_requests.saturating_add(1);
4901 let virtual_key = Self::virtual_file_key(name.as_str());
4902 let bytes = if let Some(bytes) = engine.virtual_files.get(&virtual_key) {
4903 bytes.clone()
4904 } else if let Some(bytes) = engine.resources.read(request) {
4905 bytes
4906 } else {
4907 engine.resource_request_records.push(PortableResourceRequestRecord {
4908 name,
4909 kind: request_kind,
4910 package: request_package,
4911 format,
4912 mode,
4913 source,
4914 byte_len: None,
4915 });
4916 if !file.is_null() {
4917 *file = core::ptr::null_mut();
4918 }
4919 return false_0;
4920 };
4921 let byte_len = Self::source_index(bytes.len());
4922 engine.resource_request_records.push(PortableResourceRequestRecord {
4923 name: name.clone(),
4924 kind: request_kind,
4925 package: request_package.clone(),
4926 format,
4927 mode: mode.clone(),
4928 source,
4929 byte_len: Some(byte_len),
4930 });
4931 let mut handle = Box::new(PortableFileHandle::new(
4932 name,
4933 request_kind,
4934 request_package,
4935 format,
4936 bytes,
4937 ));
4938 Self::resolve_input_encoding(engine, &mut handle);
4942 if format == resource_format_tfm {
4943 engine.state.tfmtemp = handle.read_byte().map_or(-1, |byte| byte as integer);
4944 }
4945 if !file.is_null() {
4946 *file = Box::into_raw(handle);
4947 return true_0;
4948 }
4949 drop(handle);
4950 false_0
4951 }
4952
4953 unsafe fn begin_primary_input_raw(
4954 self: &mut Self,
4955 name: &str,
4956 bytes: Vec<u8>,
4957 ) -> EngineFlow<boolean> {
4958 if self.state.inputfile.is_null() || self.state.sourcefilenamestack.is_null()
4959 || self.state.fullsourcefilenamestack.is_null()
4960 || self.state.buffer.is_null()
4961 {
4962 return Ok(false_0);
4963 }
4964 let Some(source_name) = Self::intern_static_pool_string(self, name)? else {
4965 return Ok(false_0);
4966 };
4967 self.beginfilereading()?;
4968 let slot = self.state.curinput.indexfield as isize;
4969 let mut handle = Box::new(
4970 PortableFileHandle::new(
4971 name.to_string(),
4972 ResourceKind::TexInput,
4973 None,
4974 resource_format_tex_input,
4975 bytes,
4976 ),
4977 );
4978 Self::resolve_input_encoding(self, &mut handle);
4979 *self.state.inputfile.offset(slot) = Box::into_raw(handle);
4980 self.state.curinput.namefield = source_name as halfword;
4981 *self.state.sourcefilenamestack.offset(slot) = source_name;
4982 *self.state.fullsourcefilenamestack.offset(slot) = source_name;
4983 self.state.curinput.statefield = 33 as quarterword;
4984 self.state.line = 1 as integer;
4985 self.state.src_primary_name = source_name;
4986 self.state.cmd_span = 0;
4987 self.state.pending_call_span = 0;
4988 self.state.src_user_cmd_span = 0;
4989 self.state.src_tok_span = 0;
4990 self.state.src_anchor_cmd = 0;
4991 self.state.src_grp_stack.clear();
4992 self.state.src_grp_closing = 0;
4993 self.state.src_call_user_span = 0;
4994 self.state.src_line_base = 0;
4995 self.state.src_line_buf_start = 0;
4996 self.state.src_prev_line_len = 0;
4997 self.state.src_line_initialized = false;
4998 self.state.curinput.spanfield = 0;
4999 self.state.src_native_offsets.clear();
5000 self.state.src_stack_cells.clear();
5001 self.state.cur_stack_head = 0;
5002 if Self::boundary_input_line(
5003 self as *mut PortableTexEngine<'_>,
5004 *self.state.inputfile.offset(slot) as NativeFileHandle,
5005 ) == 0
5006 {
5007 self.endfilereading();
5008 return Ok(false_0);
5009 }
5010 self.firmuptheline()?;
5011 let eqtb = self.state.zeqtb.as_mut_ptr();
5012 let endline_char_index = if self.is_xetex() && self.state.eqtbtop >= 7_892_312 {
5013 7_892_312_i64
5014 } else {
5015 27_212_i64
5016 };
5017 let endline_char = if eqtb.is_null() {
5018 -1
5019 } else {
5020 (*eqtb.offset(endline_char_index as isize)).u.CINT
5021 };
5022 if !(0..=255).contains(&endline_char) {
5023 self.state.curinput.limitfield -= 1;
5024 } else {
5025 *self.state.buffer.offset(self.state.curinput.limitfield as isize) = endline_char
5026 as UnicodeScalar;
5027 }
5028 self.state.first = (self.state.curinput.limitfield as i32 + 1) as integer;
5029 self.state.curinput.locfield = self.state.curinput.startfield;
5030 Ok(true_0)
5031 }
5032
5033 pub(crate) unsafe fn boundary_input_line(
5034 engine: *mut PortableTexEngine<'_>,
5035 file: NativeFileHandle,
5036 ) -> boolean {
5037 let Some(engine) = engine.as_mut() else {
5038 return false_0;
5039 };
5040 if file.is_null() || engine.state.buffer.is_null() {
5041 return false_0;
5042 }
5043
5044 let handle = &mut *file;
5045 if !handle.has_remaining() {
5046 return false_0;
5047 }
5048
5049 let first = engine.state.first.max(0) as usize;
5050 let limit = engine.state.bufsize.max(0) as usize;
5051 let mut last = first;
5052 while last < limit {
5056 let Some(scalar) = handle.next_input_scalar() else {
5057 break;
5058 };
5059 match scalar {
5060 0x0A => break,
5061 0x0D => {
5062 let saved_cursor = handle.cursor;
5066 let saved_lookahead = handle.saved_char;
5067 let was_eof = handle.eof_after_failed_read;
5068 match handle.next_input_scalar() {
5069 Some(0x0A) => {} _ => {
5071 handle.cursor = saved_cursor;
5073 handle.saved_char = saved_lookahead;
5074 handle.eof_after_failed_read = was_eof;
5075 }
5076 }
5077 break;
5078 }
5079 scalar => {
5080 *engine.state.buffer.offset(last as isize) = scalar as UnicodeScalar;
5081 last += 1;
5082 }
5083 }
5084 }
5085
5086 while last > first && *engine.state.buffer.offset((last - 1) as isize) == b' ' as UnicodeScalar {
5087 last -= 1;
5088 }
5089 if handle.format == resource_format_tex_input || handle.format == 0 {
5090 engine.current_input_package_owner = handle.package.clone();
5091 }
5092 if engine.state.source_tracking
5099 && engine.state.curinput.namefield as strnumber == engine.state.src_primary_name
5100 {
5101 if engine.state.src_line_initialized {
5102 engine.state.src_line_base += engine.state.src_prev_line_len + 1;
5103 } else {
5104 engine.state.src_line_base = 0;
5105 engine.state.src_line_initialized = true;
5106 }
5107 engine.state.src_line_buf_start = first as integer;
5108 engine.state.src_prev_line_len = last.saturating_sub(first) as u32;
5109 engine.state.src_token_start = first as integer;
5115 }
5116 engine.state.last = last as integer;
5117 true_0
5118 }
5119
5120 pub(crate) unsafe fn boundary_read_byte(_file: NativeFileHandle) -> integer {
5121 if _file.is_null() {
5122 return -1;
5123 }
5124 (&mut *_file).read_byte().map_or(-1, |byte| byte as integer)
5125 }
5126
5127 pub(crate) unsafe fn boundary_end_of_file(_file: NativeFileHandle) -> integer {
5128 if _file.is_null() || (&*_file).is_eof() {
5129 1
5130 } else {
5131 0
5132 }
5133 }
5134
5135 pub(crate) unsafe fn boundary_flush_file(_file: NativeFileHandle) -> integer {
5136 0
5137 }
5138
5139 pub(crate) unsafe fn boundary_write_byte(
5140 engine: *mut PortableTexEngine<'_>,
5141 character: integer,
5142 file: NativeFileHandle,
5143 ) -> integer {
5144 if !file.is_null() {
5145 if let Ok(byte) = u8::try_from(character) {
5146 (*file).bytes.push(byte);
5147 }
5148 return character;
5149 }
5150 if let Some(engine) = engine.as_mut() {
5151 if let Ok(byte) = u8::try_from(character) {
5152 engine.transcript_bytes.push(byte);
5153 }
5154 }
5155 character
5156 }
5157
5158 pub(crate) unsafe fn boundary_close_file(_file: NativeFileHandle) {
5159 if !_file.is_null() {
5160 drop(Box::from_raw(_file));
5161 }
5162 }
5163
5164 pub(crate) unsafe fn get_seconds_and_micros(
5165 engine: *mut PortableTexEngine<'_>,
5166 seconds: *mut integer,
5167 micros: *mut integer,
5168 ) {
5169 let clock = engine
5170 .as_mut()
5171 .map(|engine| engine.platform.clock())
5172 .unwrap_or_default();
5173 if !seconds.is_null() {
5174 *seconds = clock.seconds;
5175 }
5176 if !micros.is_null() {
5177 *micros = clock.micros;
5178 }
5179 }
5180
5181 pub(crate) unsafe fn linebreak_start(
5182 engine: *mut PortableTexEngine<'_>,
5183 font: integer,
5184 locale: integer,
5185 text: *mut uint16_t,
5186 text_length: integer,
5187 ) {
5188 let Some(engine) = engine.as_mut() else {
5189 return;
5190 };
5191 let text = if text.is_null() || text_length <= 0 {
5192 &[]
5193 } else {
5194 core::slice::from_raw_parts(text as *const uint16_t, text_length as usize)
5195 };
5196 engine
5197 .platform
5198 .linebreak_start(PortableLinebreakRequest { font, locale, text });
5199 }
5200
5201 pub(crate) unsafe fn linebreak_next(engine: *mut PortableTexEngine<'_>) -> integer {
5202 engine
5203 .as_mut()
5204 .and_then(|engine| engine.platform.linebreak_next())
5205 .unwrap_or(-1)
5206 }
5207
5208 pub(crate) unsafe fn abort_engine(
5209 engine: *mut PortableTexEngine<'_>,
5210 status: integer,
5211 ) -> EngineFlow<core::convert::Infallible> {
5212 if let Some(engine) = engine.as_mut() {
5213 engine.last_abort_status = Some(status);
5214 }
5215 Err(EngineBreak::Abort(EngineAbort { status }))
5216 }
5217
5218 pub(crate) unsafe fn sandbox_reject(
5222 engine: *mut PortableTexEngine<'_>,
5223 message: &str,
5224 ) -> EngineFlow<()> {
5225 if let Some(engine) = engine.as_ref() {
5226 if engine.sandbox {
5227 return Err(EngineBreak::Error(EngineError {
5228 message: message.into(),
5229 }));
5230 }
5231 }
5232 Ok(())
5233 }
5234
5235 pub(crate) unsafe fn sandbox_open_math(
5242 engine: *mut PortableTexEngine<'_>,
5243 ) -> EngineFlow<()> {
5244 if let Some(engine) = engine.as_mut() {
5245 if engine.sandbox {
5246 if engine.sandbox_math_depth == 0 && engine.sandbox_math_opened {
5247 return Err(EngineBreak::Error(EngineError {
5248 message: "math shift ($) is not allowed inside a math expression"
5249 .into(),
5250 }));
5251 }
5252 engine.sandbox_math_opened = true;
5253 engine.sandbox_math_depth += 1;
5254 }
5255 }
5256 Ok(())
5257 }
5258
5259 pub(crate) unsafe fn sandbox_close_math(
5264 engine: *mut PortableTexEngine<'_>,
5265 ) -> EngineFlow<()> {
5266 if let Some(engine) = engine.as_mut() {
5267 if engine.sandbox && engine.sandbox_math_depth > 0 {
5268 engine.sandbox_math_depth -= 1;
5269 }
5270 }
5271 Ok(())
5272 }
5273
5274 pub(crate) unsafe fn sandbox_tick(
5278 engine: *mut PortableTexEngine<'_>,
5279 ) -> EngineFlow<()> {
5280 if let Some(engine) = engine.as_mut() {
5281 if engine.sandbox {
5282 engine.sandbox_ops = engine.sandbox_ops.saturating_add(1);
5283 if engine.sandbox_ops > SANDBOX_OP_BUDGET {
5284 return Err(EngineBreak::Error(EngineError {
5285 message: "expression is too complex or did not terminate".into(),
5286 }));
5287 }
5288 }
5289 }
5290 Ok(())
5291 }
5292
5293 pub(crate) unsafe fn surface_error(
5301 engine: *mut PortableTexEngine<'_>,
5302 ) -> EngineFlow<()> {
5303 let message = engine
5304 .as_ref()
5305 .map(|engine| engine.capture_last_error_message())
5306 .unwrap_or_else(|| "TeX error".into());
5307 Err(EngineBreak::Error(EngineError { message }))
5308 }
5309
5310 pub fn set_source_tracking(self: &mut Self, on: bool) {
5325 self.state.source_tracking = on;
5326 self.state.cmd_span = 0;
5327 self.state.pending_call_span = 0;
5328 self.state.src_token_start = 0;
5329 self.state.src_line_base = 0;
5330 self.state.src_line_buf_start = 0;
5331 self.state.src_prev_line_len = 0;
5332 self.state.src_line_initialized = false;
5333 self.state.src_call_start = 0;
5334 self.state.src_call_name = 0;
5335 self.state.src_call_state = 0;
5336 self.state.src_call_index = 0;
5337 self.state.src_call_span = 0;
5338 self.state.src_call_argspan = 0;
5339 self.state.src_user_cmd_span = 0;
5340 self.state.src_tok_span = 0;
5341 self.state.src_anchor_cmd = 0;
5342 self.state.src_grp_stack.clear();
5343 self.state.src_grp_closing = 0;
5344 self.state.src_call_user_span = 0;
5345 self.state.curinput.spanfield = 0;
5346 self.state.src_spans.clear();
5347 self.state.src_dedup.clear();
5348 self.state.src_native_offsets.clear();
5349 self.state.src_stack_cells.clear();
5350 self.state.cur_stack_head = 0;
5351 let end = if on { self.state.mem.len() } else { 0 };
5352 self.state.node_src = PagedArray::new(0, end, node_src_default, node_src_sig);
5353 self.state.node_stack = PagedArray::new(0, end, node_stack_default, node_stack_sig);
5354 }
5355
5356 pub fn source_tracking_enabled(&self) -> bool {
5358 self.state.source_tracking
5359 }
5360
5361 fn intern_span_raw(self: &mut Self, name: strnumber, start: u32, end: u32, role: u8) -> SrcId {
5366 let span = RawSpan { name, start, end, role };
5367 if let Some(&id) = self.state.src_dedup.get(&span) {
5368 return id;
5369 }
5370 self.state.src_spans.push(span);
5371 let id = self.state.src_spans.len() as SrcId;
5372 self.state.src_dedup.insert(span, id);
5373 id
5374 }
5375
5376 fn src_buf_offset(&self, loc: integer) -> u32 {
5379 let col = loc as i64 - self.state.src_line_buf_start as i64;
5380 (self.state.src_line_base as i64 + col).max(0) as u32
5381 }
5382
5383 pub(crate) fn resolve_node_src(&self, node: halfword) -> Option<PortableSourceSpan> {
5387 if !self.state.source_tracking || node < 0 {
5388 return None;
5389 }
5390 let id = self.state.node_src.get_copy(node as usize);
5391 if id == 0 {
5392 return None;
5393 }
5394 let raw = *self.state.src_spans.get((id - 1) as usize)?;
5395 let name = unsafe { self.pool_string(raw.name) }?;
5396 Some(PortableSourceSpan {
5397 name,
5398 start: raw.start,
5399 end: raw.end,
5400 role: raw.role,
5401 })
5402 }
5403
5404 pub(crate) unsafe fn src_mark_token_start(engine: *mut Self) {
5408 let Some(engine) = engine.as_mut() else {
5409 return;
5410 };
5411 if engine.state.source_tracking && engine.state.curinput.statefield as i32 != 0 {
5412 engine.state.src_token_start = engine.state.curinput.locfield as integer;
5413 }
5414 }
5415
5416 pub(crate) unsafe fn src_record_buffer_span(engine: *mut Self) {
5421 let Some(engine) = engine.as_mut() else {
5422 return;
5423 };
5424 if !engine.state.source_tracking || engine.state.curinput.statefield as i32 == 0 {
5425 return;
5426 }
5427 let a = engine.src_buf_offset(engine.state.src_token_start);
5428 let b = engine.src_buf_offset(engine.state.curinput.locfield as integer);
5429 let (lo, hi) = if a <= b { (a, b) } else { (b, a) };
5430 let name = engine.state.curinput.namefield as strnumber;
5431 let id = engine.intern_span_raw(name, lo, hi, 0);
5432 engine.state.curinput.spanfield = id;
5433 engine.state.src_tok_span = id;
5434 if engine.state.curcs != 0
5451 && name == engine.state.src_primary_name
5452 && engine.state.scannerstatus as i32 == 0
5453 {
5454 engine.state.src_user_cmd_span = id;
5455 engine.state.src_anchor_cmd = 0;
5460 }
5461 }
5462
5463 pub(crate) unsafe fn src_tokenlist_span(engine: *mut Self) {
5470 let Some(engine) = engine.as_mut() else {
5471 return;
5472 };
5473 if !engine.state.source_tracking {
5474 return;
5475 }
5476 if engine.state.curinput.indexfield as i32 >= 5 {
5477 return;
5478 }
5479 {
5486 let lf = engine.state.curinput.locfield as i32;
5487 if lf >= 0 {
5488 let cid = engine.state.node_src.get_copy(lf as usize);
5489 if cid != 0 {
5490 engine.state.src_tok_span = cid;
5491 }
5492 }
5493 }
5494 let cell = engine.state.curinput.locfield as i32;
5495 if cell < 0 {
5496 return;
5497 }
5498 let id = engine.state.node_src.get_copy(cell as usize);
5499 if id != 0 {
5500 engine.state.curinput.spanfield = id;
5501 }
5502 }
5503
5504 pub(crate) unsafe fn src_back_input_stamp(engine: *mut Self, p: halfword) {
5516 let Some(engine) = engine.as_mut() else {
5517 return;
5518 };
5519 if !engine.state.source_tracking || p < 0 {
5520 return;
5521 }
5522 let id = engine.state.src_tok_span;
5523 if id != 0 {
5524 engine.state.node_src.set(p as usize, id);
5525 }
5526 }
5527
5528 pub(crate) unsafe fn src_latch_cmd_span(engine: *mut Self) {
5532 let Some(engine) = engine.as_mut() else {
5533 return;
5534 };
5535 if engine.state.source_tracking {
5536 engine.state.cmd_span = engine.state.curinput.spanfield;
5537 }
5538 }
5539
5540 pub(crate) unsafe fn src_stamp_avail(engine: *mut Self, node: halfword) {
5545 let Some(engine) = engine.as_mut() else {
5546 return;
5547 };
5548 if engine.state.source_tracking && node >= 0 {
5549 let id = engine.state.curinput.spanfield;
5550 engine.state.node_src.set(node as usize, id);
5551 engine.state.node_stack.set(node as usize, engine.state.cur_stack_head);
5552 }
5553 }
5554
5555 pub(crate) unsafe fn src_stamp_node_range(engine: *mut Self, node: halfword, size: integer) {
5562 let Some(engine) = engine.as_mut() else {
5563 return;
5564 };
5565 if !engine.state.source_tracking || node < 0 || size <= 0 {
5566 return;
5567 }
5568 let id = engine.state.cmd_span;
5569 let head = engine.state.cur_stack_head;
5570 let base = node as usize;
5571 for i in 0..size as usize {
5572 if id != 0 {
5573 engine.state.node_src.set(base + i, id);
5574 }
5575 if head != 0 {
5576 engine.state.node_stack.set(base + i, head);
5577 }
5578 }
5579 }
5580
5581 pub(crate) unsafe fn src_carry_copy(engine: *mut Self, src: halfword, dst: halfword) {
5590 let Some(engine) = engine.as_mut() else {
5591 return;
5592 };
5593 if !engine.state.source_tracking || src < 0 || dst < 0 {
5594 return;
5595 }
5596 let id = engine.state.node_src.get_copy(src as usize);
5597 if id != 0 {
5598 engine.state.node_src.set(dst as usize, id);
5599 let head = engine.state.node_stack.get_copy(src as usize);
5600 engine.state.node_stack.set(dst as usize, head);
5601 }
5602 }
5603
5604 pub(crate) unsafe fn src_carry_token_span(engine: *mut Self, dest: halfword, src: halfword) {
5617 let Some(engine) = engine.as_mut() else {
5618 return;
5619 };
5620 if !engine.state.source_tracking || dest < 0 || src < 0 {
5621 return;
5622 }
5623 let id = engine.state.node_src.get_copy(src as usize);
5624 if id != 0 {
5625 engine.state.node_src.set(dest as usize, id);
5626 let head = engine.state.node_stack.get_copy(src as usize);
5627 engine.state.node_stack.set(dest as usize, head);
5628 }
5629 }
5630
5631 pub(crate) unsafe fn src_stamp_char(engine: *mut Self, node: halfword) {
5636 let Some(engine) = engine.as_mut() else {
5637 return;
5638 };
5639 if !engine.state.source_tracking || node < 0 {
5640 return;
5641 }
5642 let id = engine.state.cmd_span;
5643 if id != 0 {
5644 engine.state.node_src.set(node as usize, id);
5645 }
5646 engine.state.node_stack.set(node as usize, engine.state.cur_stack_head);
5647 }
5648
5649 pub(crate) unsafe fn src_mlist_repoint(engine: *mut Self, q: halfword) {
5653 let Some(engine) = engine.as_mut() else {
5654 return;
5655 };
5656 if !engine.state.source_tracking || q < 0 {
5657 return;
5658 }
5659 let id = engine.state.node_src.get_copy(q as usize);
5660 if id != 0 {
5661 engine.state.cmd_span = id;
5662 }
5663 }
5664
5665 pub(crate) unsafe fn src_stamp_field(engine: *mut Self, field: halfword) {
5674 let Some(engine) = engine.as_mut() else {
5675 return;
5676 };
5677 if !engine.state.source_tracking || field < 0 {
5678 return;
5679 }
5680 let id = engine.state.curinput.spanfield;
5681 if id != 0 {
5682 engine.state.node_src.set(field as usize, id);
5683 }
5684 }
5685
5686 pub(crate) unsafe fn src_carry_field(engine: *mut Self, field: halfword, noad: halfword) {
5694 let Some(engine) = engine.as_mut() else {
5695 return;
5696 };
5697 if !engine.state.source_tracking || field < 0 || noad < 0 {
5698 return;
5699 }
5700 let id = engine.state.node_src.get_copy(field as usize);
5701 let head = engine.state.node_stack.get_copy(field as usize);
5702 if id != 0 {
5703 for i in 0..4usize {
5706 engine.state.node_src.set(noad as usize + i, id);
5707 }
5708 }
5709 if head != 0 {
5712 for i in 0..4usize {
5713 engine.state.node_stack.set(noad as usize + i, head);
5714 }
5715 }
5716 }
5717
5718 pub(crate) unsafe fn src_carry_nucleus(engine: *mut Self, noad: halfword, glyph: halfword) {
5731 let Some(engine) = engine.as_mut() else {
5732 return;
5733 };
5734 if !engine.state.source_tracking || noad < 0 || glyph < 0 {
5735 return;
5736 }
5737 let id = engine.state.node_src.get_copy(noad as usize + 1);
5738 if id != 0 {
5739 engine.state.node_src.set(glyph as usize, id);
5740 }
5741 let head = engine.state.node_stack.get_copy(noad as usize + 1);
5745 engine.state.node_stack.set(glyph as usize, head);
5746 }
5747
5748 pub(crate) unsafe fn src_carry_collapse(engine: *mut Self, noad: halfword, field: halfword) {
5755 let Some(engine) = engine.as_mut() else {
5756 return;
5757 };
5758 if !engine.state.source_tracking || noad < 0 || field < 0 {
5759 return;
5760 }
5761 let id = engine.state.node_src.get_copy(noad as usize);
5762 if id != 0 {
5763 engine.state.node_src.set(field as usize, id);
5764 }
5765 let head = engine.state.node_stack.get_copy(noad as usize);
5769 if head != 0 {
5770 engine.state.node_stack.set(field as usize, head);
5771 }
5772 }
5773
5774 pub(crate) unsafe fn src_save_cmd_span(engine: *mut Self) -> u32 {
5777 engine.as_ref().map_or(0, |engine| engine.state.cmd_span)
5778 }
5779
5780 pub(crate) unsafe fn src_restore_cmd_span(engine: *mut Self, saved: u32) {
5783 if let Some(engine) = engine.as_mut() {
5784 if engine.state.source_tracking {
5785 engine.state.cmd_span = saved;
5786 }
5787 }
5788 }
5789
5790 fn src_stack_push_span(self: &mut Self, span: SrcId) -> u32 {
5800 self.state.src_stack_cells.push(SrcStackCell {
5801 span,
5802 parent: self.state.cur_stack_head,
5803 start: 0,
5804 name: 0,
5805 pending: false,
5806 });
5807 let head = self.state.src_stack_cells.len() as u32;
5808 self.state.cur_stack_head = head;
5809 head
5810 }
5811
5812 fn src_stack_push_pending(self: &mut Self, start: u32, name: strnumber) -> u32 {
5815 self.state.src_stack_cells.push(SrcStackCell {
5816 span: 0,
5817 parent: self.state.cur_stack_head,
5818 start,
5819 name,
5820 pending: true,
5821 });
5822 let head = self.state.src_stack_cells.len() as u32;
5823 self.state.cur_stack_head = head;
5824 head
5825 }
5826
5827 fn src_stack_pop(self: &mut Self) {
5829 let head = self.state.cur_stack_head;
5830 if head != 0 {
5831 if let Some(cell) = self.state.src_stack_cells.get((head - 1) as usize) {
5832 self.state.cur_stack_head = cell.parent;
5833 }
5834 }
5835 }
5836
5837 pub(crate) unsafe fn src_end_token_list(engine: *mut Self, token_type: i32) {
5846 let Some(engine) = engine.as_mut() else {
5847 return;
5848 };
5849 if !engine.state.source_tracking {
5850 return;
5851 }
5852 let cand = engine.state.curinput.spanfield;
5853 if cand != 0 {
5854 let cand_end = engine
5855 .state
5856 .src_spans
5857 .get((cand - 1) as usize)
5858 .map(|r| r.end)
5859 .unwrap_or(0);
5860 let cur_end = if engine.state.src_call_argspan != 0 {
5861 engine
5862 .state
5863 .src_spans
5864 .get((engine.state.src_call_argspan - 1) as usize)
5865 .map(|r| r.end)
5866 .unwrap_or(0)
5867 } else {
5868 0
5869 };
5870 if engine.state.src_call_argspan == 0 || cand_end > cur_end {
5871 engine.state.src_call_argspan = cand;
5872 }
5873 }
5874 if token_type == 6 {
5875 engine.src_stack_pop();
5876 }
5877 }
5878
5879 pub(crate) unsafe fn src_scan_math_group_open(engine: *mut Self) {
5886 let Some(engine) = engine.as_mut() else {
5887 return;
5888 };
5889 if !engine.state.source_tracking {
5890 return;
5891 }
5892 let cmd = engine.state.cmd_span;
5893 let (start, name) = if cmd != 0 {
5894 match engine.state.src_spans.get((cmd - 1) as usize) {
5895 Some(raw) => (raw.start, raw.name),
5896 None => (0, 0),
5897 }
5898 } else {
5899 (0, 0)
5900 };
5901 engine.src_stack_push_pending(start, name);
5902 engine.state.src_grp_stack.push(engine.state.curinput.spanfield);
5907 }
5908
5909 pub(crate) unsafe fn src_scan_math_group_close(engine: *mut Self) {
5913 let eptr = engine;
5914 let Some(e) = engine.as_mut() else {
5915 return;
5916 };
5917 if !e.state.source_tracking {
5918 return;
5919 }
5920 e.state.src_grp_closing = e.state.src_grp_stack.pop().unwrap_or(0);
5924 let grp = e.state.src_grp_closing;
5925 let aux = e.state.curlist.auxfield.u.CINT;
5930 let frac = if aux > 0 && aux != -(268435455 as i32) { aux } else { -1 };
5931 if e.state.cur_stack_head != 0 {
5932 let idx = (e.state.cur_stack_head - 1) as usize;
5933 if let Some(cell) = e.state.src_stack_cells.get(idx).copied() {
5934 if cell.pending
5937 && cell.name != 0
5938 && cell.name == e.state.curinput.namefield as strnumber
5939 {
5940 let end = e.src_buf_offset(e.state.curinput.locfield as integer);
5941 let (lo, hi) = if cell.start <= end {
5942 (cell.start, end)
5943 } else {
5944 (end, cell.start)
5945 };
5946 let id = e.intern_span_raw(cell.name, lo, hi, 1);
5947 if let Some(c) = e.state.src_stack_cells.get_mut(idx) {
5948 c.span = id;
5949 c.pending = false;
5950 }
5951 }
5952 e.state.cur_stack_head = cell.parent;
5953 }
5954 }
5955 if frac >= 0 {
5956 Self::src_construct_extent(eptr, frac, grp);
5957 }
5958 }
5959
5960 pub(crate) unsafe fn src_construct_anchor(engine: *mut Self) {
5973 let Some(engine) = engine.as_mut() else {
5974 return;
5975 };
5976 if !engine.state.source_tracking {
5977 return;
5978 }
5979 let noad = engine.state.curlist.tailfield as i32;
5980 if noad < 0 {
5981 return;
5982 }
5983 let id = engine.state.node_src.get_copy(noad as usize);
5984 if id == 0 {
5985 return;
5986 }
5987 let Some(raw) = engine.state.src_spans.get((id - 1) as usize).copied() else {
5988 return;
5989 };
5990 let anchor = (engine.state.src_anchor_cmd != 0)
6004 .then(|| engine.state.src_spans.get((engine.state.src_anchor_cmd - 1) as usize).copied())
6005 .flatten()
6006 .filter(|u| u.name == raw.name);
6007 let chosen = match anchor {
6008 Some(u) => {
6009 if u.start < raw.start {
6010 Some(u)
6011 } else {
6012 None
6013 }
6014 }
6015 None => (engine.state.src_user_cmd_span != 0)
6016 .then(|| engine.state.src_spans.get((engine.state.src_user_cmd_span - 1) as usize).copied())
6017 .flatten()
6018 .filter(|u| u.name == raw.name && u.start < raw.start),
6019 };
6020 let Some(u) = chosen else {
6021 return;
6022 };
6023 let newid = engine.intern_span_raw(raw.name, u.start, raw.end, raw.role);
6024 engine.state.node_src.set(noad as usize, newid);
6025 }
6026
6027 pub(crate) unsafe fn src_construct_extend_to_loc(engine: *mut Self) {
6042 let e = match engine.as_ref() {
6043 Some(e) => e,
6044 None => return,
6045 };
6046 if !e.state.source_tracking {
6047 return;
6048 }
6049 let field = (*e
6052 .state
6053 .savestack
6054 .offset((e.state.saveptr as i32 + 0 as i32) as isize))
6055 .u
6056 .CINT;
6057 let noad = e.state.curlist.tailfield as i32;
6058 let grp = e.state.src_grp_closing;
6059 if noad < 0 || field != noad + 1 {
6060 return;
6061 }
6062 Self::src_construct_extent(engine, noad, grp);
6063 }
6064
6065 pub(crate) unsafe fn src_construct_extent(engine: *mut Self, noad: halfword, group_open: SrcId) {
6080 let Some(engine) = engine.as_mut() else {
6081 return;
6082 };
6083 if !engine.state.source_tracking || noad < 0 {
6084 return;
6085 }
6086 let id = engine.state.node_src.get_copy(noad as usize);
6087 if id == 0 {
6088 return;
6089 }
6090 let Some(raw) = engine.state.src_spans.get((id - 1) as usize).copied() else {
6091 return;
6092 };
6093 let (end, name) = if engine.state.curinput.statefield as i32 != 0 {
6094 (
6095 engine.src_buf_offset(engine.state.curinput.locfield as integer),
6096 engine.state.curinput.namefield as strnumber,
6097 )
6098 } else {
6099 let sid = engine.state.curinput.spanfield;
6100 if sid == 0 {
6101 return;
6102 }
6103 let Some(braw) = engine.state.src_spans.get((sid - 1) as usize).copied() else {
6104 return;
6105 };
6106 (braw.end, braw.name)
6107 };
6108 if raw.name != name {
6109 return;
6110 }
6111 let end = end.max(raw.end);
6112 let mut start = raw.start;
6113 if group_open != 0 {
6114 if let Some(g) = engine.state.src_spans.get((group_open - 1) as usize).copied() {
6115 if g.name == name && g.start < start {
6116 start = g.start;
6117 }
6118 }
6119 }
6120 if start == raw.start && end == raw.end {
6121 return;
6122 }
6123 let newid = engine.intern_span_raw(name, start, end, raw.role);
6124 engine.state.node_src.set(noad as usize, newid);
6125 }
6126
6127 pub(crate) unsafe fn src_leftright(engine: *mut Self, p: halfword, t: integer) {
6134 let Some(eng) = engine.as_mut() else {
6135 return;
6136 };
6137 if !eng.state.source_tracking {
6138 return;
6139 }
6140 if t == 30 as i32 {
6141 let cmd = eng.state.cmd_span;
6142 eng.state.src_grp_stack.push(cmd);
6143 } else if t == 31 as i32 {
6144 let open = eng.state.src_grp_stack.pop().unwrap_or(0);
6145 Self::src_construct_extent(engine, p, open);
6146 }
6147 }
6148
6149 pub fn node_enclosing_spans(&self, handle: PortableNodeHandle) -> Vec<PortableSourceSpan> {
6156 let node = handle.0 as halfword;
6157 let mut out: Vec<PortableSourceSpan> = Vec::new();
6158 if !self.state.source_tracking || node < 0 {
6159 return out;
6160 }
6161 let primary = self.resolve_node_src(node);
6162 let mut head = self.state.node_stack.get_copy(node as usize);
6163 let mut guard = 0u32;
6164 while head != 0 {
6165 guard += 1;
6166 if guard > 4096 {
6167 break;
6168 }
6169 let Some(cell) = self.state.src_stack_cells.get((head - 1) as usize) else {
6170 break;
6171 };
6172 let parent = cell.parent;
6173 let span_id = cell.span;
6174 head = parent;
6175 if span_id == 0 {
6176 continue;
6177 }
6178 let Some(raw) = self.state.src_spans.get((span_id - 1) as usize) else {
6179 continue;
6180 };
6181 let Some(name) = (unsafe { self.pool_string(raw.name) }) else {
6182 continue;
6183 };
6184 if let Some(p) = primary.as_ref() {
6185 if name != p.name || raw.start > p.start || raw.end < p.end {
6188 continue;
6189 }
6190 if raw.start == p.start && raw.end == p.end {
6191 continue;
6192 }
6193 }
6194 if let Some(last) = out.last() {
6195 if last.name == name && last.start == raw.start && last.end == raw.end {
6196 continue;
6197 }
6198 }
6199 out.push(PortableSourceSpan {
6200 name,
6201 start: raw.start,
6202 end: raw.end,
6203 role: 1,
6204 });
6205 }
6206 out
6207 }
6208
6209 pub(crate) unsafe fn src_begin_token_list(engine: *mut Self, t: quarterword) {
6214 let Some(engine) = engine.as_mut() else {
6215 return;
6216 };
6217 if !engine.state.source_tracking {
6218 return;
6219 }
6220 if t as i32 == 6 {
6222 let call = engine.state.pending_call_span;
6223 if call != 0 {
6224 engine.state.curinput.spanfield = call;
6225 }
6226 engine.state.pending_call_span = 0;
6227 engine.src_stack_push_span(call);
6231 }
6232 }
6233
6234 pub(crate) unsafe fn src_capture_tok_span(engine: *mut Self) -> u32 {
6252 engine.as_ref().map_or(0, |engine| engine.state.src_tok_span)
6253 }
6254
6255 pub(crate) unsafe fn src_restore_tok_span(engine: *mut Self, saved: u32) {
6257 if let Some(engine) = engine.as_mut() {
6258 if engine.state.source_tracking {
6259 engine.state.src_tok_span = saved;
6260 }
6261 }
6262 }
6263
6264 pub(crate) unsafe fn src_macro_begin(engine: *mut Self) {
6268 let Some(engine) = engine.as_mut() else {
6269 return;
6270 };
6271 if !engine.state.source_tracking {
6272 return;
6273 }
6274 let span = engine.state.curinput.spanfield;
6275 engine.state.src_call_span = span;
6276 engine.state.src_call_state = engine.state.curinput.statefield as integer;
6277 engine.state.src_call_index = engine.state.curinput.indexfield as integer;
6278 engine.state.src_call_name = engine.state.curinput.namefield as strnumber;
6279 engine.state.src_call_argspan = 0;
6280 engine.state.src_call_user_span = engine.state.src_user_cmd_span;
6284 engine.state.src_call_start = if span != 0 {
6285 engine
6286 .state
6287 .src_spans
6288 .get((span - 1) as usize)
6289 .map(|s| s.start)
6290 .unwrap_or(0)
6291 } else {
6292 0
6293 };
6294 if engine.state.src_call_state == 0 && engine.state.src_call_index < 3 && span != 0 {
6305 if let Some(raw) = engine.state.src_spans.get((span - 1) as usize).copied() {
6306 if raw.name == engine.state.src_primary_name {
6307 engine.state.src_anchor_cmd = span;
6308 }
6309 }
6310 }
6311 }
6312
6313 unsafe fn src_arg_hull(self: &mut Self, n: integer) -> SrcId {
6320 let mut lo = u32::MAX;
6321 let mut hi = 0u32;
6322 let mut found = false;
6323 let mut name: strnumber = self.state.src_primary_name;
6324 if self.state.src_call_span != 0 {
6325 if let Some(raw) = self
6326 .state
6327 .src_spans
6328 .get((self.state.src_call_span - 1) as usize)
6329 {
6330 name = raw.name;
6331 lo = raw.start;
6332 hi = raw.end;
6333 found = true;
6334 }
6335 }
6336 let cmd_start = if found { lo } else { 0 };
6344 let zmem = self.state.zmem;
6345 let lo_b = self.state.memmin;
6346 let hi_b = self.state.memmax;
6347 for i in 0..n.max(0) {
6348 let mut p = self.state.pstack[i as usize];
6349 let mut guard = 0i32;
6350 while p >= lo_b && p <= hi_b && p as i64 != -(268435455 as i64) {
6351 guard += 1;
6352 if guard > 100000 {
6353 break;
6354 }
6355 let id = self.state.node_src.get_copy(p as usize);
6356 if id != 0 {
6357 if let Some(raw) = self.state.src_spans.get((id - 1) as usize) {
6358 if raw.name == name && raw.start >= cmd_start {
6359 if found {
6360 lo = lo.min(raw.start);
6361 hi = hi.max(raw.end);
6362 } else {
6363 lo = raw.start;
6364 hi = raw.end;
6365 found = true;
6366 }
6367 }
6368 }
6369 }
6370 p = (*zmem.offset(p as isize)).hh.v.RH;
6371 }
6372 }
6373 for cand in [self.state.src_call_argspan, self.state.curinput.spanfield] {
6380 if cand == 0 {
6381 continue;
6382 }
6383 if let Some(raw) = self.state.src_spans.get((cand - 1) as usize) {
6384 if raw.name == name && raw.start >= cmd_start {
6385 if found {
6386 lo = lo.min(raw.start);
6387 hi = hi.max(raw.end);
6388 } else {
6389 lo = raw.start;
6390 hi = raw.end;
6391 found = true;
6392 }
6393 }
6394 }
6395 }
6396 if found && hi > lo {
6397 self.intern_span_raw(name, lo, hi, 1)
6398 } else {
6399 0
6400 }
6401 }
6402
6403 pub(crate) unsafe fn src_macro_set_pending(engine: *mut Self, n: integer) {
6421 let Some(engine) = engine.as_mut() else {
6422 return;
6423 };
6424 if !engine.state.source_tracking {
6425 return;
6426 }
6427 if engine.state.src_call_index == 0 && engine.state.src_call_span == 0 {
6428 engine.state.pending_call_span = 0;
6438 } else if engine.state.src_call_index == 0 {
6439 let hull = engine.src_arg_hull(n);
6442 engine.state.pending_call_span = if hull != 0 {
6443 hull
6444 } else {
6445 engine.state.src_call_span
6446 };
6447 } else if engine.state.curinput.statefield as i32 != 0 {
6448 let end = engine.src_buf_offset(engine.state.curinput.locfield as integer);
6458 let name = engine.state.curinput.namefield as strnumber;
6459 let mut start = engine.state.src_call_start.min(end);
6460 let user = engine.state.src_call_user_span;
6461 if user != 0 {
6462 if let Some(raw) = engine.state.src_spans.get((user - 1) as usize) {
6463 if raw.name == name && raw.start <= start {
6464 start = raw.start;
6465 }
6466 }
6467 }
6468 let id = engine.intern_span_raw(name, start, end, 1);
6469 engine.state.pending_call_span = id;
6470 } else if n > 0 {
6471 let hull = engine.src_arg_hull(n);
6482 engine.state.pending_call_span = if hull != 0 {
6483 hull
6484 } else {
6485 engine.state.src_call_span
6486 };
6487 } else {
6488 engine.state.pending_call_span = engine.state.src_call_span;
6489 }
6490 }
6491
6492 pub(crate) unsafe fn src_native_run_push(engine: *mut Self) {
6501 let Some(engine) = engine.as_mut() else {
6502 return;
6503 };
6504 if !engine.state.source_tracking {
6505 return;
6506 }
6507 let nativelen = engine.state.nativelen.max(0) as usize;
6508 let units = if engine.state.curchr as i64 > 65535 { 2 } else { 1 };
6511 let prev = nativelen.saturating_sub(units);
6512 if prev == 0 {
6513 engine.state.src_native_offsets.clear();
6514 }
6515 if engine.state.src_native_offsets.len() > prev {
6518 engine.state.src_native_offsets.truncate(prev);
6519 }
6520 let id = engine.state.curinput.spanfield;
6521 while engine.state.src_native_offsets.len() < nativelen {
6522 engine.state.src_native_offsets.push(id);
6523 }
6524 }
6525
6526 pub(crate) unsafe fn src_resolve_native_glyphs(
6542 engine: *mut Self,
6543 node: halfword,
6544 text: &[u16],
6545 glyphs: &mut [PortableNativeGlyph],
6546 ) {
6547 let Some(engine) = engine.as_mut() else {
6548 return;
6549 };
6550 if !engine.state.source_tracking {
6551 return;
6552 }
6553 let offsets = core::mem::take(&mut engine.state.src_native_offsets);
6554 if text.is_empty() || offsets.len() != text.len() {
6557 return;
6558 }
6559 if node < 0 {
6560 return;
6561 }
6562 let node_id = engine.state.node_src.get_copy(node as usize);
6565 if node_id == 0 {
6566 return;
6567 }
6568 let node_name = match engine.state.src_spans.get((node_id - 1) as usize) {
6569 Some(raw) => raw.name,
6570 None => return,
6571 };
6572 let s = String::from_utf16_lossy(text);
6578 let n = s.len();
6579 let mut byte_src = vec![0u32; n];
6580 let mut u16i = 0usize;
6581 for (b, ch) in s.char_indices() {
6582 let id = offsets.get(u16i).copied().unwrap_or(0);
6583 let upper = (b + ch.len_utf8()).min(n);
6584 for slot in byte_src.iter_mut().take(upper).skip(b) {
6585 *slot = id;
6586 }
6587 u16i += ch.len_utf16();
6588 }
6589 for gi in 0..glyphs.len() {
6590 let cs = (glyphs[gi].cluster_start as usize).min(n);
6591 let mut ce = n;
6595 for g2 in glyphs.iter() {
6596 let c2 = (g2.cluster_start as usize).min(n);
6597 if c2 > cs && c2 < ce {
6598 ce = c2;
6599 }
6600 }
6601 let mut lo = u32::MAX;
6602 let mut hi = 0u32;
6603 let mut found = false;
6604 for &id in byte_src.iter().take(ce).skip(cs) {
6605 if id == 0 {
6606 continue;
6607 }
6608 let Some(raw) = engine.state.src_spans.get((id - 1) as usize) else {
6609 continue;
6610 };
6611 if raw.name != node_name {
6612 continue;
6613 }
6614 lo = lo.min(raw.start);
6615 hi = hi.max(raw.end);
6616 found = true;
6617 }
6618 if found && hi > lo {
6619 glyphs[gi].src_start = lo;
6620 glyphs[gi].src_end = hi;
6621 }
6622 }
6623 }
6624
6625 pub fn input_source_spans(&self) -> Vec<PortableSourceSpan> {
6628 self.state
6629 .src_spans
6630 .iter()
6631 .filter_map(|raw| {
6632 let name = unsafe { self.pool_string(raw.name) }?;
6633 Some(PortableSourceSpan {
6634 name,
6635 start: raw.start,
6636 end: raw.end,
6637 role: raw.role,
6638 })
6639 })
6640 .collect()
6641 }
6642
6643 pub(crate) unsafe fn resolve_font_handle(
6644 engine: *mut PortableTexEngine<'_>,
6645 name: *mut ASCIIcode,
6646 size: integer,
6647 ) -> FontHandle {
6648 let Some(engine) = engine.as_mut() else {
6649 return 0;
6650 };
6651 let name_len = engine.state.namelength.max(0) as usize;
6652 let name = if name.is_null() || name_len == 0 {
6653 &[]
6654 } else {
6655 core::slice::from_raw_parts(name as *const i32, name_len)
6656 };
6657 engine.fonts.resolve_font_handle(name, size).unwrap_or(0)
6658 }
6659
6660 pub(crate) unsafe fn measure_font_metrics(
6661 engine: *mut PortableTexEngine<'_>,
6662 font: FontHandle,
6663 ascent: *mut integer,
6664 descent: *mut integer,
6665 xheight: *mut integer,
6666 capheight: *mut integer,
6667 slant: *mut integer,
6668 ) {
6669 let metrics = engine
6670 .as_mut()
6671 .map(|engine| engine.fonts.font_metrics(font))
6672 .unwrap_or_default();
6673 if !ascent.is_null() {
6674 *ascent = metrics.ascent;
6675 }
6676 if !descent.is_null() {
6677 *descent = metrics.descent;
6678 }
6679 if !xheight.is_null() {
6680 *xheight = metrics.xheight;
6681 }
6682 if !capheight.is_null() {
6683 *capheight = metrics.capheight;
6684 }
6685 if !slant.is_null() {
6686 *slant = metrics.slant;
6687 }
6688 }
6689
6690 pub(crate) unsafe fn get_native_mathsy_parameter(
6691 engine: *mut PortableTexEngine<'resources>,
6692 font: integer,
6693 param: integer,
6694 ) -> integer {
6695 let Some(engine) = engine.as_mut() else {
6696 return 0;
6697 };
6698 let Some(font_handle) = Self::font_handle_for_number(engine, font) else {
6699 return 0;
6700 };
6701 engine.fonts.math_symbol_parameter(font_handle, param)
6702 }
6703
6704 pub(crate) unsafe fn get_native_mathex_parameter(
6705 engine: *mut PortableTexEngine<'resources>,
6706 font: integer,
6707 param: integer,
6708 ) -> integer {
6709 let Some(engine) = engine.as_mut() else {
6710 return 0;
6711 };
6712 let Some(font_handle) = Self::font_handle_for_number(engine, font) else {
6713 return 0;
6714 };
6715 engine.fonts.math_extension_parameter(font_handle, param)
6716 }
6717
6718 pub(crate) unsafe fn get_ot_math_ital_corr(
6727 engine: *mut PortableTexEngine<'resources>,
6728 font: integer,
6729 glyph: integer,
6730 ) -> integer {
6731 let Some(engine) = engine.as_mut() else {
6732 return 0;
6733 };
6734 let Some(font_handle) = Self::font_handle_for_number(engine, font) else {
6735 return 0;
6736 };
6737 engine.fonts.math_glyph_italic_correction(font_handle, glyph)
6738 }
6739
6740 pub(crate) unsafe fn get_ot_math_variant(
6745 engine: *mut PortableTexEngine<'resources>,
6746 f_0: integer,
6747 g_0: integer,
6748 v: integer,
6749 adv: *mut integer,
6750 horiz: integer,
6751 ) -> integer {
6752 if !adv.is_null() {
6753 *adv = -1;
6754 }
6755 let Some(engine) = engine.as_mut() else {
6756 return g_0;
6757 };
6758 let Some(font_handle) = Self::font_handle_for_number(engine, f_0) else {
6759 return g_0;
6760 };
6761 let index = u16::try_from(v).unwrap_or(u16::MAX);
6762 match engine
6763 .fonts
6764 .math_glyph_variant(font_handle, g_0, index, horiz != 0)
6765 {
6766 Some(variant) => {
6767 if !adv.is_null() {
6768 *adv = variant.advance;
6769 }
6770 variant.glyph
6771 }
6772 None => g_0,
6773 }
6774 }
6775
6776 pub(crate) unsafe fn get_ot_assembly_ptr(
6782 engine: *mut PortableTexEngine<'resources>,
6783 f_0: integer,
6784 g_0: integer,
6785 horiz: integer,
6786 ) -> voidpointer {
6787 let Some(engine) = engine.as_mut() else {
6788 return nullptr;
6789 };
6790 let Some(font_handle) = Self::font_handle_for_number(engine, f_0) else {
6791 return nullptr;
6792 };
6793 let parts = engine
6794 .fonts
6795 .math_glyph_assembly(font_handle, g_0, horiz != 0);
6796 if parts.is_empty() {
6797 return nullptr;
6798 }
6799 let assembly = Box::new(GlyphAssembly { parts });
6800 Box::into_raw(assembly) as voidpointer
6801 }
6802
6803 pub(crate) unsafe fn ot_min_connector_overlap(
6806 engine: *mut PortableTexEngine<'resources>,
6807 f_0: integer,
6808 ) -> integer {
6809 let Some(engine) = engine.as_mut() else {
6810 return 0;
6811 };
6812 let Some(font_handle) = Self::font_handle_for_number(engine, f_0) else {
6813 return 0;
6814 };
6815 engine.fonts.math_min_connector_overlap(font_handle)
6816 }
6817
6818 unsafe fn math_glyph_height(
6820 engine: &mut PortableTexEngine<'resources>,
6821 f_0: integer,
6822 g_0: integer,
6823 ) -> scaled {
6824 let Some(font_handle) = Self::font_handle_for_number(engine, f_0) else {
6825 return 0;
6826 };
6827 let Ok(glyph) = u16::try_from(g_0) else {
6828 return 0;
6829 };
6830 engine.fonts.measure_native_glyph(font_handle, glyph, true).height
6831 }
6832
6833 unsafe fn math_glyph_depth(
6835 engine: &mut PortableTexEngine<'resources>,
6836 f_0: integer,
6837 g_0: integer,
6838 ) -> scaled {
6839 let Some(font_handle) = Self::font_handle_for_number(engine, f_0) else {
6840 return 0;
6841 };
6842 let Ok(glyph) = u16::try_from(g_0) else {
6843 return 0;
6844 };
6845 engine.fonts.measure_native_glyph(font_handle, glyph, true).depth
6846 }
6847
6848 unsafe fn math_kern_at(
6851 engine: &mut PortableTexEngine<'resources>,
6852 f_0: integer,
6853 g_0: integer,
6854 height: integer,
6855 corner: PortableMathKernCorner,
6856 ) -> integer {
6857 let Some(font_handle) = Self::font_handle_for_number(engine, f_0) else {
6858 return 0;
6859 };
6860 engine.fonts.math_kern_at(font_handle, g_0, corner, height)
6861 }
6862
6863 pub(crate) unsafe fn get_ot_math_kern(
6870 engine: *mut PortableTexEngine<'resources>,
6871 f_0: integer,
6872 g_0: integer,
6873 sf: integer,
6874 sg: integer,
6875 cmd: integer,
6876 shift_scaled: integer,
6877 ) -> integer {
6878 const SUP_CMD: integer = 0;
6879 const SUB_CMD: integer = 1;
6880 let Some(engine) = engine.as_mut() else {
6881 return 0;
6882 };
6883 let Some(font_handle) = Self::font_handle_for_number(engine, f_0) else {
6884 return 0;
6885 };
6886 let Some(sfont_handle) = Self::font_handle_for_number(engine, sf) else {
6887 return 0;
6888 };
6889
6890 let g_height_pt = Self::math_glyph_height(engine, f_0, g_0) as f32 / 65536.0;
6892 let g_depth_pt = Self::math_glyph_depth(engine, f_0, g_0) as f32 / 65536.0;
6893 let sg_height_pt = Self::math_glyph_height(engine, sf, sg) as f32 / 65536.0;
6894 let sg_depth_pt = Self::math_glyph_depth(engine, sf, sg) as f32 / 65536.0;
6895
6896 let g_height = engine.fonts.math_points_to_units(font_handle, g_height_pt) as integer;
6898 let g_depth = engine.fonts.math_points_to_units(font_handle, g_depth_pt) as integer;
6899 let sg_height = engine
6900 .fonts
6901 .math_points_to_units(sfont_handle, sg_height_pt) as integer;
6902 let sg_depth = engine
6903 .fonts
6904 .math_points_to_units(sfont_handle, sg_depth_pt) as integer;
6905 let shift_pt = shift_scaled as f32 / 65536.0;
6906 let shift = engine.fonts.math_points_to_units(font_handle, shift_pt) as integer;
6907
6908 let f_size = engine.fonts.math_point_size(font_handle);
6909 let sf_size = engine.fonts.math_point_size(sfont_handle);
6910 if f_size == 0.0 {
6911 return 0;
6912 }
6913 let scale_factor = sf_size / f_size;
6914
6915 let mut rval: integer;
6916 if cmd == SUP_CMD {
6917 let kern = Self::math_kern_at(
6918 engine,
6919 f_0,
6920 g_0,
6921 shift - (scale_factor * sg_depth as f32) as integer,
6922 PortableMathKernCorner::TopRight,
6923 );
6924 let skern =
6925 Self::math_kern_at(engine, sf, sg, -sg_depth, PortableMathKernCorner::BottomLeft);
6926 let top_kern = kern + (scale_factor * skern as f32) as integer;
6927
6928 let kern =
6929 Self::math_kern_at(engine, f_0, g_0, g_height, PortableMathKernCorner::TopRight);
6930 let skern = Self::math_kern_at(
6931 engine,
6932 sf,
6933 sg,
6934 ((g_height - shift) as f32 / scale_factor) as integer,
6935 PortableMathKernCorner::BottomLeft,
6936 );
6937 let bot_kern = kern + (scale_factor * skern as f32) as integer;
6938
6939 rval = if top_kern > bot_kern { top_kern } else { bot_kern };
6940 } else if cmd == SUB_CMD {
6941 let kern = Self::math_kern_at(
6942 engine,
6943 f_0,
6944 g_0,
6945 (scale_factor * sg_height as f32) as integer - shift,
6946 PortableMathKernCorner::BottomRight,
6947 );
6948 let skern =
6949 Self::math_kern_at(engine, sf, sg, sg_height, PortableMathKernCorner::TopLeft);
6950 let top_kern = kern + (scale_factor * skern as f32) as integer;
6951
6952 let kern =
6953 Self::math_kern_at(engine, f_0, g_0, -g_depth, PortableMathKernCorner::BottomRight);
6954 let skern = Self::math_kern_at(
6955 engine,
6956 sf,
6957 sg,
6958 ((shift - g_depth) as f32 / scale_factor) as integer,
6959 PortableMathKernCorner::TopLeft,
6960 );
6961 let bot_kern = kern + (scale_factor * skern as f32) as integer;
6962
6963 rval = if top_kern > bot_kern { top_kern } else { bot_kern };
6964 } else {
6965 return 0;
6966 }
6967
6968 rval = engine.fonts.math_units_to_scaled(font_handle, rval);
6969 rval
6970 }
6971
6972 pub(crate) unsafe fn get_native_word_cp(
6973 engine: *mut PortableTexEngine<'resources>,
6974 node: voidpointer,
6975 side: integer,
6976 ) -> integer {
6977 let Some(engine) = engine.as_mut() else {
6978 return 0;
6979 };
6980 let Some(node_index) = Self::node_index_for_pointer(engine, node) else {
6981 return 0;
6982 };
6983 let Some(info) = engine.native_glyph_infos.get(&node_index) else {
6984 return 0;
6985 };
6986 let glyph = if side == 0 {
6987 info.glyphs.first()
6988 } else {
6989 info.glyphs.last()
6990 };
6991 let Some(glyph) = glyph else {
6992 return 0;
6993 };
6994 let font = Self::native_node_font(engine.state.zmem, node_index);
6995 Self::character_protrusion(engine, font, u32::from(glyph.glyph_id), side)
6996 }
6997
6998 pub(crate) unsafe fn get_native_glyph(
6999 engine: *mut PortableTexEngine<'resources>,
7000 node: voidpointer,
7001 index: u32,
7002 ) -> uint16_t {
7003 let Some(engine) = engine.as_mut() else {
7004 return 0;
7005 };
7006 let Some(node_index) = Self::node_index_for_pointer(engine, node) else {
7007 return 0;
7008 };
7009 engine
7010 .native_glyph_infos
7011 .get(&node_index)
7012 .and_then(|info| info.glyphs.get(index as usize))
7013 .map_or(0, |glyph| glyph.glyph_id)
7014 }
7015
7016 pub(crate) unsafe fn get_character_protrusion(
7017 engine: *mut PortableTexEngine<'_>,
7018 font: integer,
7019 code: u32,
7020 side: integer,
7021 ) -> integer {
7022 engine
7023 .as_mut()
7024 .map_or(0, |engine| Self::character_protrusion(engine, font, code, side))
7025 }
7026
7027 pub(crate) fn character_protrusion(
7028 engine: &PortableTexEngine<'_>,
7029 font: integer,
7030 code: u32,
7031 side: integer,
7032 ) -> integer {
7033 engine
7034 .character_protrusions
7035 .get(&(font, code, side))
7036 .copied()
7037 .unwrap_or(0)
7038 }
7039
7040 pub(crate) fn set_character_protrusion(
7041 engine: &mut PortableTexEngine<'_>,
7042 font: integer,
7043 code: u32,
7044 side: integer,
7045 value: integer,
7046 ) {
7047 let key = (font, code, side);
7048 if value == 0 {
7049 engine.character_protrusions.remove(&key);
7050 } else {
7051 engine.character_protrusions.insert(key, value);
7052 }
7053 }
7054
7055 pub(crate) unsafe fn get_opentype_math_constant(
7056 engine: *mut PortableTexEngine<'resources>,
7057 font: integer,
7058 constant: integer,
7059 ) -> integer {
7060 let Some(engine) = engine.as_mut() else {
7061 return 0;
7062 };
7063 let Some(font_handle) = Self::font_handle_for_number(engine, font) else {
7064 return 0;
7065 };
7066 engine.fonts.opentype_math_constant(font_handle, constant)
7067 }
7068
7069 pub(crate) unsafe fn get_opentype_math_accent_position(
7070 engine: *mut PortableTexEngine<'resources>,
7071 font: integer,
7072 glyph: integer,
7073 ) -> integer {
7074 let Some(engine) = engine.as_mut() else {
7075 return 0;
7076 };
7077 let Some(font_handle) = Self::font_handle_for_number(engine, font) else {
7078 return 0;
7079 };
7080 engine.fonts.opentype_math_accent_position(font_handle, glyph)
7081 }
7082
7083 pub(crate) unsafe fn map_char_to_glyph(
7084 engine: *mut PortableTexEngine<'resources>,
7085 font: integer,
7086 ch: integer,
7087 ) -> integer {
7088 let Some(engine) = engine.as_mut() else {
7089 return 0;
7090 };
7091 let Some(font_handle) = Self::font_handle_for_number(engine, font) else {
7092 return 0;
7093 };
7094 engine.fonts.map_char_to_glyph(font_handle, ch)
7095 }
7096
7097 pub(crate) unsafe fn map_glyph_to_index(
7098 engine: *mut PortableTexEngine<'resources>,
7099 font: integer,
7100 ) -> integer {
7101 let Some(engine) = engine.as_mut() else {
7102 return 0;
7103 };
7104 let Some(font_handle) = Self::font_handle_for_number(engine, font) else {
7105 return 0;
7106 };
7107 let Some(name) = engine.pool_string(engine.state.curname) else {
7108 return 0;
7109 };
7110 engine.fonts.map_glyph_to_index(font_handle, name.as_str())
7111 }
7112
7113 pub(crate) unsafe fn ot_font_get(
7118 engine: *mut PortableTexEngine<'resources>,
7119 what: integer,
7120 font: integer,
7121 param1: integer,
7122 param2: integer,
7123 param3: integer,
7124 ) -> integer {
7125 let Some(engine) = engine.as_mut() else {
7126 return 0;
7127 };
7128 let Some(font_handle) = Self::font_handle_for_number(engine, font) else {
7129 return 0;
7130 };
7131 engine
7132 .fonts
7133 .ot_font_get(font_handle, what, param1, param2, param3)
7134 }
7135
7136 pub(crate) unsafe fn is_opentype_math_font(
7137 engine: *mut PortableTexEngine<'_>,
7138 font: FontHandle,
7139 ) -> boolean {
7140 engine
7141 .as_mut()
7142 .map(|engine| engine.fonts.is_opentype_math_font(font) as boolean)
7143 .unwrap_or(false_0)
7144 }
7145
7146 pub(crate) unsafe fn using_opentype(
7147 engine: *mut PortableTexEngine<'_>,
7148 font: FontHandle,
7149 ) -> boolean {
7150 engine
7151 .as_mut()
7152 .map(|engine| engine.fonts.using_opentype(font) as boolean)
7153 .unwrap_or(false_0)
7154 }
7155
7156 pub(crate) unsafe fn release_font_engine(
7157 engine: *mut PortableTexEngine<'_>,
7158 font: FontHandle,
7159 type_flag: integer,
7160 ) {
7161 if let Some(engine) = engine.as_mut() {
7162 engine.fonts.release_font_handle(font, type_flag);
7163 }
7164 }
7165
7166 pub(crate) unsafe fn measure_opentype_font_metrics(
7167 engine: *mut PortableTexEngine<'_>,
7168 font: FontHandle,
7169 ascent: *mut integer,
7170 descent: *mut integer,
7171 xheight: *mut integer,
7172 capheight: *mut integer,
7173 slant: *mut integer,
7174 ) {
7175 let metrics = engine
7176 .as_mut()
7177 .map(|engine| engine.fonts.opentype_font_metrics(font))
7178 .unwrap_or_default();
7179 if !ascent.is_null() {
7180 *ascent = metrics.ascent;
7181 }
7182 if !descent.is_null() {
7183 *descent = metrics.descent;
7184 }
7185 if !xheight.is_null() {
7186 *xheight = metrics.xheight;
7187 }
7188 if !capheight.is_null() {
7189 *capheight = metrics.capheight;
7190 }
7191 if !slant.is_null() {
7192 *slant = metrics.slant;
7193 }
7194 }
7195
7196 pub(crate) unsafe fn measure_native_node(
7197 engine: *mut PortableTexEngine<'resources>,
7198 node: voidpointer,
7199 use_glyph_metrics: integer,
7200 ) {
7201 let Some(engine) = engine.as_mut() else {
7202 return;
7203 };
7204 let Some(node_index) = Self::node_index_for_pointer(engine, node) else {
7205 return;
7206 };
7207 let mem = engine.state.zmem;
7208 let font_number = Self::native_node_font(mem, node_index);
7209 let Some(font_handle) = Self::font_handle_for_number(engine, font_number) else {
7210 return;
7211 };
7212 let text = Self::native_node_text(mem, node_index);
7213 let mut metrics =
7214 engine
7215 .fonts
7216 .shape_native_text(font_handle, text, use_glyph_metrics != 0);
7217 Self::src_resolve_native_glyphs(
7221 engine as *mut PortableTexEngine<'resources>,
7222 node_index,
7223 text,
7224 metrics.glyphs.as_mut_slice(),
7225 );
7226 Self::write_native_node_metrics(
7227 mem,
7228 node_index,
7229 metrics.width,
7230 metrics.height,
7231 metrics.depth,
7232 );
7233 (*mem.offset((node_index + 4) as isize)).v.QQQQ.u.B3 =
7234 (metrics.glyphs.len().min(i32::MAX as usize) as quarterword) as u16;
7235 (*mem.offset((node_index + 5) as isize)).ptr = nullptr;
7236 engine.native_glyph_infos.insert(
7237 node_index,
7238 PortableNativeGlyphInfo {
7239 glyphs: metrics.glyphs,
7240 },
7241 );
7242 }
7243
7244 pub(crate) unsafe fn measure_native_glyph(
7245 engine: *mut PortableTexEngine<'resources>,
7246 node: voidpointer,
7247 use_glyph_metrics: integer,
7248 ) {
7249 let Some(engine) = engine.as_mut() else {
7250 return;
7251 };
7252 let Some(node_index) = Self::node_index_for_pointer(engine, node) else {
7253 return;
7254 };
7255 let mem = engine.state.zmem;
7256 let font_number = Self::native_node_font(mem, node_index);
7257 let Some(font_handle) = Self::font_handle_for_number(engine, font_number) else {
7258 return;
7259 };
7260 let glyph = (*mem.offset((node_index + 4) as isize)).v.QQQQ.u.B2 as u16;
7261 let metrics = engine
7262 .fonts
7263 .measure_native_glyph(font_handle, glyph, use_glyph_metrics != 0);
7264 Self::write_native_node_metrics(
7265 mem,
7266 node_index,
7267 metrics.width,
7268 metrics.height,
7269 metrics.depth,
7270 );
7271 (*mem.offset((node_index + 4) as isize)).v.QQQQ.u.B3 = (1 as quarterword) as u16;
7272 engine.native_glyph_infos.insert(
7282 node_index,
7283 PortableNativeGlyphInfo {
7284 glyphs: Vec::from([PortableNativeGlyph {
7285 glyph_id: glyph,
7286 x: 0,
7287 y: 0,
7288 advance: metrics.width,
7289 cluster_start: 0,
7290 cluster_end: 0,
7291 src_start: 0,
7292 src_end: 0,
7293 }]),
7294 },
7295 );
7296 }
7297
7298 pub(crate) unsafe fn znotaatfonterror(
7299 self: &mut Self,
7300 cmd: integer,
7301 c_0: integer,
7302 f_0: integer,
7303 ) -> EngineFlow<()> {
7304 self.znototfonterror(cmd, c_0, f_0)?;
7305 Ok(())
7306 }
7307
7308 pub(crate) unsafe fn znotaatgrfonterror(
7309 self: &mut Self,
7310 cmd: integer,
7311 c_0: integer,
7312 f_0: integer,
7313 ) -> EngineFlow<()> {
7314 self.znototfonterror(cmd, c_0, f_0)?;
7315 Ok(())
7316 }
7317
7318 unsafe fn stack_glyph_into_box(
7323 self: &mut Self,
7324 b: halfword,
7325 f_0: internalfontnumber,
7326 g_0: integer,
7327 ) -> EngineFlow<()> {
7328 let mem: *mut memoryword = self.state.zmem.as_mut_ptr();
7329 const NULL: halfword = -(268435455 as i64) as halfword;
7330 let p = (&mut *(self as *mut PortableTexEngine<'_>)).zgetnode(5)?;
7331 (*mem.offset(p as isize)).hh.u.B0 = 8;
7332 (*mem.offset(p as isize)).hh.u.B1 = 42;
7333 (*mem.offset((p + 4) as isize)).v.QQQQ.u.B1 = (f_0 as quarterword) as u16;
7334 (*mem.offset((p + 4) as isize)).v.QQQQ.u.B2 = (g_0 as quarterword) as u16;
7335 Self::measure_native_glyph(
7336 self as *mut PortableTexEngine<'resources>,
7337 mem.offset(p as isize) as *mut memoryword as *mut (),
7338 1,
7339 );
7340 Ok(
7341 if (*mem.offset(b as isize)).hh.u.B0 as i32 == 0 {
7342 let mut q = (*mem.offset((b + 5) as isize)).hh.v.RH;
7343 if q == NULL {
7344 (*mem.offset((b + 5) as isize)).hh.v.RH = p;
7345 } else {
7346 while (*mem.offset(q as isize)).hh.v.RH != NULL {
7347 q = (*mem.offset(q as isize)).hh.v.RH;
7348 }
7349 (*mem.offset(q as isize)).hh.v.RH = p;
7350 if (*mem.offset((b + 3) as isize)).u.CINT
7351 < (*mem.offset((p + 3) as isize)).u.CINT
7352 {
7353 (*mem.offset((b + 3) as isize)).u.CINT = (*mem
7354 .offset((p + 3) as isize))
7355 .u
7356 .CINT;
7357 }
7358 if (*mem.offset((b + 2) as isize)).u.CINT
7359 < (*mem.offset((p + 2) as isize)).u.CINT
7360 {
7361 (*mem.offset((b + 2) as isize)).u.CINT = (*mem
7362 .offset((p + 2) as isize))
7363 .u
7364 .CINT;
7365 }
7366 }
7367 } else {
7368 (*mem.offset(p as isize)).hh.v.RH = (*mem.offset((b + 5) as isize))
7369 .hh
7370 .v
7371 .RH;
7372 (*mem.offset((b + 5) as isize)).hh.v.RH = p;
7373 (*mem.offset((b + 3) as isize)).u.CINT = (*mem.offset((p + 3) as isize))
7374 .u
7375 .CINT;
7376 if (*mem.offset((b + 1) as isize)).u.CINT
7377 < (*mem.offset((p + 1) as isize)).u.CINT
7378 {
7379 (*mem.offset((b + 1) as isize)).u.CINT = (*mem
7380 .offset((p + 1) as isize))
7381 .u
7382 .CINT;
7383 }
7384 },
7385 )
7386 }
7387
7388 unsafe fn stack_glue_into_box(
7391 self: &mut Self,
7392 b: halfword,
7393 min: scaled,
7394 max: scaled,
7395 ) -> EngineFlow<()> {
7396 let mem: *mut memoryword = self.state.zmem.as_mut_ptr();
7397 const NULL: halfword = -(268435455 as i64) as halfword;
7398 const ZERO_GLUE: halfword = 0;
7399 let q = (&mut *(self as *mut PortableTexEngine<'_>)).znewspec(ZERO_GLUE)?;
7400 (*mem.offset((q + 1) as isize)).u.CINT = min;
7401 (*mem.offset((q + 2) as isize)).u.CINT = max - min;
7402 let p = (&mut *(self as *mut PortableTexEngine<'_>)).znewglue(q)?;
7403 Ok(
7404 if (*mem.offset(b as isize)).hh.u.B0 as i32 == 0 {
7405 let mut r = (*mem.offset((b + 5) as isize)).hh.v.RH;
7406 if r == NULL {
7407 (*mem.offset((b + 5) as isize)).hh.v.RH = p;
7408 } else {
7409 while (*mem.offset(r as isize)).hh.v.RH != NULL {
7410 r = (*mem.offset(r as isize)).hh.v.RH;
7411 }
7412 (*mem.offset(r as isize)).hh.v.RH = p;
7413 }
7414 } else {
7415 (*mem.offset(p as isize)).hh.v.RH = (*mem.offset((b + 5) as isize))
7416 .hh
7417 .v
7418 .RH;
7419 (*mem.offset((b + 5) as isize)).hh.v.RH = p;
7420 (*mem.offset((b + 3) as isize)).u.CINT = (*mem.offset((p + 3) as isize))
7421 .u
7422 .CINT;
7423 (*mem.offset((b + 1) as isize)).u.CINT = (*mem.offset((p + 1) as isize))
7424 .u
7425 .CINT;
7426 },
7427 )
7428 }
7429
7430 pub(crate) unsafe fn zbuildopentypeassembly(
7435 self: &mut Self,
7436 f_0: internalfontnumber,
7437 assembly: voidpointer,
7438 s: scaled,
7439 horiz_flag: integer,
7440 ) -> EngineFlow<halfword> {
7441 let mem: *mut memoryword = self.state.zmem.as_mut_ptr();
7442 let horiz = horiz_flag != 0;
7443 let b = (&mut *(self as *mut PortableTexEngine<'_>)).newnullbox()?;
7444 (*mem.offset(b as isize)).hh.u.B0 = if horiz { 0 } else { 1 };
7445 let parts: &[PortableMathAssemblyPart] = if assembly.is_null() {
7446 &[]
7447 } else {
7448 &(*(assembly as *const GlyphAssembly)).parts
7449 };
7450 let part_count = parts.len();
7451 let min_o = Self::ot_min_connector_overlap(
7452 self as *mut PortableTexEngine<'resources>,
7453 f_0 as i32,
7454 );
7455 let mut n: integer = -1;
7456 let mut no_extenders = true;
7457 loop {
7458 n += 1;
7459 let mut s_max: scaled = 0;
7460 let mut prev_o: scaled = 0;
7461 for part in parts.iter() {
7462 if part.extender {
7463 no_extenders = false;
7464 for _ in 0..n {
7465 let mut o = part.start_connector;
7466 if min_o < o {
7467 o = min_o;
7468 }
7469 if prev_o < o {
7470 o = prev_o;
7471 }
7472 s_max = s_max - o + part.full_advance;
7473 prev_o = part.end_connector;
7474 }
7475 } else {
7476 let mut o = part.start_connector;
7477 if min_o < o {
7478 o = min_o;
7479 }
7480 if prev_o < o {
7481 o = prev_o;
7482 }
7483 s_max = s_max - o + part.full_advance;
7484 prev_o = part.end_connector;
7485 }
7486 }
7487 if s_max >= s || no_extenders {
7488 break;
7489 }
7490 }
7491 let mut prev_o: scaled = 0;
7492 for i in 0..part_count {
7493 let part = parts[i];
7494 let reps = if part.extender { n } else { 1 };
7495 for _ in 0..reps {
7496 let mut o = part.start_connector;
7497 if prev_o < o {
7498 o = prev_o;
7499 }
7500 let oo = o;
7501 if min_o < o {
7502 o = min_o;
7503 }
7504 if oo > 0 {
7505 (&mut *(self as *mut PortableTexEngine<'_>))
7506 .stack_glue_into_box(b, -oo, -o)?;
7507 }
7508 let g = part.glyph;
7509 (&mut *(self as *mut PortableTexEngine<'_>))
7510 .stack_glyph_into_box(b, f_0, g)?;
7511 prev_o = part.end_connector;
7512 }
7513 }
7514 const NULL: halfword = -(268435455 as i64) as halfword;
7515 let mut p = (*mem.offset((b + 5) as isize)).hh.v.RH;
7516 let mut nat: scaled = 0;
7517 let mut str_: scaled = 0;
7518 while p != NULL {
7519 let ty = (*mem.offset(p as isize)).hh.u.B0 as i32;
7520 if ty == 8 {
7521 if horiz {
7522 nat += (*mem.offset((p + 1) as isize)).u.CINT;
7523 } else {
7524 nat
7525 += (*mem.offset((p + 3) as isize)).u.CINT
7526 + (*mem.offset((p + 2) as isize)).u.CINT;
7527 }
7528 } else if ty == 10 {
7529 let spec = (*mem.offset((p + 1) as isize)).hh.v.LH;
7530 nat += (*mem.offset((spec + 1) as isize)).u.CINT;
7531 str_ += (*mem.offset((spec + 2) as isize)).u.CINT;
7532 }
7533 p = (*mem.offset(p as isize)).hh.v.RH;
7534 }
7535 if s > nat && str_ > 0 {
7536 let mut o = s - nat;
7537 if o > str_ {
7538 o = str_;
7539 }
7540 (*mem.offset((b + 5) as isize)).hh.u.B1 = 0;
7541 (*mem.offset((b + 5) as isize)).hh.u.B0 = 1;
7542 (*mem.offset((b + 6) as isize)).gr = o as f64 / str_ as f64;
7543 let stretched = nat
7544 + (str_ as f64 * (*mem.offset((b + 6) as isize)).gr).round() as scaled;
7545 if horiz {
7546 (*mem.offset((b + 1) as isize)).u.CINT = stretched;
7547 } else {
7548 (*mem.offset((b + 3) as isize)).u.CINT = stretched;
7549 }
7550 } else if horiz {
7551 (*mem.offset((b + 1) as isize)).u.CINT = nat;
7552 } else {
7553 (*mem.offset((b + 3) as isize)).u.CINT = nat;
7554 }
7555 Ok(b)
7556 }
7557
7558}
7559
7560pub(crate) unsafe fn fputs(_text: const_string, _file: NativeFileHandle) -> i32 {
7561 0
7562}
7563
7564pub(crate) unsafe fn free(_ptr: voidpointer) {}
7565
7566pub(crate) unsafe fn xrealloc(old_address: address, _new_size: size_t) -> address {
7567 old_address
7568}
7569
7570pub(crate) unsafe fn getcreationdate() {}
7571
7572pub(crate) unsafe fn getfilemoddate(_s: integer) {}
7573
7574pub(crate) unsafe fn getfilesize(_s: integer) {}
7575
7576pub(crate) unsafe fn getfiledump(_s: integer, _offset: i32, _length: i32) {}
7577
7578pub(crate) unsafe fn getmd5sum(_s: integer, _file: i32) {}
7579
7580pub(crate) unsafe fn u_close_file_or_pipe(file: *mut unicodefile) {
7581 if !file.is_null() {
7582 PortableTexEngine::boundary_close_file(*file);
7583 *file = core::ptr::null_mut();
7584 }
7585}
7586
7587pub(crate) unsafe fn setinputfileencoding(
7588 file: unicodefile,
7589 mode: integer,
7590 _encoding_data: integer,
7591) {
7592 if file.is_null() {
7596 return;
7597 }
7598 let handle = &mut *file;
7599 handle.encoding = match mode {
7600 1 => InputEncoding::Utf8,
7601 2 => InputEncoding::Utf16Be,
7602 3 => InputEncoding::Utf16Le,
7603 4 => InputEncoding::Bytes,
7604 0 => InputEncoding::Utf8, _ => InputEncoding::Bytes,
7606 };
7607}
7608
7609pub(crate) unsafe fn usingGraphite(_engine: FontHandle) -> boolean {
7610 false_0
7611}
7612
7613pub(crate) unsafe fn aatprintfontname(
7614 _what: i32,
7615 _attrs: CFDictionaryRef,
7616 _param1: i32,
7617 _param2: i32,
7618) {
7619}
7620
7621pub(crate) unsafe fn grprintfontname(
7622 _what: integer,
7623 _engine: voidpointer,
7624 _param1: integer,
7625 _param2: integer,
7626) {
7627}
7628
7629pub(crate) unsafe fn printglyphname(_font: integer, _gid: integer) {}
7630
7631pub(crate) unsafe fn getnativecharheightdepth(
7632 _font: integer,
7633 _ch: integer,
7634 height: *mut integer,
7635 depth: *mut integer,
7636) {
7637 if !height.is_null() {
7638 *height = 0;
7639 }
7640 if !depth.is_null() {
7641 *depth = 0;
7642 }
7643}
7644
7645pub(crate) unsafe fn getnativecharsidebearings(
7646 _font: integer,
7647 _ch: integer,
7648 lsb: *mut integer,
7649 rsb: *mut integer,
7650) {
7651 if !lsb.is_null() {
7652 *lsb = 0;
7653 }
7654 if !rsb.is_null() {
7655 *rsb = 0;
7656 }
7657}
7658
7659pub(crate) unsafe fn getnativecharwd(_font: integer, _ch: integer) -> integer {
7660 0
7661}
7662
7663pub(crate) unsafe fn getnativecharht(_font: integer, _ch: integer) -> integer {
7664 0
7665}
7666
7667pub(crate) unsafe fn getnativechardp(_font: integer, _ch: integer) -> integer {
7668 0
7669}
7670
7671pub(crate) unsafe fn getnativecharic(_font: integer, _ch: integer) -> integer {
7672 0
7673}
7674
7675pub(crate) unsafe fn getglyphbounds(_font: integer, _edge: integer, _gid: integer) -> integer {
7676 0
7677}
7678
7679pub(crate) unsafe fn getfontcharrange(_font: integer, _first: i32) -> integer {
7680 0
7681}
7682
7683pub(crate) unsafe fn get_native_italic_correction(_node: voidpointer) -> Fixed {
7684 0
7685}
7686
7687pub(crate) unsafe fn get_native_glyph_italic_correction(_node: voidpointer) -> Fixed {
7688 0
7689}
7690
7691pub(crate) unsafe fn applymapping(
7692 _mapping: voidpointer,
7693 _text: *mut uint16_t,
7694 text_len: i32,
7695) -> i32 {
7696 text_len
7697}
7698
7699pub(crate) unsafe fn checkfortfmfontmapping() {}
7700
7701pub(crate) unsafe fn loadtfmfontmapping() -> voidpointer {
7702 nullptr
7703}
7704
7705pub(crate) unsafe fn applytfmfontmapping(_mapping: voidpointer, c_0: i32) -> i32 {
7706 c_0
7707}
7708
7709pub(crate) unsafe fn set_cp_code(
7710 _font_num: i32,
7711 _code: u32,
7712 _side: i32,
7713 _value: i32,
7714) -> i32 {
7715 0
7716}
7717
7718pub(crate) unsafe fn countpdffilepages() -> i32 {
7719 0
7720}
7721
7722pub(crate) unsafe fn aatfontget(_what: i32, _attrs: CFDictionaryRef) -> i32 {
7723 0
7724}
7725
7726pub(crate) unsafe fn aatfontget1(_what: i32, _attrs: CFDictionaryRef, _param: i32) -> i32 {
7727 0
7728}
7729
7730pub(crate) unsafe fn aatfontget2(
7731 _what: i32,
7732 _attrs: CFDictionaryRef,
7733 _param1: i32,
7734 _param2: i32,
7735) -> i32 {
7736 0
7737}
7738
7739pub(crate) unsafe fn aatfontgetnamed(_what: i32, _attrs: CFDictionaryRef) -> i32 {
7740 0
7741}
7742
7743pub(crate) unsafe fn aatfontgetnamed1(
7744 _what: i32,
7745 _attrs: CFDictionaryRef,
7746 _param: i32,
7747) -> i32 {
7748 0
7749}
7750
7751pub(crate) unsafe fn grfontgetnamed(_what: integer, _engine: voidpointer) -> integer {
7752 0
7753}
7754
7755pub(crate) unsafe fn grfontgetnamed1(
7756 _what: integer,
7757 _engine: voidpointer,
7758 _param: integer,
7759) -> integer {
7760 0
7761}
7762
7763pub(crate) unsafe fn otfontget(_what: integer, _engine: voidpointer) -> integer {
7764 0
7765}
7766
7767pub(crate) unsafe fn otfontget1(
7768 _what: integer,
7769 _engine: voidpointer,
7770 _param: integer,
7771) -> integer {
7772 0
7773}
7774
7775pub(crate) unsafe fn otfontget2(
7776 _what: integer,
7777 _engine: voidpointer,
7778 _param1: integer,
7779 _param2: integer,
7780) -> integer {
7781 0
7782}
7783
7784pub(crate) unsafe fn otfontget3(
7785 _what: integer,
7786 _engine: voidpointer,
7787 _param1: integer,
7788 _param2: integer,
7789 _param3: integer,
7790) -> integer {
7791 0
7792}
7793
7794pub(crate) unsafe fn free_ot_assembly(assembly: *mut GlyphAssembly) {
7802 if !assembly.is_null() {
7803 drop(Box::from_raw(assembly));
7804 }
7805}
7806
7807#[cfg(test)]
7808mod tests {
7809 use super::*;
7810
7811 fn text_handle(bytes: Vec<u8>, encoding: InputEncoding) -> PortableFileHandle {
7813 let mut handle = PortableFileHandle::new(
7814 "test.tex".to_string(),
7815 ResourceKind::TexInput,
7816 None,
7817 resource_format_tex_input,
7818 bytes,
7819 );
7820 handle.encoding = encoding;
7821 handle
7822 }
7823
7824 fn decode_all(handle: &mut PortableFileHandle) -> Vec<u32> {
7826 let mut out = Vec::new();
7827 while let Some(scalar) = handle.next_input_scalar() {
7828 out.push(scalar);
7829 }
7830 out
7831 }
7832
7833 #[test]
7834 fn utf8_decoder_reads_multibyte_scalars() {
7835 let mut h = text_handle(vec![0xCE, 0xB1, 0xCE, 0xB2, 0xCE, 0xB3], InputEncoding::Utf8);
7837 assert_eq!(decode_all(&mut h), vec![0x3B1, 0x3B2, 0x3B3]);
7838 let mut h = text_handle(
7841 vec![b'A', 0xE2, 0x82, 0xAC, 0xF0, 0x9F, 0x98, 0x80],
7842 InputEncoding::Utf8,
7843 );
7844 assert_eq!(decode_all(&mut h), vec![0x41, 0x20AC, 0x1F600]);
7845 }
7846
7847 #[test]
7848 fn utf8_decoder_replaces_bad_sequences() {
7849 let mut h = text_handle(vec![0xCE, b'A'], InputEncoding::Utf8);
7852 assert_eq!(decode_all(&mut h), vec![0xFFFD, 0x41]);
7853 let mut h = text_handle(vec![0x80], InputEncoding::Utf8);
7857 assert_eq!(decode_all(&mut h), vec![0x80]);
7858 }
7859
7860 #[test]
7861 fn utf16_decoders_read_units_and_surrogates() {
7862 let mut h = text_handle(
7864 vec![0xB1, 0x03, 0xB2, 0x03, 0xB3, 0x03],
7865 InputEncoding::Utf16Le,
7866 );
7867 assert_eq!(decode_all(&mut h), vec![0x3B1, 0x3B2, 0x3B3]);
7868 let mut h = text_handle(
7870 vec![0x03, 0xB1, 0x03, 0xB2, 0x03, 0xB3],
7871 InputEncoding::Utf16Be,
7872 );
7873 assert_eq!(decode_all(&mut h), vec![0x3B1, 0x3B2, 0x3B3]);
7874 let mut h = text_handle(vec![0x3D, 0xD8, 0x00, 0xDE], InputEncoding::Utf16Le);
7876 assert_eq!(decode_all(&mut h), vec![0x1F600]);
7877 let mut h = text_handle(vec![0x3D, 0xD8, 0x41, 0x00], InputEncoding::Utf16Le);
7880 assert_eq!(decode_all(&mut h), vec![0xFFFD, 0x41]);
7881 let mut h = text_handle(vec![0x00, 0xDC], InputEncoding::Utf16Le);
7883 assert_eq!(decode_all(&mut h), vec![0xFFFD]);
7884 }
7885
7886 #[test]
7887 fn bytes_mode_reads_each_byte_raw() {
7888 let mut h = text_handle(vec![0xCE, 0xB1, 0x41], InputEncoding::Bytes);
7890 assert_eq!(decode_all(&mut h), vec![0xCE, 0xB1, 0x41]);
7891 }
7892
7893 #[test]
7894 fn bom_sniff_selects_encoding_and_consumes_bom() {
7895 let mut h = text_handle(vec![0xEF, 0xBB, 0xBF, b'A'], InputEncoding::Bytes);
7897 h.resolve_text_encoding_auto();
7898 assert_eq!(h.encoding, InputEncoding::Utf8);
7899 assert_eq!(h.cursor, 3);
7900 assert_eq!(decode_all(&mut h), vec![0x41]);
7901 let mut h = text_handle(vec![0xFE, 0xFF, 0x03, 0xB1], InputEncoding::Bytes);
7903 h.resolve_text_encoding_auto();
7904 assert_eq!(h.encoding, InputEncoding::Utf16Be);
7905 assert_eq!(h.cursor, 2);
7906 assert_eq!(decode_all(&mut h), vec![0x3B1]);
7907 let mut h = text_handle(vec![0xFF, 0xFE, 0xB1, 0x03], InputEncoding::Bytes);
7909 h.resolve_text_encoding_auto();
7910 assert_eq!(h.encoding, InputEncoding::Utf16Le);
7911 assert_eq!(h.cursor, 2);
7912 assert_eq!(decode_all(&mut h), vec![0x3B1]);
7913 let mut h = text_handle(vec![b'h', b'i'], InputEncoding::Bytes);
7915 h.resolve_text_encoding_auto();
7916 assert_eq!(h.encoding, InputEncoding::Utf8);
7917 assert_eq!(h.cursor, 0);
7918 let mut h = text_handle(vec![0x00, 0x41], InputEncoding::Bytes);
7920 h.resolve_text_encoding_auto();
7921 assert_eq!(h.encoding, InputEncoding::Utf16Be);
7922 assert_eq!(h.cursor, 0);
7923 assert_eq!(decode_all(&mut h), vec![0x41]);
7924 }
7925
7926 #[test]
7927 fn input_line_decodes_into_buffer_per_profile() {
7928 fn buffer_after_input_line(profile: EngineProfile, bytes: Vec<u8>) -> Vec<u32> {
7934 let image = PortableFormatImage::empty();
7935 let mut engine = PortableTexEngine::from_format(profile, &image, EmptyResourceProvider);
7936 engine.initialize_format_state();
7937 let mut handle = PortableFileHandle::new(
7940 "input.tex".to_string(),
7941 ResourceKind::TexInput,
7942 None,
7943 resource_format_tex_input,
7944 bytes,
7945 );
7946 PortableTexEngine::resolve_input_encoding(&engine, &mut handle);
7947 let raw = Box::into_raw(Box::new(handle));
7948 engine.state.first = 0;
7950 let ok = unsafe {
7951 PortableTexEngine::boundary_input_line(
7952 &mut engine as *mut PortableTexEngine<'_>,
7953 raw as NativeFileHandle,
7954 )
7955 };
7956 assert_ne!(ok, 0, "boundary_input_line should succeed");
7957 let first = engine.state.first.max(0) as usize;
7958 let last = engine.state.last.max(0) as usize;
7959 let out = (first..last)
7960 .map(|i| unsafe { *engine.state.buffer.offset(i as isize) as u32 })
7961 .collect();
7962 unsafe { drop(Box::from_raw(raw)) };
7963 out
7964 }
7965 let utf8 = vec![0xCE, 0xB1, 0xCE, 0xB2, 0xCE, 0xB3];
7967 assert_eq!(
7968 buffer_after_input_line(EngineProfile::xetex(), utf8.clone()),
7969 vec![0x3B1, 0x3B2, 0x3B3],
7970 "xetex must UTF-8 decode the input line"
7971 );
7972 assert_eq!(
7973 buffer_after_input_line(EngineProfile::tex(), utf8),
7974 vec![0xCE, 0xB1, 0xCE, 0xB2, 0xCE, 0xB3],
7975 "non-xetex must read raw bytes"
7976 );
7977 let utf16le_bom = vec![0xFF, 0xFE, 0xB1, 0x03, 0xB2, 0x03, 0xB3, 0x03];
7979 assert_eq!(
7980 buffer_after_input_line(EngineProfile::xetex(), utf16le_bom),
7981 vec![0x3B1, 0x3B2, 0x3B3],
7982 "xetex must UTF-16LE decode a BOM'd input line"
7983 );
7984 let utf16be_bom = vec![0xFE, 0xFF, 0x03, 0xB1, 0x03, 0xB2, 0x03, 0xB3];
7986 assert_eq!(
7987 buffer_after_input_line(EngineProfile::xetex(), utf16be_bom),
7988 vec![0x3B1, 0x3B2, 0x3B3],
7989 "xetex must UTF-16BE decode a BOM'd input line"
7990 );
7991 }
7992
7993 #[test]
7994 fn engine_abort_is_captured_at_runtime_boundary() {
7995 let image = PortableFormatImage::empty();
7996 let mut engine =
7997 PortableTexEngine::from_format(EngineProfile::tex(), &image, EmptyResourceProvider);
7998
7999 let completed = engine.catch_engine_abort(|engine| unsafe {
8000 PortableTexEngine::abort_engine(engine as *mut PortableTexEngine<'_>, 7)?;
8001 Ok(())
8002 });
8003
8004 assert!(!completed);
8005 assert_eq!(engine.last_abort_status(), Some(7));
8006 }
8007
8008 #[test]
8009 fn successful_engine_abort_completes_runtime_boundary() {
8010 let image = PortableFormatImage::empty();
8011 let mut engine =
8012 PortableTexEngine::from_format(EngineProfile::tex(), &image, EmptyResourceProvider);
8013
8014 let completed = engine.catch_engine_abort(|engine| unsafe {
8015 PortableTexEngine::abort_engine(engine as *mut PortableTexEngine<'_>, 0)?;
8016 Ok(())
8017 });
8018
8019 assert!(completed);
8020 assert_eq!(engine.last_abort_status(), None);
8021 }
8022}