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
583#[derive(Clone, Copy, Debug, PartialEq, Eq)]
585pub enum PortableHostBoxStyle {
586 Text,
587 Script,
588 ScriptScript,
589}
590
591#[derive(Clone, Copy, Debug, PartialEq, Eq)]
592pub struct PortableHostBoxRequest {
593 pub token: integer,
594 pub style: PortableHostBoxStyle,
595 pub font_size: scaled,
596}
597
598#[derive(Clone, Copy, Debug, PartialEq, Eq)]
600pub struct PortableHostBoxGlyph {
601 pub glyph: u16,
602 pub x: scaled,
603 pub y: scaled,
604 pub advance: scaled,
605}
606
607#[derive(Clone, Debug, PartialEq)]
608pub struct PortableHostBoxRun {
609 pub font_name: String,
610 pub font_size: scaled,
611 pub glyphs: Vec<PortableHostBoxGlyph>,
612}
613
614#[derive(Clone, Copy, Debug, PartialEq, Eq)]
616pub struct PortableHostBoxRule {
617 pub x: scaled,
618 pub y: scaled,
619 pub width: scaled,
620 pub height: scaled,
621}
622
623#[derive(Clone, Debug, PartialEq)]
624pub struct PortableHostBox {
625 pub width: scaled,
626 pub height: scaled,
627 pub depth: scaled,
628 pub runs: Vec<PortableHostBoxRun>,
629 pub rules: Vec<PortableHostBoxRule>,
630}
631
632pub(crate) const HOST_BOX_EXTENSION_CODE: i32 = 91;
634pub(crate) const HOST_BOX_PENDING_SUBTYPE: i16 = 91;
636pub(crate) const HOST_BOX_RESOLVED_SUBTYPE: i16 = 92;
637pub(crate) const EQTB_CUR_FONT_LOC: i64 = 1206823;
639pub(crate) const EQTB_MATH_FONT_FAM2_BASE: i64 = 1206826;
641
642pub trait PortablePlatform {
643 fn clock(&mut self) -> PortableClock {
644 PortableClock::default()
645 }
646
647 fn linebreak_start(&mut self, _request: PortableLinebreakRequest<'_>) {}
648
649 fn linebreak_next(&mut self) -> Option<integer> {
650 None
651 }
652
653 fn host_box(&mut self, _request: PortableHostBoxRequest) -> Option<PortableHostBox> {
654 None
655 }
656}
657
658#[derive(Default)]
659pub struct EmptyPlatform;
660
661impl PortablePlatform for EmptyPlatform {}
662
663impl PortableFileHandle {
664 fn new(
665 name: String,
666 kind: ResourceKind,
667 package: Option<String>,
668 format: integer,
669 bytes: Vec<u8>,
670 ) -> Self {
671 Self {
672 name,
673 kind,
674 package,
675 format,
676 bytes,
677 cursor: 0,
678 eof_after_failed_read: false,
679 encoding: InputEncoding::Bytes,
680 saved_char: None,
681 }
682 }
683
684 fn read_byte(&mut self) -> Option<u8> {
685 let Some(byte) = self.bytes.get(self.cursor).copied() else {
686 self.eof_after_failed_read = true;
687 return None;
688 };
689 self.cursor += 1;
690 Some(byte)
691 }
692
693 fn has_remaining(&self) -> bool {
694 self.cursor < self.bytes.len()
695 }
696
697 fn is_eof(&self) -> bool {
698 self.eof_after_failed_read
699 }
700
701 fn resolve_text_encoding_auto(&mut self) {
714 let b1 = self.bytes.first().copied();
715 let b2 = self.bytes.get(1).copied();
716 match (b1, b2) {
717 (Some(0xFE), Some(0xFF)) => {
718 self.encoding = InputEncoding::Utf16Be;
719 self.cursor = 2;
720 }
721 (Some(0xFF), Some(0xFE)) => {
722 self.encoding = InputEncoding::Utf16Le;
723 self.cursor = 2;
724 }
725 (Some(0x00), Some(b2)) if b2 != 0 => {
726 self.encoding = InputEncoding::Utf16Be;
727 }
729 (Some(b1), Some(0x00)) if b1 != 0 => {
730 self.encoding = InputEncoding::Utf16Le;
731 }
732 (Some(0xEF), Some(0xBB)) if self.bytes.get(2).copied() == Some(0xBF) => {
733 self.encoding = InputEncoding::Utf8;
734 self.cursor = 3;
735 }
736 _ => {
737 self.encoding = InputEncoding::Utf8;
738 }
739 }
740 }
741
742 fn next_input_scalar(&mut self) -> Option<u32> {
747 if let Some(saved) = self.saved_char.take() {
749 return Some(saved);
750 }
751 match self.encoding {
752 InputEncoding::Bytes => self.read_byte().map(u32::from),
753 InputEncoding::Utf8 => self.next_utf8_scalar(),
754 InputEncoding::Utf16Be => self.next_utf16_scalar(true),
755 InputEncoding::Utf16Le => self.next_utf16_scalar(false),
756 }
757 }
758
759 fn next_utf8_scalar(&mut self) -> Option<u32> {
764 const OFFSETS: [u32; 6] = [
766 0x0000_0000,
767 0x0000_3080,
768 0x000E_2080,
769 0x03C8_2080,
770 0xFA08_2080,
771 0x8208_2080,
772 ];
773 let lead = self.read_byte()?;
774 let extra: usize = match lead {
776 0x00..=0xBF => 0,
777 0xC0..=0xDF => 1,
778 0xE0..=0xEF => 2,
779 0xF0..=0xF7 => 3,
780 0xF8..=0xFB => 4,
781 0xFC..=0xFF => 5,
782 };
783 let mut rval: i64 = i64::from(lead);
785 if extra >= 4 {
788 return Some(0xFFFD);
791 }
792 for _ in 0..extra {
793 match self.read_byte() {
794 Some(c) if (0x80..0xC0).contains(&c) => {
795 rval = (rval << 6) + i64::from(c);
796 }
797 Some(c) => {
798 self.cursor -= 1;
800 let _ = c;
801 return Some(0xFFFD);
802 }
803 None => {
804 return Some(0xFFFD);
806 }
807 }
808 }
809 rval -= i64::from(OFFSETS[extra]);
810 if rval < 0 || rval > 0x10_FFFF {
811 return Some(0xFFFD);
812 }
813 Some(rval as u32)
814 }
815
816 fn next_utf16_scalar(&mut self, big_endian: bool) -> Option<u32> {
821 let unit = self.read_utf16_unit(big_endian)?;
822 if (0xD800..=0xDBFF).contains(&unit) {
823 match self.read_utf16_unit(big_endian) {
825 Some(lo) if (0xDC00..=0xDFFF).contains(&lo) => {
826 Some(0x10000 + (unit - 0xD800) * 0x400 + (lo - 0xDC00))
827 }
828 Some(lo) => {
829 self.saved_char = Some(lo);
830 Some(0xFFFD)
831 }
832 None => Some(0xFFFD),
833 }
834 } else if (0xDC00..=0xDFFF).contains(&unit) {
835 Some(0xFFFD)
837 } else {
838 Some(unit)
839 }
840 }
841
842 fn read_utf16_unit(&mut self, big_endian: bool) -> Option<u32> {
846 let first = self.read_byte()?;
847 let second = self.read_byte().unwrap_or(0);
848 let unit = if big_endian {
849 (u32::from(first) << 8) + u32::from(second)
850 } else {
851 u32::from(first) + (u32::from(second) << 8)
852 };
853 Some(unit)
854 }
855}
856
857pub(crate) trait StatePtrCompat<T> {
858 fn as_mut_ptr(self) -> *mut T;
859 fn is_empty(self) -> bool;
860}
861
862impl<T> StatePtrCompat<T> for *mut T {
863 fn as_mut_ptr(self) -> *mut T {
864 self
865 }
866
867 fn is_empty(self) -> bool {
868 self.is_null()
869 }
870}
871
872#[derive(Copy, Clone)]
873#[repr(C)]
874pub(crate) union twohalves {
875 pub v: TwoHalvesPair,
876 pub u: TwoHalvesBytes,
877}
878
879impl Default for twohalves {
880 fn default() -> Self {
881 Self {
882 v: TwoHalvesPair::default(),
883 }
884 }
885}
886
887#[derive(Copy, Clone, Default)]
888#[repr(C)]
889pub(crate) struct TwoHalvesBytes {
890 pub B1: i16,
891 pub B0: i16,
892}
893
894#[derive(Copy, Clone, Default)]
895#[repr(C)]
896pub(crate) struct TwoHalvesPair {
897 pub LH: halfword,
898 pub RH: halfword,
899}
900
901#[derive(Copy, Clone)]
902#[repr(C)]
903pub(crate) struct fourquarters {
904 pub u: FourQuarterBytes,
905}
906
907impl Default for fourquarters {
908 fn default() -> Self {
909 Self {
910 u: FourQuarterBytes::default(),
911 }
912 }
913}
914
915#[derive(Copy, Clone, Default)]
926#[repr(C)]
927pub(crate) struct FourQuarterBytes {
928 pub B3: u16,
929 pub B2: u16,
930 pub B1: u16,
931 pub B0: u16,
932}
933
934pub(crate) type C2RustUnnamed_2 = FourQuarterBytes;
935
936#[derive(Copy, Clone)]
937#[repr(C)]
938pub(crate) union memoryword {
939 pub gr: glueratio,
940 pub hh: twohalves,
941 pub u: MemoryInt,
942 pub v: MemoryQuarters,
943 pub ptr: voidpointer,
944}
945
946impl Default for memoryword {
947 fn default() -> Self {
948 Self {
949 u: MemoryInt::default(),
950 }
951 }
952}
953
954#[derive(Copy, Clone, Default)]
961#[repr(C)]
962pub(crate) struct MemoryQuarters {
963 pub QQQQ: fourquarters,
964}
965
966#[derive(Copy, Clone, Default)]
967#[repr(C)]
968pub(crate) struct MemoryInt {
969 pub CINT: integer,
970}
971
972#[derive(Copy, Clone)]
973#[repr(C)]
974pub(crate) union fmemoryword {
975 pub u: FontMemoryInt,
976 pub v: FontMemoryQuarters,
977}
978
979impl Default for fmemoryword {
980 fn default() -> Self {
981 Self {
982 u: FontMemoryInt::default(),
983 }
984 }
985}
986
987#[derive(Copy, Clone, Default)]
988#[repr(C)]
989pub(crate) struct FontMemoryQuarters {
990 pub QQQQ: fourquarters,
991}
992
993#[derive(Copy, Clone, Default)]
994#[repr(C)]
995pub(crate) struct FontMemoryInt {
996 pub CINT: integer,
997}
998
999#[derive(Copy, Clone, Default)]
1000#[repr(C)]
1001pub(crate) struct liststaterecord {
1002 pub modefield: i16,
1003 pub headfield: halfword,
1004 pub tailfield: halfword,
1005 pub eTeXauxfield: halfword,
1006 pub pgfield: integer,
1007 pub mlfield: integer,
1008 pub auxfield: memoryword,
1009}
1010
1011#[derive(Copy, Clone, Default)]
1012#[repr(C)]
1013pub(crate) struct instaterecord {
1014 pub statefield: quarterword,
1015 pub indexfield: quarterword,
1016 pub startfield: halfword,
1017 pub locfield: halfword,
1018 pub limitfield: halfword,
1019 pub namefield: halfword,
1020 pub spanfield: SrcId,
1026}
1027
1028#[derive(Copy, Clone, Default)]
1029#[repr(C)]
1030pub(crate) struct transform {
1031 pub a: f64,
1032 pub b: f64,
1033 pub c: f64,
1034 pub d: f64,
1035 pub x: f64,
1036 pub y: f64,
1037}
1038
1039#[derive(Copy, Clone, Default)]
1040#[repr(C)]
1041pub(crate) struct realpoint {
1042 pub x: f32,
1043 pub y: f32,
1044}
1045
1046#[derive(Copy, Clone, Default)]
1047#[repr(C)]
1048pub(crate) struct realrect {
1049 pub x: f32,
1050 pub y: f32,
1051 pub wd: f32,
1052 pub ht: f32,
1053}
1054
1055#[derive(Copy, Clone, Default)]
1056#[repr(C)]
1057pub(crate) struct ResourceSearchState {
1058 pub make_tex_discard_errors: boolean,
1059}
1060
1061const CODEPOINT_LO: usize = 1_207_592; const PAGE_BITS: usize = 12;
1080const PAGE_LEN: usize = 1 << PAGE_BITS;
1081fn eqtb_sig_range(i: usize) -> (usize, usize) {
1087 if (7_892_264..=9_006_997).contains(&i) {
1088 (0, 4) } else {
1090 (0, 8)
1091 }
1092}
1093
1094fn hash_sig_range(_i: usize) -> (usize, usize) {
1096 (0, 8)
1097}
1098
1099fn paged_bytes_eq<T>(a: &T, b: &T, off: usize, len: usize) -> bool {
1107 unsafe {
1109 let pa = (a as *const T as *const u8).add(off);
1110 let pb = (b as *const T as *const u8).add(off);
1111 core::slice::from_raw_parts(pa, len) == core::slice::from_raw_parts(pb, len)
1112 }
1113}
1114
1115pub(crate) struct PagedArray<T: Copy + Default> {
1116 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), }
1124
1125impl<T: Copy + Default> PagedArray<T> {
1126 fn new(
1127 base: usize,
1128 end: usize,
1129 default_fn: fn(usize) -> T,
1130 sig_range: fn(usize) -> (usize, usize),
1131 ) -> Self {
1132 let lo = base;
1137 let npages = (end - lo).div_ceil(PAGE_LEN);
1138 PagedArray {
1139 base,
1140 lo,
1141 end,
1142 low: vec![T::default(); lo - base],
1143 pages: (0..npages).map(|_| None).collect(),
1144 default_fn,
1145 sig_range,
1146 }
1147 }
1148
1149 #[inline]
1150 fn ptr(&mut self, abs: usize) -> *mut T {
1151 if abs < self.lo {
1152 return unsafe { self.low.as_mut_ptr().add(abs - self.base) };
1154 }
1155 let rel = abs - self.lo;
1156 let pg = rel >> PAGE_BITS;
1157 let off = rel & (PAGE_LEN - 1);
1158 if self.pages[pg].is_none() {
1159 let page_base = self.lo + pg * PAGE_LEN;
1160 let f = self.default_fn;
1161 let mut page: Vec<T> = Vec::with_capacity(PAGE_LEN);
1162 for j in 0..PAGE_LEN {
1163 page.push(f(page_base + j));
1164 }
1165 self.pages[pg] = Some(page.into_boxed_slice());
1166 }
1167 unsafe {
1169 self.pages[pg]
1170 .as_mut()
1171 .unwrap_unchecked()
1172 .as_mut_ptr()
1173 .add(off)
1174 }
1175 }
1176
1177 fn compact(&mut self) {
1181 let f = self.default_fn;
1182 for pg in 0..self.pages.len() {
1183 let page_base = self.lo + pg * PAGE_LEN;
1184 let is_default = match &self.pages[pg] {
1185 None => continue,
1186 Some(page) => (0..PAGE_LEN).all(|j| {
1187 let (off, len) = (self.sig_range)(page_base + j);
1188 paged_bytes_eq(&page[j], &f(page_base + j), off, len)
1189 }),
1190 };
1191 if is_default {
1192 self.pages[pg] = None;
1193 }
1194 }
1195 }
1196
1197 fn resident_bytes(&self) -> usize {
1198 let elt = core::mem::size_of::<T>();
1199 self.low.capacity() * elt
1200 + self.pages.iter().filter(|p| p.is_some()).count() * PAGE_LEN * elt
1201 + self.pages.capacity() * core::mem::size_of::<Option<Box<[T]>>>()
1202 }
1203
1204 #[inline]
1208 fn set(&mut self, abs: usize, v: T) {
1209 if abs < self.base || abs >= self.end {
1210 return;
1211 }
1212 unsafe {
1214 *self.ptr(abs) = v;
1215 }
1216 }
1217
1218 #[inline]
1222 fn get_copy(&self, abs: usize) -> T {
1223 if abs < self.base || abs >= self.end {
1224 return (self.default_fn)(abs);
1225 }
1226 if abs < self.lo {
1227 return self.low[abs - self.base];
1228 }
1229 let rel = abs - self.lo;
1230 let pg = rel >> PAGE_BITS;
1231 let off = rel & (PAGE_LEN - 1);
1232 match self.pages.get(pg).and_then(|p| p.as_ref()) {
1233 Some(page) => page[off],
1234 None => (self.default_fn)(abs),
1235 }
1236 }
1237}
1238
1239impl<T: Copy + Default> Clone for PagedArray<T> {
1240 fn clone(&self) -> Self {
1241 PagedArray {
1242 base: self.base,
1243 lo: self.lo,
1244 end: self.end,
1245 low: self.low.clone(),
1246 pages: self.pages.clone(),
1247 default_fn: self.default_fn,
1248 sig_range: self.sig_range,
1249 }
1250 }
1251}
1252
1253pub(crate) struct PagedView<T: Copy + Default>(*mut PagedArray<T>);
1261
1262impl<T: Copy + Default> Clone for PagedView<T> {
1263 fn clone(&self) -> Self {
1264 *self
1265 }
1266}
1267impl<T: Copy + Default> Copy for PagedView<T> {}
1268
1269impl<T: Copy + Default> PagedView<T> {
1270 pub(crate) fn new(arr: &mut PagedArray<T>) -> Self {
1271 PagedView(arr as *mut PagedArray<T>)
1272 }
1273 #[allow(dead_code)]
1274 pub(crate) fn null() -> Self {
1275 PagedView(core::ptr::null_mut())
1276 }
1277 #[inline]
1278 pub(crate) fn as_mut_ptr(self) -> Self {
1279 self
1280 }
1281 #[inline]
1282 pub(crate) fn is_null(self) -> bool {
1283 self.0.is_null()
1284 }
1285 #[inline]
1286 pub(crate) fn offset(self, count: isize) -> *mut T {
1287 unsafe { (*self.0).ptr(count as usize) }
1291 }
1292}
1293
1294fn eqtb_codepoint_default(i: usize) -> memoryword {
1297 let mut w: memoryword = unsafe { core::mem::zeroed() };
1302 if (1_207_592..=7_892_263).contains(&i) {
1303 let rh: i32 = if (1_207_592..=2_321_703).contains(&i) {
1305 12 } else if (4_549_928..=5_664_039).contains(&i) {
1307 1000 } else if (5_664_040..=6_778_151).contains(&i) {
1309 (i - 5_664_040) as i32 } else {
1311 0 };
1313 w.hh.u.B0 = 123;
1315 w.hh.u.B1 = 1;
1316 w.hh.v.RH = rh;
1317 } else if (7_892_607..=9_006_718).contains(&i) {
1318 w.u.CINT = -1;
1320 } else if i < CODEPOINT_LO || i > xetex_eqtb_top as usize {
1321 w.hh.u.B0 = 104;
1328 w.hh.v.RH = -(268435455 as i32);
1329 }
1330 w
1333}
1334
1335fn hash_codepoint_default(_i: usize) -> twohalves {
1338 twohalves::default()
1339}
1340
1341pub(crate) struct PortableTexState {
1342 pub mem: Vec<memoryword>,
1343 buffer_storage: Vec<UnicodeScalar>,
1344 nest_storage: Vec<liststaterecord>,
1345 savestack_storage: Vec<memoryword>,
1346 inputstack_storage: Vec<instaterecord>,
1347 inputfile_storage: Vec<unicodefile>,
1348 eofseen_storage: Vec<boolean>,
1349 linestack_storage: Vec<integer>,
1350 grpstack_storage: Vec<savepointer>,
1351 ifstack_storage: Vec<halfword>,
1352 sourcefilenamestack_storage: Vec<strnumber>,
1353 fullsourcefilenamestack_storage: Vec<strnumber>,
1354 paramstack_storage: Vec<halfword>,
1355 hyphword_storage: Vec<strnumber>,
1356 hyphlist_storage: Vec<halfword>,
1357 hyphlink_storage: Vec<hyphpointer>,
1358 hash_paged: PagedArray<twohalves>,
1359 eqtb_paged: PagedArray<memoryword>,
1360 strstart_storage: Vec<poolpointer>,
1361 strpool_storage: Vec<packedUTF16code>,
1362 fontinfo_storage: Vec<fmemoryword>,
1363 bcharlabel_storage: Vec<fontindex>,
1364 charbase_storage: Vec<integer>,
1365 widthbase_storage: Vec<integer>,
1366 heightbase_storage: Vec<integer>,
1367 depthbase_storage: Vec<integer>,
1368 italicbase_storage: Vec<integer>,
1369 ligkernbase_storage: Vec<integer>,
1370 kernbase_storage: Vec<integer>,
1371 extenbase_storage: Vec<integer>,
1372 parambase_storage: Vec<integer>,
1373 fontarea_storage: Vec<strnumber>,
1374 fontname_storage: Vec<strnumber>,
1375 fontbc_storage: Vec<UTF16code>,
1376 fontec_storage: Vec<UTF16code>,
1377 fontbchar_storage: Vec<ninebits>,
1378 fontfalsebchar_storage: Vec<ninebits>,
1379 fontcheck_storage: Vec<fourquarters>,
1380 fontdsize_storage: Vec<scaled>,
1381 fontsize_storage: Vec<scaled>,
1382 fontflags_storage: Vec<i8>,
1383 fontglue_storage: Vec<halfword>,
1384 fontlayoutengine_storage: Vec<voidpointer>,
1385 fontletterspace_storage: Vec<scaled>,
1386 fontmapping_storage: Vec<voidpointer>,
1387 fontparams_storage: Vec<fontindex>,
1388 fontused_storage: Vec<boolean>,
1389 nativetext_storage: Vec<UTF16code>,
1390 hyphenchar_storage: Vec<integer>,
1391 skewchar_storage: Vec<integer>,
1392 triec_storage: Vec<packedUTF16code>,
1393 triehash_storage: Vec<triepointer>,
1394 triel_storage: Vec<triepointer>,
1395 trieo_storage: Vec<trieopcode>,
1396 trier_storage: Vec<triepointer>,
1397 trietaken_storage: Vec<boolean>,
1398 trietrc_storage: Vec<quarterword>,
1399 trietrl_storage: Vec<triepointer>,
1400 trietro_storage: Vec<triepointer>,
1401 source_tracking: bool,
1408 cmd_span: SrcId,
1411 pending_call_span: SrcId,
1414 src_token_start: integer,
1417 src_line_base: u32,
1420 src_line_buf_start: integer,
1424 src_prev_line_len: u32,
1427 src_line_initialized: bool,
1430 src_primary_name: strnumber,
1433 src_call_start: u32,
1435 src_call_name: strnumber,
1437 src_call_state: integer,
1439 src_call_index: integer,
1445 src_call_span: SrcId,
1447 src_call_argspan: SrcId,
1452 src_user_cmd_span: SrcId,
1461 src_anchor_cmd: SrcId,
1471 src_call_user_span: SrcId,
1477 src_tok_span: SrcId,
1483 src_spans: Vec<RawSpan>,
1485 src_dedup: std::collections::HashMap<RawSpan, SrcId>,
1487 node_src: PagedArray<u32>,
1491 src_native_offsets: Vec<SrcId>,
1498 src_stack_cells: Vec<SrcStackCell>,
1502 cur_stack_head: u32,
1505 src_grp_stack: Vec<SrcId>,
1513 src_grp_closing: SrcId,
1517 node_stack: PagedArray<u32>,
1521 pub LRproblems: integer,
1522 pub LRptr: halfword,
1523 pub OKtointerrupt: boolean,
1524 pub terminal_output: NativeFileHandle,
1525 pub activenodesize: smallnumber,
1526 pub activewidth: [scaled; 7],
1527 pub actuallooseness: integer,
1528 pub adjusttail: halfword,
1529 pub aftertoken: halfword,
1530 pub alignptr: halfword,
1531 pub alignstate: integer,
1532 pub areadelimiter: poolpointer,
1533 pub aritherror: boolean,
1534 pub avail: halfword,
1535 pub background: [scaled; 7],
1536 pub baseptr: integer,
1537 pub bchar: halfword,
1538 pub bcharlabel: *mut fontindex,
1539 pub bestbet: halfword,
1540 pub bestheightplusdepth: scaled,
1541 pub bestline: halfword,
1542 pub bestplace: [halfword; 4],
1543 pub bestplglue: [scaled; 4],
1544 pub bestplline: [halfword; 4],
1545 pub bestplshort: [scaled; 4],
1546 pub breadthmax: integer,
1547 pub breakwidth: [scaled; 7],
1548 pub buffer: *mut UnicodeScalar,
1549 pub bufsize: integer,
1550 pub c: quarterword,
1551 pub cancelboundary: boolean,
1552 pub charbase: *mut integer,
1553 pub condptr: halfword,
1554 pub cscount: integer,
1555 pub curactivewidth: [scaled; 7],
1556 pub curalign: halfword,
1557 pub curarea: strnumber,
1558 pub curboundary: integer,
1559 pub curbox: halfword,
1560 pub curc: integer,
1561 pub curchr: halfword,
1562 pub curcmd: eightbits,
1563 pub curcs: halfword,
1564 pub curdir: smallnumber,
1565 pub curext: strnumber,
1566 pub curf: internalfontnumber,
1567 pub curgroup: groupcode,
1568 pub curhead: halfword,
1569 pub curi: fourquarters,
1570 pub curif: smallnumber,
1571 pub curinput: instaterecord,
1572 pub curl: halfword,
1573 pub curlang: eightbits,
1574 pub curlevel: quarterword,
1575 pub curlist: liststaterecord,
1576 pub curloop: halfword,
1577 pub curmark: [halfword; 5],
1578 pub curmlist: halfword,
1579 pub curmu: scaled,
1580 pub curname: strnumber,
1581 pub curorder: glueord,
1582 pub curp: halfword,
1583 pub curprehead: halfword,
1584 pub curpretail: halfword,
1585 pub curptr: halfword,
1586 pub curq: halfword,
1587 pub curr: halfword,
1588 pub curs: integer,
1589 pub cursize: integer,
1590 pub curspan: halfword,
1591 pub curstyle: smallnumber,
1592 pub curtail: halfword,
1593 pub curtok: halfword,
1594 pub curval: integer,
1595 pub curval1: integer,
1596 pub curvallevel: eightbits,
1597 pub deadcycles: integer,
1598 pub defref: halfword,
1599 pub deletionsallowed: boolean,
1600 pub depthbase: *mut integer,
1601 pub depththreshold: integer,
1602 pub dig: [eightbits; 23],
1603 pub discptr: [halfword; 4],
1604 pub discwidth: scaled,
1605 pub doingleaders: boolean,
1606 pub doingspecial: boolean,
1607 pub dolastlinefit: boolean,
1608 pub downptr: halfword,
1609 pub dvibufsize: integer,
1610 pub dvigone: integer,
1611 pub dvilimit: integer,
1612 pub dvioffset: integer,
1613 pub dviptr: integer,
1614 pub dynused: integer,
1615 pub eTeXmode: eightbits,
1616 pub easyline: halfword,
1617 pub editline: integer,
1618 pub editnamelength: integer,
1619 pub editnamestart: poolpointer,
1620 pub eightbitp: i32,
1621 pub emptyfield: twohalves,
1622 pub eofseen: *mut boolean,
1623 pub epochseconds: integer,
1624 pub eqtbtop: halfword,
1625 pub errorcount: schar,
1626 pub errorline: integer,
1627 pub expanddepth: integer,
1628 pub expanddepthcount: integer,
1629 pub extdelimiter: poolpointer,
1630 pub extenbase: *mut integer,
1631 pub f: internalfontnumber,
1632 pub falsebchar: halfword,
1633 pub fewestdemerits: integer,
1634 pub filelineerrorstylep: i32,
1635 pub filenamequotechar: UTF16code,
1636 pub fileoffset: integer,
1637 pub fillwidth: [scaled; 3],
1638 pub finalpass: boolean,
1639 pub first: integer,
1640 pub firstcount: integer,
1641 pub firstindent: scaled,
1642 pub firstp: halfword,
1643 pub firstwidth: scaled,
1644 pub fmemptr: fontindex,
1645 pub fontarea: *mut strnumber,
1646 pub fontbc: *mut UTF16code,
1647 pub fontbchar: *mut ninebits,
1648 pub fontcheck: *mut fourquarters,
1649 pub fontdsize: *mut scaled,
1650 pub fontec: *mut UTF16code,
1651 pub fontfalsebchar: *mut ninebits,
1652 pub fontflags: *mut i8,
1653 pub fontglue: *mut halfword,
1654 pub fontinfo: *mut fmemoryword,
1655 pub fontinshortdisplay: integer,
1656 pub fontlayoutengine: *mut voidpointer,
1657 pub fontletterspace: *mut scaled,
1658 pub fontmapping: *mut voidpointer,
1659 pub fontmax: integer,
1660 pub fontmemsize: integer,
1661 pub fontname: *mut strnumber,
1662 pub fontparams: *mut fontindex,
1663 pub fontptr: internalfontnumber,
1664 pub fontsize: *mut scaled,
1665 pub fontused: *mut boolean,
1666 pub forceeof: boolean,
1667 pub formatident: strnumber,
1668 pub fullsourcefilenamestack: *mut strnumber,
1669 pub g: halfword,
1670 pub globalprevp: halfword,
1671 pub grpstack: *mut savepointer,
1672 pub ha: halfword,
1673 pub halfbuf: integer,
1674 pub halferrorline: integer,
1675 pub haltingonerrorp: boolean,
1676 pub haltonerrorp: i32,
1677 pub hash: PagedView<twohalves>,
1678 pub hashextra: halfword,
1679 pub hashhigh: halfword,
1680 pub hashused: halfword,
1681 pub hb: halfword,
1682 pub hc: [integer; 4099],
1683 pub heightbase: *mut integer,
1684 pub helpline: [strnumber; 6],
1685 pub helpptr: eightbits,
1686 pub hf: internalfontnumber,
1687 pub himemmin: halfword,
1688 pub history: eightbits,
1689 pub hliststack: [halfword; 513],
1690 pub hliststacklevel: i16,
1691 pub hn: smallnumber,
1692 pub hu: [integer; 4097],
1693 pub hyf: [eightbits; 4097],
1694 pub hyfbchar: halfword,
1695 pub hyfchar: integer,
1696 pub hyfdistance: [smallnumber; 35112],
1697 pub hyfnext: [trieopcode; 35112],
1698 pub hyfnum: [smallnumber; 35112],
1699 pub hyphcount: integer,
1700 pub hyphenchar: *mut integer,
1701 pub hyphenpassed: smallnumber,
1702 pub hyphindex: triepointer,
1703 pub hyphlink: *mut hyphpointer,
1704 pub hyphlist: *mut halfword,
1705 pub hyphnext: integer,
1706 pub hyphsize: integer,
1707 pub hyphstart: triepointer,
1708 pub hyphword: *mut strnumber,
1709 pub iflimit: eightbits,
1710 pub ifline: integer,
1711 pub ifstack: *mut halfword,
1712 pub initcurlang: eightbits,
1713 pub initlft: boolean,
1714 pub initlhyf: integer,
1715 pub initlig: boolean,
1716 pub initlist: halfword,
1717 pub initpoolptr: poolpointer,
1718 pub initrhyf: integer,
1719 pub initstrptr: strnumber,
1720 pub iniversion: boolean,
1721 pub inopen: integer,
1722 pub inputfile: *mut unicodefile,
1723 pub inputptr: integer,
1724 pub inputstack: *mut instaterecord,
1725 pub insdisc: boolean,
1726 pub insertpenalties: integer,
1727 pub insertsrcspecialauto: boolean,
1728 pub insertsrcspecialeverymath: boolean,
1729 pub insertsrcspecialeverypar: boolean,
1730 pub insertsrcspecialeveryvbox: boolean,
1731 pub interaction: eightbits,
1732 pub interactionoption: eightbits,
1733 pub interrupt: integer,
1734 pub ishyph: boolean,
1735 pub isincsname: boolean,
1736 pub italicbase: *mut integer,
1737 pub jobname: strnumber,
1738 pub jrandom: eightbits,
1739 pub justbox: halfword,
1740 pub kernbase: *mut integer,
1741 pub resource_search_state: ResourceSearchState,
1742 pub l: eightbits,
1743 pub last: integer,
1744 pub lastbadness: integer,
1745 pub lastbop: integer,
1746 pub lastglue: halfword,
1747 pub lastkern: scaled,
1748 pub lastleftmostchar: halfword,
1749 pub lastlinefill: halfword,
1750 pub lastnodetype: integer,
1751 pub lastpenalty: integer,
1752 pub lastrightmostchar: halfword,
1753 pub lastspecialline: halfword,
1754 pub lfthit: boolean,
1755 pub lhyf: integer,
1756 pub ligaturepresent: boolean,
1757 pub ligkernbase: *mut integer,
1758 pub ligstack: halfword,
1759 pub line: integer,
1760 pub linediff: integer,
1761 pub linestack: *mut integer,
1762 pub loadedfontdesignsize: scaled,
1763 pub loadedfontflags: i8,
1764 pub loadedfontletterspace: scaled,
1765 pub loadedfontmapping: voidpointer,
1766 pub logfile: alphafile,
1767 pub logopened: boolean,
1768 pub lomemmax: halfword,
1769 pub longhelpseen: boolean,
1770 pub longstate: eightbits,
1771 pub magicoffset: integer,
1772 pub magset: integer,
1773 pub mainf: internalfontnumber,
1774 pub mainh: halfword,
1775 pub maini: fourquarters,
1776 pub mainj: fourquarters,
1777 pub maink: fontindex,
1778 pub mainp: halfword,
1779 pub mainpp: halfword,
1780 pub mainppp: halfword,
1781 pub mains: integer,
1782 pub mappedtext: *mut UTF16code,
1783 pub maxbufstack: integer,
1784 pub maxh: scaled,
1785 pub maxhyphchar: integer,
1786 pub maxinopen: integer,
1787 pub maxinstack: integer,
1788 pub maxneststack: integer,
1789 pub maxopused: trieopcode,
1790 pub maxparamstack: integer,
1791 pub maxprintline: integer,
1792 pub maxpush: integer,
1793 pub maxreghelpline: strnumber,
1794 pub maxregnum: halfword,
1795 pub maxsavestack: integer,
1796 pub maxstrings: integer,
1797 pub maxv: scaled,
1798 pub membot: integer,
1799 pub memend: halfword,
1800 pub memmax: integer,
1801 pub memmin: integer,
1802 pub memtop: integer,
1803 pub microseconds: integer,
1804 pub minimaldemerits: [integer; 4],
1805 pub minimumdemerits: integer,
1806 pub mlistpenalties: boolean,
1807 pub mltexenabledp: boolean,
1808 pub mltexp: boolean,
1809 pub mubytecswrite: [halfword; 128],
1810 pub mubytekeep: integer,
1811 pub mubyteprefix: integer,
1812 pub mubyteread: [halfword; 256],
1813 pub mubyteskip: integer,
1814 pub mubytestart: boolean,
1815 pub mubytestoken: halfword,
1816 pub mubytetoken: halfword,
1817 pub nameinprogress: boolean,
1818 pub namelength: integer,
1819 pub nameoffile: *mut UTF8code,
1820 pub nativefonttypeflag: integer,
1821 pub nativelen: integer,
1822 pub nativetext: *mut UTF16code,
1823 pub nativetextsize: integer,
1824 pub nest: *mut liststaterecord,
1825 pub nestptr: integer,
1826 pub nestsize: integer,
1827 pub nonewcontrolsequence: boolean,
1828 pub noshrinkerroryet: boolean,
1829 pub nullcharacter: fourquarters,
1830 pub nulldelimiter: fourquarters,
1831 pub oldselectorignorederr: eightbits,
1832 pub oldsetting: eightbits,
1833 pub openparens: integer,
1834 pub opstart: [integer; 256],
1835 pub outputactive: boolean,
1836 pub outputcanend: boolean,
1837 pub packbeginline: integer,
1838 pub pagecontents: eightbits,
1839 pub pagemaxdepth: scaled,
1840 pub pagesofar: [scaled; 8],
1841 pub pagetail: halfword,
1842 pub parambase: *mut integer,
1843 pub paramptr: integer,
1844 pub paramsize: integer,
1845 pub paramstack: *mut halfword,
1846 pub parloc: halfword,
1847 pub partoken: halfword,
1848 pub passive: halfword,
1849 pub passnumber: halfword,
1850 pub pdflastxpos: integer,
1851 pub pdflastypos: integer,
1852 pub poolptr: poolpointer,
1853 pub poolsize: integer,
1854 pub preadjusttail: halfword,
1855 pub prevclass: integer,
1856 pub prim: [twohalves; 2101],
1857 pub primused: halfword,
1858 pub printednode: halfword,
1859 pub pseudofiles: halfword,
1860 pub pstack: [halfword; 9],
1861 pub quotedfilename: boolean,
1862 pub radix: smallnumber,
1863 pub randoms: [integer; 55],
1864 pub randomseed: scaled,
1865 pub readfile: [unicodefile; 16],
1866 pub readopen: [eightbits; 17],
1867 pub readyalready: integer,
1868 pub restrictedshell: i32,
1869 pub rhyf: integer,
1870 pub rightptr: halfword,
1871 pub rover: halfword,
1872 pub rthit: boolean,
1873 pub sachain: halfword,
1874 pub salevel: quarterword,
1875 pub sanull: memoryword,
1876 pub saroot: [halfword; 8],
1877 pub savearitherror: boolean,
1878 pub savenativelen: integer,
1879 pub saveptr: integer,
1880 pub savesize: integer,
1881 pub savestack: *mut memoryword,
1882 pub scannerstatus: eightbits,
1883 pub secondindent: scaled,
1884 pub secondpass: boolean,
1885 pub secondwidth: scaled,
1886 pub selector: eightbits,
1887 pub setboxallowed: boolean,
1888 pub shellenabledp: i32,
1889 pub shownmode: i16,
1890 pub skewchar: *mut integer,
1891 pub skipline: integer,
1892 pub sourcefilenamestack: *mut strnumber,
1893 pub spaceclass: integer,
1894 pub speclog: [integer; 29],
1895 pub stacksize: integer,
1896 pub stopatspace: boolean,
1897 pub stringvacancies: integer,
1898 pub strpool: *mut packedUTF16code,
1899 pub strptr: strnumber,
1900 pub strstart: *mut poolpointer,
1901 pub tally: integer,
1902 pub tempptr: halfword,
1903 pub termin: unicodefile,
1904 pub termoffset: integer,
1905 pub texinputtype: i32,
1906 pub texremainder: scaled,
1907 pub tfmfile: bytefile,
1908 pub tfmtemp: i32,
1909 pub threshold: integer,
1910 pub totalpages: integer,
1911 pub totalshrink: [scaled; 4],
1912 pub totalstretch: [scaled; 4],
1913 pub trickbuf: [UnicodeScalar; 256],
1914 pub trickcount: integer,
1915 pub triec: *mut packedUTF16code,
1916 pub triehash: *mut triepointer,
1917 pub triel: *mut triepointer,
1918 pub triemax: triepointer,
1919 pub triemin: [triepointer; 65536],
1920 pub trienotready: boolean,
1921 pub trieo: *mut trieopcode,
1922 pub trieoplang: [eightbits; 35112],
1923 pub trieopptr: integer,
1924 pub trieopval: [trieopcode; 35112],
1925 pub trieptr: triepointer,
1926 pub trier: *mut triepointer,
1927 pub triesize: integer,
1928 pub trietaken: *mut boolean,
1929 pub trietrc: *mut quarterword,
1930 pub trietrl: *mut triepointer,
1931 pub trietro: *mut triepointer,
1932 pub trieused: [trieopcode; 256],
1933 pub twotothe: [integer; 31],
1934 pub useerrhelp: boolean,
1935 pub varused: integer,
1936 pub warningindex: halfword,
1937 pub widthbase: *mut integer,
1938 pub writefile: [alphafile; 16],
1939 pub writeloc: halfword,
1940 pub writeopen: [boolean; 18],
1941 pub xchr: [ASCIIcode; 256],
1942 pub xtxligaturepresent: boolean,
1943 pub zeqtb: PagedView<memoryword>,
1944 pub zmem: *mut memoryword,
1945 pub zzzaa: [quarterword; 1114734],
1946 pub zzzab: [integer; 70223],
1947}
1948
1949const PORTABLE_FORMAT_MAGIC: [u8; 8] = *b"MTXfmt\x04\x00";
1952
1953macro_rules! portable_owning_vecs {
1958 ($cb:ident) => {
1959 $cb!(buffer_storage, UnicodeScalar);
1960 $cb!(nest_storage, liststaterecord);
1961 $cb!(savestack_storage, memoryword);
1962 $cb!(inputstack_storage, instaterecord);
1963 $cb!(inputfile_storage, unicodefile);
1964 $cb!(eofseen_storage, boolean);
1965 $cb!(linestack_storage, integer);
1966 $cb!(grpstack_storage, savepointer);
1967 $cb!(ifstack_storage, halfword);
1968 $cb!(sourcefilenamestack_storage, strnumber);
1969 $cb!(fullsourcefilenamestack_storage, strnumber);
1970 $cb!(paramstack_storage, halfword);
1971 $cb!(hyphword_storage, strnumber);
1972 $cb!(hyphlist_storage, halfword);
1973 $cb!(hyphlink_storage, hyphpointer);
1974 $cb!(strstart_storage, poolpointer);
1975 $cb!(strpool_storage, packedUTF16code);
1976 $cb!(fontinfo_storage, fmemoryword);
1977 $cb!(bcharlabel_storage, fontindex);
1978 $cb!(charbase_storage, integer);
1979 $cb!(widthbase_storage, integer);
1980 $cb!(heightbase_storage, integer);
1981 $cb!(depthbase_storage, integer);
1982 $cb!(italicbase_storage, integer);
1983 $cb!(ligkernbase_storage, integer);
1984 $cb!(kernbase_storage, integer);
1985 $cb!(extenbase_storage, integer);
1986 $cb!(parambase_storage, integer);
1987 $cb!(fontarea_storage, strnumber);
1988 $cb!(fontname_storage, strnumber);
1989 $cb!(fontbc_storage, UTF16code);
1990 $cb!(fontec_storage, UTF16code);
1991 $cb!(fontbchar_storage, ninebits);
1992 $cb!(fontfalsebchar_storage, ninebits);
1993 $cb!(fontcheck_storage, fourquarters);
1994 $cb!(fontdsize_storage, scaled);
1995 $cb!(fontsize_storage, scaled);
1996 $cb!(fontflags_storage, i8);
1997 $cb!(fontglue_storage, halfword);
1998 $cb!(fontlayoutengine_storage, voidpointer);
1999 $cb!(fontletterspace_storage, scaled);
2000 $cb!(fontmapping_storage, voidpointer);
2001 $cb!(fontparams_storage, fontindex);
2002 $cb!(fontused_storage, boolean);
2003 $cb!(nativetext_storage, UTF16code);
2004 $cb!(hyphenchar_storage, integer);
2005 $cb!(skewchar_storage, integer);
2006 $cb!(triec_storage, packedUTF16code);
2007 $cb!(triehash_storage, triepointer);
2008 $cb!(triel_storage, triepointer);
2009 $cb!(trieo_storage, trieopcode);
2010 $cb!(trier_storage, triepointer);
2011 $cb!(trietaken_storage, boolean);
2012 $cb!(trietrc_storage, quarterword);
2013 $cb!(trietrl_storage, triepointer);
2014 $cb!(trietro_storage, triepointer);
2015 };
2016}
2017
2018fn portable_write_vec_ranges<T: Copy>(out: &mut Vec<u8>, v: &[T], ranges: &[(usize, usize)]) {
2023 let elt = core::mem::size_of::<T>();
2024 out.extend_from_slice(&(v.len() as u64).to_le_bytes());
2025 out.extend_from_slice(&(ranges.len() as u32).to_le_bytes());
2026 for &(start, len) in ranges {
2027 out.extend_from_slice(&(start as u64).to_le_bytes());
2028 out.extend_from_slice(&(len as u64).to_le_bytes());
2029 let bytes =
2031 unsafe { core::slice::from_raw_parts(v.as_ptr().add(start) as *const u8, len * elt) };
2032 out.extend_from_slice(bytes);
2033 }
2034}
2035
2036fn portable_read_vec_ranges<T: Copy>(bytes: &[u8], cursor: &mut usize) -> Option<Vec<T>> {
2040 let elt = core::mem::size_of::<T>();
2041 let full = u64::from_le_bytes(bytes.get(*cursor..*cursor + 8)?.try_into().ok()?) as usize;
2042 *cursor += 8;
2043 let nranges = u32::from_le_bytes(bytes.get(*cursor..*cursor + 4)?.try_into().ok()?) as usize;
2044 *cursor += 4;
2045 let total = full.checked_mul(elt)?;
2046 let mut v = Vec::<T>::with_capacity(full);
2047 unsafe {
2050 core::ptr::write_bytes(v.as_mut_ptr() as *mut u8, 0, total);
2051 for _ in 0..nranges {
2052 let start = u64::from_le_bytes(bytes.get(*cursor..*cursor + 8)?.try_into().ok()?) as usize;
2053 *cursor += 8;
2054 let len = u64::from_le_bytes(bytes.get(*cursor..*cursor + 8)?.try_into().ok()?) as usize;
2055 *cursor += 8;
2056 if start.checked_add(len)? > full {
2057 return None;
2058 }
2059 let nbytes = len.checked_mul(elt)?;
2060 let src = bytes.get(*cursor..*cursor + nbytes)?;
2061 *cursor += nbytes;
2062 core::ptr::copy_nonoverlapping(
2063 src.as_ptr(),
2064 (v.as_mut_ptr() as *mut u8).add(start * elt),
2065 nbytes,
2066 );
2067 }
2068 v.set_len(full);
2069 }
2070 Some(v)
2071}
2072
2073fn portable_used_prefix_len<T>(v: &[T]) -> usize {
2077 let bytes =
2078 unsafe { core::slice::from_raw_parts(v.as_ptr() as *const u8, core::mem::size_of_val(v)) };
2079 match bytes.iter().rposition(|&b| b != 0) {
2080 Some(last) => last / core::mem::size_of::<T>() + 1,
2081 None => 0,
2082 }
2083}
2084
2085fn portable_write_paged<T: Copy + Default>(out: &mut Vec<u8>, arr: &PagedArray<T>) {
2089 let elt = core::mem::size_of::<T>();
2090 out.extend_from_slice(&(arr.base as u64).to_le_bytes());
2091 out.extend_from_slice(&(arr.lo as u64).to_le_bytes());
2092 out.extend_from_slice(&(arr.end as u64).to_le_bytes());
2093 let used = portable_used_prefix_len(arr.low.as_slice());
2094 let ranges: &[(usize, usize)] = if used == 0 { &[] } else { &[(0, used)] };
2095 portable_write_vec_ranges::<T>(out, arr.low.as_slice(), ranges);
2096 let present: Vec<usize> = arr
2097 .pages
2098 .iter()
2099 .enumerate()
2100 .filter_map(|(i, p)| p.as_ref().map(|_| i))
2101 .collect();
2102 out.extend_from_slice(&(arr.pages.len() as u64).to_le_bytes());
2103 out.extend_from_slice(&(present.len() as u32).to_le_bytes());
2104 for pg in present {
2105 out.extend_from_slice(&(pg as u64).to_le_bytes());
2106 let page = arr.pages[pg].as_ref().unwrap();
2107 let pbytes =
2109 unsafe { core::slice::from_raw_parts(page.as_ptr() as *const u8, PAGE_LEN * elt) };
2110 out.extend_from_slice(pbytes);
2111 }
2112}
2113
2114fn portable_read_paged<T: Copy + Default>(
2117 bytes: &[u8],
2118 cursor: &mut usize,
2119 default_fn: fn(usize) -> T,
2120 sig_range: fn(usize) -> (usize, usize),
2121) -> Option<PagedArray<T>> {
2122 let elt = core::mem::size_of::<T>();
2123 let read_u64 = |cursor: &mut usize| -> Option<usize> {
2124 let v = u64::from_le_bytes(bytes.get(*cursor..*cursor + 8)?.try_into().ok()?) as usize;
2125 *cursor += 8;
2126 Some(v)
2127 };
2128 let base = read_u64(cursor)?;
2129 let lo = read_u64(cursor)?;
2130 let end = read_u64(cursor)?;
2131 let low: Vec<T> = portable_read_vec_ranges(bytes, cursor)?;
2132 let npages = read_u64(cursor)?;
2133 let npresent = u32::from_le_bytes(bytes.get(*cursor..*cursor + 4)?.try_into().ok()?) as usize;
2134 *cursor += 4;
2135 let mut pages: Vec<Option<Box<[T]>>> = (0..npages).map(|_| None).collect();
2136 for _ in 0..npresent {
2137 let pg = read_u64(cursor)?;
2138 if pg >= npages {
2139 return None;
2140 }
2141 let nbytes = PAGE_LEN.checked_mul(elt)?;
2142 let src = bytes.get(*cursor..*cursor + nbytes)?;
2143 *cursor += nbytes;
2144 let mut page: Vec<T> = Vec::with_capacity(PAGE_LEN);
2145 unsafe {
2147 core::ptr::copy_nonoverlapping(src.as_ptr(), page.as_mut_ptr() as *mut u8, nbytes);
2148 page.set_len(PAGE_LEN);
2149 }
2150 pages[pg] = Some(page.into_boxed_slice());
2151 }
2152 Some(PagedArray {
2153 base,
2154 lo,
2155 end,
2156 low,
2157 pages,
2158 default_fn,
2159 sig_range,
2160 })
2161}
2162
2163impl PortableTexState {
2164 fn new_boxed_default() -> Box<Self> {
2165 let mut state = Box::<Self>::new_uninit();
2166 let state_ptr = state.as_mut_ptr();
2167 unsafe {
2168 core::ptr::write_bytes(state_ptr, 0, 1);
2169 core::ptr::addr_of_mut!((*state_ptr).mem).write(Vec::new());
2170 core::ptr::addr_of_mut!((*state_ptr).buffer_storage).write(Vec::new());
2171 core::ptr::addr_of_mut!((*state_ptr).nest_storage).write(Vec::new());
2172 core::ptr::addr_of_mut!((*state_ptr).savestack_storage).write(Vec::new());
2173 core::ptr::addr_of_mut!((*state_ptr).inputstack_storage).write(Vec::new());
2174 core::ptr::addr_of_mut!((*state_ptr).inputfile_storage).write(Vec::new());
2175 core::ptr::addr_of_mut!((*state_ptr).eofseen_storage).write(Vec::new());
2176 core::ptr::addr_of_mut!((*state_ptr).linestack_storage).write(Vec::new());
2177 core::ptr::addr_of_mut!((*state_ptr).grpstack_storage).write(Vec::new());
2178 core::ptr::addr_of_mut!((*state_ptr).ifstack_storage).write(Vec::new());
2179 core::ptr::addr_of_mut!((*state_ptr).sourcefilenamestack_storage).write(Vec::new());
2180 core::ptr::addr_of_mut!((*state_ptr).fullsourcefilenamestack_storage).write(Vec::new());
2181 core::ptr::addr_of_mut!((*state_ptr).paramstack_storage).write(Vec::new());
2182 core::ptr::addr_of_mut!((*state_ptr).hyphword_storage).write(Vec::new());
2183 core::ptr::addr_of_mut!((*state_ptr).hyphlist_storage).write(Vec::new());
2184 core::ptr::addr_of_mut!((*state_ptr).hyphlink_storage).write(Vec::new());
2185 core::ptr::addr_of_mut!((*state_ptr).hash_paged)
2186 .write(PagedArray::new(0, 0, hash_codepoint_default, hash_sig_range));
2187 core::ptr::addr_of_mut!((*state_ptr).eqtb_paged)
2188 .write(PagedArray::new(0, 0, eqtb_codepoint_default, eqtb_sig_range));
2189 core::ptr::addr_of_mut!((*state_ptr).strstart_storage).write(Vec::new());
2190 core::ptr::addr_of_mut!((*state_ptr).strpool_storage).write(Vec::new());
2191 core::ptr::addr_of_mut!((*state_ptr).fontinfo_storage).write(Vec::new());
2192 core::ptr::addr_of_mut!((*state_ptr).bcharlabel_storage).write(Vec::new());
2193 core::ptr::addr_of_mut!((*state_ptr).charbase_storage).write(Vec::new());
2194 core::ptr::addr_of_mut!((*state_ptr).widthbase_storage).write(Vec::new());
2195 core::ptr::addr_of_mut!((*state_ptr).heightbase_storage).write(Vec::new());
2196 core::ptr::addr_of_mut!((*state_ptr).depthbase_storage).write(Vec::new());
2197 core::ptr::addr_of_mut!((*state_ptr).italicbase_storage).write(Vec::new());
2198 core::ptr::addr_of_mut!((*state_ptr).ligkernbase_storage).write(Vec::new());
2199 core::ptr::addr_of_mut!((*state_ptr).kernbase_storage).write(Vec::new());
2200 core::ptr::addr_of_mut!((*state_ptr).extenbase_storage).write(Vec::new());
2201 core::ptr::addr_of_mut!((*state_ptr).parambase_storage).write(Vec::new());
2202 core::ptr::addr_of_mut!((*state_ptr).fontarea_storage).write(Vec::new());
2203 core::ptr::addr_of_mut!((*state_ptr).fontname_storage).write(Vec::new());
2204 core::ptr::addr_of_mut!((*state_ptr).fontbc_storage).write(Vec::new());
2205 core::ptr::addr_of_mut!((*state_ptr).fontec_storage).write(Vec::new());
2206 core::ptr::addr_of_mut!((*state_ptr).fontbchar_storage).write(Vec::new());
2207 core::ptr::addr_of_mut!((*state_ptr).fontfalsebchar_storage).write(Vec::new());
2208 core::ptr::addr_of_mut!((*state_ptr).fontcheck_storage).write(Vec::new());
2209 core::ptr::addr_of_mut!((*state_ptr).fontdsize_storage).write(Vec::new());
2210 core::ptr::addr_of_mut!((*state_ptr).fontsize_storage).write(Vec::new());
2211 core::ptr::addr_of_mut!((*state_ptr).fontflags_storage).write(Vec::new());
2212 core::ptr::addr_of_mut!((*state_ptr).fontglue_storage).write(Vec::new());
2213 core::ptr::addr_of_mut!((*state_ptr).fontlayoutengine_storage).write(Vec::new());
2214 core::ptr::addr_of_mut!((*state_ptr).fontletterspace_storage).write(Vec::new());
2215 core::ptr::addr_of_mut!((*state_ptr).fontmapping_storage).write(Vec::new());
2216 core::ptr::addr_of_mut!((*state_ptr).fontparams_storage).write(Vec::new());
2217 core::ptr::addr_of_mut!((*state_ptr).fontused_storage).write(Vec::new());
2218 core::ptr::addr_of_mut!((*state_ptr).nativetext_storage).write(Vec::new());
2219 core::ptr::addr_of_mut!((*state_ptr).hyphenchar_storage).write(Vec::new());
2220 core::ptr::addr_of_mut!((*state_ptr).skewchar_storage).write(Vec::new());
2221 core::ptr::addr_of_mut!((*state_ptr).triec_storage).write(Vec::new());
2222 core::ptr::addr_of_mut!((*state_ptr).triehash_storage).write(Vec::new());
2223 core::ptr::addr_of_mut!((*state_ptr).triel_storage).write(Vec::new());
2224 core::ptr::addr_of_mut!((*state_ptr).trieo_storage).write(Vec::new());
2225 core::ptr::addr_of_mut!((*state_ptr).trier_storage).write(Vec::new());
2226 core::ptr::addr_of_mut!((*state_ptr).trietaken_storage).write(Vec::new());
2227 core::ptr::addr_of_mut!((*state_ptr).trietrc_storage).write(Vec::new());
2228 core::ptr::addr_of_mut!((*state_ptr).trietrl_storage).write(Vec::new());
2229 core::ptr::addr_of_mut!((*state_ptr).trietro_storage).write(Vec::new());
2230 core::ptr::addr_of_mut!((*state_ptr).src_spans).write(Vec::new());
2231 core::ptr::addr_of_mut!((*state_ptr).src_dedup)
2232 .write(std::collections::HashMap::new());
2233 core::ptr::addr_of_mut!((*state_ptr).node_src)
2234 .write(PagedArray::new(0, 0, node_src_default, node_src_sig));
2235 core::ptr::addr_of_mut!((*state_ptr).src_native_offsets).write(Vec::new());
2236 core::ptr::addr_of_mut!((*state_ptr).src_stack_cells).write(Vec::new());
2237 core::ptr::addr_of_mut!((*state_ptr).cur_stack_head).write(0);
2238 core::ptr::addr_of_mut!((*state_ptr).node_stack)
2239 .write(PagedArray::new(0, 0, node_stack_default, node_stack_sig));
2240 state.assume_init()
2241 }
2242 }
2243
2244 fn clone_boxed(&self) -> Box<Self> {
2245 let mem = self.mem.clone();
2246 let buffer_storage = self.buffer_storage.clone();
2247 let nest_storage = self.nest_storage.clone();
2248 let savestack_storage = self.savestack_storage.clone();
2249 let inputstack_storage = self.inputstack_storage.clone();
2250 let inputfile_storage = self.inputfile_storage.clone();
2251 let eofseen_storage = self.eofseen_storage.clone();
2252 let linestack_storage = self.linestack_storage.clone();
2253 let grpstack_storage = self.grpstack_storage.clone();
2254 let ifstack_storage = self.ifstack_storage.clone();
2255 let sourcefilenamestack_storage = self.sourcefilenamestack_storage.clone();
2256 let fullsourcefilenamestack_storage = self.fullsourcefilenamestack_storage.clone();
2257 let paramstack_storage = self.paramstack_storage.clone();
2258 let hyphword_storage = self.hyphword_storage.clone();
2259 let hyphlist_storage = self.hyphlist_storage.clone();
2260 let hyphlink_storage = self.hyphlink_storage.clone();
2261 let hash_paged = self.hash_paged.clone();
2262 let eqtb_paged = self.eqtb_paged.clone();
2263 let strstart_storage = self.strstart_storage.clone();
2264 let strpool_storage = self.strpool_storage.clone();
2265 let fontinfo_storage = self.fontinfo_storage.clone();
2266 let bcharlabel_storage = self.bcharlabel_storage.clone();
2267 let charbase_storage = self.charbase_storage.clone();
2268 let widthbase_storage = self.widthbase_storage.clone();
2269 let heightbase_storage = self.heightbase_storage.clone();
2270 let depthbase_storage = self.depthbase_storage.clone();
2271 let italicbase_storage = self.italicbase_storage.clone();
2272 let ligkernbase_storage = self.ligkernbase_storage.clone();
2273 let kernbase_storage = self.kernbase_storage.clone();
2274 let extenbase_storage = self.extenbase_storage.clone();
2275 let parambase_storage = self.parambase_storage.clone();
2276 let fontarea_storage = self.fontarea_storage.clone();
2277 let fontname_storage = self.fontname_storage.clone();
2278 let fontbc_storage = self.fontbc_storage.clone();
2279 let fontec_storage = self.fontec_storage.clone();
2280 let fontbchar_storage = self.fontbchar_storage.clone();
2281 let fontfalsebchar_storage = self.fontfalsebchar_storage.clone();
2282 let fontcheck_storage = self.fontcheck_storage.clone();
2283 let fontdsize_storage = self.fontdsize_storage.clone();
2284 let fontsize_storage = self.fontsize_storage.clone();
2285 let fontflags_storage = self.fontflags_storage.clone();
2286 let fontglue_storage = self.fontglue_storage.clone();
2287 let fontlayoutengine_storage = self.fontlayoutengine_storage.clone();
2288 let fontletterspace_storage = self.fontletterspace_storage.clone();
2289 let fontmapping_storage = self.fontmapping_storage.clone();
2290 let fontparams_storage = self.fontparams_storage.clone();
2291 let fontused_storage = self.fontused_storage.clone();
2292 let nativetext_storage = self.nativetext_storage.clone();
2293 let hyphenchar_storage = self.hyphenchar_storage.clone();
2294 let skewchar_storage = self.skewchar_storage.clone();
2295 let triec_storage = self.triec_storage.clone();
2296 let triehash_storage = self.triehash_storage.clone();
2297 let triel_storage = self.triel_storage.clone();
2298 let trieo_storage = self.trieo_storage.clone();
2299 let trier_storage = self.trier_storage.clone();
2300 let trietaken_storage = self.trietaken_storage.clone();
2301 let trietrc_storage = self.trietrc_storage.clone();
2302 let trietrl_storage = self.trietrl_storage.clone();
2303 let trietro_storage = self.trietro_storage.clone();
2304 let src_spans = self.src_spans.clone();
2305 let src_dedup = self.src_dedup.clone();
2306 let node_src = self.node_src.clone();
2307 let src_native_offsets = self.src_native_offsets.clone();
2308 let src_stack_cells = self.src_stack_cells.clone();
2309 let node_stack = self.node_stack.clone();
2310 let mut state = Box::<Self>::new_uninit();
2311 let state_ptr = state.as_mut_ptr();
2312 unsafe {
2313 core::ptr::copy_nonoverlapping(self as *const Self, state_ptr, 1);
2314 core::ptr::addr_of_mut!((*state_ptr).mem).write(mem);
2315 core::ptr::addr_of_mut!((*state_ptr).buffer_storage).write(buffer_storage);
2316 core::ptr::addr_of_mut!((*state_ptr).nest_storage).write(nest_storage);
2317 core::ptr::addr_of_mut!((*state_ptr).savestack_storage).write(savestack_storage);
2318 core::ptr::addr_of_mut!((*state_ptr).inputstack_storage).write(inputstack_storage);
2319 core::ptr::addr_of_mut!((*state_ptr).inputfile_storage).write(inputfile_storage);
2320 core::ptr::addr_of_mut!((*state_ptr).eofseen_storage).write(eofseen_storage);
2321 core::ptr::addr_of_mut!((*state_ptr).linestack_storage).write(linestack_storage);
2322 core::ptr::addr_of_mut!((*state_ptr).grpstack_storage).write(grpstack_storage);
2323 core::ptr::addr_of_mut!((*state_ptr).ifstack_storage).write(ifstack_storage);
2324 core::ptr::addr_of_mut!((*state_ptr).sourcefilenamestack_storage)
2325 .write(sourcefilenamestack_storage);
2326 core::ptr::addr_of_mut!((*state_ptr).fullsourcefilenamestack_storage)
2327 .write(fullsourcefilenamestack_storage);
2328 core::ptr::addr_of_mut!((*state_ptr).paramstack_storage).write(paramstack_storage);
2329 core::ptr::addr_of_mut!((*state_ptr).hyphword_storage).write(hyphword_storage);
2330 core::ptr::addr_of_mut!((*state_ptr).hyphlist_storage).write(hyphlist_storage);
2331 core::ptr::addr_of_mut!((*state_ptr).hyphlink_storage).write(hyphlink_storage);
2332 core::ptr::addr_of_mut!((*state_ptr).hash_paged).write(hash_paged);
2333 core::ptr::addr_of_mut!((*state_ptr).eqtb_paged).write(eqtb_paged);
2334 core::ptr::addr_of_mut!((*state_ptr).strstart_storage).write(strstart_storage);
2335 core::ptr::addr_of_mut!((*state_ptr).strpool_storage).write(strpool_storage);
2336 core::ptr::addr_of_mut!((*state_ptr).fontinfo_storage).write(fontinfo_storage);
2337 core::ptr::addr_of_mut!((*state_ptr).bcharlabel_storage).write(bcharlabel_storage);
2338 core::ptr::addr_of_mut!((*state_ptr).charbase_storage).write(charbase_storage);
2339 core::ptr::addr_of_mut!((*state_ptr).widthbase_storage).write(widthbase_storage);
2340 core::ptr::addr_of_mut!((*state_ptr).heightbase_storage).write(heightbase_storage);
2341 core::ptr::addr_of_mut!((*state_ptr).depthbase_storage).write(depthbase_storage);
2342 core::ptr::addr_of_mut!((*state_ptr).italicbase_storage).write(italicbase_storage);
2343 core::ptr::addr_of_mut!((*state_ptr).ligkernbase_storage).write(ligkernbase_storage);
2344 core::ptr::addr_of_mut!((*state_ptr).kernbase_storage).write(kernbase_storage);
2345 core::ptr::addr_of_mut!((*state_ptr).extenbase_storage).write(extenbase_storage);
2346 core::ptr::addr_of_mut!((*state_ptr).parambase_storage).write(parambase_storage);
2347 core::ptr::addr_of_mut!((*state_ptr).fontarea_storage).write(fontarea_storage);
2348 core::ptr::addr_of_mut!((*state_ptr).fontname_storage).write(fontname_storage);
2349 core::ptr::addr_of_mut!((*state_ptr).fontbc_storage).write(fontbc_storage);
2350 core::ptr::addr_of_mut!((*state_ptr).fontec_storage).write(fontec_storage);
2351 core::ptr::addr_of_mut!((*state_ptr).fontbchar_storage).write(fontbchar_storage);
2352 core::ptr::addr_of_mut!((*state_ptr).fontfalsebchar_storage).write(fontfalsebchar_storage);
2353 core::ptr::addr_of_mut!((*state_ptr).fontcheck_storage).write(fontcheck_storage);
2354 core::ptr::addr_of_mut!((*state_ptr).fontdsize_storage).write(fontdsize_storage);
2355 core::ptr::addr_of_mut!((*state_ptr).fontsize_storage).write(fontsize_storage);
2356 core::ptr::addr_of_mut!((*state_ptr).fontflags_storage).write(fontflags_storage);
2357 core::ptr::addr_of_mut!((*state_ptr).fontglue_storage).write(fontglue_storage);
2358 core::ptr::addr_of_mut!((*state_ptr).fontlayoutengine_storage).write(fontlayoutengine_storage);
2359 core::ptr::addr_of_mut!((*state_ptr).fontletterspace_storage).write(fontletterspace_storage);
2360 core::ptr::addr_of_mut!((*state_ptr).fontmapping_storage).write(fontmapping_storage);
2361 core::ptr::addr_of_mut!((*state_ptr).fontparams_storage).write(fontparams_storage);
2362 core::ptr::addr_of_mut!((*state_ptr).fontused_storage).write(fontused_storage);
2363 core::ptr::addr_of_mut!((*state_ptr).nativetext_storage).write(nativetext_storage);
2364 core::ptr::addr_of_mut!((*state_ptr).hyphenchar_storage).write(hyphenchar_storage);
2365 core::ptr::addr_of_mut!((*state_ptr).skewchar_storage).write(skewchar_storage);
2366 core::ptr::addr_of_mut!((*state_ptr).triec_storage).write(triec_storage);
2367 core::ptr::addr_of_mut!((*state_ptr).triehash_storage).write(triehash_storage);
2368 core::ptr::addr_of_mut!((*state_ptr).triel_storage).write(triel_storage);
2369 core::ptr::addr_of_mut!((*state_ptr).trieo_storage).write(trieo_storage);
2370 core::ptr::addr_of_mut!((*state_ptr).trier_storage).write(trier_storage);
2371 core::ptr::addr_of_mut!((*state_ptr).trietaken_storage).write(trietaken_storage);
2372 core::ptr::addr_of_mut!((*state_ptr).trietrc_storage).write(trietrc_storage);
2373 core::ptr::addr_of_mut!((*state_ptr).trietrl_storage).write(trietrl_storage);
2374 core::ptr::addr_of_mut!((*state_ptr).trietro_storage).write(trietro_storage);
2375 core::ptr::addr_of_mut!((*state_ptr).src_spans).write(src_spans);
2376 core::ptr::addr_of_mut!((*state_ptr).src_dedup).write(src_dedup);
2377 core::ptr::addr_of_mut!((*state_ptr).node_src).write(node_src);
2378 core::ptr::addr_of_mut!((*state_ptr).src_native_offsets).write(src_native_offsets);
2379 core::ptr::addr_of_mut!((*state_ptr).src_stack_cells).write(src_stack_cells);
2380 core::ptr::addr_of_mut!((*state_ptr).node_stack).write(node_stack);
2381 let mut state = state.assume_init();
2382 state.refresh_runtime_pointers();
2383 state
2384 }
2385 }
2386
2387 fn refresh_runtime_pointers(&mut self) {
2388 self.zmem = pointer_or_null(&mut self.mem).wrapping_offset(-(self.memmin as isize));
2389 self.buffer = pointer_or_null(&mut self.buffer_storage);
2390 self.nest = pointer_or_null(&mut self.nest_storage);
2391 self.savestack = pointer_or_null(&mut self.savestack_storage);
2392 self.inputstack = pointer_or_null(&mut self.inputstack_storage);
2393 self.inputfile = pointer_or_null(&mut self.inputfile_storage);
2394 self.eofseen = pointer_or_null(&mut self.eofseen_storage);
2395 self.linestack = pointer_or_null(&mut self.linestack_storage);
2396 self.grpstack = pointer_or_null(&mut self.grpstack_storage);
2397 self.ifstack = pointer_or_null(&mut self.ifstack_storage);
2398 self.sourcefilenamestack = pointer_or_null(&mut self.sourcefilenamestack_storage);
2399 self.fullsourcefilenamestack =
2400 pointer_or_null(&mut self.fullsourcefilenamestack_storage);
2401 self.paramstack = pointer_or_null(&mut self.paramstack_storage);
2402 self.hyphword = pointer_or_null(&mut self.hyphword_storage);
2403 self.hyphlist = pointer_or_null(&mut self.hyphlist_storage);
2404 self.hyphlink = pointer_or_null(&mut self.hyphlink_storage);
2405 self.hash = PagedView::new(&mut self.hash_paged);
2406 self.zeqtb = PagedView::new(&mut self.eqtb_paged);
2407 self.strstart = pointer_or_null(&mut self.strstart_storage);
2408 self.strpool = pointer_or_null(&mut self.strpool_storage);
2409 self.fontinfo = pointer_or_null(&mut self.fontinfo_storage);
2410 self.bcharlabel = pointer_or_null(&mut self.bcharlabel_storage);
2411 self.charbase = pointer_or_null(&mut self.charbase_storage);
2412 self.widthbase = pointer_or_null(&mut self.widthbase_storage);
2413 self.heightbase = pointer_or_null(&mut self.heightbase_storage);
2414 self.depthbase = pointer_or_null(&mut self.depthbase_storage);
2415 self.italicbase = pointer_or_null(&mut self.italicbase_storage);
2416 self.ligkernbase = pointer_or_null(&mut self.ligkernbase_storage);
2417 self.kernbase = pointer_or_null(&mut self.kernbase_storage);
2418 self.extenbase = pointer_or_null(&mut self.extenbase_storage);
2419 self.parambase = pointer_or_null(&mut self.parambase_storage);
2420 self.fontarea = pointer_or_null(&mut self.fontarea_storage);
2421 self.fontname = pointer_or_null(&mut self.fontname_storage);
2422 self.fontbc = pointer_or_null(&mut self.fontbc_storage);
2423 self.fontec = pointer_or_null(&mut self.fontec_storage);
2424 self.fontbchar = pointer_or_null(&mut self.fontbchar_storage);
2425 self.fontfalsebchar = pointer_or_null(&mut self.fontfalsebchar_storage);
2426 self.fontcheck = pointer_or_null(&mut self.fontcheck_storage);
2427 self.fontdsize = pointer_or_null(&mut self.fontdsize_storage);
2428 self.fontsize = pointer_or_null(&mut self.fontsize_storage);
2429 self.fontflags = pointer_or_null(&mut self.fontflags_storage);
2430 self.fontglue = pointer_or_null(&mut self.fontglue_storage);
2431 self.fontlayoutengine = pointer_or_null(&mut self.fontlayoutengine_storage);
2432 self.fontletterspace = pointer_or_null(&mut self.fontletterspace_storage);
2433 self.fontmapping = pointer_or_null(&mut self.fontmapping_storage);
2434 self.fontparams = pointer_or_null(&mut self.fontparams_storage);
2435 self.fontused = pointer_or_null(&mut self.fontused_storage);
2436 self.nativetext = pointer_or_null(&mut self.nativetext_storage);
2437 self.hyphenchar = pointer_or_null(&mut self.hyphenchar_storage);
2438 self.skewchar = pointer_or_null(&mut self.skewchar_storage);
2439 self.triec = pointer_or_null(&mut self.triec_storage);
2440 self.triehash = pointer_or_null(&mut self.triehash_storage);
2441 self.triel = pointer_or_null(&mut self.triel_storage);
2442 self.trieo = pointer_or_null(&mut self.trieo_storage);
2443 self.trier = pointer_or_null(&mut self.trier_storage);
2444 self.trietaken = pointer_or_null(&mut self.trietaken_storage);
2445 self.trietrc = pointer_or_null(&mut self.trietrc_storage);
2446 self.trietrl = pointer_or_null(&mut self.trietrl_storage);
2447 self.trietro = pointer_or_null(&mut self.trietro_storage);
2448 }
2449
2450 fn seal_as_format_snapshot(&mut self) {
2451 self.curinput = instaterecord::default();
2452 self.inputptr = 0;
2453 self.inopen = 0;
2454 self.baseptr = 0;
2455 self.scannerstatus = 0;
2456 self.warningindex = 0;
2457 self.defref = -(268435455 as i64) as halfword;
2458 self.paramptr = 0;
2459 self.alignstate = 1000000 as integer;
2460 self.first = 0;
2461 self.last = 0;
2462 self.line = 0;
2463 self.openparens = 0;
2464 self.inputstack_storage.fill(instaterecord::default());
2465 self.inputfile_storage.fill(core::ptr::null_mut());
2466 self.eofseen_storage.fill(false_0);
2467 self.linestack_storage.fill(0);
2468 self.grpstack_storage.fill(-(268435455 as i64) as halfword);
2469 self.ifstack_storage.fill(-(268435455 as i64) as halfword);
2470 self.sourcefilenamestack_storage.fill(0);
2471 self.fullsourcefilenamestack_storage.fill(0);
2472 self.paramstack_storage.fill(0);
2473 self.eqtb_paged.compact();
2477 self.hash_paged.compact();
2478 if self.trienotready == false_0 {
2485 self.triehash_storage = Vec::new();
2486 self.triel_storage = Vec::new();
2487 self.trier_storage = Vec::new();
2488 self.trieo_storage = Vec::new();
2489 self.triec_storage = Vec::new();
2490 self.trietaken_storage = Vec::new();
2491 }
2492 self.refresh_runtime_pointers();
2493 }
2494
2495 pub(crate) fn to_portable_bytes(&self) -> Vec<u8> {
2508 let mut out = Vec::new();
2509 out.extend_from_slice(&PORTABLE_FORMAT_MAGIC);
2510 out.push(core::mem::size_of::<usize>() as u8);
2511 out.extend_from_slice(&(core::mem::size_of::<PortableTexState>() as u64).to_le_bytes());
2512 let image = unsafe {
2515 core::slice::from_raw_parts(
2516 self as *const Self as *const u8,
2517 core::mem::size_of::<Self>(),
2518 )
2519 };
2520 out.extend_from_slice(image);
2521 let lo_len = (self.lomemmax - self.memmin + 1).max(0) as usize;
2525 let hi_start = (self.himemmin - self.memmin).max(0) as usize;
2526 let hi_len = (self.memend - self.himemmin + 1).max(0) as usize;
2527 portable_write_vec_ranges::<memoryword>(
2528 &mut out,
2529 self.mem.as_slice(),
2530 &[(0, lo_len), (hi_start, hi_len)],
2531 );
2532 macro_rules! write_field {
2534 ($name:ident, $ty:ty) => {{
2535 let slice = self.$name.as_slice();
2536 let used = portable_used_prefix_len(slice);
2537 let ranges: &[(usize, usize)] = if used == 0 { &[] } else { &[(0, used)] };
2538 portable_write_vec_ranges::<$ty>(&mut out, slice, ranges);
2539 }};
2540 }
2541 portable_owning_vecs!(write_field);
2542 portable_write_paged(&mut out, &self.eqtb_paged);
2544 portable_write_paged(&mut out, &self.hash_paged);
2545 out
2546 }
2547
2548 pub(crate) fn from_portable_bytes(bytes: &[u8]) -> Option<Box<Self>> {
2557 let mut cursor = 0usize;
2558 if bytes.get(cursor..cursor + PORTABLE_FORMAT_MAGIC.len())? != &PORTABLE_FORMAT_MAGIC[..] {
2559 return None;
2560 }
2561 cursor += PORTABLE_FORMAT_MAGIC.len();
2562 if *bytes.get(cursor)? as usize != core::mem::size_of::<usize>() {
2563 return None;
2564 }
2565 cursor += 1;
2566 let struct_size =
2567 u64::from_le_bytes(bytes.get(cursor..cursor + 8)?.try_into().ok()?) as usize;
2568 cursor += 8;
2569 if struct_size != core::mem::size_of::<Self>() {
2570 return None;
2571 }
2572 let image = bytes.get(cursor..cursor + core::mem::size_of::<Self>())?;
2573 cursor += core::mem::size_of::<Self>();
2574
2575 let mut state = Box::<Self>::new_uninit();
2576 let state_ptr = state.as_mut_ptr();
2577 let state = unsafe {
2582 core::ptr::copy_nonoverlapping(
2583 image.as_ptr(),
2584 state_ptr as *mut u8,
2585 core::mem::size_of::<Self>(),
2586 );
2587 let decoded_mem: Vec<memoryword> = portable_read_vec_ranges(bytes, &mut cursor)?;
2588 core::ptr::addr_of_mut!((*state_ptr).mem).write(decoded_mem);
2589 macro_rules! read_field {
2590 ($name:ident, $ty:ty) => {
2591 let decoded: Vec<$ty> = portable_read_vec_ranges(bytes, &mut cursor)?;
2592 core::ptr::addr_of_mut!((*state_ptr).$name).write(decoded);
2593 };
2594 }
2595 portable_owning_vecs!(read_field);
2596 let eqtb_paged =
2597 portable_read_paged(bytes, &mut cursor, eqtb_codepoint_default, eqtb_sig_range)?;
2598 core::ptr::addr_of_mut!((*state_ptr).eqtb_paged).write(eqtb_paged);
2599 let hash_paged =
2600 portable_read_paged(bytes, &mut cursor, hash_codepoint_default, hash_sig_range)?;
2601 core::ptr::addr_of_mut!((*state_ptr).hash_paged).write(hash_paged);
2602 core::ptr::addr_of_mut!((*state_ptr).src_spans).write(Vec::new());
2608 core::ptr::addr_of_mut!((*state_ptr).src_dedup)
2609 .write(std::collections::HashMap::new());
2610 core::ptr::addr_of_mut!((*state_ptr).node_src)
2611 .write(PagedArray::new(0, 0, node_src_default, node_src_sig));
2612 core::ptr::addr_of_mut!((*state_ptr).src_native_offsets).write(Vec::new());
2613 core::ptr::addr_of_mut!((*state_ptr).src_stack_cells).write(Vec::new());
2614 core::ptr::addr_of_mut!((*state_ptr).cur_stack_head).write(0);
2615 core::ptr::addr_of_mut!((*state_ptr).node_stack)
2616 .write(PagedArray::new(0, 0, node_stack_default, node_stack_sig));
2617 for slot in (*state_ptr).inputfile_storage.iter_mut() {
2621 *slot = core::ptr::null_mut();
2622 }
2623 let mut state = state.assume_init();
2624 state.refresh_runtime_pointers();
2625 state
2626 };
2627 Some(state)
2628 }
2629
2630 pub(crate) fn state_array_bytes(&self) -> usize {
2634 let mut total = self.mem.capacity() * core::mem::size_of::<memoryword>();
2635 macro_rules! accumulate {
2636 ($name:ident, $ty:ty) => {
2637 total += self.$name.capacity() * core::mem::size_of::<$ty>();
2638 };
2639 }
2640 portable_owning_vecs!(accumulate);
2641 total += self.eqtb_paged.resident_bytes() + self.hash_paged.resident_bytes();
2642 total
2643 }
2644
2645 fn allocate_initial_arrays(&mut self) {
2646 self.iniversion = true_0;
2647 self.membot = 0;
2648 self.memmin = self.membot;
2649 self.memtop = 999_999;
2654 self.memmax = self.memtop;
2655 self.hashextra = 600_000;
2656 self.eqtbtop = xetex_eqtb_top + self.hashextra;
2657 self.bufsize = 200_000;
2658 self.nestsize = 1_000;
2659 self.maxinopen = 15;
2660 self.paramsize = 20_000;
2661 self.savesize = 200_000;
2662 self.stacksize = 10_000;
2663 self.dvibufsize = 16_384;
2664 self.poolsize = 6_250_000;
2665 self.maxstrings = 500_000;
2666 self.fontmemsize = 1_000_000;
2667 self.fontmax = 500;
2668 self.triesize = 1_100_000;
2674 self.hyphsize = 8_191;
2675 self.primused = 2_100;
2676 self.errorline = 79;
2677 self.halferrorline = 50;
2678 self.maxprintline = 79;
2679 self.expanddepth = 10_000;
2680
2681 self.mem = zeroed_vec((self.memtop - self.memmin + 1) as usize);
2682 self.buffer_storage = zeroed_vec((self.bufsize + 1) as usize);
2690 self.nest_storage = zeroed_vec((self.nestsize + 1) as usize);
2691 self.savestack_storage = zeroed_vec((self.savesize + 1) as usize);
2692 self.inputstack_storage = zeroed_vec((self.stacksize + 1) as usize);
2693 self.inputfile_storage = zeroed_vec((self.maxinopen + 1) as usize);
2694 self.eofseen_storage = zeroed_vec((self.maxinopen + 1) as usize);
2695 self.linestack_storage = zeroed_vec((self.maxinopen + 1) as usize);
2696 self.grpstack_storage = zeroed_vec((self.maxinopen + 1) as usize);
2697 self.ifstack_storage = zeroed_vec((self.maxinopen + 1) as usize);
2698 self.sourcefilenamestack_storage = zeroed_vec((self.maxinopen + 1) as usize);
2699 self.fullsourcefilenamestack_storage = zeroed_vec((self.maxinopen + 1) as usize);
2700 self.paramstack_storage = zeroed_vec((self.paramsize + 1) as usize);
2701 self.hyphword_storage = zeroed_vec((self.hyphsize + 1) as usize);
2702 self.hyphlist_storage = zeroed_vec((self.hyphsize + 1) as usize);
2703 self.hyphlink_storage = zeroed_vec((self.hyphsize + 1) as usize);
2704 self.eqtb_paged = PagedArray::new(
2708 0,
2709 (self.eqtbtop + 1) as usize,
2710 eqtb_codepoint_default,
2711 eqtb_sig_range,
2712 );
2713 self.hash_paged = PagedArray::new(
2714 hashoffset as usize,
2715 (self.eqtbtop + 1) as usize,
2716 hash_codepoint_default,
2717 hash_sig_range,
2718 );
2719 self.strstart_storage = zeroed_vec((self.maxstrings + 1) as usize);
2720 self.strpool_storage = zeroed_vec((self.poolsize + 1) as usize);
2721 self.fontinfo_storage = zeroed_vec((self.fontmemsize + 1) as usize);
2722 let font_slots = (self.fontmax + 1) as usize;
2723 self.bcharlabel_storage = zeroed_vec(font_slots);
2724 self.charbase_storage = zeroed_vec(font_slots);
2725 self.widthbase_storage = zeroed_vec(font_slots);
2726 self.heightbase_storage = zeroed_vec(font_slots);
2727 self.depthbase_storage = zeroed_vec(font_slots);
2728 self.italicbase_storage = zeroed_vec(font_slots);
2729 self.ligkernbase_storage = zeroed_vec(font_slots);
2730 self.kernbase_storage = zeroed_vec(font_slots);
2731 self.extenbase_storage = zeroed_vec(font_slots);
2732 self.parambase_storage = zeroed_vec(font_slots);
2733 self.fontarea_storage = zeroed_vec(font_slots);
2734 self.fontname_storage = zeroed_vec(font_slots);
2735 self.fontbc_storage = zeroed_vec(font_slots);
2736 self.fontec_storage = zeroed_vec(font_slots);
2737 self.fontbchar_storage = zeroed_vec(font_slots);
2738 self.fontfalsebchar_storage = zeroed_vec(font_slots);
2739 self.fontcheck_storage = zeroed_vec(font_slots);
2740 self.fontdsize_storage = zeroed_vec(font_slots);
2741 self.fontsize_storage = zeroed_vec(font_slots);
2742 self.fontflags_storage = zeroed_vec(font_slots);
2743 self.fontglue_storage = zeroed_vec(font_slots);
2744 self.fontlayoutengine_storage = zeroed_vec(font_slots);
2745 self.fontletterspace_storage = zeroed_vec(font_slots);
2746 self.fontmapping_storage = zeroed_vec(font_slots);
2747 self.fontparams_storage = zeroed_vec(font_slots);
2748 self.fontused_storage = zeroed_vec(font_slots);
2749 self.nativetext_storage = Vec::new();
2750 self.hyphenchar_storage = zeroed_vec(font_slots);
2751 self.skewchar_storage = zeroed_vec(font_slots);
2752 let trie_slots = (self.triesize + 1) as usize;
2753 self.triec_storage = zeroed_vec(trie_slots);
2754 self.triehash_storage = zeroed_vec(trie_slots);
2755 self.triel_storage = zeroed_vec(trie_slots);
2756 self.trieo_storage = zeroed_vec(trie_slots);
2757 self.trier_storage = zeroed_vec(trie_slots);
2758 self.trietaken_storage = zeroed_vec(trie_slots);
2759 self.trietrc_storage = zeroed_vec(trie_slots);
2760 self.trietrl_storage = zeroed_vec(trie_slots);
2761 self.trietro_storage = zeroed_vec(trie_slots);
2762 self.refresh_runtime_pointers();
2763 }
2764}
2765
2766fn zeroed_vec<T>(len: usize) -> Vec<T>
2767where
2768 T: Clone + Default,
2769{
2770 vec![T::default(); len]
2771}
2772
2773fn pointer_or_null<T>(storage: &mut Vec<T>) -> *mut T {
2774 if storage.is_empty() {
2775 core::ptr::null_mut()
2776 } else {
2777 storage.as_mut_ptr()
2778 }
2779}
2780
2781#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2782pub enum EngineProfileKind {
2783 Tex,
2784 Etex,
2785 Xetex,
2786}
2787
2788#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2789pub struct EngineProfile {
2790 pub id: &'static str,
2791 pub kind: EngineProfileKind,
2792 pub etex: bool,
2793 pub xetex: bool,
2794 pub unicode_scalars: bool,
2795 pub unicode_math: bool,
2796 pub native_fonts: bool,
2797}
2798
2799#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2800struct WriteTokenConstants {
2801 open_group_token: halfword,
2802 end_write_token: halfword,
2803 close_group_token: halfword,
2804}
2805
2806impl EngineProfile {
2807 pub const fn tex() -> Self {
2808 Self {
2809 id: "tex",
2810 kind: EngineProfileKind::Tex,
2811 etex: false,
2812 xetex: false,
2813 unicode_scalars: false,
2814 unicode_math: false,
2815 native_fonts: false,
2816 }
2817 }
2818
2819 pub const fn etex() -> Self {
2820 Self {
2821 id: "etex",
2822 kind: EngineProfileKind::Etex,
2823 etex: true,
2824 xetex: false,
2825 unicode_scalars: false,
2826 unicode_math: false,
2827 native_fonts: false,
2828 }
2829 }
2830
2831 pub const fn xetex() -> Self {
2832 Self {
2833 id: "xetex",
2834 kind: EngineProfileKind::Xetex,
2835 etex: true,
2836 xetex: true,
2837 unicode_scalars: true,
2838 unicode_math: true,
2839 native_fonts: false,
2840 }
2841 }
2842
2843 const fn write_token_constants(self) -> WriteTokenConstants {
2844 match self.kind {
2845 EngineProfileKind::Tex | EngineProfileKind::Etex => WriteTokenConstants {
2846 open_group_token: 637,
2847 end_write_token: 19617,
2848 close_group_token: 379,
2849 },
2850 EngineProfileKind::Xetex => WriteTokenConstants {
2851 open_group_token: 4_194_429,
2852 end_write_token: 34_749_089,
2853 close_group_token: 2_097_275,
2854 },
2855 }
2856 }
2857}
2858
2859pub struct PortableFormatImage {
2860 state: Box<PortableTexState>,
2861}
2862
2863#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2864pub struct PortableNodeHandle(pub i32);
2865
2866#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2867pub enum PortableNodeKind {
2868 HorizontalBox,
2869 VerticalBox,
2870 Rule,
2871 Insertion,
2872 Mark,
2873 Adjustment,
2874 Ligature,
2875 Discretionary,
2876 OutputWhatsit,
2877 Whatsit,
2878 Math,
2879 Glue,
2880 Kern,
2881 Penalty,
2882 UnsetBox,
2883 Noad,
2884 Style,
2885 Choice,
2886 Character,
2887 NativeWord,
2888 NativeGlyph,
2889 HostBoxRef,
2890 Unknown(i32),
2891}
2892
2893#[derive(Clone, Debug, PartialEq)]
2894pub struct PortableNodeSnapshot {
2895 pub handle: PortableNodeHandle,
2896 pub kind: PortableNodeKind,
2897 pub subtype: i32,
2898 pub source: Option<PortableSourceSpan>,
2899 pub link: Option<PortableNodeHandle>,
2900 pub font: i32,
2901 pub character: i32,
2902 pub width: i32,
2903 pub height: i32,
2904 pub depth: i32,
2905 pub shift: i32,
2906 pub list: Option<PortableNodeHandle>,
2907 pub native_glyphs: Vec<PortableNativeGlyph>,
2908 pub glue_set: f64,
2910 pub glue_sign: i32,
2912 pub glue_order: i32,
2914 pub glue_stretch: i32,
2916 pub glue_shrink: i32,
2918 pub glue_stretch_order: i32,
2920 pub glue_shrink_order: i32,
2922}
2923
2924impl Clone for PortableFormatImage {
2925 fn clone(&self) -> Self {
2926 Self {
2927 state: self.state.clone_boxed(),
2928 }
2929 }
2930}
2931
2932impl PortableFormatImage {
2933 pub fn empty() -> Self {
2934 Self {
2935 state: PortableTexState::new_boxed_default(),
2936 }
2937 }
2938
2939 fn from_engine_state(state: &PortableTexState) -> Self {
2940 let mut state = state.clone_boxed();
2941 state.seal_as_format_snapshot();
2942 Self {
2943 state,
2944 }
2945 }
2946
2947 fn from_sealed_state(state: Box<PortableTexState>) -> Self {
2950 Self { state }
2951 }
2952
2953 #[must_use]
2957 pub fn to_bytes(&self) -> Vec<u8> {
2958 self.state.to_portable_bytes()
2959 }
2960
2961 #[must_use]
2964 pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
2965 Some(Self {
2966 state: PortableTexState::from_portable_bytes(bytes)?,
2967 })
2968 }
2969
2970 #[must_use]
2973 pub fn state_array_bytes(&self) -> usize {
2974 self.state.state_array_bytes()
2975 }
2976
2977}
2978
2979#[must_use]
2983pub fn memory_word_bytes() -> usize {
2984 core::mem::size_of::<memoryword>()
2985}
2986
2987pub struct PortableTexEngine<'resources> {
2988 pub(crate) state: Box<PortableTexState>,
2989 pub(crate) profile: EngineProfile,
2990 pub(crate) resources: Box<dyn ResourceProvider + 'resources>,
2991 pub(crate) fonts: Box<dyn FontPlatform + 'resources>,
2992 pub(crate) platform: Box<dyn PortablePlatform + 'resources>,
2993 pub(crate) nameoffile_storage: Vec<UTF8code>,
2994 native_glyph_infos: std::collections::BTreeMap<i32, PortableNativeGlyphInfo>,
2995 hostbox_records: Vec<PortableHostBox>,
2997 character_protrusions: std::collections::BTreeMap<(integer, u32, integer), integer>,
2998 pub(crate) resource_requests: usize,
2999 pub(crate) resource_request_records: Vec<PortableResourceRequestRecord>,
3000 pub(crate) virtual_files: std::collections::BTreeMap<String, Vec<u8>>,
3001 pub(crate) transcript_bytes: Vec<u8>,
3002 pub(crate) current_input_package_owner: Option<String>,
3003 pub(crate) stripped_page_builds: usize,
3004 pub(crate) stripped_shipouts: usize,
3005 pub(crate) stripped_special_outputs: usize,
3006 pub(crate) stripped_picture_loads: usize,
3007 pub(crate) stripped_source_specials: usize,
3008 pub(crate) stripped_write_whatsit_diagnostics: usize,
3009 pub(crate) stripped_pdf_extensions: usize,
3010 pub(crate) stripped_page_top_prunes: usize,
3011 pub(crate) last_stripped_shipout_box: Option<PortableNodeHandle>,
3012 pub(crate) fragment_capture_enabled: bool,
3013 pub(crate) format_initialization: bool,
3014 pub(crate) captured_fragment_root: Option<PortableNodeHandle>,
3015 pub(crate) last_abort_status: Option<integer>,
3016 pub(crate) last_error_message: Option<String>,
3020 pub(crate) sandbox: bool,
3026 pub(crate) sandbox_math_depth: i32,
3033 pub(crate) sandbox_math_opened: bool,
3037 pub(crate) sandbox_ops: u64,
3040}
3041
3042pub(crate) fn zround(value: real) -> integer {
3043 value.round() as integer
3044}
3045
3046impl<'resources> PortableTexEngine<'resources> {
3047 pub fn from_format<R>(
3048 profile: EngineProfile,
3049 format: &PortableFormatImage,
3050 resources: R,
3051 ) -> Self
3052 where
3053 R: ResourceProvider + 'resources,
3054 {
3055 Self {
3056 state: format.state.clone_boxed(),
3057 profile,
3058 resources: Box::new(resources),
3059 fonts: Box::<EmptyFontPlatform>::default(),
3060 platform: Box::<EmptyPlatform>::default(),
3061 nameoffile_storage: Vec::new(),
3062 native_glyph_infos: std::collections::BTreeMap::new(),
3063 hostbox_records: Vec::new(),
3064 character_protrusions: std::collections::BTreeMap::new(),
3065 resource_requests: 0,
3066 resource_request_records: Vec::new(),
3067 virtual_files: std::collections::BTreeMap::new(),
3068 transcript_bytes: Vec::new(),
3069 current_input_package_owner: None,
3070 stripped_page_builds: 0,
3071 stripped_shipouts: 0,
3072 stripped_special_outputs: 0,
3073 stripped_picture_loads: 0,
3074 stripped_source_specials: 0,
3075 stripped_write_whatsit_diagnostics: 0,
3076 stripped_pdf_extensions: 0,
3077 stripped_page_top_prunes: 0,
3078 last_stripped_shipout_box: None,
3079 fragment_capture_enabled: false,
3080 format_initialization: false,
3081 captured_fragment_root: None,
3082 last_abort_status: None,
3083 last_error_message: None,
3084 sandbox: false,
3085 sandbox_math_depth: 0,
3086 sandbox_math_opened: false,
3087 sandbox_ops: 0,
3088 }
3089 }
3090
3091 pub fn with_font_platform<F>(mut self, fonts: F) -> Self
3092 where
3093 F: FontPlatform + 'resources,
3094 {
3095 self.fonts = Box::new(fonts);
3096 self
3097 }
3098
3099 pub fn with_platform<P>(mut self, platform: P) -> Self
3100 where
3101 P: PortablePlatform + 'resources,
3102 {
3103 self.platform = Box::new(platform);
3104 self
3105 }
3106
3107 pub fn profile(&self) -> EngineProfile {
3108 self.profile
3109 }
3110
3111 pub fn initialize_format_state(self: &mut Self) -> bool {
3112 self.catch_engine_abort(|engine| unsafe {
3113 let this = engine as *mut PortableTexEngine<'_>;
3114 engine.state.allocate_initial_arrays();
3115 engine.initialize();
3116 if engine.supports_etex() {
3117 engine.state.eTeXmode = 1 as eightbits;
3118 }
3119 if engine.getstringsstarted()? == 0 {
3124 Self::abort_engine(this, 1 as integer)?;
3125 }
3126 engine.initprim()?;
3127 engine.init_etex_startup_primitives()?;
3128 engine.init_xetex_startup_primitives()?;
3129 engine.register_host_box_primitive()?;
3130 engine.state.initstrptr = engine.state.strptr;
3131 engine.state.initpoolptr = engine.state.poolptr;
3132 engine.state.magicoffset =
3141 (*engine.state.strstart.offset(784) as integer - 9 * 16) as integer;
3142 engine.state.alignstate = 1000000 as integer;
3143 Ok(())
3144 })
3145 }
3146
3147 pub(crate) fn ensure_nativetext_capacity(
3148 engine: &mut PortableTexEngine<'_>,
3149 required: integer,
3150 ) {
3151 let required = required.max(0) as usize;
3152 if engine.state.nativetext_storage.len() < required {
3153 engine.state.nativetext_storage.resize(required, UTF16code::default());
3154 }
3155 engine.state.nativetext = pointer_or_null(&mut engine.state.nativetext_storage);
3156 }
3157
3158 unsafe fn init_etex_startup_primitives(&mut self) -> EngineFlow<()> {
3159 if !self.supports_etex() || self.is_xetex() {
3160 return Ok(());
3161 }
3162 self.state.nonewcontrolsequence = false_0 as boolean;
3163 (&mut *(self as *mut PortableTexEngine<'_>))
3164 .zprimitive(1360 as i32, 70 as i32 as quarterword, 3 as i32)?;
3165 (&mut *(self as *mut PortableTexEngine<'_>))
3166 .zprimitive(1361 as i32, 70 as i32 as quarterword, 6 as i32)?;
3167 (&mut *(self as *mut PortableTexEngine<'_>))
3168 .zprimitive(765 as i32, 108 as i32 as quarterword, 5 as i32)?;
3169 (&mut *(self as *mut PortableTexEngine<'_>))
3170 .zprimitive(1363 as i32, 72 as i32 as quarterword, 25067 as i32)?;
3171 (&mut *(self as *mut PortableTexEngine<'_>))
3172 .zprimitive(1364 as i32, 73 as i32 as quarterword, 27234 as i32)?;
3173 (&mut *(self as *mut PortableTexEngine<'_>))
3174 .zprimitive(1365 as i32, 73 as i32 as quarterword, 27235 as i32)?;
3175 (&mut *(self as *mut PortableTexEngine<'_>))
3176 .zprimitive(1366 as i32, 73 as i32 as quarterword, 27236 as i32)?;
3177 (&mut *(self as *mut PortableTexEngine<'_>))
3178 .zprimitive(1367 as i32, 73 as i32 as quarterword, 27237 as i32)?;
3179 (&mut *(self as *mut PortableTexEngine<'_>))
3180 .zprimitive(1368 as i32, 73 as i32 as quarterword, 27238 as i32)?;
3181 (&mut *(self as *mut PortableTexEngine<'_>))
3182 .zprimitive(1369 as i32, 73 as i32 as quarterword, 27239 as i32)?;
3183 (&mut *(self as *mut PortableTexEngine<'_>))
3184 .zprimitive(1370 as i32, 73 as i32 as quarterword, 27240 as i32)?;
3185 (&mut *(self as *mut PortableTexEngine<'_>))
3186 .zprimitive(1371 as i32, 73 as i32 as quarterword, 27241 as i32)?;
3187 (&mut *(self as *mut PortableTexEngine<'_>))
3188 .zprimitive(1372 as i32, 73 as i32 as quarterword, 27242 as i32)?;
3189 (&mut *(self as *mut PortableTexEngine<'_>))
3190 .zprimitive(1387 as i32, 70 as i32 as quarterword, 7 as i32)?;
3191 (&mut *(self as *mut PortableTexEngine<'_>))
3192 .zprimitive(1388 as i32, 70 as i32 as quarterword, 8 as i32)?;
3193 (&mut *(self as *mut PortableTexEngine<'_>))
3194 .zprimitive(1389 as i32, 70 as i32 as quarterword, 9 as i32)?;
3195 (&mut *(self as *mut PortableTexEngine<'_>))
3196 .zprimitive(1390 as i32, 70 as i32 as quarterword, 10 as i32)?;
3197 (&mut *(self as *mut PortableTexEngine<'_>))
3198 .zprimitive(1391 as i32, 70 as i32 as quarterword, 11 as i32)?;
3199 (&mut *(self as *mut PortableTexEngine<'_>))
3200 .zprimitive(1392 as i32, 70 as i32 as quarterword, 14 as i32)?;
3201 (&mut *(self as *mut PortableTexEngine<'_>))
3202 .zprimitive(1393 as i32, 70 as i32 as quarterword, 15 as i32)?;
3203 (&mut *(self as *mut PortableTexEngine<'_>))
3204 .zprimitive(1394 as i32, 70 as i32 as quarterword, 16 as i32)?;
3205 (&mut *(self as *mut PortableTexEngine<'_>))
3206 .zprimitive(1395 as i32, 70 as i32 as quarterword, 17 as i32)?;
3207 (&mut *(self as *mut PortableTexEngine<'_>))
3208 .zprimitive(1396 as i32, 70 as i32 as quarterword, 18 as i32)?;
3209 (&mut *(self as *mut PortableTexEngine<'_>))
3210 .zprimitive(1397 as i32, 70 as i32 as quarterword, 19 as i32)?;
3211 (&mut *(self as *mut PortableTexEngine<'_>))
3212 .zprimitive(1398 as i32, 70 as i32 as quarterword, 20 as i32)?;
3213 (&mut *(self as *mut PortableTexEngine<'_>))
3214 .zprimitive(1399 as i32, 19 as i32 as quarterword, 4 as i32)?;
3215 (&mut *(self as *mut PortableTexEngine<'_>))
3216 .zprimitive(1401 as i32, 19 as i32 as quarterword, 5 as i32)?;
3217 (&mut *(self as *mut PortableTexEngine<'_>))
3218 .zprimitive(1402 as i32, 109 as i32 as quarterword, 1 as i32)?;
3219 (&mut *(self as *mut PortableTexEngine<'_>))
3220 .zprimitive(1403 as i32, 109 as i32 as quarterword, 5 as i32)?;
3221 (&mut *(self as *mut PortableTexEngine<'_>))
3222 .zprimitive(1404 as i32, 19 as i32 as quarterword, 6 as i32)?;
3223 (&mut *(self as *mut PortableTexEngine<'_>))
3224 .zprimitive(1408 as i32, 82 as i32 as quarterword, 2 as i32)?;
3225 (&mut *(self as *mut PortableTexEngine<'_>))
3226 .zprimitive(908 as i32, 49 as i32 as quarterword, 1 as i32)?;
3227 (&mut *(self as *mut PortableTexEngine<'_>))
3228 .zprimitive(1412 as i32, 73 as i32 as quarterword, 27243 as i32)?;
3229 (&mut *(self as *mut PortableTexEngine<'_>))
3230 .zprimitive(1413 as i32, 33 as i32 as quarterword, 6 as i32)?;
3231 (&mut *(self as *mut PortableTexEngine<'_>))
3232 .zprimitive(1414 as i32, 33 as i32 as quarterword, 7 as i32)?;
3233 (&mut *(self as *mut PortableTexEngine<'_>))
3234 .zprimitive(1415 as i32, 33 as i32 as quarterword, 10 as i32)?;
3235 (&mut *(self as *mut PortableTexEngine<'_>))
3236 .zprimitive(1416 as i32, 33 as i32 as quarterword, 11 as i32)?;
3237 (&mut *(self as *mut PortableTexEngine<'_>))
3238 .zprimitive(1425 as i32, 104 as i32 as quarterword, 2 as i32)?;
3239 (&mut *(self as *mut PortableTexEngine<'_>))
3240 .zprimitive(1427 as i32, 96 as i32 as quarterword, 1 as i32)?;
3241 (&mut *(self as *mut PortableTexEngine<'_>))
3242 .zprimitive(799 as i32, 102 as i32 as quarterword, 1 as i32)?;
3243 (&mut *(self as *mut PortableTexEngine<'_>))
3244 .zprimitive(1428 as i32, 105 as i32 as quarterword, 17 as i32)?;
3245 (&mut *(self as *mut PortableTexEngine<'_>))
3246 .zprimitive(1429 as i32, 105 as i32 as quarterword, 18 as i32)?;
3247 (&mut *(self as *mut PortableTexEngine<'_>))
3248 .zprimitive(1430 as i32, 105 as i32 as quarterword, 19 as i32)?;
3249 (&mut *(self as *mut PortableTexEngine<'_>))
3250 .zprimitive(1217 as i32, 93 as i32 as quarterword, 8 as i32)?;
3251 (&mut *(self as *mut PortableTexEngine<'_>))
3252 .zprimitive(1436 as i32, 70 as i32 as quarterword, 25 as i32)?;
3253 (&mut *(self as *mut PortableTexEngine<'_>))
3254 .zprimitive(1437 as i32, 70 as i32 as quarterword, 26 as i32)?;
3255 (&mut *(self as *mut PortableTexEngine<'_>))
3256 .zprimitive(1438 as i32, 70 as i32 as quarterword, 27 as i32)?;
3257 (&mut *(self as *mut PortableTexEngine<'_>))
3258 .zprimitive(1439 as i32, 70 as i32 as quarterword, 28 as i32)?;
3259 (&mut *(self as *mut PortableTexEngine<'_>))
3260 .zprimitive(1443 as i32, 70 as i32 as quarterword, 12 as i32)?;
3261 (&mut *(self as *mut PortableTexEngine<'_>))
3262 .zprimitive(1444 as i32, 70 as i32 as quarterword, 13 as i32)?;
3263 (&mut *(self as *mut PortableTexEngine<'_>))
3264 .zprimitive(1445 as i32, 70 as i32 as quarterword, 21 as i32)?;
3265 (&mut *(self as *mut PortableTexEngine<'_>))
3266 .zprimitive(1446 as i32, 70 as i32 as quarterword, 22 as i32)?;
3267 (&mut *(self as *mut PortableTexEngine<'_>))
3268 .zprimitive(1447 as i32, 70 as i32 as quarterword, 23 as i32)?;
3269 (&mut *(self as *mut PortableTexEngine<'_>))
3270 .zprimitive(1448 as i32, 70 as i32 as quarterword, 24 as i32)?;
3271 (&mut *(self as *mut PortableTexEngine<'_>))
3272 .zprimitive(1449 as i32, 18 as i32 as quarterword, 5 as i32)?;
3273 (&mut *(self as *mut PortableTexEngine<'_>))
3274 .zprimitive(1450 as i32, 110 as i32 as quarterword, 5 as i32)?;
3275 (&mut *(self as *mut PortableTexEngine<'_>))
3276 .zprimitive(1451 as i32, 110 as i32 as quarterword, 6 as i32)?;
3277 (&mut *(self as *mut PortableTexEngine<'_>))
3278 .zprimitive(1452 as i32, 110 as i32 as quarterword, 7 as i32)?;
3279 (&mut *(self as *mut PortableTexEngine<'_>))
3280 .zprimitive(1453 as i32, 110 as i32 as quarterword, 8 as i32)?;
3281 (&mut *(self as *mut PortableTexEngine<'_>))
3282 .zprimitive(1454 as i32, 110 as i32 as quarterword, 9 as i32)?;
3283 (&mut *(self as *mut PortableTexEngine<'_>))
3284 .zprimitive(1458 as i32, 24 as i32 as quarterword, 2 as i32)?;
3285 (&mut *(self as *mut PortableTexEngine<'_>))
3286 .zprimitive(1459 as i32, 24 as i32 as quarterword, 3 as i32)?;
3287 (&mut *(self as *mut PortableTexEngine<'_>))
3288 .zprimitive(1460 as i32, 84 as i32 as quarterword, 25324 as i32)?;
3289 (&mut *(self as *mut PortableTexEngine<'_>))
3290 .zprimitive(1461 as i32, 84 as i32 as quarterword, 25325 as i32)?;
3291 (&mut *(self as *mut PortableTexEngine<'_>))
3292 .zprimitive(1462 as i32, 84 as i32 as quarterword, 25326 as i32)?;
3293 (&mut *(self as *mut PortableTexEngine<'_>))
3294 .zprimitive(1463 as i32, 84 as i32 as quarterword, 25327 as i32)?;
3295 self.state.eTeXmode = 1 as eightbits;
3296 Ok(())
3297 }
3298 unsafe fn init_xetex_startup_primitives(&mut self) -> EngineFlow<()> {
3299 if !self.is_xetex() {
3300 return Ok(());
3301 }
3302 self.state.nonewcontrolsequence = false_0 as boolean;
3303 (&mut *(self as *mut PortableTexEngine<'_>))
3304 .zprimitive(66755 as i64 as strnumber, 59 as i32 as quarterword, 41 as i32)?;
3305 (&mut *(self as *mut PortableTexEngine<'_>))
3306 .zprimitive(66756 as i64 as strnumber, 59 as i32 as quarterword, 42 as i32)?;
3307 (&mut *(self as *mut PortableTexEngine<'_>))
3308 .zprimitive(66757 as i64 as strnumber, 59 as i32 as quarterword, 43 as i32)?;
3309 (&mut *(self as *mut PortableTexEngine<'_>))
3310 .zprimitive(66758 as i64 as strnumber, 59 as i32 as quarterword, 46 as i32)?;
3311 (&mut *(self as *mut PortableTexEngine<'_>))
3312 .zprimitive(
3313 66759 as i64 as strnumber,
3314 73 as i32 as quarterword,
3315 1206306 as i64 as halfword,
3316 )?;
3317 (&mut *(self as *mut PortableTexEngine<'_>))
3318 .zprimitive(66760 as i64 as strnumber, 59 as i32 as quarterword, 23 as i32)?;
3319 (&mut *(self as *mut PortableTexEngine<'_>))
3320 .zprimitive(66816 as i64 as strnumber, 71 as i32 as quarterword, 3 as i32)?;
3321 (&mut *(self as *mut PortableTexEngine<'_>))
3322 .zprimitive(66817 as i64 as strnumber, 71 as i32 as quarterword, 19 as i32)?;
3323 (&mut *(self as *mut PortableTexEngine<'_>))
3324 .zprimitive(66115 as i64 as strnumber, 111 as i32 as quarterword, 5 as i32)?;
3325 (&mut *(self as *mut PortableTexEngine<'_>))
3326 .zprimitive(66818 as i64 as strnumber, 71 as i32 as quarterword, 27 as i32)?;
3327 (&mut *(self as *mut PortableTexEngine<'_>))
3328 .zprimitive(
3329 66819 as i64 as strnumber,
3330 111 as i32 as quarterword,
3331 33 as i32,
3332 )?;
3333 (&mut *(self as *mut PortableTexEngine<'_>))
3334 .zprimitive(66820 as i64 as strnumber, 71 as i32 as quarterword, 28 as i32)?;
3335 (&mut *(self as *mut PortableTexEngine<'_>))
3336 .zprimitive(66821 as i64 as strnumber, 71 as i32 as quarterword, 29 as i32)?;
3337 (&mut *(self as *mut PortableTexEngine<'_>))
3338 .zprimitive(66822 as i64 as strnumber, 71 as i32 as quarterword, 30 as i32)?;
3339 (&mut *(self as *mut PortableTexEngine<'_>))
3340 .zprimitive(66823 as i64 as strnumber, 71 as i32 as quarterword, 31 as i32)?;
3341 (&mut *(self as *mut PortableTexEngine<'_>))
3342 .zprimitive(66824 as i64 as strnumber, 71 as i32 as quarterword, 32 as i32)?;
3343 (&mut *(self as *mut PortableTexEngine<'_>))
3344 .zprimitive(66825 as i64 as strnumber, 71 as i32 as quarterword, 33 as i32)?;
3345 (&mut *(self as *mut PortableTexEngine<'_>))
3346 .zprimitive(66826 as i64 as strnumber, 71 as i32 as quarterword, 34 as i32)?;
3347 (&mut *(self as *mut PortableTexEngine<'_>))
3348 .zprimitive(66827 as i64 as strnumber, 71 as i32 as quarterword, 35 as i32)?;
3349 (&mut *(self as *mut PortableTexEngine<'_>))
3350 .zprimitive(66828 as i64 as strnumber, 71 as i32 as quarterword, 36 as i32)?;
3351 (&mut *(self as *mut PortableTexEngine<'_>))
3352 .zprimitive(66829 as i64 as strnumber, 71 as i32 as quarterword, 37 as i32)?;
3353 (&mut *(self as *mut PortableTexEngine<'_>))
3354 .zprimitive(66830 as i64 as strnumber, 71 as i32 as quarterword, 38 as i32)?;
3355 (&mut *(self as *mut PortableTexEngine<'_>))
3356 .zprimitive(66831 as i64 as strnumber, 71 as i32 as quarterword, 39 as i32)?;
3357 (&mut *(self as *mut PortableTexEngine<'_>))
3358 .zprimitive(66832 as i64 as strnumber, 71 as i32 as quarterword, 40 as i32)?;
3359 (&mut *(self as *mut PortableTexEngine<'_>))
3360 .zprimitive(66833 as i64 as strnumber, 71 as i32 as quarterword, 41 as i32)?;
3361 (&mut *(self as *mut PortableTexEngine<'_>))
3362 .zprimitive(66834 as i64 as strnumber, 71 as i32 as quarterword, 42 as i32)?;
3363 (&mut *(self as *mut PortableTexEngine<'_>))
3364 .zprimitive(
3365 66835 as i64 as strnumber,
3366 111 as i32 as quarterword,
3367 34 as i32,
3368 )?;
3369 (&mut *(self as *mut PortableTexEngine<'_>))
3370 .zprimitive(
3371 66836 as i64 as strnumber,
3372 111 as i32 as quarterword,
3373 35 as i32,
3374 )?;
3375 (&mut *(self as *mut PortableTexEngine<'_>))
3376 .zprimitive(
3377 66837 as i64 as strnumber,
3378 111 as i32 as quarterword,
3379 36 as i32,
3380 )?;
3381 (&mut *(self as *mut PortableTexEngine<'_>))
3382 .zprimitive(66838 as i64 as strnumber, 71 as i32 as quarterword, 43 as i32)?;
3383 (&mut *(self as *mut PortableTexEngine<'_>))
3384 .zprimitive(66839 as i64 as strnumber, 71 as i32 as quarterword, 44 as i32)?;
3385 (&mut *(self as *mut PortableTexEngine<'_>))
3386 .zprimitive(66840 as i64 as strnumber, 71 as i32 as quarterword, 45 as i32)?;
3387 (&mut *(self as *mut PortableTexEngine<'_>))
3388 .zprimitive(66841 as i64 as strnumber, 71 as i32 as quarterword, 46 as i32)?;
3389 (&mut *(self as *mut PortableTexEngine<'_>))
3390 .zprimitive(66842 as i64 as strnumber, 71 as i32 as quarterword, 47 as i32)?;
3391 (&mut *(self as *mut PortableTexEngine<'_>))
3392 .zprimitive(66843 as i64 as strnumber, 71 as i32 as quarterword, 48 as i32)?;
3393 (&mut *(self as *mut PortableTexEngine<'_>))
3394 .zprimitive(66844 as i64 as strnumber, 71 as i32 as quarterword, 49 as i32)?;
3395 (&mut *(self as *mut PortableTexEngine<'_>))
3396 .zprimitive(66845 as i64 as strnumber, 71 as i32 as quarterword, 50 as i32)?;
3397 (&mut *(self as *mut PortableTexEngine<'_>))
3398 .zprimitive(66846 as i64 as strnumber, 71 as i32 as quarterword, 55 as i32)?;
3399 (&mut *(self as *mut PortableTexEngine<'_>))
3400 .zprimitive(
3401 66847 as i64 as strnumber,
3402 111 as i32 as quarterword,
3403 37 as i32,
3404 )?;
3405 (&mut *(self as *mut PortableTexEngine<'_>))
3406 .zprimitive(66848 as i64 as strnumber, 71 as i32 as quarterword, 51 as i32)?;
3407 (&mut *(self as *mut PortableTexEngine<'_>))
3408 .zprimitive(66849 as i64 as strnumber, 71 as i32 as quarterword, 52 as i32)?;
3409 (&mut *(self as *mut PortableTexEngine<'_>))
3410 .zprimitive(66850 as i64 as strnumber, 71 as i32 as quarterword, 53 as i32)?;
3411 (&mut *(self as *mut PortableTexEngine<'_>))
3412 .zprimitive(66851 as i64 as strnumber, 71 as i32 as quarterword, 54 as i32)?;
3413 (&mut *(self as *mut PortableTexEngine<'_>))
3414 .zprimitive(
3415 66861 as i64 as strnumber,
3416 73 as i32 as quarterword,
3417 1206305 as i64 as halfword,
3418 )?;
3419 (&mut *(self as *mut PortableTexEngine<'_>))
3420 .zprimitive(
3421 66862 as i64 as strnumber,
3422 74 as i32 as quarterword,
3423 7892325 as i64 as halfword,
3424 )?;
3425 (&mut *(self as *mut PortableTexEngine<'_>))
3426 .zprimitive(
3427 66863 as i64 as strnumber,
3428 74 as i32 as quarterword,
3429 7892326 as i64 as halfword,
3430 )?;
3431 (&mut *(self as *mut PortableTexEngine<'_>))
3432 .zprimitive(
3433 66864 as i64 as strnumber,
3434 74 as i32 as quarterword,
3435 7892327 as i64 as halfword,
3436 )?;
3437 (&mut *(self as *mut PortableTexEngine<'_>))
3438 .zprimitive(
3439 66865 as i64 as strnumber,
3440 74 as i32 as quarterword,
3441 7892328 as i64 as halfword,
3442 )?;
3443 (&mut *(self as *mut PortableTexEngine<'_>))
3444 .zprimitive(
3445 66866 as i64 as strnumber,
3446 74 as i32 as quarterword,
3447 7892329 as i64 as halfword,
3448 )?;
3449 (&mut *(self as *mut PortableTexEngine<'_>))
3450 .zprimitive(
3451 66867 as i64 as strnumber,
3452 74 as i32 as quarterword,
3453 7892330 as i64 as halfword,
3454 )?;
3455 (&mut *(self as *mut PortableTexEngine<'_>))
3456 .zprimitive(
3457 66868 as i64 as strnumber,
3458 74 as i32 as quarterword,
3459 7892331 as i64 as halfword,
3460 )?;
3461 (&mut *(self as *mut PortableTexEngine<'_>))
3462 .zprimitive(
3463 66869 as i64 as strnumber,
3464 74 as i32 as quarterword,
3465 7892332 as i64 as halfword,
3466 )?;
3467 (&mut *(self as *mut PortableTexEngine<'_>))
3468 .zprimitive(
3469 66870 as i64 as strnumber,
3470 74 as i32 as quarterword,
3471 7892333 as i64 as halfword,
3472 )?;
3473 (&mut *(self as *mut PortableTexEngine<'_>))
3474 .zprimitive(
3475 66871 as i64 as strnumber,
3476 74 as i32 as quarterword,
3477 7892335 as i64 as halfword,
3478 )?;
3479 (&mut *(self as *mut PortableTexEngine<'_>))
3480 .zprimitive(66885 as i64 as strnumber, 71 as i32 as quarterword, 20 as i32)?;
3481 (&mut *(self as *mut PortableTexEngine<'_>))
3482 .zprimitive(66886 as i64 as strnumber, 71 as i32 as quarterword, 21 as i32)?;
3483 (&mut *(self as *mut PortableTexEngine<'_>))
3484 .zprimitive(66887 as i64 as strnumber, 71 as i32 as quarterword, 22 as i32)?;
3485 (&mut *(self as *mut PortableTexEngine<'_>))
3486 .zprimitive(66888 as i64 as strnumber, 71 as i32 as quarterword, 23 as i32)?;
3487 (&mut *(self as *mut PortableTexEngine<'_>))
3488 .zprimitive(66889 as i64 as strnumber, 71 as i32 as quarterword, 24 as i32)?;
3489 (&mut *(self as *mut PortableTexEngine<'_>))
3490 .zprimitive(66890 as i64 as strnumber, 71 as i32 as quarterword, 56 as i32)?;
3491 (&mut *(self as *mut PortableTexEngine<'_>))
3492 .zprimitive(66891 as i64 as strnumber, 71 as i32 as quarterword, 57 as i32)?;
3493 (&mut *(self as *mut PortableTexEngine<'_>))
3494 .zprimitive(66892 as i64 as strnumber, 71 as i32 as quarterword, 58 as i32)?;
3495 (&mut *(self as *mut PortableTexEngine<'_>))
3496 .zprimitive(66893 as i64 as strnumber, 71 as i32 as quarterword, 59 as i32)?;
3497 (&mut *(self as *mut PortableTexEngine<'_>))
3498 .zprimitive(66894 as i64 as strnumber, 71 as i32 as quarterword, 60 as i32)?;
3499 (&mut *(self as *mut PortableTexEngine<'_>))
3500 .zprimitive(66895 as i64 as strnumber, 71 as i32 as quarterword, 61 as i32)?;
3501 (&mut *(self as *mut PortableTexEngine<'_>))
3502 .zprimitive(66896 as i64 as strnumber, 71 as i32 as quarterword, 62 as i32)?;
3503 (&mut *(self as *mut PortableTexEngine<'_>))
3504 .zprimitive(66897 as i64 as strnumber, 19 as i32 as quarterword, 4 as i32)?;
3505 (&mut *(self as *mut PortableTexEngine<'_>))
3506 .zprimitive(66899 as i64 as strnumber, 19 as i32 as quarterword, 5 as i32)?;
3507 (&mut *(self as *mut PortableTexEngine<'_>))
3508 .zprimitive(66900 as i64 as strnumber, 112 as i32 as quarterword, 1 as i32)?;
3509 (&mut *(self as *mut PortableTexEngine<'_>))
3510 .zprimitive(66901 as i64 as strnumber, 112 as i32 as quarterword, 5 as i32)?;
3511 (&mut *(self as *mut PortableTexEngine<'_>))
3512 .zprimitive(66902 as i64 as strnumber, 19 as i32 as quarterword, 6 as i32)?;
3513 (&mut *(self as *mut PortableTexEngine<'_>))
3514 .zprimitive(66906 as i64 as strnumber, 83 as i32 as quarterword, 2 as i32)?;
3515 (&mut *(self as *mut PortableTexEngine<'_>))
3516 .zprimitive(66288 as i64 as strnumber, 49 as i32 as quarterword, 1 as i32)?;
3517 (&mut *(self as *mut PortableTexEngine<'_>))
3518 .zprimitive(
3519 66910 as i64 as strnumber,
3520 74 as i32 as quarterword,
3521 7892334 as i64 as halfword,
3522 )?;
3523 (&mut *(self as *mut PortableTexEngine<'_>))
3524 .zprimitive(
3525 66911 as i64 as strnumber,
3526 74 as i32 as quarterword,
3527 7892339 as i64 as halfword,
3528 )?;
3529 (&mut *(self as *mut PortableTexEngine<'_>))
3530 .zprimitive(
3531 66912 as i64 as strnumber,
3532 74 as i32 as quarterword,
3533 7892341 as i64 as halfword,
3534 )?;
3535 (&mut *(self as *mut PortableTexEngine<'_>))
3536 .zprimitive(
3537 66913 as i64 as strnumber,
3538 74 as i32 as quarterword,
3539 7892342 as i64 as halfword,
3540 )?;
3541 (&mut *(self as *mut PortableTexEngine<'_>))
3542 .zprimitive(
3543 66914 as i64 as strnumber,
3544 74 as i32 as quarterword,
3545 7892343 as i64 as halfword,
3546 )?;
3547 (&mut *(self as *mut PortableTexEngine<'_>))
3548 .zprimitive(
3549 66915 as i64 as strnumber,
3550 74 as i32 as quarterword,
3551 7892340 as i64 as halfword,
3552 )?;
3553 (&mut *(self as *mut PortableTexEngine<'_>))
3554 .zprimitive(
3555 66916 as i64 as strnumber,
3556 74 as i32 as quarterword,
3557 7892344 as i64 as halfword,
3558 )?;
3559 (&mut *(self as *mut PortableTexEngine<'_>))
3560 .zprimitive(
3561 66917 as i64 as strnumber,
3562 74 as i32 as quarterword,
3563 7892347 as i64 as halfword,
3564 )?;
3565 (&mut *(self as *mut PortableTexEngine<'_>))
3566 .zprimitive(
3567 66918 as i64 as strnumber,
3568 74 as i32 as quarterword,
3569 7892348 as i64 as halfword,
3570 )?;
3571 (&mut *(self as *mut PortableTexEngine<'_>))
3572 .zprimitive(
3573 66919 as i64 as strnumber,
3574 74 as i32 as quarterword,
3575 7892349 as i64 as halfword,
3576 )?;
3577 (&mut *(self as *mut PortableTexEngine<'_>))
3578 .zprimitive(
3579 66920 as i64 as strnumber,
3580 74 as i32 as quarterword,
3581 7892350 as i64 as halfword,
3582 )?;
3583 (&mut *(self as *mut PortableTexEngine<'_>))
3584 .zprimitive(66761 as i64 as strnumber, 59 as i32 as quarterword, 44 as i32)?;
3585 (&mut *(self as *mut PortableTexEngine<'_>))
3586 .zprimitive(66762 as i64 as strnumber, 59 as i32 as quarterword, 45 as i32)?;
3587 (&mut *(self as *mut PortableTexEngine<'_>))
3588 .zprimitive(66921 as i64 as strnumber, 33 as i32 as quarterword, 6 as i32)?;
3589 (&mut *(self as *mut PortableTexEngine<'_>))
3590 .zprimitive(66922 as i64 as strnumber, 33 as i32 as quarterword, 7 as i32)?;
3591 (&mut *(self as *mut PortableTexEngine<'_>))
3592 .zprimitive(66923 as i64 as strnumber, 33 as i32 as quarterword, 10 as i32)?;
3593 (&mut *(self as *mut PortableTexEngine<'_>))
3594 .zprimitive(66924 as i64 as strnumber, 33 as i32 as quarterword, 11 as i32)?;
3595 (&mut *(self as *mut PortableTexEngine<'_>))
3596 .zprimitive(66933 as i64 as strnumber, 107 as i32 as quarterword, 2 as i32)?;
3597 (&mut *(self as *mut PortableTexEngine<'_>))
3598 .zprimitive(66935 as i64 as strnumber, 98 as i32 as quarterword, 1 as i32)?;
3599 (&mut *(self as *mut PortableTexEngine<'_>))
3600 .zprimitive(66164 as i64 as strnumber, 105 as i32 as quarterword, 1 as i32)?;
3601 (&mut *(self as *mut PortableTexEngine<'_>))
3602 .zprimitive(
3603 66936 as i64 as strnumber,
3604 108 as i32 as quarterword,
3605 17 as i32,
3606 )?;
3607 (&mut *(self as *mut PortableTexEngine<'_>))
3608 .zprimitive(
3609 66937 as i64 as strnumber,
3610 108 as i32 as quarterword,
3611 18 as i32,
3612 )?;
3613 (&mut *(self as *mut PortableTexEngine<'_>))
3614 .zprimitive(
3615 66938 as i64 as strnumber,
3616 108 as i32 as quarterword,
3617 19 as i32,
3618 )?;
3619 (&mut *(self as *mut PortableTexEngine<'_>))
3620 .zprimitive(
3621 66939 as i64 as strnumber,
3622 108 as i32 as quarterword,
3623 20 as i32,
3624 )?;
3625 (&mut *(self as *mut PortableTexEngine<'_>))
3626 .zprimitive(66623 as i64 as strnumber, 95 as i32 as quarterword, 8 as i32)?;
3627 (&mut *(self as *mut PortableTexEngine<'_>))
3628 .zprimitive(66945 as i64 as strnumber, 71 as i32 as quarterword, 67 as i32)?;
3629 (&mut *(self as *mut PortableTexEngine<'_>))
3630 .zprimitive(66946 as i64 as strnumber, 71 as i32 as quarterword, 68 as i32)?;
3631 (&mut *(self as *mut PortableTexEngine<'_>))
3632 .zprimitive(66947 as i64 as strnumber, 71 as i32 as quarterword, 69 as i32)?;
3633 (&mut *(self as *mut PortableTexEngine<'_>))
3634 .zprimitive(66948 as i64 as strnumber, 71 as i32 as quarterword, 70 as i32)?;
3635 (&mut *(self as *mut PortableTexEngine<'_>))
3636 .zprimitive(66952 as i64 as strnumber, 71 as i32 as quarterword, 25 as i32)?;
3637 (&mut *(self as *mut PortableTexEngine<'_>))
3638 .zprimitive(66953 as i64 as strnumber, 71 as i32 as quarterword, 26 as i32)?;
3639 (&mut *(self as *mut PortableTexEngine<'_>))
3640 .zprimitive(66954 as i64 as strnumber, 71 as i32 as quarterword, 63 as i32)?;
3641 (&mut *(self as *mut PortableTexEngine<'_>))
3642 .zprimitive(66955 as i64 as strnumber, 71 as i32 as quarterword, 64 as i32)?;
3643 (&mut *(self as *mut PortableTexEngine<'_>))
3644 .zprimitive(66956 as i64 as strnumber, 71 as i32 as quarterword, 65 as i32)?;
3645 (&mut *(self as *mut PortableTexEngine<'_>))
3646 .zprimitive(66957 as i64 as strnumber, 71 as i32 as quarterword, 66 as i32)?;
3647 (&mut *(self as *mut PortableTexEngine<'_>))
3648 .zprimitive(66958 as i64 as strnumber, 18 as i32 as quarterword, 5 as i32)?;
3649 (&mut *(self as *mut PortableTexEngine<'_>))
3650 .zprimitive(66959 as i64 as strnumber, 113 as i32 as quarterword, 5 as i32)?;
3651 (&mut *(self as *mut PortableTexEngine<'_>))
3652 .zprimitive(66960 as i64 as strnumber, 113 as i32 as quarterword, 6 as i32)?;
3653 (&mut *(self as *mut PortableTexEngine<'_>))
3654 .zprimitive(66961 as i64 as strnumber, 113 as i32 as quarterword, 7 as i32)?;
3655 (&mut *(self as *mut PortableTexEngine<'_>))
3656 .zprimitive(66962 as i64 as strnumber, 113 as i32 as quarterword, 8 as i32)?;
3657 (&mut *(self as *mut PortableTexEngine<'_>))
3658 .zprimitive(66963 as i64 as strnumber, 113 as i32 as quarterword, 9 as i32)?;
3659 (&mut *(self as *mut PortableTexEngine<'_>))
3660 .zprimitive(66968 as i64 as strnumber, 24 as i32 as quarterword, 2 as i32)?;
3661 (&mut *(self as *mut PortableTexEngine<'_>))
3662 .zprimitive(66969 as i64 as strnumber, 24 as i32 as quarterword, 3 as i32)?;
3663 (&mut *(self as *mut PortableTexEngine<'_>))
3664 .zprimitive(
3665 66970 as i64 as strnumber,
3666 85 as i32 as quarterword,
3667 1206563 as i64 as halfword,
3668 )?;
3669 (&mut *(self as *mut PortableTexEngine<'_>))
3670 .zprimitive(
3671 66971 as i64 as strnumber,
3672 85 as i32 as quarterword,
3673 1206564 as i64 as halfword,
3674 )?;
3675 (&mut *(self as *mut PortableTexEngine<'_>))
3676 .zprimitive(
3677 66972 as i64 as strnumber,
3678 85 as i32 as quarterword,
3679 1206565 as i64 as halfword,
3680 )?;
3681 (&mut *(self as *mut PortableTexEngine<'_>))
3682 .zprimitive(
3683 66973 as i64 as strnumber,
3684 85 as i32 as quarterword,
3685 1206566 as i64 as halfword,
3686 )?;
3687 if *self.state.buffer.offset(self.state.curinput.locfield as isize) == 42 as i32
3688 {
3689 self.state.curinput.locfield += 1;
3690 }
3691 self.state.eTeXmode = 1 as eightbits;
3692 self.state.maxregnum = 32767 as i32 as halfword;
3693 self.state.maxreghelpline = 66965 as i64 as strnumber;
3694 Ok(())
3695 }
3696
3697 pub fn begin_primary_input(self: &mut Self, name: &str, bytes: Vec<u8>) -> bool {
3698 self.last_abort_status = None;
3703 self.last_error_message = None;
3704 match unsafe { self.begin_primary_input_raw(name, bytes) } {
3705 Ok(started) => started != 0,
3706 Err(EngineBreak::Abort(EngineAbort { status })) => {
3707 self.last_abort_status = Some(status);
3708 false
3709 }
3710 Err(EngineBreak::Error(error)) => {
3711 self.last_error_message = Some(error.message);
3712 false
3713 }
3714 }
3715 }
3716
3717 pub fn run_main_control(self: &mut Self) -> bool {
3718 self.catch_engine_abort(|engine| unsafe { engine.maincontrol() })
3719 }
3720
3721 pub fn run_format_initialization(self: &mut Self) -> bool {
3722 self.format_initialization = true;
3723 let completed = self.catch_engine_abort(|engine| unsafe { engine.maincontrol() });
3724 self.format_initialization = false;
3725 completed
3726 }
3727
3728 pub fn begin_fragment_capture(self: &mut Self) {
3729 self.fragment_capture_enabled = true;
3730 self.captured_fragment_root = None;
3731 self.hostbox_records.clear();
3733 }
3734
3735 pub fn end_fragment_capture(self: &mut Self) {
3736 self.fragment_capture_enabled = false;
3737 }
3738
3739 fn catch_engine_abort<F>(self: &mut Self, run: F) -> bool
3740 where
3741 F: FnOnce(&mut Self) -> EngineFlow<()>,
3742 {
3743 self.last_abort_status = None;
3749 self.last_error_message = None;
3750 match run(self) {
3751 Ok(()) => self.last_abort_status.is_none(),
3752 Err(EngineBreak::Abort(EngineAbort { status: 0 })) => {
3753 self.last_abort_status = None;
3754 true
3755 }
3756 Err(EngineBreak::Abort(EngineAbort { status })) => {
3757 self.last_abort_status = Some(status);
3758 false
3759 }
3760 Err(EngineBreak::Error(error)) => {
3763 self.last_error_message = Some(error.message);
3764 false
3765 }
3766 }
3767 }
3768
3769 pub fn snapshot_format(&self) -> PortableFormatImage {
3770 PortableFormatImage::from_engine_state(self.state.as_ref())
3771 }
3772
3773 #[must_use]
3782 pub fn into_format(self) -> PortableFormatImage {
3783 let mut state = self.state;
3789 state.seal_as_format_snapshot();
3790 PortableFormatImage::from_sealed_state(state)
3791 }
3792
3793 pub fn finalize_trie(self: &mut Self) {
3801 if self.state.trienotready != 0 && !self.state.triehash.is_null() {
3803 let saved = self.format_initialization;
3804 self.format_initialization = false;
3805 let _ = unsafe { self.inittrie() };
3806 self.format_initialization = saved;
3807 }
3808 }
3809
3810 pub fn resource_request_count(&self) -> usize {
3811 self.resource_requests
3812 }
3813
3814 pub fn resource_request_records(&self) -> &[PortableResourceRequestRecord] {
3815 self.resource_request_records.as_slice()
3816 }
3817
3818 pub fn transcript_bytes(&self) -> &[u8] {
3819 self.transcript_bytes.as_slice()
3820 }
3821
3822 pub fn primary_input_source_span(&self) -> Option<PortableSourceSpan> {
3825 if !self.state.source_tracking {
3826 return None;
3827 }
3828 let primary = self.state.src_primary_name;
3829 let raw = self
3830 .state
3831 .src_spans
3832 .iter()
3833 .find(|raw| raw.name == primary)?;
3834 let name = unsafe { self.pool_string(raw.name) }?;
3835 Some(PortableSourceSpan {
3836 name,
3837 start: raw.start,
3838 end: raw.end,
3839 role: raw.role,
3840 })
3841 }
3842
3843 pub fn node_source_spans(&self) -> &[PortableNodeSourceSpan] {
3848 &[]
3849 }
3850
3851 pub fn stripped_page_build_count(&self) -> usize {
3852 self.stripped_page_builds
3853 }
3854
3855 pub fn stripped_shipout_count(&self) -> usize {
3856 self.stripped_shipouts
3857 }
3858
3859 pub fn stripped_special_output_count(&self) -> usize {
3860 self.stripped_special_outputs
3861 }
3862
3863 pub fn stripped_picture_load_count(&self) -> usize {
3864 self.stripped_picture_loads
3865 }
3866
3867 pub fn stripped_source_special_count(&self) -> usize {
3868 self.stripped_source_specials
3869 }
3870
3871 pub fn stripped_write_whatsit_diagnostic_count(&self) -> usize {
3872 self.stripped_write_whatsit_diagnostics
3873 }
3874
3875 pub fn stripped_pdf_extension_count(&self) -> usize {
3876 self.stripped_pdf_extensions
3877 }
3878
3879 pub fn stripped_page_top_prune_count(&self) -> usize {
3880 self.stripped_page_top_prunes
3881 }
3882
3883 pub fn last_stripped_shipout_box(&self) -> Option<PortableNodeHandle> {
3884 self.last_stripped_shipout_box
3885 }
3886
3887 pub fn captured_fragment_root(&self) -> Option<PortableNodeHandle> {
3888 self.captured_fragment_root
3889 }
3890
3891 pub fn host_box_record(&self, index: usize) -> Option<&PortableHostBox> {
3893 self.hostbox_records.get(index)
3894 }
3895
3896 pub fn font_at_size(&self, font: integer) -> integer {
3899 if font < 0 {
3900 return 0;
3901 }
3902 self.state
3903 .fontsize_storage
3904 .get(font as usize)
3905 .copied()
3906 .unwrap_or(0)
3907 }
3908
3909 pub fn font_name(&self, font: integer) -> Option<String> {
3915 if font < 0 {
3916 return None;
3917 }
3918 let name = self.state.fontname_storage.get(font as usize).copied()?;
3919 unsafe { self.pool_string(name) }
3922 }
3923
3924 pub fn native_font_spec(&self, font: integer) -> Option<String> {
3928 let handle = Self::font_handle_for_number(self, font)?;
3929 self.fonts.font_spec(handle)
3930 }
3931
3932 pub fn native_font_table(&self) -> Vec<(PortableFontHandle, String, i32)> {
3935 self.fonts.font_table()
3936 }
3937
3938 pub fn restore_native_font_table(
3943 self: &mut Self,
3944 table: &[(PortableFontHandle, String, i32)],
3945 ) -> bool {
3946 self.fonts.restore_font_table(table)
3947 }
3948
3949 pub fn last_abort_status(&self) -> Option<integer> {
3950 self.last_abort_status
3951 }
3952
3953 pub fn last_error_message(&self) -> Option<&str> {
3957 self.last_error_message.as_deref()
3958 }
3959
3960 pub fn set_sandbox(self: &mut Self, on: bool) {
3965 self.sandbox = on;
3966 self.sandbox_math_depth = 0;
3967 self.sandbox_math_opened = false;
3968 self.sandbox_ops = 0;
3969 }
3970
3971 pub(crate) fn capture_last_error_message(&self) -> String {
3978 let transcript = core::str::from_utf8(&self.transcript_bytes).unwrap_or("");
3979 for raw in transcript.lines().rev() {
3980 let collapsed = collapse_doubled_line(raw.trim());
3981 let line = collapsed.as_deref().unwrap_or(raw).trim();
3982 if let Some(rest) = line.strip_prefix("! ") {
3983 return rest.trim_end_matches('.').trim().into();
3984 }
3985 }
3986 "TeX error".into()
3987 }
3988
3989 pub fn snapshot_node(&self, handle: PortableNodeHandle) -> Option<PortableNodeSnapshot> {
3990 let node = handle.0 as halfword;
3991 let word = self.node_word(node, 0)?;
3992 let raw_kind = unsafe { word.hh.u.B0 as i32 };
3993 let subtype = unsafe { word.hh.u.B1 as i32 };
3994 let kind = self.node_kind(raw_kind, node, subtype);
3995 let link = self.node_link(node);
3996 let is_character = node >= self.state.himemmin;
3997 let native_word4 = if matches!(kind, PortableNodeKind::NativeWord | PortableNodeKind::NativeGlyph) {
3998 self.node_word(node, 4)
3999 } else {
4000 None
4001 };
4002 let font = if is_character {
4003 raw_kind
4004 } else {
4005 native_word4.map_or(0, |word| unsafe { word.v.QQQQ.u.B1 as i32 })
4006 };
4007 let character = if is_character {
4008 subtype
4009 } else if matches!(kind, PortableNodeKind::HostBoxRef) {
4010 self.node_word(node, 1).map_or(0, |word| unsafe { word.u.CINT })
4012 } else {
4013 native_word4.map_or(0, |word| unsafe { word.v.QQQQ.u.B2 as i32 })
4014 };
4015 let (width, height, depth, shift, list) = match raw_kind {
4016 _ if is_character => (
4017 self.character_width(font, character).unwrap_or_default(),
4018 0,
4019 0,
4020 0,
4021 None,
4022 ),
4023 0 | 1 | 13 => (
4024 self.node_scaled(node, 1).unwrap_or_default(),
4025 self.node_scaled(node, 3).unwrap_or_default(),
4026 self.node_scaled(node, 2).unwrap_or_default(),
4027 self.node_scaled(node, 4).unwrap_or_default(),
4028 self.node_field_link(node, 5),
4029 ),
4030 2 => (
4031 self.node_scaled(node, 1).unwrap_or_default(),
4032 self.node_scaled(node, 3).unwrap_or_default(),
4033 self.node_scaled(node, 2).unwrap_or_default(),
4034 0,
4035 None,
4036 ),
4037 10 => (
4038 self.glue_amount(node).unwrap_or_default(),
4039 0,
4040 0,
4041 0,
4042 None,
4043 ),
4044 11 => (
4045 self.node_scaled(node, 1).unwrap_or_default(),
4046 0,
4047 0,
4048 0,
4049 None,
4050 ),
4051 8 if matches!(kind, PortableNodeKind::NativeWord | PortableNodeKind::NativeGlyph) => (
4052 self.node_scaled(node, 1).unwrap_or_default(),
4053 self.node_scaled(node, 3).unwrap_or_default(),
4054 self.node_scaled(node, 2).unwrap_or_default(),
4055 0,
4056 None,
4057 ),
4058 _ => (0, 0, 0, 0, None),
4059 };
4060 let native_glyphs = if matches!(kind, PortableNodeKind::NativeWord | PortableNodeKind::NativeGlyph) {
4061 self.native_glyph_infos
4062 .get(&node)
4063 .map(|info| info.glyphs.clone())
4064 .unwrap_or_default()
4065 } else {
4066 Vec::new()
4067 };
4068
4069 let (glue_set, glue_sign, glue_order) = match raw_kind {
4074 0 | 1 | 13 => (
4075 self.node_word(node, 6).map_or(0.0, |word| unsafe { word.gr }),
4076 self.node_word(node, 5)
4077 .map_or(0, |word| unsafe { word.hh.u.B0 as i32 }),
4078 self.node_word(node, 5)
4079 .map_or(0, |word| unsafe { word.hh.u.B1 as i32 }),
4080 ),
4081 _ => (0.0, 0, 0),
4082 };
4083 let (glue_stretch, glue_shrink, glue_stretch_order, glue_shrink_order) = if raw_kind == 10 {
4085 match self.node_word(node, 1).map(|word| unsafe { word.hh.v.LH }) {
4086 Some(spec) => (
4087 self.node_scaled(spec, 2).unwrap_or_default(),
4088 self.node_scaled(spec, 3).unwrap_or_default(),
4089 self.node_word(spec, 0)
4090 .map_or(0, |word| unsafe { word.hh.u.B0 as i32 }),
4091 self.node_word(spec, 0)
4092 .map_or(0, |word| unsafe { word.hh.u.B1 as i32 }),
4093 ),
4094 None => (0, 0, 0, 0),
4095 }
4096 } else {
4097 (0, 0, 0, 0)
4098 };
4099
4100 Some(PortableNodeSnapshot {
4101 handle,
4102 kind,
4103 subtype,
4104 source: self.resolve_node_src(node),
4105 link,
4106 font,
4107 character,
4108 width,
4109 height,
4110 depth,
4111 shift,
4112 list,
4113 native_glyphs,
4114 glue_set,
4115 glue_sign,
4116 glue_order,
4117 glue_stretch,
4118 glue_shrink,
4119 glue_stretch_order,
4120 glue_shrink_order,
4121 })
4122 }
4123
4124 fn node_kind(&self, raw_kind: i32, node: halfword, subtype: i32) -> PortableNodeKind {
4125 if node >= self.state.himemmin {
4126 return PortableNodeKind::Character;
4127 }
4128
4129 match raw_kind {
4130 0 => PortableNodeKind::HorizontalBox,
4131 1 => PortableNodeKind::VerticalBox,
4132 2 => PortableNodeKind::Rule,
4133 3 => PortableNodeKind::Insertion,
4134 4 => PortableNodeKind::Mark,
4135 5 => PortableNodeKind::Adjustment,
4136 6 => PortableNodeKind::Ligature,
4137 7 => PortableNodeKind::Discretionary,
4138 8 if matches!(subtype, 40 | 41) => PortableNodeKind::NativeWord,
4139 8 if subtype == 42 => PortableNodeKind::NativeGlyph,
4140 8 if subtype == HOST_BOX_RESOLVED_SUBTYPE as i32 => PortableNodeKind::HostBoxRef,
4141 8 if matches!(subtype, 0 | 1 | 2 | 3) => PortableNodeKind::OutputWhatsit,
4142 8 => PortableNodeKind::Whatsit,
4143 9 => PortableNodeKind::Math,
4144 10 => PortableNodeKind::Glue,
4145 11 => PortableNodeKind::Kern,
4146 12 => PortableNodeKind::Penalty,
4147 13 => PortableNodeKind::UnsetBox,
4148 16 => PortableNodeKind::Noad,
4149 14 => PortableNodeKind::Style,
4150 15 => PortableNodeKind::Choice,
4151 other => PortableNodeKind::Unknown(other),
4152 }
4153 }
4154
4155 pub(crate) fn copy_native_glyph_info(
4156 this: &mut Self,
4157 src: halfword,
4158 dest: halfword,
4159 ) -> quarterword {
4160 if let Some(info) = this.native_glyph_infos.get(&src).cloned() {
4161 let glyph_count = info.glyphs.len().min(i32::MAX as usize) as quarterword;
4162 this.native_glyph_infos.insert(dest, info);
4163 glyph_count
4164 } else {
4165 this.native_glyph_infos.remove(&dest);
4166 0
4167 }
4168 }
4169
4170 fn font_handle_for_number(this: &Self, font: integer) -> Option<FontHandle> {
4171 if font < 0 || this.state.fontlayoutengine.is_null() {
4172 return None;
4173 }
4174 let handle = unsafe { *this.state.fontlayoutengine.offset(font as isize) as FontHandle };
4175 (handle != 0).then_some(handle)
4176 }
4177
4178 unsafe fn node_index_for_pointer(
4179 engine: &PortableTexEngine<'_>,
4180 node: voidpointer,
4181 ) -> Option<halfword> {
4182 if node.is_null() || engine.state.zmem.is_null() {
4183 return None;
4184 }
4185 let base = engine.state.zmem as isize;
4186 let address = node as isize;
4187 let word_size = core::mem::size_of::<memoryword>() as isize;
4188 if word_size == 0 || address < base {
4189 return None;
4190 }
4191 let bytes = address - base;
4192 if bytes % word_size != 0 {
4193 return None;
4194 }
4195 let index = (bytes / word_size) as halfword;
4196 if index < engine.state.memmin || index > engine.state.memmax {
4197 None
4198 } else {
4199 Some(index)
4200 }
4201 }
4202
4203 unsafe fn native_node_font(mem: *mut memoryword, node: halfword) -> integer {
4204 (*mem.offset((node + 4) as isize)).v.QQQQ.u.B1 as integer
4205 }
4206
4207 unsafe fn native_node_text<'a>(mem: *mut memoryword, node: halfword) -> &'a [u16] {
4208 let len = (*mem.offset((node + 4) as isize)).v.QQQQ.u.B2.max(0) as usize;
4209 if len == 0 {
4210 return &[];
4211 }
4212 core::slice::from_raw_parts(
4213 mem.offset((node + native_node_size) as isize) as *const memoryword as *const u16,
4214 len,
4215 )
4216 }
4217
4218 unsafe fn write_native_node_metrics(
4219 mem: *mut memoryword,
4220 node: halfword,
4221 width: i32,
4222 height: i32,
4223 depth: i32,
4224 ) {
4225 (*mem.offset((node + 1) as isize)).u.CINT = width;
4226 (*mem.offset((node + 2) as isize)).u.CINT = depth;
4227 (*mem.offset((node + 3) as isize)).u.CINT = height;
4228 }
4229
4230 fn node_word(&self, node: halfword, offset: halfword) -> Option<memoryword> {
4231 let index = node.checked_add(offset)?;
4232 if node as i64 == -(268435455 as i64) {
4233 return None;
4234 }
4235 if self.state.zmem.is_null() || index < self.state.memmin || index > self.state.memmax {
4236 return None;
4237 }
4238 unsafe { Some(*self.state.zmem.offset(index as isize)) }
4239 }
4240
4241 fn node_link(&self, node: halfword) -> Option<PortableNodeHandle> {
4242 let word = self.node_word(node, 0)?;
4243 let link = unsafe { word.hh.v.RH };
4244 Self::node_handle_from_raw(link)
4245 }
4246
4247 fn node_field_link(&self, node: halfword, offset: halfword) -> Option<PortableNodeHandle> {
4248 let word = self.node_word(node, offset)?;
4249 let link = unsafe { word.hh.v.RH };
4250 Self::node_handle_from_raw(link)
4251 }
4252
4253 fn node_scaled(&self, node: halfword, offset: halfword) -> Option<i32> {
4254 let word = self.node_word(node, offset)?;
4255 Some(unsafe { word.u.CINT })
4256 }
4257
4258 fn glue_amount(&self, node: halfword) -> Option<i32> {
4259 let word = self.node_word(node, 1)?;
4260 let glue_spec = unsafe { word.hh.v.LH };
4261 self.node_scaled(glue_spec, 1)
4262 }
4263
4264 fn character_width(&self, font: i32, character: i32) -> Option<i32> {
4265 if font < 0
4266 || character < 0
4267 || self.state.fontinfo.is_null()
4268 || self.state.charbase.is_null()
4269 || self.state.widthbase.is_null()
4270 {
4271 return None;
4272 }
4273 let char_info_index = unsafe {
4274 *self.state.charbase.offset(font as isize) + character
4275 };
4276 let char_info = unsafe {
4277 (*self.state.fontinfo.offset(char_info_index as isize)).v.QQQQ
4278 };
4279 let width_index = unsafe {
4280 *self.state.widthbase.offset(font as isize) as i32 + char_info.u.B0 as i32
4281 };
4282 Some(unsafe { (*self.state.fontinfo.offset(width_index as isize)).u.CINT })
4283 }
4284
4285 fn node_handle_from_raw(raw: halfword) -> Option<PortableNodeHandle> {
4286 if raw as i64 == -(268435455 as i64) {
4287 None
4288 } else {
4289 Some(PortableNodeHandle(raw))
4290 }
4291 }
4292
4293
4294 pub(crate) fn is_xetex(&self) -> bool {
4295 self.profile.xetex
4296 }
4297
4298 pub(crate) fn supports_etex(&self) -> bool {
4299 self.profile.etex
4300 }
4301
4302 pub(crate) fn supports_unicode_scalars(&self) -> bool {
4303 self.profile.unicode_scalars
4304 }
4305
4306 pub(crate) fn supports_unicode_math(&self) -> bool {
4307 self.profile.unicode_math
4308 }
4309
4310 pub(crate) fn supports_native_fonts(&self) -> bool {
4311 self.profile.native_fonts
4312 }
4313
4314 pub(crate) unsafe fn getinputnormalizationstate(&self) -> integer {
4315 if !self.is_xetex() {
4316 return 0;
4317 }
4318 let eqtb = self.state.zeqtb.as_mut_ptr();
4319 if eqtb.is_null() {
4320 return 0;
4321 }
4322 (*eqtb.offset(7892344 as i64 as isize)).u.CINT
4323 }
4324
4325 pub(crate) unsafe fn gettracingfontsstate(&self) -> integer {
4326 if !self.is_xetex() {
4327 return 0;
4328 }
4329 let eqtb = self.state.zeqtb.as_mut_ptr();
4330 if eqtb.is_null() {
4331 return 0;
4332 }
4333 (*eqtb.offset(7892347 as i64 as isize)).u.CINT
4334 }
4335
4336 unsafe fn current_resource_name(engine: *mut PortableTexEngine<'_>) -> Option<String> {
4337 let engine = engine.as_ref()?;
4338 if engine.state.nameoffile.is_null() || engine.state.namelength <= 0 {
4339 return None;
4340 }
4341
4342 let mut bytes = Vec::with_capacity(engine.state.namelength as usize);
4343 for index in 1..=engine.state.namelength {
4344 let value = *engine.state.nameoffile.offset(index as isize);
4345 if value <= 0 {
4346 continue;
4347 }
4348 bytes.push(value as u8);
4349 }
4350 Some(String::from_utf8_lossy(bytes.as_slice()).into_owned())
4351 }
4352
4353 pub(crate) unsafe fn get_encoding_mode_and_info(
4359 engine: *mut PortableTexEngine<'_>,
4360 info: *mut integer,
4361 ) -> integer {
4362 if !info.is_null() {
4363 *info = 0;
4364 }
4365 let name = Self::current_resource_name(engine).unwrap_or_default();
4366 let lowered = name.trim().to_ascii_lowercase();
4367 match lowered.as_str() {
4368 "auto" => 0, "utf8" | "utf-8" => 1, "utf16" | "utf-16" | "utf16be" | "utf-16be" => 2, "utf16le" | "utf-16le" => 3, "bytes" => 4, _ => 4,
4376 }
4377 }
4378
4379 unsafe fn mode_string(mode: const_string) -> String {
4380 if mode.is_null() {
4381 return String::new();
4382 }
4383
4384 let mut bytes = Vec::new();
4385 let mut cursor = mode;
4386 while *cursor != 0 {
4387 bytes.push(*cursor as u8);
4388 cursor = cursor.add(1);
4389 }
4390 String::from_utf8_lossy(bytes.as_slice()).into_owned()
4391 }
4392
4393 unsafe fn pool_string(&self, string: strnumber) -> Option<String> {
4394 if string < 0 || self.state.strstart.is_null() || self.state.strpool.is_null() {
4395 return None;
4396 }
4397 let index = Self::pool_string_index(string)?;
4398 let start = *self.state.strstart.offset(index);
4399 let end = *self.state.strstart.offset(index + 1);
4400 if start < 0 || end < start {
4401 return None;
4402 }
4403
4404 let len = usize::try_from(end - start).ok()?;
4405 let mut units = Vec::with_capacity(len);
4406 for offset in 0..len {
4407 units.push(*self.state.strpool.offset((start as usize + offset) as isize));
4408 }
4409 Some(
4410 char::decode_utf16(units)
4411 .map(|codepoint| codepoint.unwrap_or(char::REPLACEMENT_CHARACTER))
4412 .collect(),
4413 )
4414 }
4415
4416 pub(crate) fn pool_string_index(string: strnumber) -> Option<isize> {
4417 if string < 0 {
4418 return None;
4419 }
4420 let index = if string >= 65536 { string - 65536 } else { string };
4421 isize::try_from(index).ok()
4422 }
4423
4424 fn resource_kind(name: &str, format: integer) -> ResourceKind {
4425 match format {
4426 resource_format_tex_input | 0 => Self::tex_resource_kind(name),
4427 resource_format_tfm | resource_format_font => ResourceKind::Font,
4428 resource_format_encoding => ResourceKind::Encoding,
4429 resource_format_font_map => ResourceKind::Map,
4430 resource_format_config => ResourceKind::Config,
4431 resource_format_format_image => ResourceKind::FormatImage,
4432 other => ResourceKind::Other(other),
4433 }
4434 }
4435
4436 fn tex_resource_kind(name: &str) -> ResourceKind {
4437 let name = name.rsplit(['/', '\\']).next().unwrap_or(name);
4438 let name = name.to_ascii_lowercase();
4439 if name.ends_with(".sty") {
4440 return ResourceKind::Package;
4441 }
4442 if name.ends_with(".cls") {
4443 return ResourceKind::Class;
4444 }
4445 if name.ends_with(".fd") {
4446 return ResourceKind::FontDefinition;
4447 }
4448 if name.ends_with(".clo")
4449 || name.ends_with(".def")
4450 || name.ends_with(".ldf")
4451 || name.ends_with(".cfg")
4452 {
4453 return ResourceKind::PackageSupport;
4454 }
4455 ResourceKind::TexInput
4456 }
4457
4458 fn resource_kind_for_open(
4459 engine: &PortableTexEngine<'_>,
4460 name: &str,
4461 format: integer,
4462 ) -> ResourceKind {
4463 let kind = Self::resource_kind(name, format);
4464 if kind == ResourceKind::TexInput
4465 && Self::active_package_owner(engine).is_some()
4466 && Self::looks_like_package_asset(name)
4467 {
4468 ResourceKind::Asset
4469 } else {
4470 kind
4471 }
4472 }
4473
4474 fn resource_package_owner(
4475 engine: &PortableTexEngine<'_>,
4476 name: &str,
4477 kind: ResourceKind,
4478 ) -> Option<String> {
4479 match kind {
4480 ResourceKind::Package | ResourceKind::Class => Self::resource_stem(name),
4481 ResourceKind::PackageSupport | ResourceKind::FontDefinition | ResourceKind::Asset => {
4482 Self::active_package_owner(engine)
4483 }
4484 _ => None,
4485 }
4486 }
4487
4488 fn active_package_owner(engine: &PortableTexEngine<'_>) -> Option<String> {
4489 engine.current_input_package_owner.clone()
4490 }
4491
4492 fn looks_like_package_asset(name: &str) -> bool {
4493 let name = name.rsplit(['/', '\\']).next().unwrap_or(name);
4494 let name = name.to_ascii_lowercase();
4495 !(name.ends_with(".tex")
4496 || name.ends_with(".ltx")
4497 || name.ends_with(".sty")
4498 || name.ends_with(".cls")
4499 || name.ends_with(".fd")
4500 || name.ends_with(".clo")
4501 || name.ends_with(".def")
4502 || name.ends_with(".ldf")
4503 || name.ends_with(".cfg"))
4504 }
4505
4506 fn resource_stem(name: &str) -> Option<String> {
4507 let name = name.rsplit(['/', '\\']).next().unwrap_or(name);
4508 let stem = name.rsplit_once('.').map_or(name, |(stem, _)| stem);
4509 if stem.is_empty() {
4510 None
4511 } else {
4512 Some(stem.to_string())
4513 }
4514 }
4515
4516 fn source_index(value: usize) -> u32 {
4517 value.min(u32::MAX as usize) as u32
4518 }
4519
4520 fn virtual_file_key(name: &str) -> String {
4521 let mut name = name;
4522 while let Some(stripped) = name.strip_prefix("./") {
4523 name = stripped;
4524 }
4525 name.to_string()
4526 }
4527
4528 fn normalized_runtime_resource_name(mut name: &str) -> &str {
4529 while let Some(stripped) = name.strip_prefix("./") {
4530 name = stripped;
4531 }
4532 name
4533 }
4534
4535 unsafe fn intern_static_pool_string(
4542 engine: &mut PortableTexEngine<'_>,
4543 text: &str,
4544 ) -> EngineFlow<Option<strnumber>> {
4545 if engine.state.strpool.is_null() || engine.state.strstart.is_null() {
4546 return Ok(None);
4547 }
4548
4549 let Ok(needed) = integer::try_from(text.encode_utf16().count()) else {
4550 return Ok(None);
4551 };
4552 let Some(next_pool) = engine.state.poolptr.checked_add(needed) else {
4553 return Ok(None);
4554 };
4555 if next_pool > engine.state.poolsize {
4556 return Ok(None);
4557 }
4558
4559 for unit in text.encode_utf16() {
4560 *engine.state.strpool.offset(engine.state.poolptr as isize) = unit as packedUTF16code;
4561 engine.state.poolptr += 1;
4562 }
4563
4564 Ok(Some(engine.makestring()?))
4565 }
4566
4567 unsafe fn append_text_to_pool(engine: &mut PortableTexEngine<'_>, text: &str) -> boolean {
4568 if engine.state.strpool.is_null() {
4569 return false_0;
4570 }
4571 let needed = match integer::try_from(text.encode_utf16().count()) {
4572 Ok(needed) => needed,
4573 Err(_) => return false_0,
4574 };
4575 let Some(next_pool) = engine.state.poolptr.checked_add(needed) else {
4576 return false_0;
4577 };
4578 if next_pool > engine.state.poolsize {
4579 return false_0;
4580 }
4581 for unit in text.encode_utf16() {
4582 *engine.state.strpool.offset(engine.state.poolptr as isize) = unit as packedUTF16code;
4583 engine.state.poolptr += 1;
4584 }
4585 true_0
4586 }
4587
4588 unsafe fn resource_bytes_for_name(
4589 engine: &mut PortableTexEngine<'_>,
4590 name: &str,
4591 ) -> Option<Vec<u8>> {
4592 let name = Self::normalized_runtime_resource_name(name);
4593 let kind = Self::resource_kind_for_open(engine, name, resource_format_tex_input);
4594 let package = Self::resource_package_owner(engine, name, kind);
4595 let request = ResourceRequest {
4596 name,
4597 kind,
4598 package: package.as_deref(),
4599 format: resource_format_tex_input,
4600 mode: "rb",
4601 source: None,
4602 };
4603 let virtual_key = Self::virtual_file_key(name);
4604 if let Some(bytes) = engine.virtual_files.get(&virtual_key) {
4605 Some(bytes.clone())
4606 } else {
4607 engine.resources.read(request)
4608 }
4609 }
4610
4611 pub(crate) unsafe fn boundary_get_file_size(
4612 engine: *mut PortableTexEngine<'_>,
4613 string: integer,
4614 ) {
4615 let Some(engine) = engine.as_mut() else {
4616 return;
4617 };
4618 let Some(name) = engine.pool_string(string as strnumber) else {
4619 return;
4620 };
4621 const PLACEHOLDER_FILE_SIZE: usize = 4096;
4631 let size = Self::resource_bytes_for_name(engine, name.as_str())
4632 .map_or(PLACEHOLDER_FILE_SIZE, |bytes| bytes.len());
4633 Self::append_text_to_pool(engine, size.to_string().as_str());
4634 }
4635
4636 pub(crate) unsafe fn load_pool_strings(
4637 engine: &mut PortableTexEngine<'_>,
4638 spare_size: integer,
4639 ) -> EngineFlow<integer> {
4640 if engine.state.strpool.is_null() || engine.state.strstart.is_null()
4641 || spare_size <= 0
4642 {
4643 return Ok(0);
4644 }
4645 let mut used = 0_i32;
4646 let mut last = 0_i32;
4647 for line in include_str!("../pool/xetex.pool").lines() {
4648 if line.starts_with('*') {
4649 break;
4650 }
4651 let bytes = line.as_bytes();
4652 let text = if bytes.len() >= 2 && bytes[0].is_ascii_digit()
4653 && bytes[1].is_ascii_digit()
4654 {
4655 &line[2..]
4656 } else {
4657 line
4658 };
4659 let units = text.encode_utf16().count().min(i32::MAX as usize) as integer;
4660 used = used.saturating_add(units);
4661 if used >= spare_size
4662 || engine.state.poolptr.saturating_add(units) > engine.state.poolsize
4663 {
4664 return Ok(0);
4665 }
4666 for unit in text.encode_utf16() {
4667 *engine.state.strpool.offset(engine.state.poolptr as isize) = unit
4668 as packedUTF16code;
4669 engine.state.poolptr += 1;
4670 }
4671 last = engine.makestring()?;
4672 }
4673 Ok(last)
4674 }
4675
4676 pub(crate) unsafe fn boundary_open_log_file(
4677 engine: *mut PortableTexEngine<'_>,
4678 ) -> EngineFlow<()> {
4679 let Some(engine) = engine.as_mut() else {
4680 return Ok(());
4681 };
4682 let old_setting = engine.state.selector;
4683 if engine.state.jobname == 0 {
4684 if let Some(jobname) = Self::intern_static_pool_string(engine, "texput")? {
4685 engine.state.jobname = jobname;
4686 }
4687 }
4688 engine.state.logopened = true_0 as boolean;
4689 engine.state.selector = (old_setting as i32 + 2).clamp(0, 21) as eightbits;
4690 Ok(())
4691 }
4692
4693 pub(crate) unsafe fn boundary_jump_out(
4694 engine: *mut PortableTexEngine<'_>,
4695 ) -> EngineFlow<core::convert::Infallible> {
4696 let status = if let Some(engine) = engine.as_ref() {
4701 if engine.state.history as i32 <= 1 {
4702 0 as integer
4703 } else {
4704 1 as integer
4705 }
4706 } else {
4707 1 as integer
4708 };
4709 Self::abort_engine(engine, status)
4710 }
4711
4712 pub(crate) unsafe fn boundary_shipout(
4713 engine: *mut PortableTexEngine<'_>,
4714 box_node: halfword,
4715 ) {
4716 if let Some(engine) = engine.as_mut() {
4717 engine.stripped_shipouts = engine.stripped_shipouts.saturating_add(1);
4718 engine.last_stripped_shipout_box = Some(PortableNodeHandle(box_node));
4719 }
4720 }
4721
4722 pub(crate) unsafe fn boundary_capture_fragment_box(
4723 engine: *mut PortableTexEngine<'_>,
4724 box_node: halfword,
4725 mode: integer,
4726 boxcontext: integer,
4727 ) -> boolean {
4728 if let Some(engine) = engine.as_mut() {
4729 if engine.fragment_capture_enabled {
4730 engine.captured_fragment_root = Some(PortableNodeHandle(box_node));
4731 let absolute_mode = if mode >= 0 { mode } else { -mode };
4732 if absolute_mode == 1 && boxcontext < 1_073_741_824 {
4733 return true_0;
4734 }
4735 }
4736 }
4737 false_0
4738 }
4739
4740 pub(crate) unsafe fn boundary_build_page(
4741 engine: *mut PortableTexEngine<'_>,
4742 ) -> EngineFlow<()> {
4743 if let Some(engine) = engine.as_mut() {
4744 if engine.format_initialization
4745 && engine.state.curcmd as i32 == 15
4746 && engine.state.curchr == 1
4747 {
4748 Self::abort_engine(engine as *mut PortableTexEngine<'_>, 0 as integer)?;
4752 }
4753 engine.stripped_page_builds = engine.stripped_page_builds.saturating_add(1);
4754 }
4755 Ok(())
4756 }
4757
4758 pub(crate) unsafe fn boundary_prune_page_top(
4759 engine: *mut PortableTexEngine<'_>,
4760 node: halfword,
4761 _saving: boolean,
4762 ) -> halfword {
4763 if let Some(engine) = engine.as_mut() {
4764 engine.stripped_page_top_prunes =
4765 engine.stripped_page_top_prunes.saturating_add(1);
4766 }
4767 node
4768 }
4769
4770 pub(crate) unsafe fn boundary_special_out(
4771 engine: *mut PortableTexEngine<'_>,
4772 node: halfword,
4773 ) -> EngineFlow<()> {
4774 let Some(engine) = engine.as_mut() else {
4775 return Ok(());
4776 };
4777 if node < engine.state.memmin || node > engine.state.memend {
4778 engine.stripped_special_outputs = engine
4779 .stripped_special_outputs
4780 .saturating_add(1);
4781 return Ok(());
4782 }
4783 let mem = engine.state.zmem.as_mut_ptr();
4784 if (*mem.offset(node as isize)).hh.u.B0 as i32 == 8 {
4785 match (*mem.offset(node as isize)).hh.u.B1 as i32 {
4786 0 => {
4787 Self::boundary_open_write_whatsit(engine, node);
4788 return Ok(());
4789 }
4790 1 => {
4791 Self::boundary_write_whatsit(engine, node)?;
4792 return Ok(());
4793 }
4794 2 => {
4795 Self::boundary_close_write_whatsit(engine, node);
4796 return Ok(());
4797 }
4798 _ => {}
4799 }
4800 }
4801 engine.stripped_special_outputs = engine
4802 .stripped_special_outputs
4803 .saturating_add(1);
4804 Ok(())
4805 }
4806
4807 unsafe fn boundary_open_write_whatsit(engine: &mut PortableTexEngine<'_>, node: halfword) {
4808 let mem = engine.state.zmem.as_mut_ptr();
4809 let stream = (*mem.offset((node + 1) as isize)).hh.v.LH as usize;
4810 if stream >= 16 {
4811 return;
4812 }
4813
4814 if engine.state.writeopen[stream] != 0 {
4815 Self::boundary_close_write_stream(engine, stream);
4816 }
4817
4818 engine.state.curname = (*mem.offset((node + 1) as isize)).hh.v.RH as strnumber;
4819 engine.state.curarea = (*mem.offset((node + 2) as isize)).hh.v.LH as strnumber;
4820 engine.state.curext = (*mem.offset((node + 2) as isize)).hh.v.RH as strnumber;
4821 if engine.state.curext == 335 {
4822 engine.state.curext = 799;
4823 }
4824 engine.zpackfilename(engine.state.curname, engine.state.curarea, engine.state.curext);
4825 let Some(name) = Self::current_resource_name(engine as *mut PortableTexEngine<'_>) else {
4826 return;
4827 };
4828 let handle = Box::new(PortableFileHandle::new(
4829 name,
4830 ResourceKind::TexInput,
4831 None,
4832 resource_format_tex_input,
4833 Vec::new(),
4834 ));
4835 engine.state.writefile[stream] = Box::into_raw(handle);
4836 engine.state.writeopen[stream] = true_0;
4837 }
4838
4839 unsafe fn boundary_write_whatsit(
4840 engine: &mut PortableTexEngine<'_>,
4841 node: halfword,
4842 ) -> EngineFlow<()> {
4843 let mem = engine.state.zmem.as_mut_ptr();
4844 let stream = (*mem.offset((node + 1) as isize)).hh.v.LH as usize;
4845 if stream >= 16 || engine.state.writeopen[stream] == 0 {
4846 return Ok(());
4847 }
4848 let write_tokens = engine.profile.write_token_constants();
4849 let q = engine.getavail()?;
4850 (*mem.offset(q as isize)).hh.v.LH = write_tokens.open_group_token;
4851 let r = engine.getavail()?;
4852 (*mem.offset(q as isize)).hh.v.RH = r;
4853 (*mem.offset(r as isize)).hh.v.LH = write_tokens.end_write_token;
4854 engine.zbegintokenlist(q, 4)?;
4855 engine.zbegintokenlist((*mem.offset((node + 1) as isize)).hh.v.RH, 15)?;
4856 let q = engine.getavail()?;
4857 (*mem.offset(q as isize)).hh.v.LH = write_tokens.close_group_token;
4858 engine.zbegintokenlist(q, 4)?;
4859 let old_mode = engine.state.curlist.modefield;
4860 engine.state.curlist.modefield = 0;
4861 engine.state.curcs = engine.state.writeloc;
4862 engine.zscantoks(false_0, true_0)?;
4863 engine.state.curlist.modefield = old_mode;
4864 engine.gettoken()?;
4865 if engine.state.curtok != write_tokens.end_write_token {
4866 while engine.state.curtok != write_tokens.end_write_token {
4867 engine.gettoken()?;
4868 }
4869 }
4870 engine.endtokenlist()?;
4871 let old_setting = engine.state.selector;
4872 engine.state.selector = stream as eightbits;
4873 engine.ztokenshow(engine.state.defref);
4874 engine.println();
4875 engine.state.selector = old_setting;
4876 engine.zflushlist(engine.state.defref);
4877 Ok(())
4878 }
4879
4880 unsafe fn boundary_close_write_whatsit(engine: &mut PortableTexEngine<'_>, node: halfword) {
4881 let mem = engine.state.zmem.as_mut_ptr();
4882 let stream = (*mem.offset((node + 1) as isize)).hh.v.LH as usize;
4883 if stream < 16 {
4884 Self::boundary_close_write_stream(engine, stream);
4885 }
4886 }
4887
4888 unsafe fn boundary_close_write_stream(engine: &mut PortableTexEngine<'_>, stream: usize) {
4889 if stream >= 16 || engine.state.writeopen[stream] == 0 {
4890 return;
4891 }
4892 let file = engine.state.writefile[stream];
4893 engine.state.writefile[stream] = core::ptr::null_mut();
4894 engine.state.writeopen[stream] = false_0;
4895 if file.is_null() {
4896 return;
4897 }
4898 let handle = Box::from_raw(file);
4899 let key = Self::virtual_file_key(handle.name.as_str());
4900 engine.virtual_files.insert(key, handle.bytes);
4901 }
4902
4903 pub(crate) unsafe fn boundary_load_picture(
4904 engine: *mut PortableTexEngine<'_>,
4905 _is_pdf: boolean,
4906 ) {
4907 if let Some(engine) = engine.as_mut() {
4908 engine.stripped_picture_loads = engine.stripped_picture_loads.saturating_add(1);
4909 }
4910 }
4911
4912 pub(crate) fn record_stripped_source_special(engine: *mut PortableTexEngine<'_>) {
4913 if let Some(engine) = unsafe { engine.as_mut() } {
4914 engine.stripped_source_specials = engine.stripped_source_specials.saturating_add(1);
4915 }
4916 }
4917
4918 pub(crate) fn record_stripped_write_whatsit_diagnostic(engine: *mut PortableTexEngine<'_>) {
4919 if let Some(engine) = unsafe { engine.as_mut() } {
4920 engine.stripped_write_whatsit_diagnostics =
4921 engine.stripped_write_whatsit_diagnostics.saturating_add(1);
4922 }
4923 }
4924
4925 pub(crate) fn record_stripped_pdf_extension(engine: *mut PortableTexEngine<'_>) {
4926 if let Some(engine) = unsafe { engine.as_mut() } {
4927 engine.stripped_pdf_extensions = engine.stripped_pdf_extensions.saturating_add(1);
4928 }
4929 }
4930
4931 fn resolve_input_encoding(engine: &PortableTexEngine<'_>, handle: &mut PortableFileHandle) {
4941 let is_text = handle.format == resource_format_tex_input || handle.format == 0;
4942 if engine.is_xetex() && is_text {
4943 handle.resolve_text_encoding_auto();
4944 } else {
4945 handle.encoding = InputEncoding::Bytes;
4946 }
4947 }
4948
4949 pub(crate) unsafe fn boundary_open_input(
4950 engine: *mut PortableTexEngine<'_>,
4951 file: *mut NativeFileHandle,
4952 format: integer,
4953 mode: const_string,
4954 ) -> boolean {
4955 let Some(engine) = engine.as_mut() else {
4956 if !file.is_null() {
4957 *file = core::ptr::null_mut();
4958 }
4959 return false_0;
4960 };
4961 let Some(name) = Self::current_resource_name(engine as *mut PortableTexEngine<'_>) else {
4962 if !file.is_null() {
4963 *file = core::ptr::null_mut();
4964 }
4965 return false_0;
4966 };
4967 let mode = Self::mode_string(mode);
4968 let request_kind = Self::resource_kind_for_open(engine, name.as_str(), format);
4969 let request_package = Self::resource_package_owner(engine, name.as_str(), request_kind);
4970 let source: Option<PortableSourceSpan> = None;
4971 let request = ResourceRequest {
4972 name: name.as_str(),
4973 kind: request_kind,
4974 package: request_package.as_deref(),
4975 format,
4976 mode: mode.as_str(),
4977 source: source.clone(),
4978 };
4979 engine.resource_requests = engine.resource_requests.saturating_add(1);
4980 let virtual_key = Self::virtual_file_key(name.as_str());
4981 let bytes = if let Some(bytes) = engine.virtual_files.get(&virtual_key) {
4982 bytes.clone()
4983 } else if let Some(bytes) = engine.resources.read(request) {
4984 bytes
4985 } else {
4986 engine.resource_request_records.push(PortableResourceRequestRecord {
4987 name,
4988 kind: request_kind,
4989 package: request_package,
4990 format,
4991 mode,
4992 source,
4993 byte_len: None,
4994 });
4995 if !file.is_null() {
4996 *file = core::ptr::null_mut();
4997 }
4998 return false_0;
4999 };
5000 let byte_len = Self::source_index(bytes.len());
5001 engine.resource_request_records.push(PortableResourceRequestRecord {
5002 name: name.clone(),
5003 kind: request_kind,
5004 package: request_package.clone(),
5005 format,
5006 mode: mode.clone(),
5007 source,
5008 byte_len: Some(byte_len),
5009 });
5010 let mut handle = Box::new(PortableFileHandle::new(
5011 name,
5012 request_kind,
5013 request_package,
5014 format,
5015 bytes,
5016 ));
5017 Self::resolve_input_encoding(engine, &mut handle);
5021 if format == resource_format_tfm {
5022 engine.state.tfmtemp = handle.read_byte().map_or(-1, |byte| byte as integer);
5023 }
5024 if !file.is_null() {
5025 *file = Box::into_raw(handle);
5026 return true_0;
5027 }
5028 drop(handle);
5029 false_0
5030 }
5031
5032 unsafe fn begin_primary_input_raw(
5033 self: &mut Self,
5034 name: &str,
5035 bytes: Vec<u8>,
5036 ) -> EngineFlow<boolean> {
5037 if self.state.inputfile.is_null() || self.state.sourcefilenamestack.is_null()
5038 || self.state.fullsourcefilenamestack.is_null()
5039 || self.state.buffer.is_null()
5040 {
5041 return Ok(false_0);
5042 }
5043 let Some(source_name) = Self::intern_static_pool_string(self, name)? else {
5044 return Ok(false_0);
5045 };
5046 self.beginfilereading()?;
5047 let slot = self.state.curinput.indexfield as isize;
5048 let mut handle = Box::new(
5049 PortableFileHandle::new(
5050 name.to_string(),
5051 ResourceKind::TexInput,
5052 None,
5053 resource_format_tex_input,
5054 bytes,
5055 ),
5056 );
5057 Self::resolve_input_encoding(self, &mut handle);
5058 *self.state.inputfile.offset(slot) = Box::into_raw(handle);
5059 self.state.curinput.namefield = source_name as halfword;
5060 *self.state.sourcefilenamestack.offset(slot) = source_name;
5061 *self.state.fullsourcefilenamestack.offset(slot) = source_name;
5062 self.state.curinput.statefield = 33 as quarterword;
5063 self.state.line = 1 as integer;
5064 self.state.src_primary_name = source_name;
5065 self.state.cmd_span = 0;
5066 self.state.pending_call_span = 0;
5067 self.state.src_user_cmd_span = 0;
5068 self.state.src_tok_span = 0;
5069 self.state.src_anchor_cmd = 0;
5070 self.state.src_grp_stack.clear();
5071 self.state.src_grp_closing = 0;
5072 self.state.src_call_user_span = 0;
5073 self.state.src_line_base = 0;
5074 self.state.src_line_buf_start = 0;
5075 self.state.src_prev_line_len = 0;
5076 self.state.src_line_initialized = false;
5077 self.state.curinput.spanfield = 0;
5078 self.state.src_native_offsets.clear();
5079 self.state.src_stack_cells.clear();
5080 self.state.cur_stack_head = 0;
5081 if Self::boundary_input_line(
5082 self as *mut PortableTexEngine<'_>,
5083 *self.state.inputfile.offset(slot) as NativeFileHandle,
5084 ) == 0
5085 {
5086 self.endfilereading();
5087 return Ok(false_0);
5088 }
5089 self.firmuptheline()?;
5090 let eqtb = self.state.zeqtb.as_mut_ptr();
5091 let endline_char_index = if self.is_xetex() && self.state.eqtbtop >= 7_892_312 {
5092 7_892_312_i64
5093 } else {
5094 27_212_i64
5095 };
5096 let endline_char = if eqtb.is_null() {
5097 -1
5098 } else {
5099 (*eqtb.offset(endline_char_index as isize)).u.CINT
5100 };
5101 if !(0..=255).contains(&endline_char) {
5102 self.state.curinput.limitfield -= 1;
5103 } else {
5104 *self.state.buffer.offset(self.state.curinput.limitfield as isize) = endline_char
5105 as UnicodeScalar;
5106 }
5107 self.state.first = (self.state.curinput.limitfield as i32 + 1) as integer;
5108 self.state.curinput.locfield = self.state.curinput.startfield;
5109 Ok(true_0)
5110 }
5111
5112 pub(crate) unsafe fn boundary_input_line(
5113 engine: *mut PortableTexEngine<'_>,
5114 file: NativeFileHandle,
5115 ) -> boolean {
5116 let Some(engine) = engine.as_mut() else {
5117 return false_0;
5118 };
5119 if file.is_null() || engine.state.buffer.is_null() {
5120 return false_0;
5121 }
5122
5123 let handle = &mut *file;
5124 if !handle.has_remaining() {
5125 return false_0;
5126 }
5127
5128 let first = engine.state.first.max(0) as usize;
5129 let limit = engine.state.bufsize.max(0) as usize;
5130 let mut last = first;
5131 while last < limit {
5135 let Some(scalar) = handle.next_input_scalar() else {
5136 break;
5137 };
5138 match scalar {
5139 0x0A => break,
5140 0x0D => {
5141 let saved_cursor = handle.cursor;
5145 let saved_lookahead = handle.saved_char;
5146 let was_eof = handle.eof_after_failed_read;
5147 match handle.next_input_scalar() {
5148 Some(0x0A) => {} _ => {
5150 handle.cursor = saved_cursor;
5152 handle.saved_char = saved_lookahead;
5153 handle.eof_after_failed_read = was_eof;
5154 }
5155 }
5156 break;
5157 }
5158 scalar => {
5159 *engine.state.buffer.offset(last as isize) = scalar as UnicodeScalar;
5160 last += 1;
5161 }
5162 }
5163 }
5164
5165 while last > first && *engine.state.buffer.offset((last - 1) as isize) == b' ' as UnicodeScalar {
5166 last -= 1;
5167 }
5168 if handle.format == resource_format_tex_input || handle.format == 0 {
5169 engine.current_input_package_owner = handle.package.clone();
5170 }
5171 if engine.state.source_tracking
5178 && engine.state.curinput.namefield as strnumber == engine.state.src_primary_name
5179 {
5180 if engine.state.src_line_initialized {
5181 engine.state.src_line_base += engine.state.src_prev_line_len + 1;
5182 } else {
5183 engine.state.src_line_base = 0;
5184 engine.state.src_line_initialized = true;
5185 }
5186 engine.state.src_line_buf_start = first as integer;
5187 engine.state.src_prev_line_len = last.saturating_sub(first) as u32;
5188 engine.state.src_token_start = first as integer;
5194 }
5195 engine.state.last = last as integer;
5196 true_0
5197 }
5198
5199 pub(crate) unsafe fn boundary_read_byte(_file: NativeFileHandle) -> integer {
5200 if _file.is_null() {
5201 return -1;
5202 }
5203 (&mut *_file).read_byte().map_or(-1, |byte| byte as integer)
5204 }
5205
5206 pub(crate) unsafe fn boundary_end_of_file(_file: NativeFileHandle) -> integer {
5207 if _file.is_null() || (&*_file).is_eof() {
5208 1
5209 } else {
5210 0
5211 }
5212 }
5213
5214 pub(crate) unsafe fn boundary_flush_file(_file: NativeFileHandle) -> integer {
5215 0
5216 }
5217
5218 pub(crate) unsafe fn boundary_write_byte(
5219 engine: *mut PortableTexEngine<'_>,
5220 character: integer,
5221 file: NativeFileHandle,
5222 ) -> integer {
5223 if !file.is_null() {
5224 if let Ok(byte) = u8::try_from(character) {
5225 (*file).bytes.push(byte);
5226 }
5227 return character;
5228 }
5229 if let Some(engine) = engine.as_mut() {
5230 if let Ok(byte) = u8::try_from(character) {
5231 engine.transcript_bytes.push(byte);
5232 }
5233 }
5234 character
5235 }
5236
5237 pub(crate) unsafe fn boundary_close_file(_file: NativeFileHandle) {
5238 if !_file.is_null() {
5239 drop(Box::from_raw(_file));
5240 }
5241 }
5242
5243 pub(crate) unsafe fn get_seconds_and_micros(
5244 engine: *mut PortableTexEngine<'_>,
5245 seconds: *mut integer,
5246 micros: *mut integer,
5247 ) {
5248 let clock = engine
5249 .as_mut()
5250 .map(|engine| engine.platform.clock())
5251 .unwrap_or_default();
5252 if !seconds.is_null() {
5253 *seconds = clock.seconds;
5254 }
5255 if !micros.is_null() {
5256 *micros = clock.micros;
5257 }
5258 }
5259
5260 pub(crate) unsafe fn linebreak_start(
5261 engine: *mut PortableTexEngine<'_>,
5262 font: integer,
5263 locale: integer,
5264 text: *mut uint16_t,
5265 text_length: integer,
5266 ) {
5267 let Some(engine) = engine.as_mut() else {
5268 return;
5269 };
5270 let text = if text.is_null() || text_length <= 0 {
5271 &[]
5272 } else {
5273 core::slice::from_raw_parts(text as *const uint16_t, text_length as usize)
5274 };
5275 engine
5276 .platform
5277 .linebreak_start(PortableLinebreakRequest { font, locale, text });
5278 }
5279
5280 pub(crate) unsafe fn linebreak_next(engine: *mut PortableTexEngine<'_>) -> integer {
5281 engine
5282 .as_mut()
5283 .and_then(|engine| engine.platform.linebreak_next())
5284 .unwrap_or(-1)
5285 }
5286
5287 pub(crate) unsafe fn register_host_box_primitive(self: &mut Self) -> EngineFlow<()> {
5289 let eqtb = self.state.zeqtb.as_mut_ptr();
5290 let name = b"Uhostbox";
5291 for (index, byte) in name.iter().enumerate() {
5292 *self.state.buffer.offset(index as isize) = *byte as UnicodeScalar;
5293 }
5294 let saved = self.state.nonewcontrolsequence;
5295 self.state.nonewcontrolsequence = 0 as boolean;
5296 let cs = (&mut *(self as *mut PortableTexEngine<'_>))
5297 .zidlookup(0 as integer, name.len() as integer)?;
5298 self.state.nonewcontrolsequence = saved;
5299 (*eqtb.offset(cs as isize)).hh.u.B1 = 1 as i16;
5301 (*eqtb.offset(cs as isize)).hh.u.B0 = 59 as i16;
5302 (*eqtb.offset(cs as isize)).hh.v.RH = HOST_BOX_EXTENSION_CODE as halfword;
5303 Ok(())
5304 }
5305
5306 unsafe fn host_box_marker(
5308 engine: *mut PortableTexEngine<'_>,
5309 subtype: i16,
5310 payload: integer,
5311 ) -> EngineFlow<halfword> {
5312 let this = &mut *engine;
5313 let marker = this.zgetnode(2 as i32)?;
5314 let mem: *mut memoryword = this.state.zmem.as_mut_ptr();
5315 (*mem.offset(marker as isize)).hh.u.B0 = 8 as i16;
5316 (*mem.offset(marker as isize)).hh.u.B1 = subtype;
5317 (*mem.offset(marker as isize)).hh.v.RH = -(268435455 as i64) as halfword;
5318 (*mem.offset((marker as i32 + 1 as i32) as isize)).u.CINT = payload;
5319 Ok(marker)
5320 }
5321
5322 unsafe fn host_box_build(
5324 engine: *mut PortableTexEngine<'_>,
5325 token: integer,
5326 style: PortableHostBoxStyle,
5327 font_size: scaled,
5328 ) -> EngineFlow<halfword> {
5329 let this = &mut *engine;
5330 let response = this.platform.host_box(PortableHostBoxRequest {
5331 token,
5332 style,
5333 font_size,
5334 });
5335 let hbox = this.newnullbox()?;
5336 let Some(host_box) = response else {
5337 return Ok(hbox);
5338 };
5339 let mem: *mut memoryword = this.state.zmem.as_mut_ptr();
5340 (*mem.offset((hbox as i32 + 1 as i32) as isize)).u.CINT = host_box.width;
5341 (*mem.offset((hbox as i32 + 2 as i32) as isize)).u.CINT = host_box.depth;
5342 (*mem.offset((hbox as i32 + 3 as i32) as isize)).u.CINT = host_box.height;
5343 let index = this.hostbox_records.len();
5344 this.hostbox_records.push(host_box);
5345 let marker =
5346 Self::host_box_marker(engine, HOST_BOX_RESOLVED_SUBTYPE, index as integer)?;
5347 (*mem.offset((hbox as i32 + 5 as i32) as isize)).hh.v.RH = marker;
5348 Ok(hbox)
5349 }
5350
5351 pub(crate) unsafe fn host_box_insert(
5353 engine: *mut PortableTexEngine<'_>,
5354 token: integer,
5355 ) -> EngineFlow<()> {
5356 let Some(this) = engine.as_mut() else {
5357 return Ok(());
5358 };
5359 let mode = (this.state.curlist.modefield as i32).abs();
5360 if mode == 209 as i32 {
5361 let marker =
5362 Self::host_box_marker(engine, HOST_BOX_PENDING_SUBTYPE, token)?;
5363 let this = &mut *engine;
5364 let placeholder = this.newnullbox()?;
5365 let noad = this.newnoad()?;
5366 let mem: *mut memoryword = this.state.zmem.as_mut_ptr();
5367 (*mem.offset((placeholder as i32 + 5 as i32) as isize)).hh.v.RH = marker;
5368 (*mem.offset((noad as i32 + 1 as i32) as isize)).hh.v.RH = 2 as i32 as halfword;
5369 (*mem.offset((noad as i32 + 1 as i32) as isize)).hh.v.LH = placeholder;
5370 (*mem.offset(this.state.curlist.tailfield as isize)).hh.v.RH = noad;
5371 this.state.curlist.tailfield = noad;
5372 } else {
5373 let eqtb = this.state.zeqtb.as_mut_ptr();
5374 let font = (*eqtb.offset(EQTB_CUR_FONT_LOC as isize)).hh.v.RH as integer;
5375 let font_size = this.font_at_size(font);
5376 let hbox =
5377 Self::host_box_build(engine, token, PortableHostBoxStyle::Text, font_size)?;
5378 let this = &mut *engine;
5379 let mem: *mut memoryword = this.state.zmem.as_mut_ptr();
5380 (*mem.offset(this.state.curlist.tailfield as isize)).hh.v.RH = hbox;
5381 this.state.curlist.tailfield = hbox;
5382 }
5383 Ok(())
5384 }
5385
5386 pub(crate) unsafe fn host_box_resolve_noad(
5388 engine: *mut PortableTexEngine<'_>,
5389 q: halfword,
5390 ) -> EngineFlow<()> {
5391 let Some(this) = engine.as_mut() else {
5392 return Ok(());
5393 };
5394 if q < 0 || q >= this.state.himemmin {
5395 return Ok(());
5396 }
5397 let mem: *mut memoryword = this.state.zmem.as_mut_ptr();
5398 if (*mem.offset(q as isize)).hh.u.B0 as i32 != 16 as i32 {
5400 return Ok(());
5401 }
5402 let style_code = this.state.curstyle as i32;
5403 Self::host_box_resolve_field(engine, (q as i32 + 1 as i32) as halfword, style_code)
5404 }
5405
5406 pub(crate) unsafe fn host_box_resolve_field(
5408 engine: *mut PortableTexEngine<'_>,
5409 field: halfword,
5410 style_code: i32,
5411 ) -> EngineFlow<()> {
5412 let Some(this) = engine.as_mut() else {
5413 return Ok(());
5414 };
5415 if field < 0 {
5416 return Ok(());
5417 }
5418 let mem: *mut memoryword = this.state.zmem.as_mut_ptr();
5419 if (*mem.offset(field as isize)).hh.v.RH as i32 != 2 as i32 {
5421 return Ok(());
5422 }
5423 let placeholder = (*mem.offset(field as isize)).hh.v.LH;
5424 if placeholder < 0 || placeholder as i64 == -(268435455 as i64) {
5425 return Ok(());
5426 }
5427 let marker = (*mem.offset((placeholder as i32 + 5 as i32) as isize)).hh.v.RH;
5428 if marker < 0 || marker as i64 == -(268435455 as i64) || marker >= this.state.himemmin {
5429 return Ok(());
5430 }
5431 if (*mem.offset(marker as isize)).hh.u.B0 as i32 != 8 as i32
5432 || (*mem.offset(marker as isize)).hh.u.B1 as i32 != HOST_BOX_PENDING_SUBTYPE as i32
5433 {
5434 return Ok(());
5435 }
5436 let token = (*mem.offset((marker as i32 + 1 as i32) as isize)).u.CINT;
5437 let size = if style_code < 4 {
5439 0
5440 } else {
5441 256 * ((style_code - 2) / 2)
5442 };
5443 let style = match size {
5444 0 => PortableHostBoxStyle::Text,
5445 256 => PortableHostBoxStyle::Script,
5446 _ => PortableHostBoxStyle::ScriptScript,
5447 };
5448 let eqtb = this.state.zeqtb.as_mut_ptr();
5450 let font = (*eqtb.offset((EQTB_MATH_FONT_FAM2_BASE + size as i64) as isize))
5451 .hh
5452 .v
5453 .RH as integer;
5454 let font_size = this.font_at_size(font);
5455 let hbox = Self::host_box_build(engine, token, style, font_size)?;
5456 Self::src_carry_copy(engine as *mut Self, placeholder, hbox);
5459 let mem: *mut memoryword = (*engine).state.zmem.as_mut_ptr();
5460 let resolved_marker = (*mem.offset((hbox as i32 + 5 as i32) as isize)).hh.v.RH;
5461 if resolved_marker >= 0 && resolved_marker as i64 != -(268435455 as i64) {
5462 Self::src_carry_copy(engine as *mut Self, placeholder, resolved_marker);
5463 }
5464 (&mut *engine).zflushnodelist(placeholder)?;
5465 let this = &mut *engine;
5466 let mem: *mut memoryword = this.state.zmem.as_mut_ptr();
5467 (*mem.offset(field as isize)).hh.v.LH = hbox;
5468 Ok(())
5469 }
5470
5471 pub(crate) unsafe fn abort_engine(
5472 engine: *mut PortableTexEngine<'_>,
5473 status: integer,
5474 ) -> EngineFlow<core::convert::Infallible> {
5475 if let Some(engine) = engine.as_mut() {
5476 engine.last_abort_status = Some(status);
5477 }
5478 Err(EngineBreak::Abort(EngineAbort { status }))
5479 }
5480
5481 pub(crate) unsafe fn sandbox_reject(
5485 engine: *mut PortableTexEngine<'_>,
5486 message: &str,
5487 ) -> EngineFlow<()> {
5488 if let Some(engine) = engine.as_ref() {
5489 if engine.sandbox {
5490 return Err(EngineBreak::Error(EngineError {
5491 message: message.into(),
5492 }));
5493 }
5494 }
5495 Ok(())
5496 }
5497
5498 pub(crate) unsafe fn sandbox_open_math(
5505 engine: *mut PortableTexEngine<'_>,
5506 ) -> EngineFlow<()> {
5507 if let Some(engine) = engine.as_mut() {
5508 if engine.sandbox {
5509 if engine.sandbox_math_depth == 0 && engine.sandbox_math_opened {
5510 return Err(EngineBreak::Error(EngineError {
5511 message: "math shift ($) is not allowed inside a math expression"
5512 .into(),
5513 }));
5514 }
5515 engine.sandbox_math_opened = true;
5516 engine.sandbox_math_depth += 1;
5517 }
5518 }
5519 Ok(())
5520 }
5521
5522 pub(crate) unsafe fn sandbox_close_math(
5527 engine: *mut PortableTexEngine<'_>,
5528 ) -> EngineFlow<()> {
5529 if let Some(engine) = engine.as_mut() {
5530 if engine.sandbox && engine.sandbox_math_depth > 0 {
5531 engine.sandbox_math_depth -= 1;
5532 }
5533 }
5534 Ok(())
5535 }
5536
5537 pub(crate) unsafe fn sandbox_tick(
5541 engine: *mut PortableTexEngine<'_>,
5542 ) -> EngineFlow<()> {
5543 if let Some(engine) = engine.as_mut() {
5544 if engine.sandbox {
5545 engine.sandbox_ops = engine.sandbox_ops.saturating_add(1);
5546 if engine.sandbox_ops > SANDBOX_OP_BUDGET {
5547 return Err(EngineBreak::Error(EngineError {
5548 message: "expression is too complex or did not terminate".into(),
5549 }));
5550 }
5551 }
5552 }
5553 Ok(())
5554 }
5555
5556 pub(crate) unsafe fn surface_error(
5564 engine: *mut PortableTexEngine<'_>,
5565 ) -> EngineFlow<()> {
5566 let message = engine
5567 .as_ref()
5568 .map(|engine| engine.capture_last_error_message())
5569 .unwrap_or_else(|| "TeX error".into());
5570 Err(EngineBreak::Error(EngineError { message }))
5571 }
5572
5573 pub fn set_source_tracking(self: &mut Self, on: bool) {
5588 self.state.source_tracking = on;
5589 self.state.cmd_span = 0;
5590 self.state.pending_call_span = 0;
5591 self.state.src_token_start = 0;
5592 self.state.src_line_base = 0;
5593 self.state.src_line_buf_start = 0;
5594 self.state.src_prev_line_len = 0;
5595 self.state.src_line_initialized = false;
5596 self.state.src_call_start = 0;
5597 self.state.src_call_name = 0;
5598 self.state.src_call_state = 0;
5599 self.state.src_call_index = 0;
5600 self.state.src_call_span = 0;
5601 self.state.src_call_argspan = 0;
5602 self.state.src_user_cmd_span = 0;
5603 self.state.src_tok_span = 0;
5604 self.state.src_anchor_cmd = 0;
5605 self.state.src_grp_stack.clear();
5606 self.state.src_grp_closing = 0;
5607 self.state.src_call_user_span = 0;
5608 self.state.curinput.spanfield = 0;
5609 self.state.src_spans.clear();
5610 self.state.src_dedup.clear();
5611 self.state.src_native_offsets.clear();
5612 self.state.src_stack_cells.clear();
5613 self.state.cur_stack_head = 0;
5614 let end = if on { self.state.mem.len() } else { 0 };
5615 self.state.node_src = PagedArray::new(0, end, node_src_default, node_src_sig);
5616 self.state.node_stack = PagedArray::new(0, end, node_stack_default, node_stack_sig);
5617 }
5618
5619 pub fn source_tracking_enabled(&self) -> bool {
5621 self.state.source_tracking
5622 }
5623
5624 fn intern_span_raw(self: &mut Self, name: strnumber, start: u32, end: u32, role: u8) -> SrcId {
5629 let span = RawSpan { name, start, end, role };
5630 if let Some(&id) = self.state.src_dedup.get(&span) {
5631 return id;
5632 }
5633 self.state.src_spans.push(span);
5634 let id = self.state.src_spans.len() as SrcId;
5635 self.state.src_dedup.insert(span, id);
5636 id
5637 }
5638
5639 fn src_buf_offset(&self, loc: integer) -> u32 {
5642 let col = loc as i64 - self.state.src_line_buf_start as i64;
5643 (self.state.src_line_base as i64 + col).max(0) as u32
5644 }
5645
5646 pub(crate) fn resolve_node_src(&self, node: halfword) -> Option<PortableSourceSpan> {
5650 if !self.state.source_tracking || node < 0 {
5651 return None;
5652 }
5653 let id = self.state.node_src.get_copy(node as usize);
5654 if id == 0 {
5655 return None;
5656 }
5657 let raw = *self.state.src_spans.get((id - 1) as usize)?;
5658 let name = unsafe { self.pool_string(raw.name) }?;
5659 Some(PortableSourceSpan {
5660 name,
5661 start: raw.start,
5662 end: raw.end,
5663 role: raw.role,
5664 })
5665 }
5666
5667 pub(crate) unsafe fn src_mark_token_start(engine: *mut Self) {
5671 let Some(engine) = engine.as_mut() else {
5672 return;
5673 };
5674 if engine.state.source_tracking && engine.state.curinput.statefield as i32 != 0 {
5675 engine.state.src_token_start = engine.state.curinput.locfield as integer;
5676 }
5677 }
5678
5679 pub(crate) unsafe fn src_record_buffer_span(engine: *mut Self) {
5684 let Some(engine) = engine.as_mut() else {
5685 return;
5686 };
5687 if !engine.state.source_tracking || engine.state.curinput.statefield as i32 == 0 {
5688 return;
5689 }
5690 let a = engine.src_buf_offset(engine.state.src_token_start);
5691 let b = engine.src_buf_offset(engine.state.curinput.locfield as integer);
5692 let (lo, hi) = if a <= b { (a, b) } else { (b, a) };
5693 let name = engine.state.curinput.namefield as strnumber;
5694 let id = engine.intern_span_raw(name, lo, hi, 0);
5695 engine.state.curinput.spanfield = id;
5696 engine.state.src_tok_span = id;
5697 if engine.state.curcs != 0
5714 && name == engine.state.src_primary_name
5715 && engine.state.scannerstatus as i32 == 0
5716 {
5717 engine.state.src_user_cmd_span = id;
5718 engine.state.src_anchor_cmd = 0;
5723 }
5724 }
5725
5726 pub(crate) unsafe fn src_tokenlist_span(engine: *mut Self) {
5733 let Some(engine) = engine.as_mut() else {
5734 return;
5735 };
5736 if !engine.state.source_tracking {
5737 return;
5738 }
5739 if engine.state.curinput.indexfield as i32 >= 5 {
5740 return;
5741 }
5742 {
5749 let lf = engine.state.curinput.locfield as i32;
5750 if lf >= 0 {
5751 let cid = engine.state.node_src.get_copy(lf as usize);
5752 if cid != 0 {
5753 engine.state.src_tok_span = cid;
5754 }
5755 }
5756 }
5757 let cell = engine.state.curinput.locfield as i32;
5758 if cell < 0 {
5759 return;
5760 }
5761 let id = engine.state.node_src.get_copy(cell as usize);
5762 if id != 0 {
5763 engine.state.curinput.spanfield = id;
5764 }
5765 }
5766
5767 pub(crate) unsafe fn src_back_input_stamp(engine: *mut Self, p: halfword) {
5779 let Some(engine) = engine.as_mut() else {
5780 return;
5781 };
5782 if !engine.state.source_tracking || p < 0 {
5783 return;
5784 }
5785 let id = engine.state.src_tok_span;
5786 if id != 0 {
5787 engine.state.node_src.set(p as usize, id);
5788 }
5789 }
5790
5791 pub(crate) unsafe fn src_latch_cmd_span(engine: *mut Self) {
5795 let Some(engine) = engine.as_mut() else {
5796 return;
5797 };
5798 if engine.state.source_tracking {
5799 engine.state.cmd_span = engine.state.curinput.spanfield;
5800 }
5801 }
5802
5803 pub(crate) unsafe fn src_stamp_avail(engine: *mut Self, node: halfword) {
5808 let Some(engine) = engine.as_mut() else {
5809 return;
5810 };
5811 if engine.state.source_tracking && node >= 0 {
5812 let id = engine.state.curinput.spanfield;
5813 engine.state.node_src.set(node as usize, id);
5814 engine.state.node_stack.set(node as usize, engine.state.cur_stack_head);
5815 }
5816 }
5817
5818 pub(crate) unsafe fn src_stamp_node_range(engine: *mut Self, node: halfword, size: integer) {
5825 let Some(engine) = engine.as_mut() else {
5826 return;
5827 };
5828 if !engine.state.source_tracking || node < 0 || size <= 0 {
5829 return;
5830 }
5831 let id = engine.state.cmd_span;
5832 let head = engine.state.cur_stack_head;
5833 let base = node as usize;
5834 for i in 0..size as usize {
5835 if id != 0 {
5836 engine.state.node_src.set(base + i, id);
5837 }
5838 if head != 0 {
5839 engine.state.node_stack.set(base + i, head);
5840 }
5841 }
5842 }
5843
5844 pub(crate) unsafe fn src_carry_copy(engine: *mut Self, src: halfword, dst: halfword) {
5853 let Some(engine) = engine.as_mut() else {
5854 return;
5855 };
5856 if !engine.state.source_tracking || src < 0 || dst < 0 {
5857 return;
5858 }
5859 let id = engine.state.node_src.get_copy(src as usize);
5860 if id != 0 {
5861 engine.state.node_src.set(dst as usize, id);
5862 let head = engine.state.node_stack.get_copy(src as usize);
5863 engine.state.node_stack.set(dst as usize, head);
5864 }
5865 }
5866
5867 pub(crate) unsafe fn src_carry_token_span(engine: *mut Self, dest: halfword, src: halfword) {
5880 let Some(engine) = engine.as_mut() else {
5881 return;
5882 };
5883 if !engine.state.source_tracking || dest < 0 || src < 0 {
5884 return;
5885 }
5886 let id = engine.state.node_src.get_copy(src as usize);
5887 if id != 0 {
5888 engine.state.node_src.set(dest as usize, id);
5889 let head = engine.state.node_stack.get_copy(src as usize);
5890 engine.state.node_stack.set(dest as usize, head);
5891 }
5892 }
5893
5894 pub(crate) unsafe fn src_stamp_char(engine: *mut Self, node: halfword) {
5899 let Some(engine) = engine.as_mut() else {
5900 return;
5901 };
5902 if !engine.state.source_tracking || node < 0 {
5903 return;
5904 }
5905 let id = engine.state.cmd_span;
5906 if id != 0 {
5907 engine.state.node_src.set(node as usize, id);
5908 }
5909 engine.state.node_stack.set(node as usize, engine.state.cur_stack_head);
5910 }
5911
5912 pub(crate) unsafe fn src_mlist_repoint(engine: *mut Self, q: halfword) {
5916 let Some(engine) = engine.as_mut() else {
5917 return;
5918 };
5919 if !engine.state.source_tracking || q < 0 {
5920 return;
5921 }
5922 let id = engine.state.node_src.get_copy(q as usize);
5923 if id != 0 {
5924 engine.state.cmd_span = id;
5925 }
5926 }
5927
5928 pub(crate) unsafe fn src_stamp_field(engine: *mut Self, field: halfword) {
5937 let Some(engine) = engine.as_mut() else {
5938 return;
5939 };
5940 if !engine.state.source_tracking || field < 0 {
5941 return;
5942 }
5943 let id = engine.state.curinput.spanfield;
5944 if id != 0 {
5945 engine.state.node_src.set(field as usize, id);
5946 }
5947 }
5948
5949 pub(crate) unsafe fn src_carry_field(engine: *mut Self, field: halfword, noad: halfword) {
5957 let Some(engine) = engine.as_mut() else {
5958 return;
5959 };
5960 if !engine.state.source_tracking || field < 0 || noad < 0 {
5961 return;
5962 }
5963 let id = engine.state.node_src.get_copy(field as usize);
5964 let head = engine.state.node_stack.get_copy(field as usize);
5965 if id != 0 {
5966 for i in 0..4usize {
5969 engine.state.node_src.set(noad as usize + i, id);
5970 }
5971 }
5972 if head != 0 {
5975 for i in 0..4usize {
5976 engine.state.node_stack.set(noad as usize + i, head);
5977 }
5978 }
5979 }
5980
5981 pub(crate) unsafe fn src_carry_nucleus(engine: *mut Self, noad: halfword, glyph: halfword) {
5994 let Some(engine) = engine.as_mut() else {
5995 return;
5996 };
5997 if !engine.state.source_tracking || noad < 0 || glyph < 0 {
5998 return;
5999 }
6000 let id = engine.state.node_src.get_copy(noad as usize + 1);
6001 if id != 0 {
6002 engine.state.node_src.set(glyph as usize, id);
6003 }
6004 let head = engine.state.node_stack.get_copy(noad as usize + 1);
6008 engine.state.node_stack.set(glyph as usize, head);
6009 }
6010
6011 pub(crate) unsafe fn src_carry_collapse(engine: *mut Self, noad: halfword, field: halfword) {
6018 let Some(engine) = engine.as_mut() else {
6019 return;
6020 };
6021 if !engine.state.source_tracking || noad < 0 || field < 0 {
6022 return;
6023 }
6024 let id = engine.state.node_src.get_copy(noad as usize);
6025 if id != 0 {
6026 engine.state.node_src.set(field as usize, id);
6027 }
6028 let head = engine.state.node_stack.get_copy(noad as usize);
6032 if head != 0 {
6033 engine.state.node_stack.set(field as usize, head);
6034 }
6035 }
6036
6037 pub(crate) unsafe fn src_save_cmd_span(engine: *mut Self) -> u32 {
6040 engine.as_ref().map_or(0, |engine| engine.state.cmd_span)
6041 }
6042
6043 pub(crate) unsafe fn src_restore_cmd_span(engine: *mut Self, saved: u32) {
6046 if let Some(engine) = engine.as_mut() {
6047 if engine.state.source_tracking {
6048 engine.state.cmd_span = saved;
6049 }
6050 }
6051 }
6052
6053 fn src_stack_push_span(self: &mut Self, span: SrcId) -> u32 {
6063 self.state.src_stack_cells.push(SrcStackCell {
6064 span,
6065 parent: self.state.cur_stack_head,
6066 start: 0,
6067 name: 0,
6068 pending: false,
6069 });
6070 let head = self.state.src_stack_cells.len() as u32;
6071 self.state.cur_stack_head = head;
6072 head
6073 }
6074
6075 fn src_stack_push_pending(self: &mut Self, start: u32, name: strnumber) -> u32 {
6078 self.state.src_stack_cells.push(SrcStackCell {
6079 span: 0,
6080 parent: self.state.cur_stack_head,
6081 start,
6082 name,
6083 pending: true,
6084 });
6085 let head = self.state.src_stack_cells.len() as u32;
6086 self.state.cur_stack_head = head;
6087 head
6088 }
6089
6090 fn src_stack_pop(self: &mut Self) {
6092 let head = self.state.cur_stack_head;
6093 if head != 0 {
6094 if let Some(cell) = self.state.src_stack_cells.get((head - 1) as usize) {
6095 self.state.cur_stack_head = cell.parent;
6096 }
6097 }
6098 }
6099
6100 pub(crate) unsafe fn src_end_token_list(engine: *mut Self, token_type: i32) {
6109 let Some(engine) = engine.as_mut() else {
6110 return;
6111 };
6112 if !engine.state.source_tracking {
6113 return;
6114 }
6115 let cand = engine.state.curinput.spanfield;
6116 if cand != 0 {
6117 let cand_end = engine
6118 .state
6119 .src_spans
6120 .get((cand - 1) as usize)
6121 .map(|r| r.end)
6122 .unwrap_or(0);
6123 let cur_end = if engine.state.src_call_argspan != 0 {
6124 engine
6125 .state
6126 .src_spans
6127 .get((engine.state.src_call_argspan - 1) as usize)
6128 .map(|r| r.end)
6129 .unwrap_or(0)
6130 } else {
6131 0
6132 };
6133 if engine.state.src_call_argspan == 0 || cand_end > cur_end {
6134 engine.state.src_call_argspan = cand;
6135 }
6136 }
6137 if token_type == 6 {
6138 engine.src_stack_pop();
6139 }
6140 }
6141
6142 pub(crate) unsafe fn src_scan_math_group_open(engine: *mut Self) {
6149 let Some(engine) = engine.as_mut() else {
6150 return;
6151 };
6152 if !engine.state.source_tracking {
6153 return;
6154 }
6155 let cmd = engine.state.cmd_span;
6156 let (start, name) = if cmd != 0 {
6157 match engine.state.src_spans.get((cmd - 1) as usize) {
6158 Some(raw) => (raw.start, raw.name),
6159 None => (0, 0),
6160 }
6161 } else {
6162 (0, 0)
6163 };
6164 engine.src_stack_push_pending(start, name);
6165 engine.state.src_grp_stack.push(engine.state.curinput.spanfield);
6170 }
6171
6172 pub(crate) unsafe fn src_scan_math_group_close(engine: *mut Self) {
6176 let eptr = engine;
6177 let Some(e) = engine.as_mut() else {
6178 return;
6179 };
6180 if !e.state.source_tracking {
6181 return;
6182 }
6183 e.state.src_grp_closing = e.state.src_grp_stack.pop().unwrap_or(0);
6187 let grp = e.state.src_grp_closing;
6188 let aux = e.state.curlist.auxfield.u.CINT;
6193 let frac = if aux > 0 && aux != -(268435455 as i32) { aux } else { -1 };
6194 if e.state.cur_stack_head != 0 {
6195 let idx = (e.state.cur_stack_head - 1) as usize;
6196 if let Some(cell) = e.state.src_stack_cells.get(idx).copied() {
6197 if cell.pending
6200 && cell.name != 0
6201 && cell.name == e.state.curinput.namefield as strnumber
6202 {
6203 let end = e.src_buf_offset(e.state.curinput.locfield as integer);
6204 let (lo, hi) = if cell.start <= end {
6205 (cell.start, end)
6206 } else {
6207 (end, cell.start)
6208 };
6209 let id = e.intern_span_raw(cell.name, lo, hi, 1);
6210 if let Some(c) = e.state.src_stack_cells.get_mut(idx) {
6211 c.span = id;
6212 c.pending = false;
6213 }
6214 }
6215 e.state.cur_stack_head = cell.parent;
6216 }
6217 }
6218 if frac >= 0 {
6219 Self::src_construct_extent(eptr, frac, grp);
6220 }
6221 }
6222
6223 pub(crate) unsafe fn src_construct_anchor(engine: *mut Self) {
6236 let Some(engine) = engine.as_mut() else {
6237 return;
6238 };
6239 if !engine.state.source_tracking {
6240 return;
6241 }
6242 let noad = engine.state.curlist.tailfield as i32;
6243 if noad < 0 {
6244 return;
6245 }
6246 let id = engine.state.node_src.get_copy(noad as usize);
6247 if id == 0 {
6248 return;
6249 }
6250 let Some(raw) = engine.state.src_spans.get((id - 1) as usize).copied() else {
6251 return;
6252 };
6253 let anchor = (engine.state.src_anchor_cmd != 0)
6267 .then(|| engine.state.src_spans.get((engine.state.src_anchor_cmd - 1) as usize).copied())
6268 .flatten()
6269 .filter(|u| u.name == raw.name);
6270 let chosen = match anchor {
6271 Some(u) => {
6272 if u.start < raw.start {
6273 Some(u)
6274 } else {
6275 None
6276 }
6277 }
6278 None => (engine.state.src_user_cmd_span != 0)
6279 .then(|| engine.state.src_spans.get((engine.state.src_user_cmd_span - 1) as usize).copied())
6280 .flatten()
6281 .filter(|u| u.name == raw.name && u.start < raw.start),
6282 };
6283 let Some(u) = chosen else {
6284 return;
6285 };
6286 let newid = engine.intern_span_raw(raw.name, u.start, raw.end, raw.role);
6287 engine.state.node_src.set(noad as usize, newid);
6288 }
6289
6290 pub(crate) unsafe fn src_construct_extend_to_loc(engine: *mut Self) {
6305 let e = match engine.as_ref() {
6306 Some(e) => e,
6307 None => return,
6308 };
6309 if !e.state.source_tracking {
6310 return;
6311 }
6312 let field = (*e
6315 .state
6316 .savestack
6317 .offset((e.state.saveptr as i32 + 0 as i32) as isize))
6318 .u
6319 .CINT;
6320 let noad = e.state.curlist.tailfield as i32;
6321 let grp = e.state.src_grp_closing;
6322 if noad < 0 || field != noad + 1 {
6323 return;
6324 }
6325 Self::src_construct_extent(engine, noad, grp);
6326 }
6327
6328 pub(crate) unsafe fn src_construct_extent(engine: *mut Self, noad: halfword, group_open: SrcId) {
6343 let Some(engine) = engine.as_mut() else {
6344 return;
6345 };
6346 if !engine.state.source_tracking || noad < 0 {
6347 return;
6348 }
6349 let id = engine.state.node_src.get_copy(noad as usize);
6350 if id == 0 {
6351 return;
6352 }
6353 let Some(raw) = engine.state.src_spans.get((id - 1) as usize).copied() else {
6354 return;
6355 };
6356 let (end, name) = if engine.state.curinput.statefield as i32 != 0 {
6357 (
6358 engine.src_buf_offset(engine.state.curinput.locfield as integer),
6359 engine.state.curinput.namefield as strnumber,
6360 )
6361 } else {
6362 let sid = engine.state.curinput.spanfield;
6363 if sid == 0 {
6364 return;
6365 }
6366 let Some(braw) = engine.state.src_spans.get((sid - 1) as usize).copied() else {
6367 return;
6368 };
6369 (braw.end, braw.name)
6370 };
6371 if raw.name != name {
6372 return;
6373 }
6374 let end = end.max(raw.end);
6375 let mut start = raw.start;
6376 if group_open != 0 {
6377 if let Some(g) = engine.state.src_spans.get((group_open - 1) as usize).copied() {
6378 if g.name == name && g.start < start {
6379 start = g.start;
6380 }
6381 }
6382 }
6383 if start == raw.start && end == raw.end {
6384 return;
6385 }
6386 let newid = engine.intern_span_raw(name, start, end, raw.role);
6387 engine.state.node_src.set(noad as usize, newid);
6388 }
6389
6390 pub(crate) unsafe fn src_leftright(engine: *mut Self, p: halfword, t: integer) {
6397 let Some(eng) = engine.as_mut() else {
6398 return;
6399 };
6400 if !eng.state.source_tracking {
6401 return;
6402 }
6403 if t == 30 as i32 {
6404 let cmd = eng.state.cmd_span;
6405 eng.state.src_grp_stack.push(cmd);
6406 } else if t == 31 as i32 {
6407 let open = eng.state.src_grp_stack.pop().unwrap_or(0);
6408 Self::src_construct_extent(engine, p, open);
6409 }
6410 }
6411
6412 pub fn node_enclosing_spans(&self, handle: PortableNodeHandle) -> Vec<PortableSourceSpan> {
6419 let node = handle.0 as halfword;
6420 let mut out: Vec<PortableSourceSpan> = Vec::new();
6421 if !self.state.source_tracking || node < 0 {
6422 return out;
6423 }
6424 let primary = self.resolve_node_src(node);
6425 let mut head = self.state.node_stack.get_copy(node as usize);
6426 let mut guard = 0u32;
6427 while head != 0 {
6428 guard += 1;
6429 if guard > 4096 {
6430 break;
6431 }
6432 let Some(cell) = self.state.src_stack_cells.get((head - 1) as usize) else {
6433 break;
6434 };
6435 let parent = cell.parent;
6436 let span_id = cell.span;
6437 head = parent;
6438 if span_id == 0 {
6439 continue;
6440 }
6441 let Some(raw) = self.state.src_spans.get((span_id - 1) as usize) else {
6442 continue;
6443 };
6444 let Some(name) = (unsafe { self.pool_string(raw.name) }) else {
6445 continue;
6446 };
6447 if let Some(p) = primary.as_ref() {
6448 if name != p.name || raw.start > p.start || raw.end < p.end {
6451 continue;
6452 }
6453 if raw.start == p.start && raw.end == p.end {
6454 continue;
6455 }
6456 }
6457 if let Some(last) = out.last() {
6458 if last.name == name && last.start == raw.start && last.end == raw.end {
6459 continue;
6460 }
6461 }
6462 out.push(PortableSourceSpan {
6463 name,
6464 start: raw.start,
6465 end: raw.end,
6466 role: 1,
6467 });
6468 }
6469 out
6470 }
6471
6472 pub(crate) unsafe fn src_begin_token_list(engine: *mut Self, t: quarterword) {
6477 let Some(engine) = engine.as_mut() else {
6478 return;
6479 };
6480 if !engine.state.source_tracking {
6481 return;
6482 }
6483 if t as i32 == 6 {
6485 let call = engine.state.pending_call_span;
6486 if call != 0 {
6487 engine.state.curinput.spanfield = call;
6488 }
6489 engine.state.pending_call_span = 0;
6490 engine.src_stack_push_span(call);
6494 }
6495 }
6496
6497 pub(crate) unsafe fn src_capture_tok_span(engine: *mut Self) -> u32 {
6515 engine.as_ref().map_or(0, |engine| engine.state.src_tok_span)
6516 }
6517
6518 pub(crate) unsafe fn src_restore_tok_span(engine: *mut Self, saved: u32) {
6520 if let Some(engine) = engine.as_mut() {
6521 if engine.state.source_tracking {
6522 engine.state.src_tok_span = saved;
6523 }
6524 }
6525 }
6526
6527 pub(crate) unsafe fn src_macro_begin(engine: *mut Self) {
6531 let Some(engine) = engine.as_mut() else {
6532 return;
6533 };
6534 if !engine.state.source_tracking {
6535 return;
6536 }
6537 let span = engine.state.curinput.spanfield;
6538 engine.state.src_call_span = span;
6539 engine.state.src_call_state = engine.state.curinput.statefield as integer;
6540 engine.state.src_call_index = engine.state.curinput.indexfield as integer;
6541 engine.state.src_call_name = engine.state.curinput.namefield as strnumber;
6542 engine.state.src_call_argspan = 0;
6543 engine.state.src_call_user_span = engine.state.src_user_cmd_span;
6547 engine.state.src_call_start = if span != 0 {
6548 engine
6549 .state
6550 .src_spans
6551 .get((span - 1) as usize)
6552 .map(|s| s.start)
6553 .unwrap_or(0)
6554 } else {
6555 0
6556 };
6557 if engine.state.src_call_state == 0 && engine.state.src_call_index < 3 && span != 0 {
6568 if let Some(raw) = engine.state.src_spans.get((span - 1) as usize).copied() {
6569 if raw.name == engine.state.src_primary_name {
6570 engine.state.src_anchor_cmd = span;
6571 }
6572 }
6573 }
6574 }
6575
6576 unsafe fn src_arg_hull(self: &mut Self, n: integer) -> SrcId {
6583 let mut lo = u32::MAX;
6584 let mut hi = 0u32;
6585 let mut found = false;
6586 let mut name: strnumber = self.state.src_primary_name;
6587 if self.state.src_call_span != 0 {
6588 if let Some(raw) = self
6589 .state
6590 .src_spans
6591 .get((self.state.src_call_span - 1) as usize)
6592 {
6593 name = raw.name;
6594 lo = raw.start;
6595 hi = raw.end;
6596 found = true;
6597 }
6598 }
6599 let cmd_start = if found { lo } else { 0 };
6607 let zmem = self.state.zmem;
6608 let lo_b = self.state.memmin;
6609 let hi_b = self.state.memmax;
6610 for i in 0..n.max(0) {
6611 let mut p = self.state.pstack[i as usize];
6612 let mut guard = 0i32;
6613 while p >= lo_b && p <= hi_b && p as i64 != -(268435455 as i64) {
6614 guard += 1;
6615 if guard > 100000 {
6616 break;
6617 }
6618 let id = self.state.node_src.get_copy(p as usize);
6619 if id != 0 {
6620 if let Some(raw) = self.state.src_spans.get((id - 1) as usize) {
6621 if raw.name == name && raw.start >= cmd_start {
6622 if found {
6623 lo = lo.min(raw.start);
6624 hi = hi.max(raw.end);
6625 } else {
6626 lo = raw.start;
6627 hi = raw.end;
6628 found = true;
6629 }
6630 }
6631 }
6632 }
6633 p = (*zmem.offset(p as isize)).hh.v.RH;
6634 }
6635 }
6636 for cand in [self.state.src_call_argspan, self.state.curinput.spanfield] {
6643 if cand == 0 {
6644 continue;
6645 }
6646 if let Some(raw) = self.state.src_spans.get((cand - 1) as usize) {
6647 if raw.name == name && raw.start >= cmd_start {
6648 if found {
6649 lo = lo.min(raw.start);
6650 hi = hi.max(raw.end);
6651 } else {
6652 lo = raw.start;
6653 hi = raw.end;
6654 found = true;
6655 }
6656 }
6657 }
6658 }
6659 if found && hi > lo {
6660 self.intern_span_raw(name, lo, hi, 1)
6661 } else {
6662 0
6663 }
6664 }
6665
6666 pub(crate) unsafe fn src_macro_set_pending(engine: *mut Self, n: integer) {
6684 let Some(engine) = engine.as_mut() else {
6685 return;
6686 };
6687 if !engine.state.source_tracking {
6688 return;
6689 }
6690 if engine.state.src_call_index == 0 && engine.state.src_call_span == 0 {
6691 engine.state.pending_call_span = 0;
6701 } else if engine.state.src_call_index == 0 {
6702 let hull = engine.src_arg_hull(n);
6705 engine.state.pending_call_span = if hull != 0 {
6706 hull
6707 } else {
6708 engine.state.src_call_span
6709 };
6710 } else if engine.state.curinput.statefield as i32 != 0 {
6711 let end = engine.src_buf_offset(engine.state.curinput.locfield as integer);
6721 let name = engine.state.curinput.namefield as strnumber;
6722 let mut start = engine.state.src_call_start.min(end);
6723 let user = engine.state.src_call_user_span;
6724 if user != 0 {
6725 if let Some(raw) = engine.state.src_spans.get((user - 1) as usize) {
6726 if raw.name == name && raw.start <= start {
6727 start = raw.start;
6728 }
6729 }
6730 }
6731 let id = engine.intern_span_raw(name, start, end, 1);
6732 engine.state.pending_call_span = id;
6733 } else if n > 0 {
6734 let hull = engine.src_arg_hull(n);
6745 engine.state.pending_call_span = if hull != 0 {
6746 hull
6747 } else {
6748 engine.state.src_call_span
6749 };
6750 } else {
6751 engine.state.pending_call_span = engine.state.src_call_span;
6752 }
6753 }
6754
6755 pub(crate) unsafe fn src_native_run_push(engine: *mut Self) {
6764 let Some(engine) = engine.as_mut() else {
6765 return;
6766 };
6767 if !engine.state.source_tracking {
6768 return;
6769 }
6770 let nativelen = engine.state.nativelen.max(0) as usize;
6771 let units = if engine.state.curchr as i64 > 65535 { 2 } else { 1 };
6774 let prev = nativelen.saturating_sub(units);
6775 if prev == 0 {
6776 engine.state.src_native_offsets.clear();
6777 }
6778 if engine.state.src_native_offsets.len() > prev {
6781 engine.state.src_native_offsets.truncate(prev);
6782 }
6783 let id = engine.state.curinput.spanfield;
6784 while engine.state.src_native_offsets.len() < nativelen {
6785 engine.state.src_native_offsets.push(id);
6786 }
6787 }
6788
6789 pub(crate) unsafe fn src_resolve_native_glyphs(
6805 engine: *mut Self,
6806 node: halfword,
6807 text: &[u16],
6808 glyphs: &mut [PortableNativeGlyph],
6809 ) {
6810 let Some(engine) = engine.as_mut() else {
6811 return;
6812 };
6813 if !engine.state.source_tracking {
6814 return;
6815 }
6816 let offsets = core::mem::take(&mut engine.state.src_native_offsets);
6817 if text.is_empty() || offsets.len() != text.len() {
6820 return;
6821 }
6822 if node < 0 {
6823 return;
6824 }
6825 let node_id = engine.state.node_src.get_copy(node as usize);
6828 if node_id == 0 {
6829 return;
6830 }
6831 let node_name = match engine.state.src_spans.get((node_id - 1) as usize) {
6832 Some(raw) => raw.name,
6833 None => return,
6834 };
6835 let s = String::from_utf16_lossy(text);
6841 let n = s.len();
6842 let mut byte_src = vec![0u32; n];
6843 let mut u16i = 0usize;
6844 for (b, ch) in s.char_indices() {
6845 let id = offsets.get(u16i).copied().unwrap_or(0);
6846 let upper = (b + ch.len_utf8()).min(n);
6847 for slot in byte_src.iter_mut().take(upper).skip(b) {
6848 *slot = id;
6849 }
6850 u16i += ch.len_utf16();
6851 }
6852 for gi in 0..glyphs.len() {
6853 let cs = (glyphs[gi].cluster_start as usize).min(n);
6854 let mut ce = n;
6858 for g2 in glyphs.iter() {
6859 let c2 = (g2.cluster_start as usize).min(n);
6860 if c2 > cs && c2 < ce {
6861 ce = c2;
6862 }
6863 }
6864 let mut lo = u32::MAX;
6865 let mut hi = 0u32;
6866 let mut found = false;
6867 for &id in byte_src.iter().take(ce).skip(cs) {
6868 if id == 0 {
6869 continue;
6870 }
6871 let Some(raw) = engine.state.src_spans.get((id - 1) as usize) else {
6872 continue;
6873 };
6874 if raw.name != node_name {
6875 continue;
6876 }
6877 lo = lo.min(raw.start);
6878 hi = hi.max(raw.end);
6879 found = true;
6880 }
6881 if found && hi > lo {
6882 glyphs[gi].src_start = lo;
6883 glyphs[gi].src_end = hi;
6884 }
6885 }
6886 }
6887
6888 pub fn input_source_spans(&self) -> Vec<PortableSourceSpan> {
6891 self.state
6892 .src_spans
6893 .iter()
6894 .filter_map(|raw| {
6895 let name = unsafe { self.pool_string(raw.name) }?;
6896 Some(PortableSourceSpan {
6897 name,
6898 start: raw.start,
6899 end: raw.end,
6900 role: raw.role,
6901 })
6902 })
6903 .collect()
6904 }
6905
6906 pub(crate) unsafe fn resolve_font_handle(
6907 engine: *mut PortableTexEngine<'_>,
6908 name: *mut ASCIIcode,
6909 size: integer,
6910 ) -> FontHandle {
6911 let Some(engine) = engine.as_mut() else {
6912 return 0;
6913 };
6914 let name_len = engine.state.namelength.max(0) as usize;
6915 let name = if name.is_null() || name_len == 0 {
6916 &[]
6917 } else {
6918 core::slice::from_raw_parts(name as *const i32, name_len)
6919 };
6920 engine.fonts.resolve_font_handle(name, size).unwrap_or(0)
6921 }
6922
6923 pub(crate) unsafe fn measure_font_metrics(
6924 engine: *mut PortableTexEngine<'_>,
6925 font: FontHandle,
6926 ascent: *mut integer,
6927 descent: *mut integer,
6928 xheight: *mut integer,
6929 capheight: *mut integer,
6930 slant: *mut integer,
6931 ) {
6932 let metrics = engine
6933 .as_mut()
6934 .map(|engine| engine.fonts.font_metrics(font))
6935 .unwrap_or_default();
6936 if !ascent.is_null() {
6937 *ascent = metrics.ascent;
6938 }
6939 if !descent.is_null() {
6940 *descent = metrics.descent;
6941 }
6942 if !xheight.is_null() {
6943 *xheight = metrics.xheight;
6944 }
6945 if !capheight.is_null() {
6946 *capheight = metrics.capheight;
6947 }
6948 if !slant.is_null() {
6949 *slant = metrics.slant;
6950 }
6951 }
6952
6953 pub(crate) unsafe fn get_native_mathsy_parameter(
6954 engine: *mut PortableTexEngine<'resources>,
6955 font: integer,
6956 param: integer,
6957 ) -> integer {
6958 let Some(engine) = engine.as_mut() else {
6959 return 0;
6960 };
6961 let Some(font_handle) = Self::font_handle_for_number(engine, font) else {
6962 return 0;
6963 };
6964 engine.fonts.math_symbol_parameter(font_handle, param)
6965 }
6966
6967 pub(crate) unsafe fn get_native_mathex_parameter(
6968 engine: *mut PortableTexEngine<'resources>,
6969 font: integer,
6970 param: integer,
6971 ) -> integer {
6972 let Some(engine) = engine.as_mut() else {
6973 return 0;
6974 };
6975 let Some(font_handle) = Self::font_handle_for_number(engine, font) else {
6976 return 0;
6977 };
6978 engine.fonts.math_extension_parameter(font_handle, param)
6979 }
6980
6981 pub(crate) unsafe fn get_ot_math_ital_corr(
6990 engine: *mut PortableTexEngine<'resources>,
6991 font: integer,
6992 glyph: integer,
6993 ) -> integer {
6994 let Some(engine) = engine.as_mut() else {
6995 return 0;
6996 };
6997 let Some(font_handle) = Self::font_handle_for_number(engine, font) else {
6998 return 0;
6999 };
7000 engine.fonts.math_glyph_italic_correction(font_handle, glyph)
7001 }
7002
7003 pub(crate) unsafe fn get_ot_math_variant(
7008 engine: *mut PortableTexEngine<'resources>,
7009 f_0: integer,
7010 g_0: integer,
7011 v: integer,
7012 adv: *mut integer,
7013 horiz: integer,
7014 ) -> integer {
7015 if !adv.is_null() {
7016 *adv = -1;
7017 }
7018 let Some(engine) = engine.as_mut() else {
7019 return g_0;
7020 };
7021 let Some(font_handle) = Self::font_handle_for_number(engine, f_0) else {
7022 return g_0;
7023 };
7024 let index = u16::try_from(v).unwrap_or(u16::MAX);
7025 match engine
7026 .fonts
7027 .math_glyph_variant(font_handle, g_0, index, horiz != 0)
7028 {
7029 Some(variant) => {
7030 if !adv.is_null() {
7031 *adv = variant.advance;
7032 }
7033 variant.glyph
7034 }
7035 None => g_0,
7036 }
7037 }
7038
7039 pub(crate) unsafe fn get_ot_assembly_ptr(
7045 engine: *mut PortableTexEngine<'resources>,
7046 f_0: integer,
7047 g_0: integer,
7048 horiz: integer,
7049 ) -> voidpointer {
7050 let Some(engine) = engine.as_mut() else {
7051 return nullptr;
7052 };
7053 let Some(font_handle) = Self::font_handle_for_number(engine, f_0) else {
7054 return nullptr;
7055 };
7056 let parts = engine
7057 .fonts
7058 .math_glyph_assembly(font_handle, g_0, horiz != 0);
7059 if parts.is_empty() {
7060 return nullptr;
7061 }
7062 let assembly = Box::new(GlyphAssembly { parts });
7063 Box::into_raw(assembly) as voidpointer
7064 }
7065
7066 pub(crate) unsafe fn ot_min_connector_overlap(
7069 engine: *mut PortableTexEngine<'resources>,
7070 f_0: integer,
7071 ) -> integer {
7072 let Some(engine) = engine.as_mut() else {
7073 return 0;
7074 };
7075 let Some(font_handle) = Self::font_handle_for_number(engine, f_0) else {
7076 return 0;
7077 };
7078 engine.fonts.math_min_connector_overlap(font_handle)
7079 }
7080
7081 unsafe fn math_glyph_height(
7083 engine: &mut PortableTexEngine<'resources>,
7084 f_0: integer,
7085 g_0: integer,
7086 ) -> scaled {
7087 let Some(font_handle) = Self::font_handle_for_number(engine, f_0) else {
7088 return 0;
7089 };
7090 let Ok(glyph) = u16::try_from(g_0) else {
7091 return 0;
7092 };
7093 engine.fonts.measure_native_glyph(font_handle, glyph, true).height
7094 }
7095
7096 unsafe fn math_glyph_depth(
7098 engine: &mut PortableTexEngine<'resources>,
7099 f_0: integer,
7100 g_0: integer,
7101 ) -> scaled {
7102 let Some(font_handle) = Self::font_handle_for_number(engine, f_0) else {
7103 return 0;
7104 };
7105 let Ok(glyph) = u16::try_from(g_0) else {
7106 return 0;
7107 };
7108 engine.fonts.measure_native_glyph(font_handle, glyph, true).depth
7109 }
7110
7111 unsafe fn math_kern_at(
7114 engine: &mut PortableTexEngine<'resources>,
7115 f_0: integer,
7116 g_0: integer,
7117 height: integer,
7118 corner: PortableMathKernCorner,
7119 ) -> integer {
7120 let Some(font_handle) = Self::font_handle_for_number(engine, f_0) else {
7121 return 0;
7122 };
7123 engine.fonts.math_kern_at(font_handle, g_0, corner, height)
7124 }
7125
7126 pub(crate) unsafe fn get_ot_math_kern(
7133 engine: *mut PortableTexEngine<'resources>,
7134 f_0: integer,
7135 g_0: integer,
7136 sf: integer,
7137 sg: integer,
7138 cmd: integer,
7139 shift_scaled: integer,
7140 ) -> integer {
7141 const SUP_CMD: integer = 0;
7142 const SUB_CMD: integer = 1;
7143 let Some(engine) = engine.as_mut() else {
7144 return 0;
7145 };
7146 let Some(font_handle) = Self::font_handle_for_number(engine, f_0) else {
7147 return 0;
7148 };
7149 let Some(sfont_handle) = Self::font_handle_for_number(engine, sf) else {
7150 return 0;
7151 };
7152
7153 let g_height_pt = Self::math_glyph_height(engine, f_0, g_0) as f32 / 65536.0;
7155 let g_depth_pt = Self::math_glyph_depth(engine, f_0, g_0) as f32 / 65536.0;
7156 let sg_height_pt = Self::math_glyph_height(engine, sf, sg) as f32 / 65536.0;
7157 let sg_depth_pt = Self::math_glyph_depth(engine, sf, sg) as f32 / 65536.0;
7158
7159 let g_height = engine.fonts.math_points_to_units(font_handle, g_height_pt) as integer;
7161 let g_depth = engine.fonts.math_points_to_units(font_handle, g_depth_pt) as integer;
7162 let sg_height = engine
7163 .fonts
7164 .math_points_to_units(sfont_handle, sg_height_pt) as integer;
7165 let sg_depth = engine
7166 .fonts
7167 .math_points_to_units(sfont_handle, sg_depth_pt) as integer;
7168 let shift_pt = shift_scaled as f32 / 65536.0;
7169 let shift = engine.fonts.math_points_to_units(font_handle, shift_pt) as integer;
7170
7171 let f_size = engine.fonts.math_point_size(font_handle);
7172 let sf_size = engine.fonts.math_point_size(sfont_handle);
7173 if f_size == 0.0 {
7174 return 0;
7175 }
7176 let scale_factor = sf_size / f_size;
7177
7178 let mut rval: integer;
7179 if cmd == SUP_CMD {
7180 let kern = Self::math_kern_at(
7181 engine,
7182 f_0,
7183 g_0,
7184 shift - (scale_factor * sg_depth as f32) as integer,
7185 PortableMathKernCorner::TopRight,
7186 );
7187 let skern =
7188 Self::math_kern_at(engine, sf, sg, -sg_depth, PortableMathKernCorner::BottomLeft);
7189 let top_kern = kern + (scale_factor * skern as f32) as integer;
7190
7191 let kern =
7192 Self::math_kern_at(engine, f_0, g_0, g_height, PortableMathKernCorner::TopRight);
7193 let skern = Self::math_kern_at(
7194 engine,
7195 sf,
7196 sg,
7197 ((g_height - shift) as f32 / scale_factor) as integer,
7198 PortableMathKernCorner::BottomLeft,
7199 );
7200 let bot_kern = kern + (scale_factor * skern as f32) as integer;
7201
7202 rval = if top_kern > bot_kern { top_kern } else { bot_kern };
7203 } else if cmd == SUB_CMD {
7204 let kern = Self::math_kern_at(
7205 engine,
7206 f_0,
7207 g_0,
7208 (scale_factor * sg_height as f32) as integer - shift,
7209 PortableMathKernCorner::BottomRight,
7210 );
7211 let skern =
7212 Self::math_kern_at(engine, sf, sg, sg_height, PortableMathKernCorner::TopLeft);
7213 let top_kern = kern + (scale_factor * skern as f32) as integer;
7214
7215 let kern =
7216 Self::math_kern_at(engine, f_0, g_0, -g_depth, PortableMathKernCorner::BottomRight);
7217 let skern = Self::math_kern_at(
7218 engine,
7219 sf,
7220 sg,
7221 ((shift - g_depth) as f32 / scale_factor) as integer,
7222 PortableMathKernCorner::TopLeft,
7223 );
7224 let bot_kern = kern + (scale_factor * skern as f32) as integer;
7225
7226 rval = if top_kern > bot_kern { top_kern } else { bot_kern };
7227 } else {
7228 return 0;
7229 }
7230
7231 rval = engine.fonts.math_units_to_scaled(font_handle, rval);
7232 rval
7233 }
7234
7235 pub(crate) unsafe fn get_native_word_cp(
7236 engine: *mut PortableTexEngine<'resources>,
7237 node: voidpointer,
7238 side: integer,
7239 ) -> integer {
7240 let Some(engine) = engine.as_mut() else {
7241 return 0;
7242 };
7243 let Some(node_index) = Self::node_index_for_pointer(engine, node) else {
7244 return 0;
7245 };
7246 let Some(info) = engine.native_glyph_infos.get(&node_index) else {
7247 return 0;
7248 };
7249 let glyph = if side == 0 {
7250 info.glyphs.first()
7251 } else {
7252 info.glyphs.last()
7253 };
7254 let Some(glyph) = glyph else {
7255 return 0;
7256 };
7257 let font = Self::native_node_font(engine.state.zmem, node_index);
7258 Self::character_protrusion(engine, font, u32::from(glyph.glyph_id), side)
7259 }
7260
7261 pub(crate) unsafe fn get_native_glyph(
7262 engine: *mut PortableTexEngine<'resources>,
7263 node: voidpointer,
7264 index: u32,
7265 ) -> uint16_t {
7266 let Some(engine) = engine.as_mut() else {
7267 return 0;
7268 };
7269 let Some(node_index) = Self::node_index_for_pointer(engine, node) else {
7270 return 0;
7271 };
7272 engine
7273 .native_glyph_infos
7274 .get(&node_index)
7275 .and_then(|info| info.glyphs.get(index as usize))
7276 .map_or(0, |glyph| glyph.glyph_id)
7277 }
7278
7279 pub(crate) unsafe fn get_character_protrusion(
7280 engine: *mut PortableTexEngine<'_>,
7281 font: integer,
7282 code: u32,
7283 side: integer,
7284 ) -> integer {
7285 engine
7286 .as_mut()
7287 .map_or(0, |engine| Self::character_protrusion(engine, font, code, side))
7288 }
7289
7290 pub(crate) fn character_protrusion(
7291 engine: &PortableTexEngine<'_>,
7292 font: integer,
7293 code: u32,
7294 side: integer,
7295 ) -> integer {
7296 engine
7297 .character_protrusions
7298 .get(&(font, code, side))
7299 .copied()
7300 .unwrap_or(0)
7301 }
7302
7303 pub(crate) fn set_character_protrusion(
7304 engine: &mut PortableTexEngine<'_>,
7305 font: integer,
7306 code: u32,
7307 side: integer,
7308 value: integer,
7309 ) {
7310 let key = (font, code, side);
7311 if value == 0 {
7312 engine.character_protrusions.remove(&key);
7313 } else {
7314 engine.character_protrusions.insert(key, value);
7315 }
7316 }
7317
7318 pub(crate) unsafe fn get_opentype_math_constant(
7319 engine: *mut PortableTexEngine<'resources>,
7320 font: integer,
7321 constant: integer,
7322 ) -> integer {
7323 let Some(engine) = engine.as_mut() else {
7324 return 0;
7325 };
7326 let Some(font_handle) = Self::font_handle_for_number(engine, font) else {
7327 return 0;
7328 };
7329 engine.fonts.opentype_math_constant(font_handle, constant)
7330 }
7331
7332 pub(crate) unsafe fn get_opentype_math_accent_position(
7333 engine: *mut PortableTexEngine<'resources>,
7334 font: integer,
7335 glyph: integer,
7336 ) -> integer {
7337 let Some(engine) = engine.as_mut() else {
7338 return 0;
7339 };
7340 let Some(font_handle) = Self::font_handle_for_number(engine, font) else {
7341 return 0;
7342 };
7343 engine.fonts.opentype_math_accent_position(font_handle, glyph)
7344 }
7345
7346 pub(crate) unsafe fn map_char_to_glyph(
7347 engine: *mut PortableTexEngine<'resources>,
7348 font: integer,
7349 ch: integer,
7350 ) -> integer {
7351 let Some(engine) = engine.as_mut() else {
7352 return 0;
7353 };
7354 let Some(font_handle) = Self::font_handle_for_number(engine, font) else {
7355 return 0;
7356 };
7357 engine.fonts.map_char_to_glyph(font_handle, ch)
7358 }
7359
7360 pub(crate) unsafe fn map_glyph_to_index(
7361 engine: *mut PortableTexEngine<'resources>,
7362 font: integer,
7363 ) -> integer {
7364 let Some(engine) = engine.as_mut() else {
7365 return 0;
7366 };
7367 let Some(font_handle) = Self::font_handle_for_number(engine, font) else {
7368 return 0;
7369 };
7370 let Some(name) = engine.pool_string(engine.state.curname) else {
7371 return 0;
7372 };
7373 engine.fonts.map_glyph_to_index(font_handle, name.as_str())
7374 }
7375
7376 pub(crate) unsafe fn ot_font_get(
7381 engine: *mut PortableTexEngine<'resources>,
7382 what: integer,
7383 font: integer,
7384 param1: integer,
7385 param2: integer,
7386 param3: integer,
7387 ) -> integer {
7388 let Some(engine) = engine.as_mut() else {
7389 return 0;
7390 };
7391 let Some(font_handle) = Self::font_handle_for_number(engine, font) else {
7392 return 0;
7393 };
7394 engine
7395 .fonts
7396 .ot_font_get(font_handle, what, param1, param2, param3)
7397 }
7398
7399 pub(crate) unsafe fn is_opentype_math_font(
7400 engine: *mut PortableTexEngine<'_>,
7401 font: FontHandle,
7402 ) -> boolean {
7403 engine
7404 .as_mut()
7405 .map(|engine| engine.fonts.is_opentype_math_font(font) as boolean)
7406 .unwrap_or(false_0)
7407 }
7408
7409 pub(crate) unsafe fn using_opentype(
7410 engine: *mut PortableTexEngine<'_>,
7411 font: FontHandle,
7412 ) -> boolean {
7413 engine
7414 .as_mut()
7415 .map(|engine| engine.fonts.using_opentype(font) as boolean)
7416 .unwrap_or(false_0)
7417 }
7418
7419 pub(crate) unsafe fn release_font_engine(
7420 engine: *mut PortableTexEngine<'_>,
7421 font: FontHandle,
7422 type_flag: integer,
7423 ) {
7424 if let Some(engine) = engine.as_mut() {
7425 engine.fonts.release_font_handle(font, type_flag);
7426 }
7427 }
7428
7429 pub(crate) unsafe fn measure_opentype_font_metrics(
7430 engine: *mut PortableTexEngine<'_>,
7431 font: FontHandle,
7432 ascent: *mut integer,
7433 descent: *mut integer,
7434 xheight: *mut integer,
7435 capheight: *mut integer,
7436 slant: *mut integer,
7437 ) {
7438 let metrics = engine
7439 .as_mut()
7440 .map(|engine| engine.fonts.opentype_font_metrics(font))
7441 .unwrap_or_default();
7442 if !ascent.is_null() {
7443 *ascent = metrics.ascent;
7444 }
7445 if !descent.is_null() {
7446 *descent = metrics.descent;
7447 }
7448 if !xheight.is_null() {
7449 *xheight = metrics.xheight;
7450 }
7451 if !capheight.is_null() {
7452 *capheight = metrics.capheight;
7453 }
7454 if !slant.is_null() {
7455 *slant = metrics.slant;
7456 }
7457 }
7458
7459 pub(crate) unsafe fn measure_native_node(
7460 engine: *mut PortableTexEngine<'resources>,
7461 node: voidpointer,
7462 use_glyph_metrics: integer,
7463 ) {
7464 let Some(engine) = engine.as_mut() else {
7465 return;
7466 };
7467 let Some(node_index) = Self::node_index_for_pointer(engine, node) else {
7468 return;
7469 };
7470 let mem = engine.state.zmem;
7471 let font_number = Self::native_node_font(mem, node_index);
7472 let Some(font_handle) = Self::font_handle_for_number(engine, font_number) else {
7473 return;
7474 };
7475 let text = Self::native_node_text(mem, node_index);
7476 let mut metrics =
7477 engine
7478 .fonts
7479 .shape_native_text(font_handle, text, use_glyph_metrics != 0);
7480 Self::src_resolve_native_glyphs(
7484 engine as *mut PortableTexEngine<'resources>,
7485 node_index,
7486 text,
7487 metrics.glyphs.as_mut_slice(),
7488 );
7489 Self::write_native_node_metrics(
7490 mem,
7491 node_index,
7492 metrics.width,
7493 metrics.height,
7494 metrics.depth,
7495 );
7496 (*mem.offset((node_index + 4) as isize)).v.QQQQ.u.B3 =
7497 (metrics.glyphs.len().min(i32::MAX as usize) as quarterword) as u16;
7498 (*mem.offset((node_index + 5) as isize)).ptr = nullptr;
7499 engine.native_glyph_infos.insert(
7500 node_index,
7501 PortableNativeGlyphInfo {
7502 glyphs: metrics.glyphs,
7503 },
7504 );
7505 }
7506
7507 pub(crate) unsafe fn measure_native_glyph(
7508 engine: *mut PortableTexEngine<'resources>,
7509 node: voidpointer,
7510 use_glyph_metrics: integer,
7511 ) {
7512 let Some(engine) = engine.as_mut() else {
7513 return;
7514 };
7515 let Some(node_index) = Self::node_index_for_pointer(engine, node) else {
7516 return;
7517 };
7518 let mem = engine.state.zmem;
7519 let font_number = Self::native_node_font(mem, node_index);
7520 let Some(font_handle) = Self::font_handle_for_number(engine, font_number) else {
7521 return;
7522 };
7523 let glyph = (*mem.offset((node_index + 4) as isize)).v.QQQQ.u.B2 as u16;
7524 let metrics = engine
7525 .fonts
7526 .measure_native_glyph(font_handle, glyph, use_glyph_metrics != 0);
7527 Self::write_native_node_metrics(
7528 mem,
7529 node_index,
7530 metrics.width,
7531 metrics.height,
7532 metrics.depth,
7533 );
7534 (*mem.offset((node_index + 4) as isize)).v.QQQQ.u.B3 = (1 as quarterword) as u16;
7535 engine.native_glyph_infos.insert(
7545 node_index,
7546 PortableNativeGlyphInfo {
7547 glyphs: Vec::from([PortableNativeGlyph {
7548 glyph_id: glyph,
7549 x: 0,
7550 y: 0,
7551 advance: metrics.width,
7552 cluster_start: 0,
7553 cluster_end: 0,
7554 src_start: 0,
7555 src_end: 0,
7556 }]),
7557 },
7558 );
7559 }
7560
7561 pub(crate) unsafe fn znotaatfonterror(
7562 self: &mut Self,
7563 cmd: integer,
7564 c_0: integer,
7565 f_0: integer,
7566 ) -> EngineFlow<()> {
7567 self.znototfonterror(cmd, c_0, f_0)?;
7568 Ok(())
7569 }
7570
7571 pub(crate) unsafe fn znotaatgrfonterror(
7572 self: &mut Self,
7573 cmd: integer,
7574 c_0: integer,
7575 f_0: integer,
7576 ) -> EngineFlow<()> {
7577 self.znototfonterror(cmd, c_0, f_0)?;
7578 Ok(())
7579 }
7580
7581 unsafe fn stack_glyph_into_box(
7586 self: &mut Self,
7587 b: halfword,
7588 f_0: internalfontnumber,
7589 g_0: integer,
7590 ) -> EngineFlow<()> {
7591 let mem: *mut memoryword = self.state.zmem.as_mut_ptr();
7592 const NULL: halfword = -(268435455 as i64) as halfword;
7593 let p = (&mut *(self as *mut PortableTexEngine<'_>)).zgetnode(5)?;
7594 (*mem.offset(p as isize)).hh.u.B0 = 8;
7595 (*mem.offset(p as isize)).hh.u.B1 = 42;
7596 (*mem.offset((p + 4) as isize)).v.QQQQ.u.B1 = (f_0 as quarterword) as u16;
7597 (*mem.offset((p + 4) as isize)).v.QQQQ.u.B2 = (g_0 as quarterword) as u16;
7598 Self::measure_native_glyph(
7599 self as *mut PortableTexEngine<'resources>,
7600 mem.offset(p as isize) as *mut memoryword as *mut (),
7601 1,
7602 );
7603 Ok(
7604 if (*mem.offset(b as isize)).hh.u.B0 as i32 == 0 {
7605 let mut q = (*mem.offset((b + 5) as isize)).hh.v.RH;
7606 if q == NULL {
7607 (*mem.offset((b + 5) as isize)).hh.v.RH = p;
7608 } else {
7609 while (*mem.offset(q as isize)).hh.v.RH != NULL {
7610 q = (*mem.offset(q as isize)).hh.v.RH;
7611 }
7612 (*mem.offset(q as isize)).hh.v.RH = p;
7613 if (*mem.offset((b + 3) as isize)).u.CINT
7614 < (*mem.offset((p + 3) as isize)).u.CINT
7615 {
7616 (*mem.offset((b + 3) as isize)).u.CINT = (*mem
7617 .offset((p + 3) as isize))
7618 .u
7619 .CINT;
7620 }
7621 if (*mem.offset((b + 2) as isize)).u.CINT
7622 < (*mem.offset((p + 2) as isize)).u.CINT
7623 {
7624 (*mem.offset((b + 2) as isize)).u.CINT = (*mem
7625 .offset((p + 2) as isize))
7626 .u
7627 .CINT;
7628 }
7629 }
7630 } else {
7631 (*mem.offset(p as isize)).hh.v.RH = (*mem.offset((b + 5) as isize))
7632 .hh
7633 .v
7634 .RH;
7635 (*mem.offset((b + 5) as isize)).hh.v.RH = p;
7636 (*mem.offset((b + 3) as isize)).u.CINT = (*mem.offset((p + 3) as isize))
7637 .u
7638 .CINT;
7639 if (*mem.offset((b + 1) as isize)).u.CINT
7640 < (*mem.offset((p + 1) as isize)).u.CINT
7641 {
7642 (*mem.offset((b + 1) as isize)).u.CINT = (*mem
7643 .offset((p + 1) as isize))
7644 .u
7645 .CINT;
7646 }
7647 },
7648 )
7649 }
7650
7651 unsafe fn stack_glue_into_box(
7654 self: &mut Self,
7655 b: halfword,
7656 min: scaled,
7657 max: scaled,
7658 ) -> EngineFlow<()> {
7659 let mem: *mut memoryword = self.state.zmem.as_mut_ptr();
7660 const NULL: halfword = -(268435455 as i64) as halfword;
7661 const ZERO_GLUE: halfword = 0;
7662 let q = (&mut *(self as *mut PortableTexEngine<'_>)).znewspec(ZERO_GLUE)?;
7663 (*mem.offset((q + 1) as isize)).u.CINT = min;
7664 (*mem.offset((q + 2) as isize)).u.CINT = max - min;
7665 let p = (&mut *(self as *mut PortableTexEngine<'_>)).znewglue(q)?;
7666 Ok(
7667 if (*mem.offset(b as isize)).hh.u.B0 as i32 == 0 {
7668 let mut r = (*mem.offset((b + 5) as isize)).hh.v.RH;
7669 if r == NULL {
7670 (*mem.offset((b + 5) as isize)).hh.v.RH = p;
7671 } else {
7672 while (*mem.offset(r as isize)).hh.v.RH != NULL {
7673 r = (*mem.offset(r as isize)).hh.v.RH;
7674 }
7675 (*mem.offset(r as isize)).hh.v.RH = p;
7676 }
7677 } else {
7678 (*mem.offset(p as isize)).hh.v.RH = (*mem.offset((b + 5) as isize))
7679 .hh
7680 .v
7681 .RH;
7682 (*mem.offset((b + 5) as isize)).hh.v.RH = p;
7683 (*mem.offset((b + 3) as isize)).u.CINT = (*mem.offset((p + 3) as isize))
7684 .u
7685 .CINT;
7686 (*mem.offset((b + 1) as isize)).u.CINT = (*mem.offset((p + 1) as isize))
7687 .u
7688 .CINT;
7689 },
7690 )
7691 }
7692
7693 pub(crate) unsafe fn zbuildopentypeassembly(
7698 self: &mut Self,
7699 f_0: internalfontnumber,
7700 assembly: voidpointer,
7701 s: scaled,
7702 horiz_flag: integer,
7703 ) -> EngineFlow<halfword> {
7704 let mem: *mut memoryword = self.state.zmem.as_mut_ptr();
7705 let horiz = horiz_flag != 0;
7706 let b = (&mut *(self as *mut PortableTexEngine<'_>)).newnullbox()?;
7707 (*mem.offset(b as isize)).hh.u.B0 = if horiz { 0 } else { 1 };
7708 let parts: &[PortableMathAssemblyPart] = if assembly.is_null() {
7709 &[]
7710 } else {
7711 &(*(assembly as *const GlyphAssembly)).parts
7712 };
7713 let part_count = parts.len();
7714 let min_o = Self::ot_min_connector_overlap(
7715 self as *mut PortableTexEngine<'resources>,
7716 f_0 as i32,
7717 );
7718 let mut n: integer = -1;
7719 let mut no_extenders = true;
7720 loop {
7721 n += 1;
7722 let mut s_max: scaled = 0;
7723 let mut prev_o: scaled = 0;
7724 for part in parts.iter() {
7725 if part.extender {
7726 no_extenders = false;
7727 for _ in 0..n {
7728 let mut o = part.start_connector;
7729 if min_o < o {
7730 o = min_o;
7731 }
7732 if prev_o < o {
7733 o = prev_o;
7734 }
7735 s_max = s_max - o + part.full_advance;
7736 prev_o = part.end_connector;
7737 }
7738 } else {
7739 let mut o = part.start_connector;
7740 if min_o < o {
7741 o = min_o;
7742 }
7743 if prev_o < o {
7744 o = prev_o;
7745 }
7746 s_max = s_max - o + part.full_advance;
7747 prev_o = part.end_connector;
7748 }
7749 }
7750 if s_max >= s || no_extenders {
7751 break;
7752 }
7753 }
7754 let mut prev_o: scaled = 0;
7755 for i in 0..part_count {
7756 let part = parts[i];
7757 let reps = if part.extender { n } else { 1 };
7758 for _ in 0..reps {
7759 let mut o = part.start_connector;
7760 if prev_o < o {
7761 o = prev_o;
7762 }
7763 let oo = o;
7764 if min_o < o {
7765 o = min_o;
7766 }
7767 if oo > 0 {
7768 (&mut *(self as *mut PortableTexEngine<'_>))
7769 .stack_glue_into_box(b, -oo, -o)?;
7770 }
7771 let g = part.glyph;
7772 (&mut *(self as *mut PortableTexEngine<'_>))
7773 .stack_glyph_into_box(b, f_0, g)?;
7774 prev_o = part.end_connector;
7775 }
7776 }
7777 const NULL: halfword = -(268435455 as i64) as halfword;
7778 let mut p = (*mem.offset((b + 5) as isize)).hh.v.RH;
7779 let mut nat: scaled = 0;
7780 let mut str_: scaled = 0;
7781 while p != NULL {
7782 let ty = (*mem.offset(p as isize)).hh.u.B0 as i32;
7783 if ty == 8 {
7784 if horiz {
7785 nat += (*mem.offset((p + 1) as isize)).u.CINT;
7786 } else {
7787 nat
7788 += (*mem.offset((p + 3) as isize)).u.CINT
7789 + (*mem.offset((p + 2) as isize)).u.CINT;
7790 }
7791 } else if ty == 10 {
7792 let spec = (*mem.offset((p + 1) as isize)).hh.v.LH;
7793 nat += (*mem.offset((spec + 1) as isize)).u.CINT;
7794 str_ += (*mem.offset((spec + 2) as isize)).u.CINT;
7795 }
7796 p = (*mem.offset(p as isize)).hh.v.RH;
7797 }
7798 if s > nat && str_ > 0 {
7799 let mut o = s - nat;
7800 if o > str_ {
7801 o = str_;
7802 }
7803 (*mem.offset((b + 5) as isize)).hh.u.B1 = 0;
7804 (*mem.offset((b + 5) as isize)).hh.u.B0 = 1;
7805 (*mem.offset((b + 6) as isize)).gr = o as f64 / str_ as f64;
7806 let stretched = nat
7807 + (str_ as f64 * (*mem.offset((b + 6) as isize)).gr).round() as scaled;
7808 if horiz {
7809 (*mem.offset((b + 1) as isize)).u.CINT = stretched;
7810 } else {
7811 (*mem.offset((b + 3) as isize)).u.CINT = stretched;
7812 }
7813 } else if horiz {
7814 (*mem.offset((b + 1) as isize)).u.CINT = nat;
7815 } else {
7816 (*mem.offset((b + 3) as isize)).u.CINT = nat;
7817 }
7818 Ok(b)
7819 }
7820
7821}
7822
7823pub(crate) unsafe fn fputs(_text: const_string, _file: NativeFileHandle) -> i32 {
7824 0
7825}
7826
7827pub(crate) unsafe fn free(_ptr: voidpointer) {}
7828
7829pub(crate) unsafe fn xrealloc(old_address: address, _new_size: size_t) -> address {
7830 old_address
7831}
7832
7833pub(crate) unsafe fn getcreationdate() {}
7834
7835pub(crate) unsafe fn getfilemoddate(_s: integer) {}
7836
7837pub(crate) unsafe fn getfilesize(_s: integer) {}
7838
7839pub(crate) unsafe fn getfiledump(_s: integer, _offset: i32, _length: i32) {}
7840
7841pub(crate) unsafe fn getmd5sum(_s: integer, _file: i32) {}
7842
7843pub(crate) unsafe fn u_close_file_or_pipe(file: *mut unicodefile) {
7844 if !file.is_null() {
7845 PortableTexEngine::boundary_close_file(*file);
7846 *file = core::ptr::null_mut();
7847 }
7848}
7849
7850pub(crate) unsafe fn setinputfileencoding(
7851 file: unicodefile,
7852 mode: integer,
7853 _encoding_data: integer,
7854) {
7855 if file.is_null() {
7859 return;
7860 }
7861 let handle = &mut *file;
7862 handle.encoding = match mode {
7863 1 => InputEncoding::Utf8,
7864 2 => InputEncoding::Utf16Be,
7865 3 => InputEncoding::Utf16Le,
7866 4 => InputEncoding::Bytes,
7867 0 => InputEncoding::Utf8, _ => InputEncoding::Bytes,
7869 };
7870}
7871
7872pub(crate) unsafe fn usingGraphite(_engine: FontHandle) -> boolean {
7873 false_0
7874}
7875
7876pub(crate) unsafe fn aatprintfontname(
7877 _what: i32,
7878 _attrs: CFDictionaryRef,
7879 _param1: i32,
7880 _param2: i32,
7881) {
7882}
7883
7884pub(crate) unsafe fn grprintfontname(
7885 _what: integer,
7886 _engine: voidpointer,
7887 _param1: integer,
7888 _param2: integer,
7889) {
7890}
7891
7892pub(crate) unsafe fn printglyphname(_font: integer, _gid: integer) {}
7893
7894pub(crate) unsafe fn getnativecharheightdepth(
7895 _font: integer,
7896 _ch: integer,
7897 height: *mut integer,
7898 depth: *mut integer,
7899) {
7900 if !height.is_null() {
7901 *height = 0;
7902 }
7903 if !depth.is_null() {
7904 *depth = 0;
7905 }
7906}
7907
7908pub(crate) unsafe fn getnativecharsidebearings(
7909 _font: integer,
7910 _ch: integer,
7911 lsb: *mut integer,
7912 rsb: *mut integer,
7913) {
7914 if !lsb.is_null() {
7915 *lsb = 0;
7916 }
7917 if !rsb.is_null() {
7918 *rsb = 0;
7919 }
7920}
7921
7922pub(crate) unsafe fn getnativecharwd(_font: integer, _ch: integer) -> integer {
7923 0
7924}
7925
7926pub(crate) unsafe fn getnativecharht(_font: integer, _ch: integer) -> integer {
7927 0
7928}
7929
7930pub(crate) unsafe fn getnativechardp(_font: integer, _ch: integer) -> integer {
7931 0
7932}
7933
7934pub(crate) unsafe fn getnativecharic(_font: integer, _ch: integer) -> integer {
7935 0
7936}
7937
7938pub(crate) unsafe fn getglyphbounds(_font: integer, _edge: integer, _gid: integer) -> integer {
7939 0
7940}
7941
7942pub(crate) unsafe fn getfontcharrange(_font: integer, _first: i32) -> integer {
7943 0
7944}
7945
7946pub(crate) unsafe fn get_native_italic_correction(_node: voidpointer) -> Fixed {
7947 0
7948}
7949
7950pub(crate) unsafe fn get_native_glyph_italic_correction(_node: voidpointer) -> Fixed {
7951 0
7952}
7953
7954pub(crate) unsafe fn applymapping(
7955 _mapping: voidpointer,
7956 _text: *mut uint16_t,
7957 text_len: i32,
7958) -> i32 {
7959 text_len
7960}
7961
7962pub(crate) unsafe fn checkfortfmfontmapping() {}
7963
7964pub(crate) unsafe fn loadtfmfontmapping() -> voidpointer {
7965 nullptr
7966}
7967
7968pub(crate) unsafe fn applytfmfontmapping(_mapping: voidpointer, c_0: i32) -> i32 {
7969 c_0
7970}
7971
7972pub(crate) unsafe fn set_cp_code(
7973 _font_num: i32,
7974 _code: u32,
7975 _side: i32,
7976 _value: i32,
7977) -> i32 {
7978 0
7979}
7980
7981pub(crate) unsafe fn countpdffilepages() -> i32 {
7982 0
7983}
7984
7985pub(crate) unsafe fn aatfontget(_what: i32, _attrs: CFDictionaryRef) -> i32 {
7986 0
7987}
7988
7989pub(crate) unsafe fn aatfontget1(_what: i32, _attrs: CFDictionaryRef, _param: i32) -> i32 {
7990 0
7991}
7992
7993pub(crate) unsafe fn aatfontget2(
7994 _what: i32,
7995 _attrs: CFDictionaryRef,
7996 _param1: i32,
7997 _param2: i32,
7998) -> i32 {
7999 0
8000}
8001
8002pub(crate) unsafe fn aatfontgetnamed(_what: i32, _attrs: CFDictionaryRef) -> i32 {
8003 0
8004}
8005
8006pub(crate) unsafe fn aatfontgetnamed1(
8007 _what: i32,
8008 _attrs: CFDictionaryRef,
8009 _param: i32,
8010) -> i32 {
8011 0
8012}
8013
8014pub(crate) unsafe fn grfontgetnamed(_what: integer, _engine: voidpointer) -> integer {
8015 0
8016}
8017
8018pub(crate) unsafe fn grfontgetnamed1(
8019 _what: integer,
8020 _engine: voidpointer,
8021 _param: integer,
8022) -> integer {
8023 0
8024}
8025
8026pub(crate) unsafe fn otfontget(_what: integer, _engine: voidpointer) -> integer {
8027 0
8028}
8029
8030pub(crate) unsafe fn otfontget1(
8031 _what: integer,
8032 _engine: voidpointer,
8033 _param: integer,
8034) -> integer {
8035 0
8036}
8037
8038pub(crate) unsafe fn otfontget2(
8039 _what: integer,
8040 _engine: voidpointer,
8041 _param1: integer,
8042 _param2: integer,
8043) -> integer {
8044 0
8045}
8046
8047pub(crate) unsafe fn otfontget3(
8048 _what: integer,
8049 _engine: voidpointer,
8050 _param1: integer,
8051 _param2: integer,
8052 _param3: integer,
8053) -> integer {
8054 0
8055}
8056
8057pub(crate) unsafe fn free_ot_assembly(assembly: *mut GlyphAssembly) {
8065 if !assembly.is_null() {
8066 drop(Box::from_raw(assembly));
8067 }
8068}
8069
8070#[cfg(test)]
8071mod tests {
8072 use super::*;
8073
8074 fn text_handle(bytes: Vec<u8>, encoding: InputEncoding) -> PortableFileHandle {
8076 let mut handle = PortableFileHandle::new(
8077 "test.tex".to_string(),
8078 ResourceKind::TexInput,
8079 None,
8080 resource_format_tex_input,
8081 bytes,
8082 );
8083 handle.encoding = encoding;
8084 handle
8085 }
8086
8087 fn decode_all(handle: &mut PortableFileHandle) -> Vec<u32> {
8089 let mut out = Vec::new();
8090 while let Some(scalar) = handle.next_input_scalar() {
8091 out.push(scalar);
8092 }
8093 out
8094 }
8095
8096 #[test]
8097 fn utf8_decoder_reads_multibyte_scalars() {
8098 let mut h = text_handle(vec![0xCE, 0xB1, 0xCE, 0xB2, 0xCE, 0xB3], InputEncoding::Utf8);
8100 assert_eq!(decode_all(&mut h), vec![0x3B1, 0x3B2, 0x3B3]);
8101 let mut h = text_handle(
8104 vec![b'A', 0xE2, 0x82, 0xAC, 0xF0, 0x9F, 0x98, 0x80],
8105 InputEncoding::Utf8,
8106 );
8107 assert_eq!(decode_all(&mut h), vec![0x41, 0x20AC, 0x1F600]);
8108 }
8109
8110 #[test]
8111 fn utf8_decoder_replaces_bad_sequences() {
8112 let mut h = text_handle(vec![0xCE, b'A'], InputEncoding::Utf8);
8115 assert_eq!(decode_all(&mut h), vec![0xFFFD, 0x41]);
8116 let mut h = text_handle(vec![0x80], InputEncoding::Utf8);
8120 assert_eq!(decode_all(&mut h), vec![0x80]);
8121 }
8122
8123 #[test]
8124 fn utf16_decoders_read_units_and_surrogates() {
8125 let mut h = text_handle(
8127 vec![0xB1, 0x03, 0xB2, 0x03, 0xB3, 0x03],
8128 InputEncoding::Utf16Le,
8129 );
8130 assert_eq!(decode_all(&mut h), vec![0x3B1, 0x3B2, 0x3B3]);
8131 let mut h = text_handle(
8133 vec![0x03, 0xB1, 0x03, 0xB2, 0x03, 0xB3],
8134 InputEncoding::Utf16Be,
8135 );
8136 assert_eq!(decode_all(&mut h), vec![0x3B1, 0x3B2, 0x3B3]);
8137 let mut h = text_handle(vec![0x3D, 0xD8, 0x00, 0xDE], InputEncoding::Utf16Le);
8139 assert_eq!(decode_all(&mut h), vec![0x1F600]);
8140 let mut h = text_handle(vec![0x3D, 0xD8, 0x41, 0x00], InputEncoding::Utf16Le);
8143 assert_eq!(decode_all(&mut h), vec![0xFFFD, 0x41]);
8144 let mut h = text_handle(vec![0x00, 0xDC], InputEncoding::Utf16Le);
8146 assert_eq!(decode_all(&mut h), vec![0xFFFD]);
8147 }
8148
8149 #[test]
8150 fn bytes_mode_reads_each_byte_raw() {
8151 let mut h = text_handle(vec![0xCE, 0xB1, 0x41], InputEncoding::Bytes);
8153 assert_eq!(decode_all(&mut h), vec![0xCE, 0xB1, 0x41]);
8154 }
8155
8156 #[test]
8157 fn bom_sniff_selects_encoding_and_consumes_bom() {
8158 let mut h = text_handle(vec![0xEF, 0xBB, 0xBF, b'A'], InputEncoding::Bytes);
8160 h.resolve_text_encoding_auto();
8161 assert_eq!(h.encoding, InputEncoding::Utf8);
8162 assert_eq!(h.cursor, 3);
8163 assert_eq!(decode_all(&mut h), vec![0x41]);
8164 let mut h = text_handle(vec![0xFE, 0xFF, 0x03, 0xB1], InputEncoding::Bytes);
8166 h.resolve_text_encoding_auto();
8167 assert_eq!(h.encoding, InputEncoding::Utf16Be);
8168 assert_eq!(h.cursor, 2);
8169 assert_eq!(decode_all(&mut h), vec![0x3B1]);
8170 let mut h = text_handle(vec![0xFF, 0xFE, 0xB1, 0x03], InputEncoding::Bytes);
8172 h.resolve_text_encoding_auto();
8173 assert_eq!(h.encoding, InputEncoding::Utf16Le);
8174 assert_eq!(h.cursor, 2);
8175 assert_eq!(decode_all(&mut h), vec![0x3B1]);
8176 let mut h = text_handle(vec![b'h', b'i'], InputEncoding::Bytes);
8178 h.resolve_text_encoding_auto();
8179 assert_eq!(h.encoding, InputEncoding::Utf8);
8180 assert_eq!(h.cursor, 0);
8181 let mut h = text_handle(vec![0x00, 0x41], InputEncoding::Bytes);
8183 h.resolve_text_encoding_auto();
8184 assert_eq!(h.encoding, InputEncoding::Utf16Be);
8185 assert_eq!(h.cursor, 0);
8186 assert_eq!(decode_all(&mut h), vec![0x41]);
8187 }
8188
8189 #[test]
8190 fn input_line_decodes_into_buffer_per_profile() {
8191 fn buffer_after_input_line(profile: EngineProfile, bytes: Vec<u8>) -> Vec<u32> {
8197 let image = PortableFormatImage::empty();
8198 let mut engine = PortableTexEngine::from_format(profile, &image, EmptyResourceProvider);
8199 engine.initialize_format_state();
8200 let mut handle = PortableFileHandle::new(
8203 "input.tex".to_string(),
8204 ResourceKind::TexInput,
8205 None,
8206 resource_format_tex_input,
8207 bytes,
8208 );
8209 PortableTexEngine::resolve_input_encoding(&engine, &mut handle);
8210 let raw = Box::into_raw(Box::new(handle));
8211 engine.state.first = 0;
8213 let ok = unsafe {
8214 PortableTexEngine::boundary_input_line(
8215 &mut engine as *mut PortableTexEngine<'_>,
8216 raw as NativeFileHandle,
8217 )
8218 };
8219 assert_ne!(ok, 0, "boundary_input_line should succeed");
8220 let first = engine.state.first.max(0) as usize;
8221 let last = engine.state.last.max(0) as usize;
8222 let out = (first..last)
8223 .map(|i| unsafe { *engine.state.buffer.offset(i as isize) as u32 })
8224 .collect();
8225 unsafe { drop(Box::from_raw(raw)) };
8226 out
8227 }
8228 let utf8 = vec![0xCE, 0xB1, 0xCE, 0xB2, 0xCE, 0xB3];
8230 assert_eq!(
8231 buffer_after_input_line(EngineProfile::xetex(), utf8.clone()),
8232 vec![0x3B1, 0x3B2, 0x3B3],
8233 "xetex must UTF-8 decode the input line"
8234 );
8235 assert_eq!(
8236 buffer_after_input_line(EngineProfile::tex(), utf8),
8237 vec![0xCE, 0xB1, 0xCE, 0xB2, 0xCE, 0xB3],
8238 "non-xetex must read raw bytes"
8239 );
8240 let utf16le_bom = vec![0xFF, 0xFE, 0xB1, 0x03, 0xB2, 0x03, 0xB3, 0x03];
8242 assert_eq!(
8243 buffer_after_input_line(EngineProfile::xetex(), utf16le_bom),
8244 vec![0x3B1, 0x3B2, 0x3B3],
8245 "xetex must UTF-16LE decode a BOM'd input line"
8246 );
8247 let utf16be_bom = vec![0xFE, 0xFF, 0x03, 0xB1, 0x03, 0xB2, 0x03, 0xB3];
8249 assert_eq!(
8250 buffer_after_input_line(EngineProfile::xetex(), utf16be_bom),
8251 vec![0x3B1, 0x3B2, 0x3B3],
8252 "xetex must UTF-16BE decode a BOM'd input line"
8253 );
8254 }
8255
8256 #[test]
8257 fn engine_abort_is_captured_at_runtime_boundary() {
8258 let image = PortableFormatImage::empty();
8259 let mut engine =
8260 PortableTexEngine::from_format(EngineProfile::tex(), &image, EmptyResourceProvider);
8261
8262 let completed = engine.catch_engine_abort(|engine| unsafe {
8263 PortableTexEngine::abort_engine(engine as *mut PortableTexEngine<'_>, 7)?;
8264 Ok(())
8265 });
8266
8267 assert!(!completed);
8268 assert_eq!(engine.last_abort_status(), Some(7));
8269 }
8270
8271 #[test]
8272 fn successful_engine_abort_completes_runtime_boundary() {
8273 let image = PortableFormatImage::empty();
8274 let mut engine =
8275 PortableTexEngine::from_format(EngineProfile::tex(), &image, EmptyResourceProvider);
8276
8277 let completed = engine.catch_engine_abort(|engine| unsafe {
8278 PortableTexEngine::abort_engine(engine as *mut PortableTexEngine<'_>, 0)?;
8279 Ok(())
8280 });
8281
8282 assert!(completed);
8283 assert_eq!(engine.last_abort_status(), None);
8284 }
8285}