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, 4).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!(
4052 kind,
4053 PortableNodeKind::NativeWord
4054 | PortableNodeKind::NativeGlyph
4055 | PortableNodeKind::HostBoxRef
4056 ) => (
4057 self.node_scaled(node, 1).unwrap_or_default(),
4058 self.node_scaled(node, 3).unwrap_or_default(),
4059 self.node_scaled(node, 2).unwrap_or_default(),
4060 0,
4061 None,
4062 ),
4063 _ => (0, 0, 0, 0, None),
4064 };
4065 let native_glyphs = if matches!(kind, PortableNodeKind::NativeWord | PortableNodeKind::NativeGlyph) {
4066 self.native_glyph_infos
4067 .get(&node)
4068 .map(|info| info.glyphs.clone())
4069 .unwrap_or_default()
4070 } else {
4071 Vec::new()
4072 };
4073
4074 let (glue_set, glue_sign, glue_order) = match raw_kind {
4079 0 | 1 | 13 => (
4080 self.node_word(node, 6).map_or(0.0, |word| unsafe { word.gr }),
4081 self.node_word(node, 5)
4082 .map_or(0, |word| unsafe { word.hh.u.B0 as i32 }),
4083 self.node_word(node, 5)
4084 .map_or(0, |word| unsafe { word.hh.u.B1 as i32 }),
4085 ),
4086 _ => (0.0, 0, 0),
4087 };
4088 let (glue_stretch, glue_shrink, glue_stretch_order, glue_shrink_order) = if raw_kind == 10 {
4090 match self.node_word(node, 1).map(|word| unsafe { word.hh.v.LH }) {
4091 Some(spec) => (
4092 self.node_scaled(spec, 2).unwrap_or_default(),
4093 self.node_scaled(spec, 3).unwrap_or_default(),
4094 self.node_word(spec, 0)
4095 .map_or(0, |word| unsafe { word.hh.u.B0 as i32 }),
4096 self.node_word(spec, 0)
4097 .map_or(0, |word| unsafe { word.hh.u.B1 as i32 }),
4098 ),
4099 None => (0, 0, 0, 0),
4100 }
4101 } else {
4102 (0, 0, 0, 0)
4103 };
4104
4105 Some(PortableNodeSnapshot {
4106 handle,
4107 kind,
4108 subtype,
4109 source: self.resolve_node_src(node),
4110 link,
4111 font,
4112 character,
4113 width,
4114 height,
4115 depth,
4116 shift,
4117 list,
4118 native_glyphs,
4119 glue_set,
4120 glue_sign,
4121 glue_order,
4122 glue_stretch,
4123 glue_shrink,
4124 glue_stretch_order,
4125 glue_shrink_order,
4126 })
4127 }
4128
4129 fn node_kind(&self, raw_kind: i32, node: halfword, subtype: i32) -> PortableNodeKind {
4130 if node >= self.state.himemmin {
4131 return PortableNodeKind::Character;
4132 }
4133
4134 match raw_kind {
4135 0 => PortableNodeKind::HorizontalBox,
4136 1 => PortableNodeKind::VerticalBox,
4137 2 => PortableNodeKind::Rule,
4138 3 => PortableNodeKind::Insertion,
4139 4 => PortableNodeKind::Mark,
4140 5 => PortableNodeKind::Adjustment,
4141 6 => PortableNodeKind::Ligature,
4142 7 => PortableNodeKind::Discretionary,
4143 8 if matches!(subtype, 40 | 41) => PortableNodeKind::NativeWord,
4144 8 if subtype == 42 => PortableNodeKind::NativeGlyph,
4145 8 if subtype == HOST_BOX_RESOLVED_SUBTYPE as i32 => PortableNodeKind::HostBoxRef,
4146 8 if matches!(subtype, 0 | 1 | 2 | 3) => PortableNodeKind::OutputWhatsit,
4147 8 => PortableNodeKind::Whatsit,
4148 9 => PortableNodeKind::Math,
4149 10 => PortableNodeKind::Glue,
4150 11 => PortableNodeKind::Kern,
4151 12 => PortableNodeKind::Penalty,
4152 13 => PortableNodeKind::UnsetBox,
4153 16 => PortableNodeKind::Noad,
4154 14 => PortableNodeKind::Style,
4155 15 => PortableNodeKind::Choice,
4156 other => PortableNodeKind::Unknown(other),
4157 }
4158 }
4159
4160 pub(crate) fn copy_native_glyph_info(
4161 this: &mut Self,
4162 src: halfword,
4163 dest: halfword,
4164 ) -> quarterword {
4165 if let Some(info) = this.native_glyph_infos.get(&src).cloned() {
4166 let glyph_count = info.glyphs.len().min(i32::MAX as usize) as quarterword;
4167 this.native_glyph_infos.insert(dest, info);
4168 glyph_count
4169 } else {
4170 this.native_glyph_infos.remove(&dest);
4171 0
4172 }
4173 }
4174
4175 fn font_handle_for_number(this: &Self, font: integer) -> Option<FontHandle> {
4176 if font < 0 || this.state.fontlayoutengine.is_null() {
4177 return None;
4178 }
4179 let handle = unsafe { *this.state.fontlayoutengine.offset(font as isize) as FontHandle };
4180 (handle != 0).then_some(handle)
4181 }
4182
4183 unsafe fn node_index_for_pointer(
4184 engine: &PortableTexEngine<'_>,
4185 node: voidpointer,
4186 ) -> Option<halfword> {
4187 if node.is_null() || engine.state.zmem.is_null() {
4188 return None;
4189 }
4190 let base = engine.state.zmem as isize;
4191 let address = node as isize;
4192 let word_size = core::mem::size_of::<memoryword>() as isize;
4193 if word_size == 0 || address < base {
4194 return None;
4195 }
4196 let bytes = address - base;
4197 if bytes % word_size != 0 {
4198 return None;
4199 }
4200 let index = (bytes / word_size) as halfword;
4201 if index < engine.state.memmin || index > engine.state.memmax {
4202 None
4203 } else {
4204 Some(index)
4205 }
4206 }
4207
4208 unsafe fn native_node_font(mem: *mut memoryword, node: halfword) -> integer {
4209 (*mem.offset((node + 4) as isize)).v.QQQQ.u.B1 as integer
4210 }
4211
4212 unsafe fn native_node_text<'a>(mem: *mut memoryword, node: halfword) -> &'a [u16] {
4213 let len = (*mem.offset((node + 4) as isize)).v.QQQQ.u.B2.max(0) as usize;
4214 if len == 0 {
4215 return &[];
4216 }
4217 core::slice::from_raw_parts(
4218 mem.offset((node + native_node_size) as isize) as *const memoryword as *const u16,
4219 len,
4220 )
4221 }
4222
4223 unsafe fn write_native_node_metrics(
4224 mem: *mut memoryword,
4225 node: halfword,
4226 width: i32,
4227 height: i32,
4228 depth: i32,
4229 ) {
4230 (*mem.offset((node + 1) as isize)).u.CINT = width;
4231 (*mem.offset((node + 2) as isize)).u.CINT = depth;
4232 (*mem.offset((node + 3) as isize)).u.CINT = height;
4233 }
4234
4235 fn node_word(&self, node: halfword, offset: halfword) -> Option<memoryword> {
4236 let index = node.checked_add(offset)?;
4237 if node as i64 == -(268435455 as i64) {
4238 return None;
4239 }
4240 if self.state.zmem.is_null() || index < self.state.memmin || index > self.state.memmax {
4241 return None;
4242 }
4243 unsafe { Some(*self.state.zmem.offset(index as isize)) }
4244 }
4245
4246 fn node_link(&self, node: halfword) -> Option<PortableNodeHandle> {
4247 let word = self.node_word(node, 0)?;
4248 let link = unsafe { word.hh.v.RH };
4249 Self::node_handle_from_raw(link)
4250 }
4251
4252 fn node_field_link(&self, node: halfword, offset: halfword) -> Option<PortableNodeHandle> {
4253 let word = self.node_word(node, offset)?;
4254 let link = unsafe { word.hh.v.RH };
4255 Self::node_handle_from_raw(link)
4256 }
4257
4258 fn node_scaled(&self, node: halfword, offset: halfword) -> Option<i32> {
4259 let word = self.node_word(node, offset)?;
4260 Some(unsafe { word.u.CINT })
4261 }
4262
4263 fn glue_amount(&self, node: halfword) -> Option<i32> {
4264 let word = self.node_word(node, 1)?;
4265 let glue_spec = unsafe { word.hh.v.LH };
4266 self.node_scaled(glue_spec, 1)
4267 }
4268
4269 fn character_width(&self, font: i32, character: i32) -> Option<i32> {
4270 if font < 0
4271 || character < 0
4272 || self.state.fontinfo.is_null()
4273 || self.state.charbase.is_null()
4274 || self.state.widthbase.is_null()
4275 {
4276 return None;
4277 }
4278 let char_info_index = unsafe {
4279 *self.state.charbase.offset(font as isize) + character
4280 };
4281 let char_info = unsafe {
4282 (*self.state.fontinfo.offset(char_info_index as isize)).v.QQQQ
4283 };
4284 let width_index = unsafe {
4285 *self.state.widthbase.offset(font as isize) as i32 + char_info.u.B0 as i32
4286 };
4287 Some(unsafe { (*self.state.fontinfo.offset(width_index as isize)).u.CINT })
4288 }
4289
4290 fn node_handle_from_raw(raw: halfword) -> Option<PortableNodeHandle> {
4291 if raw as i64 == -(268435455 as i64) {
4292 None
4293 } else {
4294 Some(PortableNodeHandle(raw))
4295 }
4296 }
4297
4298
4299 pub(crate) fn is_xetex(&self) -> bool {
4300 self.profile.xetex
4301 }
4302
4303 pub(crate) fn supports_etex(&self) -> bool {
4304 self.profile.etex
4305 }
4306
4307 pub(crate) fn supports_unicode_scalars(&self) -> bool {
4308 self.profile.unicode_scalars
4309 }
4310
4311 pub(crate) fn supports_unicode_math(&self) -> bool {
4312 self.profile.unicode_math
4313 }
4314
4315 pub(crate) fn supports_native_fonts(&self) -> bool {
4316 self.profile.native_fonts
4317 }
4318
4319 pub(crate) unsafe fn getinputnormalizationstate(&self) -> integer {
4320 if !self.is_xetex() {
4321 return 0;
4322 }
4323 let eqtb = self.state.zeqtb.as_mut_ptr();
4324 if eqtb.is_null() {
4325 return 0;
4326 }
4327 (*eqtb.offset(7892344 as i64 as isize)).u.CINT
4328 }
4329
4330 pub(crate) unsafe fn gettracingfontsstate(&self) -> integer {
4331 if !self.is_xetex() {
4332 return 0;
4333 }
4334 let eqtb = self.state.zeqtb.as_mut_ptr();
4335 if eqtb.is_null() {
4336 return 0;
4337 }
4338 (*eqtb.offset(7892347 as i64 as isize)).u.CINT
4339 }
4340
4341 unsafe fn current_resource_name(engine: *mut PortableTexEngine<'_>) -> Option<String> {
4342 let engine = engine.as_ref()?;
4343 if engine.state.nameoffile.is_null() || engine.state.namelength <= 0 {
4344 return None;
4345 }
4346
4347 let mut bytes = Vec::with_capacity(engine.state.namelength as usize);
4348 for index in 1..=engine.state.namelength {
4349 let value = *engine.state.nameoffile.offset(index as isize);
4350 if value <= 0 {
4351 continue;
4352 }
4353 bytes.push(value as u8);
4354 }
4355 Some(String::from_utf8_lossy(bytes.as_slice()).into_owned())
4356 }
4357
4358 pub(crate) unsafe fn get_encoding_mode_and_info(
4364 engine: *mut PortableTexEngine<'_>,
4365 info: *mut integer,
4366 ) -> integer {
4367 if !info.is_null() {
4368 *info = 0;
4369 }
4370 let name = Self::current_resource_name(engine).unwrap_or_default();
4371 let lowered = name.trim().to_ascii_lowercase();
4372 match lowered.as_str() {
4373 "auto" => 0, "utf8" | "utf-8" => 1, "utf16" | "utf-16" | "utf16be" | "utf-16be" => 2, "utf16le" | "utf-16le" => 3, "bytes" => 4, _ => 4,
4381 }
4382 }
4383
4384 unsafe fn mode_string(mode: const_string) -> String {
4385 if mode.is_null() {
4386 return String::new();
4387 }
4388
4389 let mut bytes = Vec::new();
4390 let mut cursor = mode;
4391 while *cursor != 0 {
4392 bytes.push(*cursor as u8);
4393 cursor = cursor.add(1);
4394 }
4395 String::from_utf8_lossy(bytes.as_slice()).into_owned()
4396 }
4397
4398 unsafe fn pool_string(&self, string: strnumber) -> Option<String> {
4399 if string < 0 || self.state.strstart.is_null() || self.state.strpool.is_null() {
4400 return None;
4401 }
4402 let index = Self::pool_string_index(string)?;
4403 let start = *self.state.strstart.offset(index);
4404 let end = *self.state.strstart.offset(index + 1);
4405 if start < 0 || end < start {
4406 return None;
4407 }
4408
4409 let len = usize::try_from(end - start).ok()?;
4410 let mut units = Vec::with_capacity(len);
4411 for offset in 0..len {
4412 units.push(*self.state.strpool.offset((start as usize + offset) as isize));
4413 }
4414 Some(
4415 char::decode_utf16(units)
4416 .map(|codepoint| codepoint.unwrap_or(char::REPLACEMENT_CHARACTER))
4417 .collect(),
4418 )
4419 }
4420
4421 pub(crate) fn pool_string_index(string: strnumber) -> Option<isize> {
4422 if string < 0 {
4423 return None;
4424 }
4425 let index = if string >= 65536 { string - 65536 } else { string };
4426 isize::try_from(index).ok()
4427 }
4428
4429 fn resource_kind(name: &str, format: integer) -> ResourceKind {
4430 match format {
4431 resource_format_tex_input | 0 => Self::tex_resource_kind(name),
4432 resource_format_tfm | resource_format_font => ResourceKind::Font,
4433 resource_format_encoding => ResourceKind::Encoding,
4434 resource_format_font_map => ResourceKind::Map,
4435 resource_format_config => ResourceKind::Config,
4436 resource_format_format_image => ResourceKind::FormatImage,
4437 other => ResourceKind::Other(other),
4438 }
4439 }
4440
4441 fn tex_resource_kind(name: &str) -> ResourceKind {
4442 let name = name.rsplit(['/', '\\']).next().unwrap_or(name);
4443 let name = name.to_ascii_lowercase();
4444 if name.ends_with(".sty") {
4445 return ResourceKind::Package;
4446 }
4447 if name.ends_with(".cls") {
4448 return ResourceKind::Class;
4449 }
4450 if name.ends_with(".fd") {
4451 return ResourceKind::FontDefinition;
4452 }
4453 if name.ends_with(".clo")
4454 || name.ends_with(".def")
4455 || name.ends_with(".ldf")
4456 || name.ends_with(".cfg")
4457 {
4458 return ResourceKind::PackageSupport;
4459 }
4460 ResourceKind::TexInput
4461 }
4462
4463 fn resource_kind_for_open(
4464 engine: &PortableTexEngine<'_>,
4465 name: &str,
4466 format: integer,
4467 ) -> ResourceKind {
4468 let kind = Self::resource_kind(name, format);
4469 if kind == ResourceKind::TexInput
4470 && Self::active_package_owner(engine).is_some()
4471 && Self::looks_like_package_asset(name)
4472 {
4473 ResourceKind::Asset
4474 } else {
4475 kind
4476 }
4477 }
4478
4479 fn resource_package_owner(
4480 engine: &PortableTexEngine<'_>,
4481 name: &str,
4482 kind: ResourceKind,
4483 ) -> Option<String> {
4484 match kind {
4485 ResourceKind::Package | ResourceKind::Class => Self::resource_stem(name),
4486 ResourceKind::PackageSupport | ResourceKind::FontDefinition | ResourceKind::Asset => {
4487 Self::active_package_owner(engine)
4488 }
4489 _ => None,
4490 }
4491 }
4492
4493 fn active_package_owner(engine: &PortableTexEngine<'_>) -> Option<String> {
4494 engine.current_input_package_owner.clone()
4495 }
4496
4497 fn looks_like_package_asset(name: &str) -> bool {
4498 let name = name.rsplit(['/', '\\']).next().unwrap_or(name);
4499 let name = name.to_ascii_lowercase();
4500 !(name.ends_with(".tex")
4501 || name.ends_with(".ltx")
4502 || name.ends_with(".sty")
4503 || name.ends_with(".cls")
4504 || name.ends_with(".fd")
4505 || name.ends_with(".clo")
4506 || name.ends_with(".def")
4507 || name.ends_with(".ldf")
4508 || name.ends_with(".cfg"))
4509 }
4510
4511 fn resource_stem(name: &str) -> Option<String> {
4512 let name = name.rsplit(['/', '\\']).next().unwrap_or(name);
4513 let stem = name.rsplit_once('.').map_or(name, |(stem, _)| stem);
4514 if stem.is_empty() {
4515 None
4516 } else {
4517 Some(stem.to_string())
4518 }
4519 }
4520
4521 fn source_index(value: usize) -> u32 {
4522 value.min(u32::MAX as usize) as u32
4523 }
4524
4525 fn virtual_file_key(name: &str) -> String {
4526 let mut name = name;
4527 while let Some(stripped) = name.strip_prefix("./") {
4528 name = stripped;
4529 }
4530 name.to_string()
4531 }
4532
4533 fn normalized_runtime_resource_name(mut name: &str) -> &str {
4534 while let Some(stripped) = name.strip_prefix("./") {
4535 name = stripped;
4536 }
4537 name
4538 }
4539
4540 unsafe fn intern_static_pool_string(
4547 engine: &mut PortableTexEngine<'_>,
4548 text: &str,
4549 ) -> EngineFlow<Option<strnumber>> {
4550 if engine.state.strpool.is_null() || engine.state.strstart.is_null() {
4551 return Ok(None);
4552 }
4553
4554 let Ok(needed) = integer::try_from(text.encode_utf16().count()) else {
4555 return Ok(None);
4556 };
4557 let Some(next_pool) = engine.state.poolptr.checked_add(needed) else {
4558 return Ok(None);
4559 };
4560 if next_pool > engine.state.poolsize {
4561 return Ok(None);
4562 }
4563
4564 for unit in text.encode_utf16() {
4565 *engine.state.strpool.offset(engine.state.poolptr as isize) = unit as packedUTF16code;
4566 engine.state.poolptr += 1;
4567 }
4568
4569 Ok(Some(engine.makestring()?))
4570 }
4571
4572 unsafe fn append_text_to_pool(engine: &mut PortableTexEngine<'_>, text: &str) -> boolean {
4573 if engine.state.strpool.is_null() {
4574 return false_0;
4575 }
4576 let needed = match integer::try_from(text.encode_utf16().count()) {
4577 Ok(needed) => needed,
4578 Err(_) => return false_0,
4579 };
4580 let Some(next_pool) = engine.state.poolptr.checked_add(needed) else {
4581 return false_0;
4582 };
4583 if next_pool > engine.state.poolsize {
4584 return false_0;
4585 }
4586 for unit in text.encode_utf16() {
4587 *engine.state.strpool.offset(engine.state.poolptr as isize) = unit as packedUTF16code;
4588 engine.state.poolptr += 1;
4589 }
4590 true_0
4591 }
4592
4593 unsafe fn resource_bytes_for_name(
4594 engine: &mut PortableTexEngine<'_>,
4595 name: &str,
4596 ) -> Option<Vec<u8>> {
4597 let name = Self::normalized_runtime_resource_name(name);
4598 let kind = Self::resource_kind_for_open(engine, name, resource_format_tex_input);
4599 let package = Self::resource_package_owner(engine, name, kind);
4600 let request = ResourceRequest {
4601 name,
4602 kind,
4603 package: package.as_deref(),
4604 format: resource_format_tex_input,
4605 mode: "rb",
4606 source: None,
4607 };
4608 let virtual_key = Self::virtual_file_key(name);
4609 if let Some(bytes) = engine.virtual_files.get(&virtual_key) {
4610 Some(bytes.clone())
4611 } else {
4612 engine.resources.read(request)
4613 }
4614 }
4615
4616 pub(crate) unsafe fn boundary_get_file_size(
4617 engine: *mut PortableTexEngine<'_>,
4618 string: integer,
4619 ) {
4620 let Some(engine) = engine.as_mut() else {
4621 return;
4622 };
4623 let Some(name) = engine.pool_string(string as strnumber) else {
4624 return;
4625 };
4626 const PLACEHOLDER_FILE_SIZE: usize = 4096;
4636 let size = Self::resource_bytes_for_name(engine, name.as_str())
4637 .map_or(PLACEHOLDER_FILE_SIZE, |bytes| bytes.len());
4638 Self::append_text_to_pool(engine, size.to_string().as_str());
4639 }
4640
4641 pub(crate) unsafe fn load_pool_strings(
4642 engine: &mut PortableTexEngine<'_>,
4643 spare_size: integer,
4644 ) -> EngineFlow<integer> {
4645 if engine.state.strpool.is_null() || engine.state.strstart.is_null()
4646 || spare_size <= 0
4647 {
4648 return Ok(0);
4649 }
4650 let mut used = 0_i32;
4651 let mut last = 0_i32;
4652 for line in include_str!("../pool/xetex.pool").lines() {
4653 if line.starts_with('*') {
4654 break;
4655 }
4656 let bytes = line.as_bytes();
4657 let text = if bytes.len() >= 2 && bytes[0].is_ascii_digit()
4658 && bytes[1].is_ascii_digit()
4659 {
4660 &line[2..]
4661 } else {
4662 line
4663 };
4664 let units = text.encode_utf16().count().min(i32::MAX as usize) as integer;
4665 used = used.saturating_add(units);
4666 if used >= spare_size
4667 || engine.state.poolptr.saturating_add(units) > engine.state.poolsize
4668 {
4669 return Ok(0);
4670 }
4671 for unit in text.encode_utf16() {
4672 *engine.state.strpool.offset(engine.state.poolptr as isize) = unit
4673 as packedUTF16code;
4674 engine.state.poolptr += 1;
4675 }
4676 last = engine.makestring()?;
4677 }
4678 Ok(last)
4679 }
4680
4681 pub(crate) unsafe fn boundary_open_log_file(
4682 engine: *mut PortableTexEngine<'_>,
4683 ) -> EngineFlow<()> {
4684 let Some(engine) = engine.as_mut() else {
4685 return Ok(());
4686 };
4687 let old_setting = engine.state.selector;
4688 if engine.state.jobname == 0 {
4689 if let Some(jobname) = Self::intern_static_pool_string(engine, "texput")? {
4690 engine.state.jobname = jobname;
4691 }
4692 }
4693 engine.state.logopened = true_0 as boolean;
4694 engine.state.selector = (old_setting as i32 + 2).clamp(0, 21) as eightbits;
4695 Ok(())
4696 }
4697
4698 pub(crate) unsafe fn boundary_jump_out(
4699 engine: *mut PortableTexEngine<'_>,
4700 ) -> EngineFlow<core::convert::Infallible> {
4701 let status = if let Some(engine) = engine.as_ref() {
4706 if engine.state.history as i32 <= 1 {
4707 0 as integer
4708 } else {
4709 1 as integer
4710 }
4711 } else {
4712 1 as integer
4713 };
4714 Self::abort_engine(engine, status)
4715 }
4716
4717 pub(crate) unsafe fn boundary_shipout(
4718 engine: *mut PortableTexEngine<'_>,
4719 box_node: halfword,
4720 ) {
4721 if let Some(engine) = engine.as_mut() {
4722 engine.stripped_shipouts = engine.stripped_shipouts.saturating_add(1);
4723 engine.last_stripped_shipout_box = Some(PortableNodeHandle(box_node));
4724 }
4725 }
4726
4727 pub(crate) unsafe fn boundary_capture_fragment_box(
4728 engine: *mut PortableTexEngine<'_>,
4729 box_node: halfword,
4730 mode: integer,
4731 boxcontext: integer,
4732 ) -> boolean {
4733 if let Some(engine) = engine.as_mut() {
4734 if engine.fragment_capture_enabled {
4735 engine.captured_fragment_root = Some(PortableNodeHandle(box_node));
4736 let absolute_mode = if mode >= 0 { mode } else { -mode };
4737 if absolute_mode == 1 && boxcontext < 1_073_741_824 {
4738 return true_0;
4739 }
4740 }
4741 }
4742 false_0
4743 }
4744
4745 pub(crate) unsafe fn boundary_build_page(
4746 engine: *mut PortableTexEngine<'_>,
4747 ) -> EngineFlow<()> {
4748 if let Some(engine) = engine.as_mut() {
4749 if engine.format_initialization
4750 && engine.state.curcmd as i32 == 15
4751 && engine.state.curchr == 1
4752 {
4753 Self::abort_engine(engine as *mut PortableTexEngine<'_>, 0 as integer)?;
4757 }
4758 engine.stripped_page_builds = engine.stripped_page_builds.saturating_add(1);
4759 }
4760 Ok(())
4761 }
4762
4763 pub(crate) unsafe fn boundary_prune_page_top(
4764 engine: *mut PortableTexEngine<'_>,
4765 node: halfword,
4766 _saving: boolean,
4767 ) -> halfword {
4768 if let Some(engine) = engine.as_mut() {
4769 engine.stripped_page_top_prunes =
4770 engine.stripped_page_top_prunes.saturating_add(1);
4771 }
4772 node
4773 }
4774
4775 pub(crate) unsafe fn boundary_special_out(
4776 engine: *mut PortableTexEngine<'_>,
4777 node: halfword,
4778 ) -> EngineFlow<()> {
4779 let Some(engine) = engine.as_mut() else {
4780 return Ok(());
4781 };
4782 if node < engine.state.memmin || node > engine.state.memend {
4783 engine.stripped_special_outputs = engine
4784 .stripped_special_outputs
4785 .saturating_add(1);
4786 return Ok(());
4787 }
4788 let mem = engine.state.zmem.as_mut_ptr();
4789 if (*mem.offset(node as isize)).hh.u.B0 as i32 == 8 {
4790 match (*mem.offset(node as isize)).hh.u.B1 as i32 {
4791 0 => {
4792 Self::boundary_open_write_whatsit(engine, node);
4793 return Ok(());
4794 }
4795 1 => {
4796 Self::boundary_write_whatsit(engine, node)?;
4797 return Ok(());
4798 }
4799 2 => {
4800 Self::boundary_close_write_whatsit(engine, node);
4801 return Ok(());
4802 }
4803 _ => {}
4804 }
4805 }
4806 engine.stripped_special_outputs = engine
4807 .stripped_special_outputs
4808 .saturating_add(1);
4809 Ok(())
4810 }
4811
4812 unsafe fn boundary_open_write_whatsit(engine: &mut PortableTexEngine<'_>, node: halfword) {
4813 let mem = engine.state.zmem.as_mut_ptr();
4814 let stream = (*mem.offset((node + 1) as isize)).hh.v.LH as usize;
4815 if stream >= 16 {
4816 return;
4817 }
4818
4819 if engine.state.writeopen[stream] != 0 {
4820 Self::boundary_close_write_stream(engine, stream);
4821 }
4822
4823 engine.state.curname = (*mem.offset((node + 1) as isize)).hh.v.RH as strnumber;
4824 engine.state.curarea = (*mem.offset((node + 2) as isize)).hh.v.LH as strnumber;
4825 engine.state.curext = (*mem.offset((node + 2) as isize)).hh.v.RH as strnumber;
4826 if engine.state.curext == 335 {
4827 engine.state.curext = 799;
4828 }
4829 engine.zpackfilename(engine.state.curname, engine.state.curarea, engine.state.curext);
4830 let Some(name) = Self::current_resource_name(engine as *mut PortableTexEngine<'_>) else {
4831 return;
4832 };
4833 let handle = Box::new(PortableFileHandle::new(
4834 name,
4835 ResourceKind::TexInput,
4836 None,
4837 resource_format_tex_input,
4838 Vec::new(),
4839 ));
4840 engine.state.writefile[stream] = Box::into_raw(handle);
4841 engine.state.writeopen[stream] = true_0;
4842 }
4843
4844 unsafe fn boundary_write_whatsit(
4845 engine: &mut PortableTexEngine<'_>,
4846 node: halfword,
4847 ) -> EngineFlow<()> {
4848 let mem = engine.state.zmem.as_mut_ptr();
4849 let stream = (*mem.offset((node + 1) as isize)).hh.v.LH as usize;
4850 if stream >= 16 || engine.state.writeopen[stream] == 0 {
4851 return Ok(());
4852 }
4853 let write_tokens = engine.profile.write_token_constants();
4854 let q = engine.getavail()?;
4855 (*mem.offset(q as isize)).hh.v.LH = write_tokens.open_group_token;
4856 let r = engine.getavail()?;
4857 (*mem.offset(q as isize)).hh.v.RH = r;
4858 (*mem.offset(r as isize)).hh.v.LH = write_tokens.end_write_token;
4859 engine.zbegintokenlist(q, 4)?;
4860 engine.zbegintokenlist((*mem.offset((node + 1) as isize)).hh.v.RH, 15)?;
4861 let q = engine.getavail()?;
4862 (*mem.offset(q as isize)).hh.v.LH = write_tokens.close_group_token;
4863 engine.zbegintokenlist(q, 4)?;
4864 let old_mode = engine.state.curlist.modefield;
4865 engine.state.curlist.modefield = 0;
4866 engine.state.curcs = engine.state.writeloc;
4867 engine.zscantoks(false_0, true_0)?;
4868 engine.state.curlist.modefield = old_mode;
4869 engine.gettoken()?;
4870 if engine.state.curtok != write_tokens.end_write_token {
4871 while engine.state.curtok != write_tokens.end_write_token {
4872 engine.gettoken()?;
4873 }
4874 }
4875 engine.endtokenlist()?;
4876 let old_setting = engine.state.selector;
4877 engine.state.selector = stream as eightbits;
4878 engine.ztokenshow(engine.state.defref);
4879 engine.println();
4880 engine.state.selector = old_setting;
4881 engine.zflushlist(engine.state.defref);
4882 Ok(())
4883 }
4884
4885 unsafe fn boundary_close_write_whatsit(engine: &mut PortableTexEngine<'_>, node: halfword) {
4886 let mem = engine.state.zmem.as_mut_ptr();
4887 let stream = (*mem.offset((node + 1) as isize)).hh.v.LH as usize;
4888 if stream < 16 {
4889 Self::boundary_close_write_stream(engine, stream);
4890 }
4891 }
4892
4893 unsafe fn boundary_close_write_stream(engine: &mut PortableTexEngine<'_>, stream: usize) {
4894 if stream >= 16 || engine.state.writeopen[stream] == 0 {
4895 return;
4896 }
4897 let file = engine.state.writefile[stream];
4898 engine.state.writefile[stream] = core::ptr::null_mut();
4899 engine.state.writeopen[stream] = false_0;
4900 if file.is_null() {
4901 return;
4902 }
4903 let handle = Box::from_raw(file);
4904 let key = Self::virtual_file_key(handle.name.as_str());
4905 engine.virtual_files.insert(key, handle.bytes);
4906 }
4907
4908 pub(crate) unsafe fn boundary_load_picture(
4909 engine: *mut PortableTexEngine<'_>,
4910 _is_pdf: boolean,
4911 ) {
4912 if let Some(engine) = engine.as_mut() {
4913 engine.stripped_picture_loads = engine.stripped_picture_loads.saturating_add(1);
4914 }
4915 }
4916
4917 pub(crate) fn record_stripped_source_special(engine: *mut PortableTexEngine<'_>) {
4918 if let Some(engine) = unsafe { engine.as_mut() } {
4919 engine.stripped_source_specials = engine.stripped_source_specials.saturating_add(1);
4920 }
4921 }
4922
4923 pub(crate) fn record_stripped_write_whatsit_diagnostic(engine: *mut PortableTexEngine<'_>) {
4924 if let Some(engine) = unsafe { engine.as_mut() } {
4925 engine.stripped_write_whatsit_diagnostics =
4926 engine.stripped_write_whatsit_diagnostics.saturating_add(1);
4927 }
4928 }
4929
4930 pub(crate) fn record_stripped_pdf_extension(engine: *mut PortableTexEngine<'_>) {
4931 if let Some(engine) = unsafe { engine.as_mut() } {
4932 engine.stripped_pdf_extensions = engine.stripped_pdf_extensions.saturating_add(1);
4933 }
4934 }
4935
4936 fn resolve_input_encoding(engine: &PortableTexEngine<'_>, handle: &mut PortableFileHandle) {
4946 let is_text = handle.format == resource_format_tex_input || handle.format == 0;
4947 if engine.is_xetex() && is_text {
4948 handle.resolve_text_encoding_auto();
4949 } else {
4950 handle.encoding = InputEncoding::Bytes;
4951 }
4952 }
4953
4954 pub(crate) unsafe fn boundary_open_input(
4955 engine: *mut PortableTexEngine<'_>,
4956 file: *mut NativeFileHandle,
4957 format: integer,
4958 mode: const_string,
4959 ) -> boolean {
4960 let Some(engine) = engine.as_mut() else {
4961 if !file.is_null() {
4962 *file = core::ptr::null_mut();
4963 }
4964 return false_0;
4965 };
4966 let Some(name) = Self::current_resource_name(engine as *mut PortableTexEngine<'_>) else {
4967 if !file.is_null() {
4968 *file = core::ptr::null_mut();
4969 }
4970 return false_0;
4971 };
4972 let mode = Self::mode_string(mode);
4973 let request_kind = Self::resource_kind_for_open(engine, name.as_str(), format);
4974 let request_package = Self::resource_package_owner(engine, name.as_str(), request_kind);
4975 let source: Option<PortableSourceSpan> = None;
4976 let request = ResourceRequest {
4977 name: name.as_str(),
4978 kind: request_kind,
4979 package: request_package.as_deref(),
4980 format,
4981 mode: mode.as_str(),
4982 source: source.clone(),
4983 };
4984 engine.resource_requests = engine.resource_requests.saturating_add(1);
4985 let virtual_key = Self::virtual_file_key(name.as_str());
4986 let bytes = if let Some(bytes) = engine.virtual_files.get(&virtual_key) {
4987 bytes.clone()
4988 } else if let Some(bytes) = engine.resources.read(request) {
4989 bytes
4990 } else {
4991 engine.resource_request_records.push(PortableResourceRequestRecord {
4992 name,
4993 kind: request_kind,
4994 package: request_package,
4995 format,
4996 mode,
4997 source,
4998 byte_len: None,
4999 });
5000 if !file.is_null() {
5001 *file = core::ptr::null_mut();
5002 }
5003 return false_0;
5004 };
5005 let byte_len = Self::source_index(bytes.len());
5006 engine.resource_request_records.push(PortableResourceRequestRecord {
5007 name: name.clone(),
5008 kind: request_kind,
5009 package: request_package.clone(),
5010 format,
5011 mode: mode.clone(),
5012 source,
5013 byte_len: Some(byte_len),
5014 });
5015 let mut handle = Box::new(PortableFileHandle::new(
5016 name,
5017 request_kind,
5018 request_package,
5019 format,
5020 bytes,
5021 ));
5022 Self::resolve_input_encoding(engine, &mut handle);
5026 if format == resource_format_tfm {
5027 engine.state.tfmtemp = handle.read_byte().map_or(-1, |byte| byte as integer);
5028 }
5029 if !file.is_null() {
5030 *file = Box::into_raw(handle);
5031 return true_0;
5032 }
5033 drop(handle);
5034 false_0
5035 }
5036
5037 unsafe fn begin_primary_input_raw(
5038 self: &mut Self,
5039 name: &str,
5040 bytes: Vec<u8>,
5041 ) -> EngineFlow<boolean> {
5042 if self.state.inputfile.is_null() || self.state.sourcefilenamestack.is_null()
5043 || self.state.fullsourcefilenamestack.is_null()
5044 || self.state.buffer.is_null()
5045 {
5046 return Ok(false_0);
5047 }
5048 let Some(source_name) = Self::intern_static_pool_string(self, name)? else {
5049 return Ok(false_0);
5050 };
5051 self.beginfilereading()?;
5052 let slot = self.state.curinput.indexfield as isize;
5053 let mut handle = Box::new(
5054 PortableFileHandle::new(
5055 name.to_string(),
5056 ResourceKind::TexInput,
5057 None,
5058 resource_format_tex_input,
5059 bytes,
5060 ),
5061 );
5062 Self::resolve_input_encoding(self, &mut handle);
5063 *self.state.inputfile.offset(slot) = Box::into_raw(handle);
5064 self.state.curinput.namefield = source_name as halfword;
5065 *self.state.sourcefilenamestack.offset(slot) = source_name;
5066 *self.state.fullsourcefilenamestack.offset(slot) = source_name;
5067 self.state.curinput.statefield = 33 as quarterword;
5068 self.state.line = 1 as integer;
5069 self.state.src_primary_name = source_name;
5070 self.state.cmd_span = 0;
5071 self.state.pending_call_span = 0;
5072 self.state.src_user_cmd_span = 0;
5073 self.state.src_tok_span = 0;
5074 self.state.src_anchor_cmd = 0;
5075 self.state.src_grp_stack.clear();
5076 self.state.src_grp_closing = 0;
5077 self.state.src_call_user_span = 0;
5078 self.state.src_line_base = 0;
5079 self.state.src_line_buf_start = 0;
5080 self.state.src_prev_line_len = 0;
5081 self.state.src_line_initialized = false;
5082 self.state.curinput.spanfield = 0;
5083 self.state.src_native_offsets.clear();
5084 self.state.src_stack_cells.clear();
5085 self.state.cur_stack_head = 0;
5086 if Self::boundary_input_line(
5087 self as *mut PortableTexEngine<'_>,
5088 *self.state.inputfile.offset(slot) as NativeFileHandle,
5089 ) == 0
5090 {
5091 self.endfilereading();
5092 return Ok(false_0);
5093 }
5094 self.firmuptheline()?;
5095 let eqtb = self.state.zeqtb.as_mut_ptr();
5096 let endline_char_index = if self.is_xetex() && self.state.eqtbtop >= 7_892_312 {
5097 7_892_312_i64
5098 } else {
5099 27_212_i64
5100 };
5101 let endline_char = if eqtb.is_null() {
5102 -1
5103 } else {
5104 (*eqtb.offset(endline_char_index as isize)).u.CINT
5105 };
5106 if !(0..=255).contains(&endline_char) {
5107 self.state.curinput.limitfield -= 1;
5108 } else {
5109 *self.state.buffer.offset(self.state.curinput.limitfield as isize) = endline_char
5110 as UnicodeScalar;
5111 }
5112 self.state.first = (self.state.curinput.limitfield as i32 + 1) as integer;
5113 self.state.curinput.locfield = self.state.curinput.startfield;
5114 Ok(true_0)
5115 }
5116
5117 pub(crate) unsafe fn boundary_input_line(
5118 engine: *mut PortableTexEngine<'_>,
5119 file: NativeFileHandle,
5120 ) -> boolean {
5121 let Some(engine) = engine.as_mut() else {
5122 return false_0;
5123 };
5124 if file.is_null() || engine.state.buffer.is_null() {
5125 return false_0;
5126 }
5127
5128 let handle = &mut *file;
5129 if !handle.has_remaining() {
5130 return false_0;
5131 }
5132
5133 let first = engine.state.first.max(0) as usize;
5134 let limit = engine.state.bufsize.max(0) as usize;
5135 let mut last = first;
5136 while last < limit {
5140 let Some(scalar) = handle.next_input_scalar() else {
5141 break;
5142 };
5143 match scalar {
5144 0x0A => break,
5145 0x0D => {
5146 let saved_cursor = handle.cursor;
5150 let saved_lookahead = handle.saved_char;
5151 let was_eof = handle.eof_after_failed_read;
5152 match handle.next_input_scalar() {
5153 Some(0x0A) => {} _ => {
5155 handle.cursor = saved_cursor;
5157 handle.saved_char = saved_lookahead;
5158 handle.eof_after_failed_read = was_eof;
5159 }
5160 }
5161 break;
5162 }
5163 scalar => {
5164 *engine.state.buffer.offset(last as isize) = scalar as UnicodeScalar;
5165 last += 1;
5166 }
5167 }
5168 }
5169
5170 while last > first && *engine.state.buffer.offset((last - 1) as isize) == b' ' as UnicodeScalar {
5171 last -= 1;
5172 }
5173 if handle.format == resource_format_tex_input || handle.format == 0 {
5174 engine.current_input_package_owner = handle.package.clone();
5175 }
5176 if engine.state.source_tracking
5183 && engine.state.curinput.namefield as strnumber == engine.state.src_primary_name
5184 {
5185 if engine.state.src_line_initialized {
5186 engine.state.src_line_base += engine.state.src_prev_line_len + 1;
5187 } else {
5188 engine.state.src_line_base = 0;
5189 engine.state.src_line_initialized = true;
5190 }
5191 engine.state.src_line_buf_start = first as integer;
5192 engine.state.src_prev_line_len = last.saturating_sub(first) as u32;
5193 engine.state.src_token_start = first as integer;
5199 }
5200 engine.state.last = last as integer;
5201 true_0
5202 }
5203
5204 pub(crate) unsafe fn boundary_read_byte(_file: NativeFileHandle) -> integer {
5205 if _file.is_null() {
5206 return -1;
5207 }
5208 (&mut *_file).read_byte().map_or(-1, |byte| byte as integer)
5209 }
5210
5211 pub(crate) unsafe fn boundary_end_of_file(_file: NativeFileHandle) -> integer {
5212 if _file.is_null() || (&*_file).is_eof() {
5213 1
5214 } else {
5215 0
5216 }
5217 }
5218
5219 pub(crate) unsafe fn boundary_flush_file(_file: NativeFileHandle) -> integer {
5220 0
5221 }
5222
5223 pub(crate) unsafe fn boundary_write_byte(
5224 engine: *mut PortableTexEngine<'_>,
5225 character: integer,
5226 file: NativeFileHandle,
5227 ) -> integer {
5228 if !file.is_null() {
5229 if let Ok(byte) = u8::try_from(character) {
5230 (*file).bytes.push(byte);
5231 }
5232 return character;
5233 }
5234 if let Some(engine) = engine.as_mut() {
5235 if let Ok(byte) = u8::try_from(character) {
5236 engine.transcript_bytes.push(byte);
5237 }
5238 }
5239 character
5240 }
5241
5242 pub(crate) unsafe fn boundary_close_file(_file: NativeFileHandle) {
5243 if !_file.is_null() {
5244 drop(Box::from_raw(_file));
5245 }
5246 }
5247
5248 pub(crate) unsafe fn get_seconds_and_micros(
5249 engine: *mut PortableTexEngine<'_>,
5250 seconds: *mut integer,
5251 micros: *mut integer,
5252 ) {
5253 let clock = engine
5254 .as_mut()
5255 .map(|engine| engine.platform.clock())
5256 .unwrap_or_default();
5257 if !seconds.is_null() {
5258 *seconds = clock.seconds;
5259 }
5260 if !micros.is_null() {
5261 *micros = clock.micros;
5262 }
5263 }
5264
5265 pub(crate) unsafe fn linebreak_start(
5266 engine: *mut PortableTexEngine<'_>,
5267 font: integer,
5268 locale: integer,
5269 text: *mut uint16_t,
5270 text_length: integer,
5271 ) {
5272 let Some(engine) = engine.as_mut() else {
5273 return;
5274 };
5275 let text = if text.is_null() || text_length <= 0 {
5276 &[]
5277 } else {
5278 core::slice::from_raw_parts(text as *const uint16_t, text_length as usize)
5279 };
5280 engine
5281 .platform
5282 .linebreak_start(PortableLinebreakRequest { font, locale, text });
5283 }
5284
5285 pub(crate) unsafe fn linebreak_next(engine: *mut PortableTexEngine<'_>) -> integer {
5286 engine
5287 .as_mut()
5288 .and_then(|engine| engine.platform.linebreak_next())
5289 .unwrap_or(-1)
5290 }
5291
5292 pub(crate) unsafe fn register_host_box_primitive(self: &mut Self) -> EngineFlow<()> {
5294 let eqtb = self.state.zeqtb.as_mut_ptr();
5295 let name = b"Uhostbox";
5296 for (index, byte) in name.iter().enumerate() {
5297 *self.state.buffer.offset(index as isize) = *byte as UnicodeScalar;
5298 }
5299 let saved = self.state.nonewcontrolsequence;
5300 self.state.nonewcontrolsequence = 0 as boolean;
5301 let cs = (&mut *(self as *mut PortableTexEngine<'_>))
5302 .zidlookup(0 as integer, name.len() as integer)?;
5303 self.state.nonewcontrolsequence = saved;
5304 (*eqtb.offset(cs as isize)).hh.u.B1 = 1 as i16;
5306 (*eqtb.offset(cs as isize)).hh.u.B0 = 59 as i16;
5307 (*eqtb.offset(cs as isize)).hh.v.RH = HOST_BOX_EXTENSION_CODE as halfword;
5308 Ok(())
5309 }
5310
5311 unsafe fn host_box_marker(
5315 engine: *mut PortableTexEngine<'_>,
5316 subtype: i16,
5317 payload: integer,
5318 width: scaled,
5319 height: scaled,
5320 depth: scaled,
5321 ) -> EngineFlow<halfword> {
5322 let this = &mut *engine;
5323 let marker = this.zgetnode(5 as i32)?;
5324 let mem: *mut memoryword = this.state.zmem.as_mut_ptr();
5325 (*mem.offset(marker as isize)).hh.u.B0 = 8 as i16;
5326 (*mem.offset(marker as isize)).hh.u.B1 = subtype;
5327 (*mem.offset(marker as isize)).hh.v.RH = -(268435455 as i64) as halfword;
5328 (*mem.offset((marker as i32 + 1 as i32) as isize)).u.CINT = width;
5329 (*mem.offset((marker as i32 + 2 as i32) as isize)).u.CINT = depth;
5330 (*mem.offset((marker as i32 + 3 as i32) as isize)).u.CINT = height;
5331 (*mem.offset((marker as i32 + 4 as i32) as isize)).u.CINT = payload;
5332 Ok(marker)
5333 }
5334
5335 unsafe fn host_box_build(
5337 engine: *mut PortableTexEngine<'_>,
5338 token: integer,
5339 style: PortableHostBoxStyle,
5340 font_size: scaled,
5341 ) -> EngineFlow<halfword> {
5342 let this = &mut *engine;
5343 let response = this.platform.host_box(PortableHostBoxRequest {
5344 token,
5345 style,
5346 font_size,
5347 });
5348 let hbox = this.newnullbox()?;
5349 let Some(host_box) = response else {
5350 return Ok(hbox);
5351 };
5352 let mem: *mut memoryword = this.state.zmem.as_mut_ptr();
5353 (*mem.offset((hbox as i32 + 1 as i32) as isize)).u.CINT = host_box.width;
5354 (*mem.offset((hbox as i32 + 2 as i32) as isize)).u.CINT = host_box.depth;
5355 (*mem.offset((hbox as i32 + 3 as i32) as isize)).u.CINT = host_box.height;
5356 let index = this.hostbox_records.len();
5357 let (width, height, depth) = (host_box.width, host_box.height, host_box.depth);
5358 this.hostbox_records.push(host_box);
5359 let marker = Self::host_box_marker(
5360 engine,
5361 HOST_BOX_RESOLVED_SUBTYPE,
5362 index as integer,
5363 width,
5364 height,
5365 depth,
5366 )?;
5367 (*mem.offset((hbox as i32 + 5 as i32) as isize)).hh.v.RH = marker;
5368 Ok(hbox)
5369 }
5370
5371 pub(crate) unsafe fn host_box_insert(
5373 engine: *mut PortableTexEngine<'_>,
5374 token: integer,
5375 ) -> EngineFlow<()> {
5376 let Some(this) = engine.as_mut() else {
5377 return Ok(());
5378 };
5379 let mode = (this.state.curlist.modefield as i32).abs();
5380 if mode == 209 as i32 {
5381 let marker =
5382 Self::host_box_marker(engine, HOST_BOX_PENDING_SUBTYPE, token, 0, 0, 0)?;
5383 let this = &mut *engine;
5384 let placeholder = this.newnullbox()?;
5385 let noad = this.newnoad()?;
5386 let mem: *mut memoryword = this.state.zmem.as_mut_ptr();
5387 (*mem.offset((placeholder as i32 + 5 as i32) as isize)).hh.v.RH = marker;
5388 (*mem.offset((noad as i32 + 1 as i32) as isize)).hh.v.RH = 2 as i32 as halfword;
5389 (*mem.offset((noad as i32 + 1 as i32) as isize)).hh.v.LH = placeholder;
5390 (*mem.offset(this.state.curlist.tailfield as isize)).hh.v.RH = noad;
5391 this.state.curlist.tailfield = noad;
5392 } else {
5393 let eqtb = this.state.zeqtb.as_mut_ptr();
5394 let font = (*eqtb.offset(EQTB_CUR_FONT_LOC as isize)).hh.v.RH as integer;
5395 let font_size = this.font_at_size(font);
5396 let hbox =
5397 Self::host_box_build(engine, token, PortableHostBoxStyle::Text, font_size)?;
5398 let this = &mut *engine;
5399 let mem: *mut memoryword = this.state.zmem.as_mut_ptr();
5400 (*mem.offset(this.state.curlist.tailfield as isize)).hh.v.RH = hbox;
5401 this.state.curlist.tailfield = hbox;
5402 }
5403 Ok(())
5404 }
5405
5406 pub(crate) unsafe fn host_box_resolve_noad(
5408 engine: *mut PortableTexEngine<'_>,
5409 q: halfword,
5410 ) -> EngineFlow<()> {
5411 let Some(this) = engine.as_mut() else {
5412 return Ok(());
5413 };
5414 if q < 0 || q >= this.state.himemmin {
5415 return Ok(());
5416 }
5417 let mem: *mut memoryword = this.state.zmem.as_mut_ptr();
5418 if (*mem.offset(q as isize)).hh.u.B0 as i32 != 16 as i32 {
5420 return Ok(());
5421 }
5422 let style_code = this.state.curstyle as i32;
5423 Self::host_box_resolve_field(engine, (q as i32 + 1 as i32) as halfword, style_code)
5424 }
5425
5426 pub(crate) unsafe fn host_box_resolve_field(
5428 engine: *mut PortableTexEngine<'_>,
5429 field: halfword,
5430 style_code: i32,
5431 ) -> EngineFlow<()> {
5432 let Some(this) = engine.as_mut() else {
5433 return Ok(());
5434 };
5435 if field < 0 {
5436 return Ok(());
5437 }
5438 let mem: *mut memoryword = this.state.zmem.as_mut_ptr();
5439 if (*mem.offset(field as isize)).hh.v.RH as i32 != 2 as i32 {
5441 return Ok(());
5442 }
5443 let placeholder = (*mem.offset(field as isize)).hh.v.LH;
5444 if placeholder < 0 || placeholder as i64 == -(268435455 as i64) {
5445 return Ok(());
5446 }
5447 let marker = (*mem.offset((placeholder as i32 + 5 as i32) as isize)).hh.v.RH;
5448 if marker < 0 || marker as i64 == -(268435455 as i64) || marker >= this.state.himemmin {
5449 return Ok(());
5450 }
5451 if (*mem.offset(marker as isize)).hh.u.B0 as i32 != 8 as i32
5452 || (*mem.offset(marker as isize)).hh.u.B1 as i32 != HOST_BOX_PENDING_SUBTYPE as i32
5453 {
5454 return Ok(());
5455 }
5456 let token = (*mem.offset((marker as i32 + 4 as i32) as isize)).u.CINT;
5457 let size = if style_code < 4 {
5459 0
5460 } else {
5461 256 * ((style_code - 2) / 2)
5462 };
5463 let style = match size {
5464 0 => PortableHostBoxStyle::Text,
5465 256 => PortableHostBoxStyle::Script,
5466 _ => PortableHostBoxStyle::ScriptScript,
5467 };
5468 let eqtb = this.state.zeqtb.as_mut_ptr();
5470 let font = (*eqtb.offset((EQTB_MATH_FONT_FAM2_BASE + size as i64) as isize))
5471 .hh
5472 .v
5473 .RH as integer;
5474 let font_size = this.font_at_size(font);
5475 let hbox = Self::host_box_build(engine, token, style, font_size)?;
5476 Self::src_carry_copy(engine as *mut Self, placeholder, hbox);
5479 let mem: *mut memoryword = (*engine).state.zmem.as_mut_ptr();
5480 let resolved_marker = (*mem.offset((hbox as i32 + 5 as i32) as isize)).hh.v.RH;
5481 if resolved_marker >= 0 && resolved_marker as i64 != -(268435455 as i64) {
5482 Self::src_carry_copy(engine as *mut Self, placeholder, resolved_marker);
5483 }
5484 (&mut *engine).zflushnodelist(placeholder)?;
5485 let this = &mut *engine;
5486 let mem: *mut memoryword = this.state.zmem.as_mut_ptr();
5487 (*mem.offset(field as isize)).hh.v.LH = hbox;
5488 Ok(())
5489 }
5490
5491 pub(crate) unsafe fn abort_engine(
5492 engine: *mut PortableTexEngine<'_>,
5493 status: integer,
5494 ) -> EngineFlow<core::convert::Infallible> {
5495 if let Some(engine) = engine.as_mut() {
5496 engine.last_abort_status = Some(status);
5497 }
5498 Err(EngineBreak::Abort(EngineAbort { status }))
5499 }
5500
5501 pub(crate) unsafe fn sandbox_reject(
5505 engine: *mut PortableTexEngine<'_>,
5506 message: &str,
5507 ) -> EngineFlow<()> {
5508 if let Some(engine) = engine.as_ref() {
5509 if engine.sandbox {
5510 return Err(EngineBreak::Error(EngineError {
5511 message: message.into(),
5512 }));
5513 }
5514 }
5515 Ok(())
5516 }
5517
5518 pub(crate) unsafe fn sandbox_open_math(
5525 engine: *mut PortableTexEngine<'_>,
5526 ) -> EngineFlow<()> {
5527 if let Some(engine) = engine.as_mut() {
5528 if engine.sandbox {
5529 if engine.sandbox_math_depth == 0 && engine.sandbox_math_opened {
5530 return Err(EngineBreak::Error(EngineError {
5531 message: "math shift ($) is not allowed inside a math expression"
5532 .into(),
5533 }));
5534 }
5535 engine.sandbox_math_opened = true;
5536 engine.sandbox_math_depth += 1;
5537 }
5538 }
5539 Ok(())
5540 }
5541
5542 pub(crate) unsafe fn sandbox_close_math(
5547 engine: *mut PortableTexEngine<'_>,
5548 ) -> EngineFlow<()> {
5549 if let Some(engine) = engine.as_mut() {
5550 if engine.sandbox && engine.sandbox_math_depth > 0 {
5551 engine.sandbox_math_depth -= 1;
5552 }
5553 }
5554 Ok(())
5555 }
5556
5557 pub(crate) unsafe fn sandbox_tick(
5561 engine: *mut PortableTexEngine<'_>,
5562 ) -> EngineFlow<()> {
5563 if let Some(engine) = engine.as_mut() {
5564 if engine.sandbox {
5565 engine.sandbox_ops = engine.sandbox_ops.saturating_add(1);
5566 if engine.sandbox_ops > SANDBOX_OP_BUDGET {
5567 return Err(EngineBreak::Error(EngineError {
5568 message: "expression is too complex or did not terminate".into(),
5569 }));
5570 }
5571 }
5572 }
5573 Ok(())
5574 }
5575
5576 pub(crate) unsafe fn surface_error(
5584 engine: *mut PortableTexEngine<'_>,
5585 ) -> EngineFlow<()> {
5586 let message = engine
5587 .as_ref()
5588 .map(|engine| engine.capture_last_error_message())
5589 .unwrap_or_else(|| "TeX error".into());
5590 Err(EngineBreak::Error(EngineError { message }))
5591 }
5592
5593 pub fn set_source_tracking(self: &mut Self, on: bool) {
5608 self.state.source_tracking = on;
5609 self.state.cmd_span = 0;
5610 self.state.pending_call_span = 0;
5611 self.state.src_token_start = 0;
5612 self.state.src_line_base = 0;
5613 self.state.src_line_buf_start = 0;
5614 self.state.src_prev_line_len = 0;
5615 self.state.src_line_initialized = false;
5616 self.state.src_call_start = 0;
5617 self.state.src_call_name = 0;
5618 self.state.src_call_state = 0;
5619 self.state.src_call_index = 0;
5620 self.state.src_call_span = 0;
5621 self.state.src_call_argspan = 0;
5622 self.state.src_user_cmd_span = 0;
5623 self.state.src_tok_span = 0;
5624 self.state.src_anchor_cmd = 0;
5625 self.state.src_grp_stack.clear();
5626 self.state.src_grp_closing = 0;
5627 self.state.src_call_user_span = 0;
5628 self.state.curinput.spanfield = 0;
5629 self.state.src_spans.clear();
5630 self.state.src_dedup.clear();
5631 self.state.src_native_offsets.clear();
5632 self.state.src_stack_cells.clear();
5633 self.state.cur_stack_head = 0;
5634 let end = if on { self.state.mem.len() } else { 0 };
5635 self.state.node_src = PagedArray::new(0, end, node_src_default, node_src_sig);
5636 self.state.node_stack = PagedArray::new(0, end, node_stack_default, node_stack_sig);
5637 }
5638
5639 pub fn source_tracking_enabled(&self) -> bool {
5641 self.state.source_tracking
5642 }
5643
5644 fn intern_span_raw(self: &mut Self, name: strnumber, start: u32, end: u32, role: u8) -> SrcId {
5649 let span = RawSpan { name, start, end, role };
5650 if let Some(&id) = self.state.src_dedup.get(&span) {
5651 return id;
5652 }
5653 self.state.src_spans.push(span);
5654 let id = self.state.src_spans.len() as SrcId;
5655 self.state.src_dedup.insert(span, id);
5656 id
5657 }
5658
5659 fn src_buf_offset(&self, loc: integer) -> u32 {
5662 let col = loc as i64 - self.state.src_line_buf_start as i64;
5663 (self.state.src_line_base as i64 + col).max(0) as u32
5664 }
5665
5666 pub(crate) fn resolve_node_src(&self, node: halfword) -> Option<PortableSourceSpan> {
5670 if !self.state.source_tracking || node < 0 {
5671 return None;
5672 }
5673 let id = self.state.node_src.get_copy(node as usize);
5674 if id == 0 {
5675 return None;
5676 }
5677 let raw = *self.state.src_spans.get((id - 1) as usize)?;
5678 let name = unsafe { self.pool_string(raw.name) }?;
5679 Some(PortableSourceSpan {
5680 name,
5681 start: raw.start,
5682 end: raw.end,
5683 role: raw.role,
5684 })
5685 }
5686
5687 pub(crate) unsafe fn src_mark_token_start(engine: *mut Self) {
5691 let Some(engine) = engine.as_mut() else {
5692 return;
5693 };
5694 if engine.state.source_tracking && engine.state.curinput.statefield as i32 != 0 {
5695 engine.state.src_token_start = engine.state.curinput.locfield as integer;
5696 }
5697 }
5698
5699 pub(crate) unsafe fn src_record_buffer_span(engine: *mut Self) {
5704 let Some(engine) = engine.as_mut() else {
5705 return;
5706 };
5707 if !engine.state.source_tracking || engine.state.curinput.statefield as i32 == 0 {
5708 return;
5709 }
5710 let a = engine.src_buf_offset(engine.state.src_token_start);
5711 let b = engine.src_buf_offset(engine.state.curinput.locfield as integer);
5712 let (lo, hi) = if a <= b { (a, b) } else { (b, a) };
5713 let name = engine.state.curinput.namefield as strnumber;
5714 let id = engine.intern_span_raw(name, lo, hi, 0);
5715 engine.state.curinput.spanfield = id;
5716 engine.state.src_tok_span = id;
5717 if engine.state.curcs != 0
5734 && name == engine.state.src_primary_name
5735 && engine.state.scannerstatus as i32 == 0
5736 {
5737 engine.state.src_user_cmd_span = id;
5738 engine.state.src_anchor_cmd = 0;
5743 }
5744 }
5745
5746 pub(crate) unsafe fn src_tokenlist_span(engine: *mut Self) {
5753 let Some(engine) = engine.as_mut() else {
5754 return;
5755 };
5756 if !engine.state.source_tracking {
5757 return;
5758 }
5759 if engine.state.curinput.indexfield as i32 >= 5 {
5760 return;
5761 }
5762 {
5769 let lf = engine.state.curinput.locfield as i32;
5770 if lf >= 0 {
5771 let cid = engine.state.node_src.get_copy(lf as usize);
5772 if cid != 0 {
5773 engine.state.src_tok_span = cid;
5774 }
5775 }
5776 }
5777 let cell = engine.state.curinput.locfield as i32;
5778 if cell < 0 {
5779 return;
5780 }
5781 let id = engine.state.node_src.get_copy(cell as usize);
5782 if id != 0 {
5783 engine.state.curinput.spanfield = id;
5784 }
5785 }
5786
5787 pub(crate) unsafe fn src_back_input_stamp(engine: *mut Self, p: halfword) {
5799 let Some(engine) = engine.as_mut() else {
5800 return;
5801 };
5802 if !engine.state.source_tracking || p < 0 {
5803 return;
5804 }
5805 let id = engine.state.src_tok_span;
5806 if id != 0 {
5807 engine.state.node_src.set(p as usize, id);
5808 }
5809 }
5810
5811 pub(crate) unsafe fn src_latch_cmd_span(engine: *mut Self) {
5815 let Some(engine) = engine.as_mut() else {
5816 return;
5817 };
5818 if engine.state.source_tracking {
5819 engine.state.cmd_span = engine.state.curinput.spanfield;
5820 }
5821 }
5822
5823 pub(crate) unsafe fn src_stamp_avail(engine: *mut Self, node: halfword) {
5828 let Some(engine) = engine.as_mut() else {
5829 return;
5830 };
5831 if engine.state.source_tracking && node >= 0 {
5832 let id = engine.state.curinput.spanfield;
5833 engine.state.node_src.set(node as usize, id);
5834 engine.state.node_stack.set(node as usize, engine.state.cur_stack_head);
5835 }
5836 }
5837
5838 pub(crate) unsafe fn src_stamp_node_range(engine: *mut Self, node: halfword, size: integer) {
5845 let Some(engine) = engine.as_mut() else {
5846 return;
5847 };
5848 if !engine.state.source_tracking || node < 0 || size <= 0 {
5849 return;
5850 }
5851 let id = engine.state.cmd_span;
5852 let head = engine.state.cur_stack_head;
5853 let base = node as usize;
5854 for i in 0..size as usize {
5855 if id != 0 {
5856 engine.state.node_src.set(base + i, id);
5857 }
5858 if head != 0 {
5859 engine.state.node_stack.set(base + i, head);
5860 }
5861 }
5862 }
5863
5864 pub(crate) unsafe fn src_carry_copy(engine: *mut Self, src: halfword, dst: halfword) {
5873 let Some(engine) = engine.as_mut() else {
5874 return;
5875 };
5876 if !engine.state.source_tracking || src < 0 || dst < 0 {
5877 return;
5878 }
5879 let id = engine.state.node_src.get_copy(src as usize);
5880 if id != 0 {
5881 engine.state.node_src.set(dst as usize, id);
5882 let head = engine.state.node_stack.get_copy(src as usize);
5883 engine.state.node_stack.set(dst as usize, head);
5884 }
5885 }
5886
5887 pub(crate) unsafe fn src_carry_token_span(engine: *mut Self, dest: halfword, src: halfword) {
5900 let Some(engine) = engine.as_mut() else {
5901 return;
5902 };
5903 if !engine.state.source_tracking || dest < 0 || src < 0 {
5904 return;
5905 }
5906 let id = engine.state.node_src.get_copy(src as usize);
5907 if id != 0 {
5908 engine.state.node_src.set(dest as usize, id);
5909 let head = engine.state.node_stack.get_copy(src as usize);
5910 engine.state.node_stack.set(dest as usize, head);
5911 }
5912 }
5913
5914 pub(crate) unsafe fn src_stamp_char(engine: *mut Self, node: halfword) {
5919 let Some(engine) = engine.as_mut() else {
5920 return;
5921 };
5922 if !engine.state.source_tracking || node < 0 {
5923 return;
5924 }
5925 let id = engine.state.cmd_span;
5926 if id != 0 {
5927 engine.state.node_src.set(node as usize, id);
5928 }
5929 engine.state.node_stack.set(node as usize, engine.state.cur_stack_head);
5930 }
5931
5932 pub(crate) unsafe fn src_mlist_repoint(engine: *mut Self, q: halfword) {
5936 let Some(engine) = engine.as_mut() else {
5937 return;
5938 };
5939 if !engine.state.source_tracking || q < 0 {
5940 return;
5941 }
5942 let id = engine.state.node_src.get_copy(q as usize);
5943 if id != 0 {
5944 engine.state.cmd_span = id;
5945 }
5946 }
5947
5948 pub(crate) unsafe fn src_stamp_field(engine: *mut Self, field: halfword) {
5957 let Some(engine) = engine.as_mut() else {
5958 return;
5959 };
5960 if !engine.state.source_tracking || field < 0 {
5961 return;
5962 }
5963 let id = engine.state.curinput.spanfield;
5964 if id != 0 {
5965 engine.state.node_src.set(field as usize, id);
5966 }
5967 }
5968
5969 pub(crate) unsafe fn src_carry_field(engine: *mut Self, field: halfword, noad: halfword) {
5977 let Some(engine) = engine.as_mut() else {
5978 return;
5979 };
5980 if !engine.state.source_tracking || field < 0 || noad < 0 {
5981 return;
5982 }
5983 let id = engine.state.node_src.get_copy(field as usize);
5984 let head = engine.state.node_stack.get_copy(field as usize);
5985 if id != 0 {
5986 for i in 0..4usize {
5989 engine.state.node_src.set(noad as usize + i, id);
5990 }
5991 }
5992 if head != 0 {
5995 for i in 0..4usize {
5996 engine.state.node_stack.set(noad as usize + i, head);
5997 }
5998 }
5999 }
6000
6001 pub(crate) unsafe fn src_carry_nucleus(engine: *mut Self, noad: halfword, glyph: halfword) {
6014 let Some(engine) = engine.as_mut() else {
6015 return;
6016 };
6017 if !engine.state.source_tracking || noad < 0 || glyph < 0 {
6018 return;
6019 }
6020 let id = engine.state.node_src.get_copy(noad as usize + 1);
6021 if id != 0 {
6022 engine.state.node_src.set(glyph as usize, id);
6023 }
6024 let head = engine.state.node_stack.get_copy(noad as usize + 1);
6028 engine.state.node_stack.set(glyph as usize, head);
6029 }
6030
6031 pub(crate) unsafe fn src_carry_collapse(engine: *mut Self, noad: halfword, field: halfword) {
6038 let Some(engine) = engine.as_mut() else {
6039 return;
6040 };
6041 if !engine.state.source_tracking || noad < 0 || field < 0 {
6042 return;
6043 }
6044 let id = engine.state.node_src.get_copy(noad as usize);
6045 if id != 0 {
6046 engine.state.node_src.set(field as usize, id);
6047 }
6048 let head = engine.state.node_stack.get_copy(noad as usize);
6052 if head != 0 {
6053 engine.state.node_stack.set(field as usize, head);
6054 }
6055 }
6056
6057 pub(crate) unsafe fn src_save_cmd_span(engine: *mut Self) -> u32 {
6060 engine.as_ref().map_or(0, |engine| engine.state.cmd_span)
6061 }
6062
6063 pub(crate) unsafe fn src_restore_cmd_span(engine: *mut Self, saved: u32) {
6066 if let Some(engine) = engine.as_mut() {
6067 if engine.state.source_tracking {
6068 engine.state.cmd_span = saved;
6069 }
6070 }
6071 }
6072
6073 fn src_stack_push_span(self: &mut Self, span: SrcId) -> u32 {
6083 self.state.src_stack_cells.push(SrcStackCell {
6084 span,
6085 parent: self.state.cur_stack_head,
6086 start: 0,
6087 name: 0,
6088 pending: false,
6089 });
6090 let head = self.state.src_stack_cells.len() as u32;
6091 self.state.cur_stack_head = head;
6092 head
6093 }
6094
6095 fn src_stack_push_pending(self: &mut Self, start: u32, name: strnumber) -> u32 {
6098 self.state.src_stack_cells.push(SrcStackCell {
6099 span: 0,
6100 parent: self.state.cur_stack_head,
6101 start,
6102 name,
6103 pending: true,
6104 });
6105 let head = self.state.src_stack_cells.len() as u32;
6106 self.state.cur_stack_head = head;
6107 head
6108 }
6109
6110 fn src_stack_pop(self: &mut Self) {
6112 let head = self.state.cur_stack_head;
6113 if head != 0 {
6114 if let Some(cell) = self.state.src_stack_cells.get((head - 1) as usize) {
6115 self.state.cur_stack_head = cell.parent;
6116 }
6117 }
6118 }
6119
6120 pub(crate) unsafe fn src_end_token_list(engine: *mut Self, token_type: i32) {
6129 let Some(engine) = engine.as_mut() else {
6130 return;
6131 };
6132 if !engine.state.source_tracking {
6133 return;
6134 }
6135 let cand = engine.state.curinput.spanfield;
6136 if cand != 0 {
6137 let cand_end = engine
6138 .state
6139 .src_spans
6140 .get((cand - 1) as usize)
6141 .map(|r| r.end)
6142 .unwrap_or(0);
6143 let cur_end = if engine.state.src_call_argspan != 0 {
6144 engine
6145 .state
6146 .src_spans
6147 .get((engine.state.src_call_argspan - 1) as usize)
6148 .map(|r| r.end)
6149 .unwrap_or(0)
6150 } else {
6151 0
6152 };
6153 if engine.state.src_call_argspan == 0 || cand_end > cur_end {
6154 engine.state.src_call_argspan = cand;
6155 }
6156 }
6157 if token_type == 6 {
6158 engine.src_stack_pop();
6159 }
6160 }
6161
6162 pub(crate) unsafe fn src_scan_math_group_open(engine: *mut Self) {
6169 let Some(engine) = engine.as_mut() else {
6170 return;
6171 };
6172 if !engine.state.source_tracking {
6173 return;
6174 }
6175 let cmd = engine.state.cmd_span;
6176 let (start, name) = if cmd != 0 {
6177 match engine.state.src_spans.get((cmd - 1) as usize) {
6178 Some(raw) => (raw.start, raw.name),
6179 None => (0, 0),
6180 }
6181 } else {
6182 (0, 0)
6183 };
6184 engine.src_stack_push_pending(start, name);
6185 engine.state.src_grp_stack.push(engine.state.curinput.spanfield);
6190 }
6191
6192 pub(crate) unsafe fn src_scan_math_group_close(engine: *mut Self) {
6196 let eptr = engine;
6197 let Some(e) = engine.as_mut() else {
6198 return;
6199 };
6200 if !e.state.source_tracking {
6201 return;
6202 }
6203 e.state.src_grp_closing = e.state.src_grp_stack.pop().unwrap_or(0);
6207 let grp = e.state.src_grp_closing;
6208 let aux = e.state.curlist.auxfield.u.CINT;
6213 let frac = if aux > 0 && aux != -(268435455 as i32) { aux } else { -1 };
6214 if e.state.cur_stack_head != 0 {
6215 let idx = (e.state.cur_stack_head - 1) as usize;
6216 if let Some(cell) = e.state.src_stack_cells.get(idx).copied() {
6217 if cell.pending
6220 && cell.name != 0
6221 && cell.name == e.state.curinput.namefield as strnumber
6222 {
6223 let end = e.src_buf_offset(e.state.curinput.locfield as integer);
6224 let (lo, hi) = if cell.start <= end {
6225 (cell.start, end)
6226 } else {
6227 (end, cell.start)
6228 };
6229 let id = e.intern_span_raw(cell.name, lo, hi, 1);
6230 if let Some(c) = e.state.src_stack_cells.get_mut(idx) {
6231 c.span = id;
6232 c.pending = false;
6233 }
6234 }
6235 e.state.cur_stack_head = cell.parent;
6236 }
6237 }
6238 if frac >= 0 {
6239 Self::src_construct_extent(eptr, frac, grp);
6240 }
6241 }
6242
6243 pub(crate) unsafe fn src_construct_anchor(engine: *mut Self) {
6256 let Some(engine) = engine.as_mut() else {
6257 return;
6258 };
6259 if !engine.state.source_tracking {
6260 return;
6261 }
6262 let noad = engine.state.curlist.tailfield as i32;
6263 if noad < 0 {
6264 return;
6265 }
6266 let id = engine.state.node_src.get_copy(noad as usize);
6267 if id == 0 {
6268 return;
6269 }
6270 let Some(raw) = engine.state.src_spans.get((id - 1) as usize).copied() else {
6271 return;
6272 };
6273 let anchor = (engine.state.src_anchor_cmd != 0)
6287 .then(|| engine.state.src_spans.get((engine.state.src_anchor_cmd - 1) as usize).copied())
6288 .flatten()
6289 .filter(|u| u.name == raw.name);
6290 let chosen = match anchor {
6291 Some(u) => {
6292 if u.start < raw.start {
6293 Some(u)
6294 } else {
6295 None
6296 }
6297 }
6298 None => (engine.state.src_user_cmd_span != 0)
6299 .then(|| engine.state.src_spans.get((engine.state.src_user_cmd_span - 1) as usize).copied())
6300 .flatten()
6301 .filter(|u| u.name == raw.name && u.start < raw.start),
6302 };
6303 let Some(u) = chosen else {
6304 return;
6305 };
6306 let newid = engine.intern_span_raw(raw.name, u.start, raw.end, raw.role);
6307 engine.state.node_src.set(noad as usize, newid);
6308 }
6309
6310 pub(crate) unsafe fn src_construct_extend_to_loc(engine: *mut Self) {
6325 let e = match engine.as_ref() {
6326 Some(e) => e,
6327 None => return,
6328 };
6329 if !e.state.source_tracking {
6330 return;
6331 }
6332 let field = (*e
6335 .state
6336 .savestack
6337 .offset((e.state.saveptr as i32 + 0 as i32) as isize))
6338 .u
6339 .CINT;
6340 let noad = e.state.curlist.tailfield as i32;
6341 let grp = e.state.src_grp_closing;
6342 if noad < 0 || field != noad + 1 {
6343 return;
6344 }
6345 Self::src_construct_extent(engine, noad, grp);
6346 }
6347
6348 pub(crate) unsafe fn src_construct_extent(engine: *mut Self, noad: halfword, group_open: SrcId) {
6363 let Some(engine) = engine.as_mut() else {
6364 return;
6365 };
6366 if !engine.state.source_tracking || noad < 0 {
6367 return;
6368 }
6369 let id = engine.state.node_src.get_copy(noad as usize);
6370 if id == 0 {
6371 return;
6372 }
6373 let Some(raw) = engine.state.src_spans.get((id - 1) as usize).copied() else {
6374 return;
6375 };
6376 let (end, name) = if engine.state.curinput.statefield as i32 != 0 {
6377 (
6378 engine.src_buf_offset(engine.state.curinput.locfield as integer),
6379 engine.state.curinput.namefield as strnumber,
6380 )
6381 } else {
6382 let sid = engine.state.curinput.spanfield;
6383 if sid == 0 {
6384 return;
6385 }
6386 let Some(braw) = engine.state.src_spans.get((sid - 1) as usize).copied() else {
6387 return;
6388 };
6389 (braw.end, braw.name)
6390 };
6391 if raw.name != name {
6392 return;
6393 }
6394 let end = end.max(raw.end);
6395 let mut start = raw.start;
6396 if group_open != 0 {
6397 if let Some(g) = engine.state.src_spans.get((group_open - 1) as usize).copied() {
6398 if g.name == name && g.start < start {
6399 start = g.start;
6400 }
6401 }
6402 }
6403 if start == raw.start && end == raw.end {
6404 return;
6405 }
6406 let newid = engine.intern_span_raw(name, start, end, raw.role);
6407 engine.state.node_src.set(noad as usize, newid);
6408 }
6409
6410 pub(crate) unsafe fn src_leftright(engine: *mut Self, p: halfword, t: integer) {
6417 let Some(eng) = engine.as_mut() else {
6418 return;
6419 };
6420 if !eng.state.source_tracking {
6421 return;
6422 }
6423 if t == 30 as i32 {
6424 let cmd = eng.state.cmd_span;
6425 eng.state.src_grp_stack.push(cmd);
6426 } else if t == 31 as i32 {
6427 let open = eng.state.src_grp_stack.pop().unwrap_or(0);
6428 Self::src_construct_extent(engine, p, open);
6429 }
6430 }
6431
6432 pub fn node_enclosing_spans(&self, handle: PortableNodeHandle) -> Vec<PortableSourceSpan> {
6439 let node = handle.0 as halfword;
6440 let mut out: Vec<PortableSourceSpan> = Vec::new();
6441 if !self.state.source_tracking || node < 0 {
6442 return out;
6443 }
6444 let primary = self.resolve_node_src(node);
6445 let mut head = self.state.node_stack.get_copy(node as usize);
6446 let mut guard = 0u32;
6447 while head != 0 {
6448 guard += 1;
6449 if guard > 4096 {
6450 break;
6451 }
6452 let Some(cell) = self.state.src_stack_cells.get((head - 1) as usize) else {
6453 break;
6454 };
6455 let parent = cell.parent;
6456 let span_id = cell.span;
6457 head = parent;
6458 if span_id == 0 {
6459 continue;
6460 }
6461 let Some(raw) = self.state.src_spans.get((span_id - 1) as usize) else {
6462 continue;
6463 };
6464 let Some(name) = (unsafe { self.pool_string(raw.name) }) else {
6465 continue;
6466 };
6467 if let Some(p) = primary.as_ref() {
6468 if name != p.name || raw.start > p.start || raw.end < p.end {
6471 continue;
6472 }
6473 if raw.start == p.start && raw.end == p.end {
6474 continue;
6475 }
6476 }
6477 if let Some(last) = out.last() {
6478 if last.name == name && last.start == raw.start && last.end == raw.end {
6479 continue;
6480 }
6481 }
6482 out.push(PortableSourceSpan {
6483 name,
6484 start: raw.start,
6485 end: raw.end,
6486 role: 1,
6487 });
6488 }
6489 out
6490 }
6491
6492 pub(crate) unsafe fn src_begin_token_list(engine: *mut Self, t: quarterword) {
6497 let Some(engine) = engine.as_mut() else {
6498 return;
6499 };
6500 if !engine.state.source_tracking {
6501 return;
6502 }
6503 if t as i32 == 6 {
6505 let call = engine.state.pending_call_span;
6506 if call != 0 {
6507 engine.state.curinput.spanfield = call;
6508 }
6509 engine.state.pending_call_span = 0;
6510 engine.src_stack_push_span(call);
6514 }
6515 }
6516
6517 pub(crate) unsafe fn src_capture_tok_span(engine: *mut Self) -> u32 {
6535 engine.as_ref().map_or(0, |engine| engine.state.src_tok_span)
6536 }
6537
6538 pub(crate) unsafe fn src_restore_tok_span(engine: *mut Self, saved: u32) {
6540 if let Some(engine) = engine.as_mut() {
6541 if engine.state.source_tracking {
6542 engine.state.src_tok_span = saved;
6543 }
6544 }
6545 }
6546
6547 pub(crate) unsafe fn src_macro_begin(engine: *mut Self) {
6551 let Some(engine) = engine.as_mut() else {
6552 return;
6553 };
6554 if !engine.state.source_tracking {
6555 return;
6556 }
6557 let span = engine.state.curinput.spanfield;
6558 engine.state.src_call_span = span;
6559 engine.state.src_call_state = engine.state.curinput.statefield as integer;
6560 engine.state.src_call_index = engine.state.curinput.indexfield as integer;
6561 engine.state.src_call_name = engine.state.curinput.namefield as strnumber;
6562 engine.state.src_call_argspan = 0;
6563 engine.state.src_call_user_span = engine.state.src_user_cmd_span;
6567 engine.state.src_call_start = if span != 0 {
6568 engine
6569 .state
6570 .src_spans
6571 .get((span - 1) as usize)
6572 .map(|s| s.start)
6573 .unwrap_or(0)
6574 } else {
6575 0
6576 };
6577 if engine.state.src_call_state == 0 && engine.state.src_call_index < 3 && span != 0 {
6588 if let Some(raw) = engine.state.src_spans.get((span - 1) as usize).copied() {
6589 if raw.name == engine.state.src_primary_name {
6590 engine.state.src_anchor_cmd = span;
6591 }
6592 }
6593 }
6594 }
6595
6596 unsafe fn src_arg_hull(self: &mut Self, n: integer) -> SrcId {
6603 let mut lo = u32::MAX;
6604 let mut hi = 0u32;
6605 let mut found = false;
6606 let mut name: strnumber = self.state.src_primary_name;
6607 if self.state.src_call_span != 0 {
6608 if let Some(raw) = self
6609 .state
6610 .src_spans
6611 .get((self.state.src_call_span - 1) as usize)
6612 {
6613 name = raw.name;
6614 lo = raw.start;
6615 hi = raw.end;
6616 found = true;
6617 }
6618 }
6619 let cmd_start = if found { lo } else { 0 };
6627 let zmem = self.state.zmem;
6628 let lo_b = self.state.memmin;
6629 let hi_b = self.state.memmax;
6630 for i in 0..n.max(0) {
6631 let mut p = self.state.pstack[i as usize];
6632 let mut guard = 0i32;
6633 while p >= lo_b && p <= hi_b && p as i64 != -(268435455 as i64) {
6634 guard += 1;
6635 if guard > 100000 {
6636 break;
6637 }
6638 let id = self.state.node_src.get_copy(p as usize);
6639 if id != 0 {
6640 if let Some(raw) = self.state.src_spans.get((id - 1) as usize) {
6641 if raw.name == name && raw.start >= cmd_start {
6642 if found {
6643 lo = lo.min(raw.start);
6644 hi = hi.max(raw.end);
6645 } else {
6646 lo = raw.start;
6647 hi = raw.end;
6648 found = true;
6649 }
6650 }
6651 }
6652 }
6653 p = (*zmem.offset(p as isize)).hh.v.RH;
6654 }
6655 }
6656 for cand in [self.state.src_call_argspan, self.state.curinput.spanfield] {
6663 if cand == 0 {
6664 continue;
6665 }
6666 if let Some(raw) = self.state.src_spans.get((cand - 1) as usize) {
6667 if raw.name == name && raw.start >= cmd_start {
6668 if found {
6669 lo = lo.min(raw.start);
6670 hi = hi.max(raw.end);
6671 } else {
6672 lo = raw.start;
6673 hi = raw.end;
6674 found = true;
6675 }
6676 }
6677 }
6678 }
6679 if found && hi > lo {
6680 self.intern_span_raw(name, lo, hi, 1)
6681 } else {
6682 0
6683 }
6684 }
6685
6686 pub(crate) unsafe fn src_macro_set_pending(engine: *mut Self, n: integer) {
6704 let Some(engine) = engine.as_mut() else {
6705 return;
6706 };
6707 if !engine.state.source_tracking {
6708 return;
6709 }
6710 if engine.state.src_call_index == 0 && engine.state.src_call_span == 0 {
6711 engine.state.pending_call_span = 0;
6721 } else if engine.state.src_call_index == 0 {
6722 let hull = engine.src_arg_hull(n);
6725 engine.state.pending_call_span = if hull != 0 {
6726 hull
6727 } else {
6728 engine.state.src_call_span
6729 };
6730 } else if engine.state.curinput.statefield as i32 != 0 {
6731 let end = engine.src_buf_offset(engine.state.curinput.locfield as integer);
6741 let name = engine.state.curinput.namefield as strnumber;
6742 let mut start = engine.state.src_call_start.min(end);
6743 let user = engine.state.src_call_user_span;
6744 if user != 0 {
6745 if let Some(raw) = engine.state.src_spans.get((user - 1) as usize) {
6746 if raw.name == name && raw.start <= start {
6747 start = raw.start;
6748 }
6749 }
6750 }
6751 let id = engine.intern_span_raw(name, start, end, 1);
6752 engine.state.pending_call_span = id;
6753 } else if n > 0 {
6754 let hull = engine.src_arg_hull(n);
6765 engine.state.pending_call_span = if hull != 0 {
6766 hull
6767 } else {
6768 engine.state.src_call_span
6769 };
6770 } else {
6771 engine.state.pending_call_span = engine.state.src_call_span;
6772 }
6773 }
6774
6775 pub(crate) unsafe fn src_native_run_push(engine: *mut Self) {
6784 let Some(engine) = engine.as_mut() else {
6785 return;
6786 };
6787 if !engine.state.source_tracking {
6788 return;
6789 }
6790 let nativelen = engine.state.nativelen.max(0) as usize;
6791 let units = if engine.state.curchr as i64 > 65535 { 2 } else { 1 };
6794 let prev = nativelen.saturating_sub(units);
6795 if prev == 0 {
6796 engine.state.src_native_offsets.clear();
6797 }
6798 if engine.state.src_native_offsets.len() > prev {
6801 engine.state.src_native_offsets.truncate(prev);
6802 }
6803 let id = engine.state.curinput.spanfield;
6804 while engine.state.src_native_offsets.len() < nativelen {
6805 engine.state.src_native_offsets.push(id);
6806 }
6807 }
6808
6809 pub(crate) unsafe fn src_resolve_native_glyphs(
6825 engine: *mut Self,
6826 node: halfword,
6827 text: &[u16],
6828 glyphs: &mut [PortableNativeGlyph],
6829 ) {
6830 let Some(engine) = engine.as_mut() else {
6831 return;
6832 };
6833 if !engine.state.source_tracking {
6834 return;
6835 }
6836 let offsets = core::mem::take(&mut engine.state.src_native_offsets);
6837 if text.is_empty() || offsets.len() != text.len() {
6840 return;
6841 }
6842 if node < 0 {
6843 return;
6844 }
6845 let node_id = engine.state.node_src.get_copy(node as usize);
6848 if node_id == 0 {
6849 return;
6850 }
6851 let node_name = match engine.state.src_spans.get((node_id - 1) as usize) {
6852 Some(raw) => raw.name,
6853 None => return,
6854 };
6855 let s = String::from_utf16_lossy(text);
6861 let n = s.len();
6862 let mut byte_src = vec![0u32; n];
6863 let mut u16i = 0usize;
6864 for (b, ch) in s.char_indices() {
6865 let id = offsets.get(u16i).copied().unwrap_or(0);
6866 let upper = (b + ch.len_utf8()).min(n);
6867 for slot in byte_src.iter_mut().take(upper).skip(b) {
6868 *slot = id;
6869 }
6870 u16i += ch.len_utf16();
6871 }
6872 for gi in 0..glyphs.len() {
6873 let cs = (glyphs[gi].cluster_start as usize).min(n);
6874 let mut ce = n;
6878 for g2 in glyphs.iter() {
6879 let c2 = (g2.cluster_start as usize).min(n);
6880 if c2 > cs && c2 < ce {
6881 ce = c2;
6882 }
6883 }
6884 let mut lo = u32::MAX;
6885 let mut hi = 0u32;
6886 let mut found = false;
6887 for &id in byte_src.iter().take(ce).skip(cs) {
6888 if id == 0 {
6889 continue;
6890 }
6891 let Some(raw) = engine.state.src_spans.get((id - 1) as usize) else {
6892 continue;
6893 };
6894 if raw.name != node_name {
6895 continue;
6896 }
6897 lo = lo.min(raw.start);
6898 hi = hi.max(raw.end);
6899 found = true;
6900 }
6901 if found && hi > lo {
6902 glyphs[gi].src_start = lo;
6903 glyphs[gi].src_end = hi;
6904 }
6905 }
6906 }
6907
6908 pub fn input_source_spans(&self) -> Vec<PortableSourceSpan> {
6911 self.state
6912 .src_spans
6913 .iter()
6914 .filter_map(|raw| {
6915 let name = unsafe { self.pool_string(raw.name) }?;
6916 Some(PortableSourceSpan {
6917 name,
6918 start: raw.start,
6919 end: raw.end,
6920 role: raw.role,
6921 })
6922 })
6923 .collect()
6924 }
6925
6926 pub(crate) unsafe fn resolve_font_handle(
6927 engine: *mut PortableTexEngine<'_>,
6928 name: *mut ASCIIcode,
6929 size: integer,
6930 ) -> FontHandle {
6931 let Some(engine) = engine.as_mut() else {
6932 return 0;
6933 };
6934 let name_len = engine.state.namelength.max(0) as usize;
6935 let name = if name.is_null() || name_len == 0 {
6936 &[]
6937 } else {
6938 core::slice::from_raw_parts(name as *const i32, name_len)
6939 };
6940 engine.fonts.resolve_font_handle(name, size).unwrap_or(0)
6941 }
6942
6943 pub(crate) unsafe fn measure_font_metrics(
6944 engine: *mut PortableTexEngine<'_>,
6945 font: FontHandle,
6946 ascent: *mut integer,
6947 descent: *mut integer,
6948 xheight: *mut integer,
6949 capheight: *mut integer,
6950 slant: *mut integer,
6951 ) {
6952 let metrics = engine
6953 .as_mut()
6954 .map(|engine| engine.fonts.font_metrics(font))
6955 .unwrap_or_default();
6956 if !ascent.is_null() {
6957 *ascent = metrics.ascent;
6958 }
6959 if !descent.is_null() {
6960 *descent = metrics.descent;
6961 }
6962 if !xheight.is_null() {
6963 *xheight = metrics.xheight;
6964 }
6965 if !capheight.is_null() {
6966 *capheight = metrics.capheight;
6967 }
6968 if !slant.is_null() {
6969 *slant = metrics.slant;
6970 }
6971 }
6972
6973 pub(crate) unsafe fn get_native_mathsy_parameter(
6974 engine: *mut PortableTexEngine<'resources>,
6975 font: integer,
6976 param: integer,
6977 ) -> integer {
6978 let Some(engine) = engine.as_mut() else {
6979 return 0;
6980 };
6981 let Some(font_handle) = Self::font_handle_for_number(engine, font) else {
6982 return 0;
6983 };
6984 engine.fonts.math_symbol_parameter(font_handle, param)
6985 }
6986
6987 pub(crate) unsafe fn get_native_mathex_parameter(
6988 engine: *mut PortableTexEngine<'resources>,
6989 font: integer,
6990 param: integer,
6991 ) -> integer {
6992 let Some(engine) = engine.as_mut() else {
6993 return 0;
6994 };
6995 let Some(font_handle) = Self::font_handle_for_number(engine, font) else {
6996 return 0;
6997 };
6998 engine.fonts.math_extension_parameter(font_handle, param)
6999 }
7000
7001 pub(crate) unsafe fn get_ot_math_ital_corr(
7010 engine: *mut PortableTexEngine<'resources>,
7011 font: integer,
7012 glyph: integer,
7013 ) -> integer {
7014 let Some(engine) = engine.as_mut() else {
7015 return 0;
7016 };
7017 let Some(font_handle) = Self::font_handle_for_number(engine, font) else {
7018 return 0;
7019 };
7020 engine.fonts.math_glyph_italic_correction(font_handle, glyph)
7021 }
7022
7023 pub(crate) unsafe fn get_ot_math_variant(
7028 engine: *mut PortableTexEngine<'resources>,
7029 f_0: integer,
7030 g_0: integer,
7031 v: integer,
7032 adv: *mut integer,
7033 horiz: integer,
7034 ) -> integer {
7035 if !adv.is_null() {
7036 *adv = -1;
7037 }
7038 let Some(engine) = engine.as_mut() else {
7039 return g_0;
7040 };
7041 let Some(font_handle) = Self::font_handle_for_number(engine, f_0) else {
7042 return g_0;
7043 };
7044 let index = u16::try_from(v).unwrap_or(u16::MAX);
7045 match engine
7046 .fonts
7047 .math_glyph_variant(font_handle, g_0, index, horiz != 0)
7048 {
7049 Some(variant) => {
7050 if !adv.is_null() {
7051 *adv = variant.advance;
7052 }
7053 variant.glyph
7054 }
7055 None => g_0,
7056 }
7057 }
7058
7059 pub(crate) unsafe fn get_ot_assembly_ptr(
7065 engine: *mut PortableTexEngine<'resources>,
7066 f_0: integer,
7067 g_0: integer,
7068 horiz: integer,
7069 ) -> voidpointer {
7070 let Some(engine) = engine.as_mut() else {
7071 return nullptr;
7072 };
7073 let Some(font_handle) = Self::font_handle_for_number(engine, f_0) else {
7074 return nullptr;
7075 };
7076 let parts = engine
7077 .fonts
7078 .math_glyph_assembly(font_handle, g_0, horiz != 0);
7079 if parts.is_empty() {
7080 return nullptr;
7081 }
7082 let assembly = Box::new(GlyphAssembly { parts });
7083 Box::into_raw(assembly) as voidpointer
7084 }
7085
7086 pub(crate) unsafe fn ot_min_connector_overlap(
7089 engine: *mut PortableTexEngine<'resources>,
7090 f_0: integer,
7091 ) -> integer {
7092 let Some(engine) = engine.as_mut() else {
7093 return 0;
7094 };
7095 let Some(font_handle) = Self::font_handle_for_number(engine, f_0) else {
7096 return 0;
7097 };
7098 engine.fonts.math_min_connector_overlap(font_handle)
7099 }
7100
7101 unsafe fn math_glyph_height(
7103 engine: &mut PortableTexEngine<'resources>,
7104 f_0: integer,
7105 g_0: integer,
7106 ) -> scaled {
7107 let Some(font_handle) = Self::font_handle_for_number(engine, f_0) else {
7108 return 0;
7109 };
7110 let Ok(glyph) = u16::try_from(g_0) else {
7111 return 0;
7112 };
7113 engine.fonts.measure_native_glyph(font_handle, glyph, true).height
7114 }
7115
7116 unsafe fn math_glyph_depth(
7118 engine: &mut PortableTexEngine<'resources>,
7119 f_0: integer,
7120 g_0: integer,
7121 ) -> scaled {
7122 let Some(font_handle) = Self::font_handle_for_number(engine, f_0) else {
7123 return 0;
7124 };
7125 let Ok(glyph) = u16::try_from(g_0) else {
7126 return 0;
7127 };
7128 engine.fonts.measure_native_glyph(font_handle, glyph, true).depth
7129 }
7130
7131 unsafe fn math_kern_at(
7134 engine: &mut PortableTexEngine<'resources>,
7135 f_0: integer,
7136 g_0: integer,
7137 height: integer,
7138 corner: PortableMathKernCorner,
7139 ) -> integer {
7140 let Some(font_handle) = Self::font_handle_for_number(engine, f_0) else {
7141 return 0;
7142 };
7143 engine.fonts.math_kern_at(font_handle, g_0, corner, height)
7144 }
7145
7146 pub(crate) unsafe fn get_ot_math_kern(
7153 engine: *mut PortableTexEngine<'resources>,
7154 f_0: integer,
7155 g_0: integer,
7156 sf: integer,
7157 sg: integer,
7158 cmd: integer,
7159 shift_scaled: integer,
7160 ) -> integer {
7161 const SUP_CMD: integer = 0;
7162 const SUB_CMD: integer = 1;
7163 let Some(engine) = engine.as_mut() else {
7164 return 0;
7165 };
7166 let Some(font_handle) = Self::font_handle_for_number(engine, f_0) else {
7167 return 0;
7168 };
7169 let Some(sfont_handle) = Self::font_handle_for_number(engine, sf) else {
7170 return 0;
7171 };
7172
7173 let g_height_pt = Self::math_glyph_height(engine, f_0, g_0) as f32 / 65536.0;
7175 let g_depth_pt = Self::math_glyph_depth(engine, f_0, g_0) as f32 / 65536.0;
7176 let sg_height_pt = Self::math_glyph_height(engine, sf, sg) as f32 / 65536.0;
7177 let sg_depth_pt = Self::math_glyph_depth(engine, sf, sg) as f32 / 65536.0;
7178
7179 let g_height = engine.fonts.math_points_to_units(font_handle, g_height_pt) as integer;
7181 let g_depth = engine.fonts.math_points_to_units(font_handle, g_depth_pt) as integer;
7182 let sg_height = engine
7183 .fonts
7184 .math_points_to_units(sfont_handle, sg_height_pt) as integer;
7185 let sg_depth = engine
7186 .fonts
7187 .math_points_to_units(sfont_handle, sg_depth_pt) as integer;
7188 let shift_pt = shift_scaled as f32 / 65536.0;
7189 let shift = engine.fonts.math_points_to_units(font_handle, shift_pt) as integer;
7190
7191 let f_size = engine.fonts.math_point_size(font_handle);
7192 let sf_size = engine.fonts.math_point_size(sfont_handle);
7193 if f_size == 0.0 {
7194 return 0;
7195 }
7196 let scale_factor = sf_size / f_size;
7197
7198 let mut rval: integer;
7199 if cmd == SUP_CMD {
7200 let kern = Self::math_kern_at(
7201 engine,
7202 f_0,
7203 g_0,
7204 shift - (scale_factor * sg_depth as f32) as integer,
7205 PortableMathKernCorner::TopRight,
7206 );
7207 let skern =
7208 Self::math_kern_at(engine, sf, sg, -sg_depth, PortableMathKernCorner::BottomLeft);
7209 let top_kern = kern + (scale_factor * skern as f32) as integer;
7210
7211 let kern =
7212 Self::math_kern_at(engine, f_0, g_0, g_height, PortableMathKernCorner::TopRight);
7213 let skern = Self::math_kern_at(
7214 engine,
7215 sf,
7216 sg,
7217 ((g_height - shift) as f32 / scale_factor) as integer,
7218 PortableMathKernCorner::BottomLeft,
7219 );
7220 let bot_kern = kern + (scale_factor * skern as f32) as integer;
7221
7222 rval = if top_kern > bot_kern { top_kern } else { bot_kern };
7223 } else if cmd == SUB_CMD {
7224 let kern = Self::math_kern_at(
7225 engine,
7226 f_0,
7227 g_0,
7228 (scale_factor * sg_height as f32) as integer - shift,
7229 PortableMathKernCorner::BottomRight,
7230 );
7231 let skern =
7232 Self::math_kern_at(engine, sf, sg, sg_height, PortableMathKernCorner::TopLeft);
7233 let top_kern = kern + (scale_factor * skern as f32) as integer;
7234
7235 let kern =
7236 Self::math_kern_at(engine, f_0, g_0, -g_depth, PortableMathKernCorner::BottomRight);
7237 let skern = Self::math_kern_at(
7238 engine,
7239 sf,
7240 sg,
7241 ((shift - g_depth) as f32 / scale_factor) as integer,
7242 PortableMathKernCorner::TopLeft,
7243 );
7244 let bot_kern = kern + (scale_factor * skern as f32) as integer;
7245
7246 rval = if top_kern > bot_kern { top_kern } else { bot_kern };
7247 } else {
7248 return 0;
7249 }
7250
7251 rval = engine.fonts.math_units_to_scaled(font_handle, rval);
7252 rval
7253 }
7254
7255 pub(crate) unsafe fn get_native_word_cp(
7256 engine: *mut PortableTexEngine<'resources>,
7257 node: voidpointer,
7258 side: integer,
7259 ) -> integer {
7260 let Some(engine) = engine.as_mut() else {
7261 return 0;
7262 };
7263 let Some(node_index) = Self::node_index_for_pointer(engine, node) else {
7264 return 0;
7265 };
7266 let Some(info) = engine.native_glyph_infos.get(&node_index) else {
7267 return 0;
7268 };
7269 let glyph = if side == 0 {
7270 info.glyphs.first()
7271 } else {
7272 info.glyphs.last()
7273 };
7274 let Some(glyph) = glyph else {
7275 return 0;
7276 };
7277 let font = Self::native_node_font(engine.state.zmem, node_index);
7278 Self::character_protrusion(engine, font, u32::from(glyph.glyph_id), side)
7279 }
7280
7281 pub(crate) unsafe fn get_native_glyph(
7282 engine: *mut PortableTexEngine<'resources>,
7283 node: voidpointer,
7284 index: u32,
7285 ) -> uint16_t {
7286 let Some(engine) = engine.as_mut() else {
7287 return 0;
7288 };
7289 let Some(node_index) = Self::node_index_for_pointer(engine, node) else {
7290 return 0;
7291 };
7292 engine
7293 .native_glyph_infos
7294 .get(&node_index)
7295 .and_then(|info| info.glyphs.get(index as usize))
7296 .map_or(0, |glyph| glyph.glyph_id)
7297 }
7298
7299 pub(crate) unsafe fn get_character_protrusion(
7300 engine: *mut PortableTexEngine<'_>,
7301 font: integer,
7302 code: u32,
7303 side: integer,
7304 ) -> integer {
7305 engine
7306 .as_mut()
7307 .map_or(0, |engine| Self::character_protrusion(engine, font, code, side))
7308 }
7309
7310 pub(crate) fn character_protrusion(
7311 engine: &PortableTexEngine<'_>,
7312 font: integer,
7313 code: u32,
7314 side: integer,
7315 ) -> integer {
7316 engine
7317 .character_protrusions
7318 .get(&(font, code, side))
7319 .copied()
7320 .unwrap_or(0)
7321 }
7322
7323 pub(crate) fn set_character_protrusion(
7324 engine: &mut PortableTexEngine<'_>,
7325 font: integer,
7326 code: u32,
7327 side: integer,
7328 value: integer,
7329 ) {
7330 let key = (font, code, side);
7331 if value == 0 {
7332 engine.character_protrusions.remove(&key);
7333 } else {
7334 engine.character_protrusions.insert(key, value);
7335 }
7336 }
7337
7338 pub(crate) unsafe fn get_opentype_math_constant(
7339 engine: *mut PortableTexEngine<'resources>,
7340 font: integer,
7341 constant: integer,
7342 ) -> integer {
7343 let Some(engine) = engine.as_mut() else {
7344 return 0;
7345 };
7346 let Some(font_handle) = Self::font_handle_for_number(engine, font) else {
7347 return 0;
7348 };
7349 engine.fonts.opentype_math_constant(font_handle, constant)
7350 }
7351
7352 pub(crate) unsafe fn get_opentype_math_accent_position(
7353 engine: *mut PortableTexEngine<'resources>,
7354 font: integer,
7355 glyph: integer,
7356 ) -> integer {
7357 let Some(engine) = engine.as_mut() else {
7358 return 0;
7359 };
7360 let Some(font_handle) = Self::font_handle_for_number(engine, font) else {
7361 return 0;
7362 };
7363 engine.fonts.opentype_math_accent_position(font_handle, glyph)
7364 }
7365
7366 pub(crate) unsafe fn map_char_to_glyph(
7367 engine: *mut PortableTexEngine<'resources>,
7368 font: integer,
7369 ch: integer,
7370 ) -> integer {
7371 let Some(engine) = engine.as_mut() else {
7372 return 0;
7373 };
7374 let Some(font_handle) = Self::font_handle_for_number(engine, font) else {
7375 return 0;
7376 };
7377 engine.fonts.map_char_to_glyph(font_handle, ch)
7378 }
7379
7380 pub(crate) unsafe fn map_glyph_to_index(
7381 engine: *mut PortableTexEngine<'resources>,
7382 font: integer,
7383 ) -> integer {
7384 let Some(engine) = engine.as_mut() else {
7385 return 0;
7386 };
7387 let Some(font_handle) = Self::font_handle_for_number(engine, font) else {
7388 return 0;
7389 };
7390 let Some(name) = engine.pool_string(engine.state.curname) else {
7391 return 0;
7392 };
7393 engine.fonts.map_glyph_to_index(font_handle, name.as_str())
7394 }
7395
7396 pub(crate) unsafe fn ot_font_get(
7401 engine: *mut PortableTexEngine<'resources>,
7402 what: integer,
7403 font: integer,
7404 param1: integer,
7405 param2: integer,
7406 param3: integer,
7407 ) -> integer {
7408 let Some(engine) = engine.as_mut() else {
7409 return 0;
7410 };
7411 let Some(font_handle) = Self::font_handle_for_number(engine, font) else {
7412 return 0;
7413 };
7414 engine
7415 .fonts
7416 .ot_font_get(font_handle, what, param1, param2, param3)
7417 }
7418
7419 pub(crate) unsafe fn is_opentype_math_font(
7420 engine: *mut PortableTexEngine<'_>,
7421 font: FontHandle,
7422 ) -> boolean {
7423 engine
7424 .as_mut()
7425 .map(|engine| engine.fonts.is_opentype_math_font(font) as boolean)
7426 .unwrap_or(false_0)
7427 }
7428
7429 pub(crate) unsafe fn using_opentype(
7430 engine: *mut PortableTexEngine<'_>,
7431 font: FontHandle,
7432 ) -> boolean {
7433 engine
7434 .as_mut()
7435 .map(|engine| engine.fonts.using_opentype(font) as boolean)
7436 .unwrap_or(false_0)
7437 }
7438
7439 pub(crate) unsafe fn release_font_engine(
7440 engine: *mut PortableTexEngine<'_>,
7441 font: FontHandle,
7442 type_flag: integer,
7443 ) {
7444 if let Some(engine) = engine.as_mut() {
7445 engine.fonts.release_font_handle(font, type_flag);
7446 }
7447 }
7448
7449 pub(crate) unsafe fn measure_opentype_font_metrics(
7450 engine: *mut PortableTexEngine<'_>,
7451 font: FontHandle,
7452 ascent: *mut integer,
7453 descent: *mut integer,
7454 xheight: *mut integer,
7455 capheight: *mut integer,
7456 slant: *mut integer,
7457 ) {
7458 let metrics = engine
7459 .as_mut()
7460 .map(|engine| engine.fonts.opentype_font_metrics(font))
7461 .unwrap_or_default();
7462 if !ascent.is_null() {
7463 *ascent = metrics.ascent;
7464 }
7465 if !descent.is_null() {
7466 *descent = metrics.descent;
7467 }
7468 if !xheight.is_null() {
7469 *xheight = metrics.xheight;
7470 }
7471 if !capheight.is_null() {
7472 *capheight = metrics.capheight;
7473 }
7474 if !slant.is_null() {
7475 *slant = metrics.slant;
7476 }
7477 }
7478
7479 pub(crate) unsafe fn measure_native_node(
7480 engine: *mut PortableTexEngine<'resources>,
7481 node: voidpointer,
7482 use_glyph_metrics: integer,
7483 ) {
7484 let Some(engine) = engine.as_mut() else {
7485 return;
7486 };
7487 let Some(node_index) = Self::node_index_for_pointer(engine, node) else {
7488 return;
7489 };
7490 let mem = engine.state.zmem;
7491 let font_number = Self::native_node_font(mem, node_index);
7492 let Some(font_handle) = Self::font_handle_for_number(engine, font_number) else {
7493 return;
7494 };
7495 let text = Self::native_node_text(mem, node_index);
7496 let mut metrics =
7497 engine
7498 .fonts
7499 .shape_native_text(font_handle, text, use_glyph_metrics != 0);
7500 Self::src_resolve_native_glyphs(
7504 engine as *mut PortableTexEngine<'resources>,
7505 node_index,
7506 text,
7507 metrics.glyphs.as_mut_slice(),
7508 );
7509 Self::write_native_node_metrics(
7510 mem,
7511 node_index,
7512 metrics.width,
7513 metrics.height,
7514 metrics.depth,
7515 );
7516 (*mem.offset((node_index + 4) as isize)).v.QQQQ.u.B3 =
7517 (metrics.glyphs.len().min(i32::MAX as usize) as quarterword) as u16;
7518 (*mem.offset((node_index + 5) as isize)).ptr = nullptr;
7519 engine.native_glyph_infos.insert(
7520 node_index,
7521 PortableNativeGlyphInfo {
7522 glyphs: metrics.glyphs,
7523 },
7524 );
7525 }
7526
7527 pub(crate) unsafe fn measure_native_glyph(
7528 engine: *mut PortableTexEngine<'resources>,
7529 node: voidpointer,
7530 use_glyph_metrics: integer,
7531 ) {
7532 let Some(engine) = engine.as_mut() else {
7533 return;
7534 };
7535 let Some(node_index) = Self::node_index_for_pointer(engine, node) else {
7536 return;
7537 };
7538 let mem = engine.state.zmem;
7539 let font_number = Self::native_node_font(mem, node_index);
7540 let Some(font_handle) = Self::font_handle_for_number(engine, font_number) else {
7541 return;
7542 };
7543 let glyph = (*mem.offset((node_index + 4) as isize)).v.QQQQ.u.B2 as u16;
7544 let metrics = engine
7545 .fonts
7546 .measure_native_glyph(font_handle, glyph, use_glyph_metrics != 0);
7547 Self::write_native_node_metrics(
7548 mem,
7549 node_index,
7550 metrics.width,
7551 metrics.height,
7552 metrics.depth,
7553 );
7554 (*mem.offset((node_index + 4) as isize)).v.QQQQ.u.B3 = (1 as quarterword) as u16;
7555 engine.native_glyph_infos.insert(
7565 node_index,
7566 PortableNativeGlyphInfo {
7567 glyphs: Vec::from([PortableNativeGlyph {
7568 glyph_id: glyph,
7569 x: 0,
7570 y: 0,
7571 advance: metrics.width,
7572 cluster_start: 0,
7573 cluster_end: 0,
7574 src_start: 0,
7575 src_end: 0,
7576 }]),
7577 },
7578 );
7579 }
7580
7581 pub(crate) unsafe fn znotaatfonterror(
7582 self: &mut Self,
7583 cmd: integer,
7584 c_0: integer,
7585 f_0: integer,
7586 ) -> EngineFlow<()> {
7587 self.znototfonterror(cmd, c_0, f_0)?;
7588 Ok(())
7589 }
7590
7591 pub(crate) unsafe fn znotaatgrfonterror(
7592 self: &mut Self,
7593 cmd: integer,
7594 c_0: integer,
7595 f_0: integer,
7596 ) -> EngineFlow<()> {
7597 self.znototfonterror(cmd, c_0, f_0)?;
7598 Ok(())
7599 }
7600
7601 unsafe fn stack_glyph_into_box(
7606 self: &mut Self,
7607 b: halfword,
7608 f_0: internalfontnumber,
7609 g_0: integer,
7610 ) -> EngineFlow<()> {
7611 let mem: *mut memoryword = self.state.zmem.as_mut_ptr();
7612 const NULL: halfword = -(268435455 as i64) as halfword;
7613 let p = (&mut *(self as *mut PortableTexEngine<'_>)).zgetnode(5)?;
7614 (*mem.offset(p as isize)).hh.u.B0 = 8;
7615 (*mem.offset(p as isize)).hh.u.B1 = 42;
7616 (*mem.offset((p + 4) as isize)).v.QQQQ.u.B1 = (f_0 as quarterword) as u16;
7617 (*mem.offset((p + 4) as isize)).v.QQQQ.u.B2 = (g_0 as quarterword) as u16;
7618 Self::measure_native_glyph(
7619 self as *mut PortableTexEngine<'resources>,
7620 mem.offset(p as isize) as *mut memoryword as *mut (),
7621 1,
7622 );
7623 Ok(
7624 if (*mem.offset(b as isize)).hh.u.B0 as i32 == 0 {
7625 let mut q = (*mem.offset((b + 5) as isize)).hh.v.RH;
7626 if q == NULL {
7627 (*mem.offset((b + 5) as isize)).hh.v.RH = p;
7628 } else {
7629 while (*mem.offset(q as isize)).hh.v.RH != NULL {
7630 q = (*mem.offset(q as isize)).hh.v.RH;
7631 }
7632 (*mem.offset(q as isize)).hh.v.RH = p;
7633 if (*mem.offset((b + 3) as isize)).u.CINT
7634 < (*mem.offset((p + 3) as isize)).u.CINT
7635 {
7636 (*mem.offset((b + 3) as isize)).u.CINT = (*mem
7637 .offset((p + 3) as isize))
7638 .u
7639 .CINT;
7640 }
7641 if (*mem.offset((b + 2) as isize)).u.CINT
7642 < (*mem.offset((p + 2) as isize)).u.CINT
7643 {
7644 (*mem.offset((b + 2) as isize)).u.CINT = (*mem
7645 .offset((p + 2) as isize))
7646 .u
7647 .CINT;
7648 }
7649 }
7650 } else {
7651 (*mem.offset(p as isize)).hh.v.RH = (*mem.offset((b + 5) as isize))
7652 .hh
7653 .v
7654 .RH;
7655 (*mem.offset((b + 5) as isize)).hh.v.RH = p;
7656 (*mem.offset((b + 3) as isize)).u.CINT = (*mem.offset((p + 3) as isize))
7657 .u
7658 .CINT;
7659 if (*mem.offset((b + 1) as isize)).u.CINT
7660 < (*mem.offset((p + 1) as isize)).u.CINT
7661 {
7662 (*mem.offset((b + 1) as isize)).u.CINT = (*mem
7663 .offset((p + 1) as isize))
7664 .u
7665 .CINT;
7666 }
7667 },
7668 )
7669 }
7670
7671 unsafe fn stack_glue_into_box(
7674 self: &mut Self,
7675 b: halfword,
7676 min: scaled,
7677 max: scaled,
7678 ) -> EngineFlow<()> {
7679 let mem: *mut memoryword = self.state.zmem.as_mut_ptr();
7680 const NULL: halfword = -(268435455 as i64) as halfword;
7681 const ZERO_GLUE: halfword = 0;
7682 let q = (&mut *(self as *mut PortableTexEngine<'_>)).znewspec(ZERO_GLUE)?;
7683 (*mem.offset((q + 1) as isize)).u.CINT = min;
7684 (*mem.offset((q + 2) as isize)).u.CINT = max - min;
7685 let p = (&mut *(self as *mut PortableTexEngine<'_>)).znewglue(q)?;
7686 Ok(
7687 if (*mem.offset(b as isize)).hh.u.B0 as i32 == 0 {
7688 let mut r = (*mem.offset((b + 5) as isize)).hh.v.RH;
7689 if r == NULL {
7690 (*mem.offset((b + 5) as isize)).hh.v.RH = p;
7691 } else {
7692 while (*mem.offset(r as isize)).hh.v.RH != NULL {
7693 r = (*mem.offset(r as isize)).hh.v.RH;
7694 }
7695 (*mem.offset(r as isize)).hh.v.RH = p;
7696 }
7697 } else {
7698 (*mem.offset(p as isize)).hh.v.RH = (*mem.offset((b + 5) as isize))
7699 .hh
7700 .v
7701 .RH;
7702 (*mem.offset((b + 5) as isize)).hh.v.RH = p;
7703 (*mem.offset((b + 3) as isize)).u.CINT = (*mem.offset((p + 3) as isize))
7704 .u
7705 .CINT;
7706 (*mem.offset((b + 1) as isize)).u.CINT = (*mem.offset((p + 1) as isize))
7707 .u
7708 .CINT;
7709 },
7710 )
7711 }
7712
7713 pub(crate) unsafe fn zbuildopentypeassembly(
7718 self: &mut Self,
7719 f_0: internalfontnumber,
7720 assembly: voidpointer,
7721 s: scaled,
7722 horiz_flag: integer,
7723 ) -> EngineFlow<halfword> {
7724 let mem: *mut memoryword = self.state.zmem.as_mut_ptr();
7725 let horiz = horiz_flag != 0;
7726 let b = (&mut *(self as *mut PortableTexEngine<'_>)).newnullbox()?;
7727 (*mem.offset(b as isize)).hh.u.B0 = if horiz { 0 } else { 1 };
7728 let parts: &[PortableMathAssemblyPart] = if assembly.is_null() {
7729 &[]
7730 } else {
7731 &(*(assembly as *const GlyphAssembly)).parts
7732 };
7733 let part_count = parts.len();
7734 let min_o = Self::ot_min_connector_overlap(
7735 self as *mut PortableTexEngine<'resources>,
7736 f_0 as i32,
7737 );
7738 let mut n: integer = -1;
7739 let mut no_extenders = true;
7740 loop {
7741 n += 1;
7742 let mut s_max: scaled = 0;
7743 let mut prev_o: scaled = 0;
7744 for part in parts.iter() {
7745 if part.extender {
7746 no_extenders = false;
7747 for _ in 0..n {
7748 let mut o = part.start_connector;
7749 if min_o < o {
7750 o = min_o;
7751 }
7752 if prev_o < o {
7753 o = prev_o;
7754 }
7755 s_max = s_max - o + part.full_advance;
7756 prev_o = part.end_connector;
7757 }
7758 } else {
7759 let mut o = part.start_connector;
7760 if min_o < o {
7761 o = min_o;
7762 }
7763 if prev_o < o {
7764 o = prev_o;
7765 }
7766 s_max = s_max - o + part.full_advance;
7767 prev_o = part.end_connector;
7768 }
7769 }
7770 if s_max >= s || no_extenders {
7771 break;
7772 }
7773 }
7774 let mut prev_o: scaled = 0;
7775 for i in 0..part_count {
7776 let part = parts[i];
7777 let reps = if part.extender { n } else { 1 };
7778 for _ in 0..reps {
7779 let mut o = part.start_connector;
7780 if prev_o < o {
7781 o = prev_o;
7782 }
7783 let oo = o;
7784 if min_o < o {
7785 o = min_o;
7786 }
7787 if oo > 0 {
7788 (&mut *(self as *mut PortableTexEngine<'_>))
7789 .stack_glue_into_box(b, -oo, -o)?;
7790 }
7791 let g = part.glyph;
7792 (&mut *(self as *mut PortableTexEngine<'_>))
7793 .stack_glyph_into_box(b, f_0, g)?;
7794 prev_o = part.end_connector;
7795 }
7796 }
7797 const NULL: halfword = -(268435455 as i64) as halfword;
7798 let mut p = (*mem.offset((b + 5) as isize)).hh.v.RH;
7799 let mut nat: scaled = 0;
7800 let mut str_: scaled = 0;
7801 while p != NULL {
7802 let ty = (*mem.offset(p as isize)).hh.u.B0 as i32;
7803 if ty == 8 {
7804 if horiz {
7805 nat += (*mem.offset((p + 1) as isize)).u.CINT;
7806 } else {
7807 nat
7808 += (*mem.offset((p + 3) as isize)).u.CINT
7809 + (*mem.offset((p + 2) as isize)).u.CINT;
7810 }
7811 } else if ty == 10 {
7812 let spec = (*mem.offset((p + 1) as isize)).hh.v.LH;
7813 nat += (*mem.offset((spec + 1) as isize)).u.CINT;
7814 str_ += (*mem.offset((spec + 2) as isize)).u.CINT;
7815 }
7816 p = (*mem.offset(p as isize)).hh.v.RH;
7817 }
7818 if s > nat && str_ > 0 {
7819 let mut o = s - nat;
7820 if o > str_ {
7821 o = str_;
7822 }
7823 (*mem.offset((b + 5) as isize)).hh.u.B1 = 0;
7824 (*mem.offset((b + 5) as isize)).hh.u.B0 = 1;
7825 (*mem.offset((b + 6) as isize)).gr = o as f64 / str_ as f64;
7826 let stretched = nat
7827 + (str_ as f64 * (*mem.offset((b + 6) as isize)).gr).round() as scaled;
7828 if horiz {
7829 (*mem.offset((b + 1) as isize)).u.CINT = stretched;
7830 } else {
7831 (*mem.offset((b + 3) as isize)).u.CINT = stretched;
7832 }
7833 } else if horiz {
7834 (*mem.offset((b + 1) as isize)).u.CINT = nat;
7835 } else {
7836 (*mem.offset((b + 3) as isize)).u.CINT = nat;
7837 }
7838 Ok(b)
7839 }
7840
7841}
7842
7843pub(crate) unsafe fn fputs(_text: const_string, _file: NativeFileHandle) -> i32 {
7844 0
7845}
7846
7847pub(crate) unsafe fn free(_ptr: voidpointer) {}
7848
7849pub(crate) unsafe fn xrealloc(old_address: address, _new_size: size_t) -> address {
7850 old_address
7851}
7852
7853pub(crate) unsafe fn getcreationdate() {}
7854
7855pub(crate) unsafe fn getfilemoddate(_s: integer) {}
7856
7857pub(crate) unsafe fn getfilesize(_s: integer) {}
7858
7859pub(crate) unsafe fn getfiledump(_s: integer, _offset: i32, _length: i32) {}
7860
7861pub(crate) unsafe fn getmd5sum(_s: integer, _file: i32) {}
7862
7863pub(crate) unsafe fn u_close_file_or_pipe(file: *mut unicodefile) {
7864 if !file.is_null() {
7865 PortableTexEngine::boundary_close_file(*file);
7866 *file = core::ptr::null_mut();
7867 }
7868}
7869
7870pub(crate) unsafe fn setinputfileencoding(
7871 file: unicodefile,
7872 mode: integer,
7873 _encoding_data: integer,
7874) {
7875 if file.is_null() {
7879 return;
7880 }
7881 let handle = &mut *file;
7882 handle.encoding = match mode {
7883 1 => InputEncoding::Utf8,
7884 2 => InputEncoding::Utf16Be,
7885 3 => InputEncoding::Utf16Le,
7886 4 => InputEncoding::Bytes,
7887 0 => InputEncoding::Utf8, _ => InputEncoding::Bytes,
7889 };
7890}
7891
7892pub(crate) unsafe fn usingGraphite(_engine: FontHandle) -> boolean {
7893 false_0
7894}
7895
7896pub(crate) unsafe fn aatprintfontname(
7897 _what: i32,
7898 _attrs: CFDictionaryRef,
7899 _param1: i32,
7900 _param2: i32,
7901) {
7902}
7903
7904pub(crate) unsafe fn grprintfontname(
7905 _what: integer,
7906 _engine: voidpointer,
7907 _param1: integer,
7908 _param2: integer,
7909) {
7910}
7911
7912pub(crate) unsafe fn printglyphname(_font: integer, _gid: integer) {}
7913
7914pub(crate) unsafe fn getnativecharheightdepth(
7915 _font: integer,
7916 _ch: integer,
7917 height: *mut integer,
7918 depth: *mut integer,
7919) {
7920 if !height.is_null() {
7921 *height = 0;
7922 }
7923 if !depth.is_null() {
7924 *depth = 0;
7925 }
7926}
7927
7928pub(crate) unsafe fn getnativecharsidebearings(
7929 _font: integer,
7930 _ch: integer,
7931 lsb: *mut integer,
7932 rsb: *mut integer,
7933) {
7934 if !lsb.is_null() {
7935 *lsb = 0;
7936 }
7937 if !rsb.is_null() {
7938 *rsb = 0;
7939 }
7940}
7941
7942pub(crate) unsafe fn getnativecharwd(_font: integer, _ch: integer) -> integer {
7943 0
7944}
7945
7946pub(crate) unsafe fn getnativecharht(_font: integer, _ch: integer) -> integer {
7947 0
7948}
7949
7950pub(crate) unsafe fn getnativechardp(_font: integer, _ch: integer) -> integer {
7951 0
7952}
7953
7954pub(crate) unsafe fn getnativecharic(_font: integer, _ch: integer) -> integer {
7955 0
7956}
7957
7958pub(crate) unsafe fn getglyphbounds(_font: integer, _edge: integer, _gid: integer) -> integer {
7959 0
7960}
7961
7962pub(crate) unsafe fn getfontcharrange(_font: integer, _first: i32) -> integer {
7963 0
7964}
7965
7966pub(crate) unsafe fn get_native_italic_correction(_node: voidpointer) -> Fixed {
7967 0
7968}
7969
7970pub(crate) unsafe fn get_native_glyph_italic_correction(_node: voidpointer) -> Fixed {
7971 0
7972}
7973
7974pub(crate) unsafe fn applymapping(
7975 _mapping: voidpointer,
7976 _text: *mut uint16_t,
7977 text_len: i32,
7978) -> i32 {
7979 text_len
7980}
7981
7982pub(crate) unsafe fn checkfortfmfontmapping() {}
7983
7984pub(crate) unsafe fn loadtfmfontmapping() -> voidpointer {
7985 nullptr
7986}
7987
7988pub(crate) unsafe fn applytfmfontmapping(_mapping: voidpointer, c_0: i32) -> i32 {
7989 c_0
7990}
7991
7992pub(crate) unsafe fn set_cp_code(
7993 _font_num: i32,
7994 _code: u32,
7995 _side: i32,
7996 _value: i32,
7997) -> i32 {
7998 0
7999}
8000
8001pub(crate) unsafe fn countpdffilepages() -> i32 {
8002 0
8003}
8004
8005pub(crate) unsafe fn aatfontget(_what: i32, _attrs: CFDictionaryRef) -> i32 {
8006 0
8007}
8008
8009pub(crate) unsafe fn aatfontget1(_what: i32, _attrs: CFDictionaryRef, _param: i32) -> i32 {
8010 0
8011}
8012
8013pub(crate) unsafe fn aatfontget2(
8014 _what: i32,
8015 _attrs: CFDictionaryRef,
8016 _param1: i32,
8017 _param2: i32,
8018) -> i32 {
8019 0
8020}
8021
8022pub(crate) unsafe fn aatfontgetnamed(_what: i32, _attrs: CFDictionaryRef) -> i32 {
8023 0
8024}
8025
8026pub(crate) unsafe fn aatfontgetnamed1(
8027 _what: i32,
8028 _attrs: CFDictionaryRef,
8029 _param: i32,
8030) -> i32 {
8031 0
8032}
8033
8034pub(crate) unsafe fn grfontgetnamed(_what: integer, _engine: voidpointer) -> integer {
8035 0
8036}
8037
8038pub(crate) unsafe fn grfontgetnamed1(
8039 _what: integer,
8040 _engine: voidpointer,
8041 _param: integer,
8042) -> integer {
8043 0
8044}
8045
8046pub(crate) unsafe fn otfontget(_what: integer, _engine: voidpointer) -> integer {
8047 0
8048}
8049
8050pub(crate) unsafe fn otfontget1(
8051 _what: integer,
8052 _engine: voidpointer,
8053 _param: integer,
8054) -> integer {
8055 0
8056}
8057
8058pub(crate) unsafe fn otfontget2(
8059 _what: integer,
8060 _engine: voidpointer,
8061 _param1: integer,
8062 _param2: integer,
8063) -> integer {
8064 0
8065}
8066
8067pub(crate) unsafe fn otfontget3(
8068 _what: integer,
8069 _engine: voidpointer,
8070 _param1: integer,
8071 _param2: integer,
8072 _param3: integer,
8073) -> integer {
8074 0
8075}
8076
8077pub(crate) unsafe fn free_ot_assembly(assembly: *mut GlyphAssembly) {
8085 if !assembly.is_null() {
8086 drop(Box::from_raw(assembly));
8087 }
8088}
8089
8090#[cfg(test)]
8091mod tests {
8092 use super::*;
8093
8094 fn text_handle(bytes: Vec<u8>, encoding: InputEncoding) -> PortableFileHandle {
8096 let mut handle = PortableFileHandle::new(
8097 "test.tex".to_string(),
8098 ResourceKind::TexInput,
8099 None,
8100 resource_format_tex_input,
8101 bytes,
8102 );
8103 handle.encoding = encoding;
8104 handle
8105 }
8106
8107 fn decode_all(handle: &mut PortableFileHandle) -> Vec<u32> {
8109 let mut out = Vec::new();
8110 while let Some(scalar) = handle.next_input_scalar() {
8111 out.push(scalar);
8112 }
8113 out
8114 }
8115
8116 #[test]
8117 fn utf8_decoder_reads_multibyte_scalars() {
8118 let mut h = text_handle(vec![0xCE, 0xB1, 0xCE, 0xB2, 0xCE, 0xB3], InputEncoding::Utf8);
8120 assert_eq!(decode_all(&mut h), vec![0x3B1, 0x3B2, 0x3B3]);
8121 let mut h = text_handle(
8124 vec![b'A', 0xE2, 0x82, 0xAC, 0xF0, 0x9F, 0x98, 0x80],
8125 InputEncoding::Utf8,
8126 );
8127 assert_eq!(decode_all(&mut h), vec![0x41, 0x20AC, 0x1F600]);
8128 }
8129
8130 #[test]
8131 fn utf8_decoder_replaces_bad_sequences() {
8132 let mut h = text_handle(vec![0xCE, b'A'], InputEncoding::Utf8);
8135 assert_eq!(decode_all(&mut h), vec![0xFFFD, 0x41]);
8136 let mut h = text_handle(vec![0x80], InputEncoding::Utf8);
8140 assert_eq!(decode_all(&mut h), vec![0x80]);
8141 }
8142
8143 #[test]
8144 fn utf16_decoders_read_units_and_surrogates() {
8145 let mut h = text_handle(
8147 vec![0xB1, 0x03, 0xB2, 0x03, 0xB3, 0x03],
8148 InputEncoding::Utf16Le,
8149 );
8150 assert_eq!(decode_all(&mut h), vec![0x3B1, 0x3B2, 0x3B3]);
8151 let mut h = text_handle(
8153 vec![0x03, 0xB1, 0x03, 0xB2, 0x03, 0xB3],
8154 InputEncoding::Utf16Be,
8155 );
8156 assert_eq!(decode_all(&mut h), vec![0x3B1, 0x3B2, 0x3B3]);
8157 let mut h = text_handle(vec![0x3D, 0xD8, 0x00, 0xDE], InputEncoding::Utf16Le);
8159 assert_eq!(decode_all(&mut h), vec![0x1F600]);
8160 let mut h = text_handle(vec![0x3D, 0xD8, 0x41, 0x00], InputEncoding::Utf16Le);
8163 assert_eq!(decode_all(&mut h), vec![0xFFFD, 0x41]);
8164 let mut h = text_handle(vec![0x00, 0xDC], InputEncoding::Utf16Le);
8166 assert_eq!(decode_all(&mut h), vec![0xFFFD]);
8167 }
8168
8169 #[test]
8170 fn bytes_mode_reads_each_byte_raw() {
8171 let mut h = text_handle(vec![0xCE, 0xB1, 0x41], InputEncoding::Bytes);
8173 assert_eq!(decode_all(&mut h), vec![0xCE, 0xB1, 0x41]);
8174 }
8175
8176 #[test]
8177 fn bom_sniff_selects_encoding_and_consumes_bom() {
8178 let mut h = text_handle(vec![0xEF, 0xBB, 0xBF, b'A'], InputEncoding::Bytes);
8180 h.resolve_text_encoding_auto();
8181 assert_eq!(h.encoding, InputEncoding::Utf8);
8182 assert_eq!(h.cursor, 3);
8183 assert_eq!(decode_all(&mut h), vec![0x41]);
8184 let mut h = text_handle(vec![0xFE, 0xFF, 0x03, 0xB1], InputEncoding::Bytes);
8186 h.resolve_text_encoding_auto();
8187 assert_eq!(h.encoding, InputEncoding::Utf16Be);
8188 assert_eq!(h.cursor, 2);
8189 assert_eq!(decode_all(&mut h), vec![0x3B1]);
8190 let mut h = text_handle(vec![0xFF, 0xFE, 0xB1, 0x03], InputEncoding::Bytes);
8192 h.resolve_text_encoding_auto();
8193 assert_eq!(h.encoding, InputEncoding::Utf16Le);
8194 assert_eq!(h.cursor, 2);
8195 assert_eq!(decode_all(&mut h), vec![0x3B1]);
8196 let mut h = text_handle(vec![b'h', b'i'], InputEncoding::Bytes);
8198 h.resolve_text_encoding_auto();
8199 assert_eq!(h.encoding, InputEncoding::Utf8);
8200 assert_eq!(h.cursor, 0);
8201 let mut h = text_handle(vec![0x00, 0x41], InputEncoding::Bytes);
8203 h.resolve_text_encoding_auto();
8204 assert_eq!(h.encoding, InputEncoding::Utf16Be);
8205 assert_eq!(h.cursor, 0);
8206 assert_eq!(decode_all(&mut h), vec![0x41]);
8207 }
8208
8209 #[test]
8210 fn input_line_decodes_into_buffer_per_profile() {
8211 fn buffer_after_input_line(profile: EngineProfile, bytes: Vec<u8>) -> Vec<u32> {
8217 let image = PortableFormatImage::empty();
8218 let mut engine = PortableTexEngine::from_format(profile, &image, EmptyResourceProvider);
8219 engine.initialize_format_state();
8220 let mut handle = PortableFileHandle::new(
8223 "input.tex".to_string(),
8224 ResourceKind::TexInput,
8225 None,
8226 resource_format_tex_input,
8227 bytes,
8228 );
8229 PortableTexEngine::resolve_input_encoding(&engine, &mut handle);
8230 let raw = Box::into_raw(Box::new(handle));
8231 engine.state.first = 0;
8233 let ok = unsafe {
8234 PortableTexEngine::boundary_input_line(
8235 &mut engine as *mut PortableTexEngine<'_>,
8236 raw as NativeFileHandle,
8237 )
8238 };
8239 assert_ne!(ok, 0, "boundary_input_line should succeed");
8240 let first = engine.state.first.max(0) as usize;
8241 let last = engine.state.last.max(0) as usize;
8242 let out = (first..last)
8243 .map(|i| unsafe { *engine.state.buffer.offset(i as isize) as u32 })
8244 .collect();
8245 unsafe { drop(Box::from_raw(raw)) };
8246 out
8247 }
8248 let utf8 = vec![0xCE, 0xB1, 0xCE, 0xB2, 0xCE, 0xB3];
8250 assert_eq!(
8251 buffer_after_input_line(EngineProfile::xetex(), utf8.clone()),
8252 vec![0x3B1, 0x3B2, 0x3B3],
8253 "xetex must UTF-8 decode the input line"
8254 );
8255 assert_eq!(
8256 buffer_after_input_line(EngineProfile::tex(), utf8),
8257 vec![0xCE, 0xB1, 0xCE, 0xB2, 0xCE, 0xB3],
8258 "non-xetex must read raw bytes"
8259 );
8260 let utf16le_bom = vec![0xFF, 0xFE, 0xB1, 0x03, 0xB2, 0x03, 0xB3, 0x03];
8262 assert_eq!(
8263 buffer_after_input_line(EngineProfile::xetex(), utf16le_bom),
8264 vec![0x3B1, 0x3B2, 0x3B3],
8265 "xetex must UTF-16LE decode a BOM'd input line"
8266 );
8267 let utf16be_bom = vec![0xFE, 0xFF, 0x03, 0xB1, 0x03, 0xB2, 0x03, 0xB3];
8269 assert_eq!(
8270 buffer_after_input_line(EngineProfile::xetex(), utf16be_bom),
8271 vec![0x3B1, 0x3B2, 0x3B3],
8272 "xetex must UTF-16BE decode a BOM'd input line"
8273 );
8274 }
8275
8276 #[test]
8277 fn engine_abort_is_captured_at_runtime_boundary() {
8278 let image = PortableFormatImage::empty();
8279 let mut engine =
8280 PortableTexEngine::from_format(EngineProfile::tex(), &image, EmptyResourceProvider);
8281
8282 let completed = engine.catch_engine_abort(|engine| unsafe {
8283 PortableTexEngine::abort_engine(engine as *mut PortableTexEngine<'_>, 7)?;
8284 Ok(())
8285 });
8286
8287 assert!(!completed);
8288 assert_eq!(engine.last_abort_status(), Some(7));
8289 }
8290
8291 #[test]
8292 fn successful_engine_abort_completes_runtime_boundary() {
8293 let image = PortableFormatImage::empty();
8294 let mut engine =
8295 PortableTexEngine::from_format(EngineProfile::tex(), &image, EmptyResourceProvider);
8296
8297 let completed = engine.catch_engine_abort(|engine| unsafe {
8298 PortableTexEngine::abort_engine(engine as *mut PortableTexEngine<'_>, 0)?;
8299 Ok(())
8300 });
8301
8302 assert!(completed);
8303 assert_eq!(engine.last_abort_status(), None);
8304 }
8305}