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 fn portable_bytes_header_len(bytes: &[u8]) -> Option<usize> {
2549 let mut cursor = 0usize;
2550 if bytes.get(cursor..cursor + PORTABLE_FORMAT_MAGIC.len())? != &PORTABLE_FORMAT_MAGIC[..] {
2551 return None;
2552 }
2553 cursor += PORTABLE_FORMAT_MAGIC.len();
2554 if *bytes.get(cursor)? as usize != core::mem::size_of::<usize>() {
2555 return None;
2556 }
2557 cursor += 1;
2558 let struct_size =
2559 u64::from_le_bytes(bytes.get(cursor..cursor + 8)?.try_into().ok()?) as usize;
2560 cursor += 8;
2561 if struct_size != core::mem::size_of::<Self>() {
2562 return None;
2563 }
2564 bytes.get(cursor..cursor + struct_size)?;
2565 Some(cursor)
2566 }
2567
2568 fn portable_validation_tag() -> [u8; 17] {
2569 let mut tag = [0u8; 17];
2570 tag[..8].copy_from_slice(&PORTABLE_FORMAT_MAGIC);
2571 tag[8] = core::mem::size_of::<usize>() as u8;
2572 tag[9..].copy_from_slice(&(core::mem::size_of::<Self>() as u64).to_le_bytes());
2573 tag
2574 }
2575
2576 pub(crate) fn from_portable_bytes(bytes: &[u8]) -> Option<Box<Self>> {
2585 let mut cursor = Self::portable_bytes_header_len(bytes)?;
2586 let image = bytes.get(cursor..cursor + core::mem::size_of::<Self>())?;
2587 cursor += core::mem::size_of::<Self>();
2588
2589 let mut state = Box::<Self>::new_uninit();
2590 let state_ptr = state.as_mut_ptr();
2591 let state = unsafe {
2596 core::ptr::copy_nonoverlapping(
2597 image.as_ptr(),
2598 state_ptr as *mut u8,
2599 core::mem::size_of::<Self>(),
2600 );
2601 let decoded_mem: Vec<memoryword> = portable_read_vec_ranges(bytes, &mut cursor)?;
2602 core::ptr::addr_of_mut!((*state_ptr).mem).write(decoded_mem);
2603 macro_rules! read_field {
2604 ($name:ident, $ty:ty) => {
2605 let decoded: Vec<$ty> = portable_read_vec_ranges(bytes, &mut cursor)?;
2606 core::ptr::addr_of_mut!((*state_ptr).$name).write(decoded);
2607 };
2608 }
2609 portable_owning_vecs!(read_field);
2610 let eqtb_paged =
2611 portable_read_paged(bytes, &mut cursor, eqtb_codepoint_default, eqtb_sig_range)?;
2612 core::ptr::addr_of_mut!((*state_ptr).eqtb_paged).write(eqtb_paged);
2613 let hash_paged =
2614 portable_read_paged(bytes, &mut cursor, hash_codepoint_default, hash_sig_range)?;
2615 core::ptr::addr_of_mut!((*state_ptr).hash_paged).write(hash_paged);
2616 core::ptr::addr_of_mut!((*state_ptr).src_spans).write(Vec::new());
2622 core::ptr::addr_of_mut!((*state_ptr).src_dedup)
2623 .write(std::collections::HashMap::new());
2624 core::ptr::addr_of_mut!((*state_ptr).node_src)
2625 .write(PagedArray::new(0, 0, node_src_default, node_src_sig));
2626 core::ptr::addr_of_mut!((*state_ptr).src_native_offsets).write(Vec::new());
2627 core::ptr::addr_of_mut!((*state_ptr).src_stack_cells).write(Vec::new());
2628 core::ptr::addr_of_mut!((*state_ptr).cur_stack_head).write(0);
2629 core::ptr::addr_of_mut!((*state_ptr).node_stack)
2630 .write(PagedArray::new(0, 0, node_stack_default, node_stack_sig));
2631 for slot in (*state_ptr).inputfile_storage.iter_mut() {
2635 *slot = core::ptr::null_mut();
2636 }
2637 let mut state = state.assume_init();
2638 state.refresh_runtime_pointers();
2639 state
2640 };
2641 Some(state)
2642 }
2643
2644 pub(crate) fn state_array_bytes(&self) -> usize {
2648 let mut total = self.mem.capacity() * core::mem::size_of::<memoryword>();
2649 macro_rules! accumulate {
2650 ($name:ident, $ty:ty) => {
2651 total += self.$name.capacity() * core::mem::size_of::<$ty>();
2652 };
2653 }
2654 portable_owning_vecs!(accumulate);
2655 total += self.eqtb_paged.resident_bytes() + self.hash_paged.resident_bytes();
2656 total
2657 }
2658
2659 fn allocate_initial_arrays(&mut self) {
2660 self.iniversion = true_0;
2661 self.membot = 0;
2662 self.memmin = self.membot;
2663 self.memtop = 999_999;
2668 self.memmax = self.memtop;
2669 self.hashextra = 600_000;
2670 self.eqtbtop = xetex_eqtb_top + self.hashextra;
2671 self.bufsize = 200_000;
2672 self.nestsize = 1_000;
2673 self.maxinopen = 15;
2674 self.paramsize = 20_000;
2675 self.savesize = 200_000;
2676 self.stacksize = 10_000;
2677 self.dvibufsize = 16_384;
2678 self.poolsize = 6_250_000;
2679 self.maxstrings = 500_000;
2680 self.fontmemsize = 1_000_000;
2681 self.fontmax = 500;
2682 self.triesize = 1_100_000;
2688 self.hyphsize = 8_191;
2689 self.primused = 2_100;
2690 self.errorline = 79;
2691 self.halferrorline = 50;
2692 self.maxprintline = 79;
2693 self.expanddepth = 10_000;
2694
2695 self.mem = zeroed_vec((self.memtop - self.memmin + 1) as usize);
2696 self.buffer_storage = zeroed_vec((self.bufsize + 1) as usize);
2704 self.nest_storage = zeroed_vec((self.nestsize + 1) as usize);
2705 self.savestack_storage = zeroed_vec((self.savesize + 1) as usize);
2706 self.inputstack_storage = zeroed_vec((self.stacksize + 1) as usize);
2707 self.inputfile_storage = zeroed_vec((self.maxinopen + 1) as usize);
2708 self.eofseen_storage = zeroed_vec((self.maxinopen + 1) as usize);
2709 self.linestack_storage = zeroed_vec((self.maxinopen + 1) as usize);
2710 self.grpstack_storage = zeroed_vec((self.maxinopen + 1) as usize);
2711 self.ifstack_storage = zeroed_vec((self.maxinopen + 1) as usize);
2712 self.sourcefilenamestack_storage = zeroed_vec((self.maxinopen + 1) as usize);
2713 self.fullsourcefilenamestack_storage = zeroed_vec((self.maxinopen + 1) as usize);
2714 self.paramstack_storage = zeroed_vec((self.paramsize + 1) as usize);
2715 self.hyphword_storage = zeroed_vec((self.hyphsize + 1) as usize);
2716 self.hyphlist_storage = zeroed_vec((self.hyphsize + 1) as usize);
2717 self.hyphlink_storage = zeroed_vec((self.hyphsize + 1) as usize);
2718 self.eqtb_paged = PagedArray::new(
2722 0,
2723 (self.eqtbtop + 1) as usize,
2724 eqtb_codepoint_default,
2725 eqtb_sig_range,
2726 );
2727 self.hash_paged = PagedArray::new(
2728 hashoffset as usize,
2729 (self.eqtbtop + 1) as usize,
2730 hash_codepoint_default,
2731 hash_sig_range,
2732 );
2733 self.strstart_storage = zeroed_vec((self.maxstrings + 1) as usize);
2734 self.strpool_storage = zeroed_vec((self.poolsize + 1) as usize);
2735 self.fontinfo_storage = zeroed_vec((self.fontmemsize + 1) as usize);
2736 let font_slots = (self.fontmax + 1) as usize;
2737 self.bcharlabel_storage = zeroed_vec(font_slots);
2738 self.charbase_storage = zeroed_vec(font_slots);
2739 self.widthbase_storage = zeroed_vec(font_slots);
2740 self.heightbase_storage = zeroed_vec(font_slots);
2741 self.depthbase_storage = zeroed_vec(font_slots);
2742 self.italicbase_storage = zeroed_vec(font_slots);
2743 self.ligkernbase_storage = zeroed_vec(font_slots);
2744 self.kernbase_storage = zeroed_vec(font_slots);
2745 self.extenbase_storage = zeroed_vec(font_slots);
2746 self.parambase_storage = zeroed_vec(font_slots);
2747 self.fontarea_storage = zeroed_vec(font_slots);
2748 self.fontname_storage = zeroed_vec(font_slots);
2749 self.fontbc_storage = zeroed_vec(font_slots);
2750 self.fontec_storage = zeroed_vec(font_slots);
2751 self.fontbchar_storage = zeroed_vec(font_slots);
2752 self.fontfalsebchar_storage = zeroed_vec(font_slots);
2753 self.fontcheck_storage = zeroed_vec(font_slots);
2754 self.fontdsize_storage = zeroed_vec(font_slots);
2755 self.fontsize_storage = zeroed_vec(font_slots);
2756 self.fontflags_storage = zeroed_vec(font_slots);
2757 self.fontglue_storage = zeroed_vec(font_slots);
2758 self.fontlayoutengine_storage = zeroed_vec(font_slots);
2759 self.fontletterspace_storage = zeroed_vec(font_slots);
2760 self.fontmapping_storage = zeroed_vec(font_slots);
2761 self.fontparams_storage = zeroed_vec(font_slots);
2762 self.fontused_storage = zeroed_vec(font_slots);
2763 self.nativetext_storage = Vec::new();
2764 self.hyphenchar_storage = zeroed_vec(font_slots);
2765 self.skewchar_storage = zeroed_vec(font_slots);
2766 let trie_slots = (self.triesize + 1) as usize;
2767 self.triec_storage = zeroed_vec(trie_slots);
2768 self.triehash_storage = zeroed_vec(trie_slots);
2769 self.triel_storage = zeroed_vec(trie_slots);
2770 self.trieo_storage = zeroed_vec(trie_slots);
2771 self.trier_storage = zeroed_vec(trie_slots);
2772 self.trietaken_storage = zeroed_vec(trie_slots);
2773 self.trietrc_storage = zeroed_vec(trie_slots);
2774 self.trietrl_storage = zeroed_vec(trie_slots);
2775 self.trietro_storage = zeroed_vec(trie_slots);
2776 self.refresh_runtime_pointers();
2777 }
2778}
2779
2780fn zeroed_vec<T>(len: usize) -> Vec<T>
2781where
2782 T: Clone + Default,
2783{
2784 vec![T::default(); len]
2785}
2786
2787fn pointer_or_null<T>(storage: &mut Vec<T>) -> *mut T {
2788 if storage.is_empty() {
2789 core::ptr::null_mut()
2790 } else {
2791 storage.as_mut_ptr()
2792 }
2793}
2794
2795#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2796pub enum EngineProfileKind {
2797 Tex,
2798 Etex,
2799 Xetex,
2800}
2801
2802#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2803pub struct EngineProfile {
2804 pub id: &'static str,
2805 pub kind: EngineProfileKind,
2806 pub etex: bool,
2807 pub xetex: bool,
2808 pub unicode_scalars: bool,
2809 pub unicode_math: bool,
2810 pub native_fonts: bool,
2811}
2812
2813#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2814struct WriteTokenConstants {
2815 open_group_token: halfword,
2816 end_write_token: halfword,
2817 close_group_token: halfword,
2818}
2819
2820impl EngineProfile {
2821 pub const fn tex() -> Self {
2822 Self {
2823 id: "tex",
2824 kind: EngineProfileKind::Tex,
2825 etex: false,
2826 xetex: false,
2827 unicode_scalars: false,
2828 unicode_math: false,
2829 native_fonts: false,
2830 }
2831 }
2832
2833 pub const fn etex() -> Self {
2834 Self {
2835 id: "etex",
2836 kind: EngineProfileKind::Etex,
2837 etex: true,
2838 xetex: false,
2839 unicode_scalars: false,
2840 unicode_math: false,
2841 native_fonts: false,
2842 }
2843 }
2844
2845 pub const fn xetex() -> Self {
2846 Self {
2847 id: "xetex",
2848 kind: EngineProfileKind::Xetex,
2849 etex: true,
2850 xetex: true,
2851 unicode_scalars: true,
2852 unicode_math: true,
2853 native_fonts: false,
2854 }
2855 }
2856
2857 const fn write_token_constants(self) -> WriteTokenConstants {
2858 match self.kind {
2859 EngineProfileKind::Tex | EngineProfileKind::Etex => WriteTokenConstants {
2860 open_group_token: 637,
2861 end_write_token: 19617,
2862 close_group_token: 379,
2863 },
2864 EngineProfileKind::Xetex => WriteTokenConstants {
2865 open_group_token: 4_194_429,
2866 end_write_token: 34_749_089,
2867 close_group_token: 2_097_275,
2868 },
2869 }
2870 }
2871}
2872
2873pub struct PortableFormatImage {
2874 source: PortableFormatSource,
2875}
2876
2877enum PortableFormatSource {
2878 Owned(Box<PortableTexState>),
2879 Static(&'static [u8]),
2880}
2881
2882#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2883pub struct PortableNodeHandle(pub i32);
2884
2885#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2886pub enum PortableNodeKind {
2887 HorizontalBox,
2888 VerticalBox,
2889 Rule,
2890 Insertion,
2891 Mark,
2892 Adjustment,
2893 Ligature,
2894 Discretionary,
2895 OutputWhatsit,
2896 Whatsit,
2897 Math,
2898 Glue,
2899 Kern,
2900 Penalty,
2901 UnsetBox,
2902 Noad,
2903 Style,
2904 Choice,
2905 Character,
2906 NativeWord,
2907 NativeGlyph,
2908 HostBoxRef,
2909 Unknown(i32),
2910}
2911
2912#[derive(Clone, Debug, PartialEq)]
2913pub struct PortableNodeSnapshot {
2914 pub handle: PortableNodeHandle,
2915 pub kind: PortableNodeKind,
2916 pub subtype: i32,
2917 pub source: Option<PortableSourceSpan>,
2918 pub link: Option<PortableNodeHandle>,
2919 pub font: i32,
2920 pub character: i32,
2921 pub width: i32,
2922 pub height: i32,
2923 pub depth: i32,
2924 pub shift: i32,
2925 pub list: Option<PortableNodeHandle>,
2926 pub native_glyphs: Vec<PortableNativeGlyph>,
2927 pub glue_set: f64,
2929 pub glue_sign: i32,
2931 pub glue_order: i32,
2933 pub glue_stretch: i32,
2935 pub glue_shrink: i32,
2937 pub glue_stretch_order: i32,
2939 pub glue_shrink_order: i32,
2941}
2942
2943impl Clone for PortableFormatImage {
2944 fn clone(&self) -> Self {
2945 match &self.source {
2946 PortableFormatSource::Owned(state) => Self {
2947 source: PortableFormatSource::Owned(state.clone_boxed()),
2948 },
2949 PortableFormatSource::Static(bytes) => Self {
2950 source: PortableFormatSource::Static(bytes),
2951 },
2952 }
2953 }
2954}
2955
2956impl PortableFormatImage {
2957 pub fn empty() -> Self {
2958 Self {
2959 source: PortableFormatSource::Owned(PortableTexState::new_boxed_default()),
2960 }
2961 }
2962
2963 fn from_engine_state(state: &PortableTexState) -> Self {
2964 let mut state = state.clone_boxed();
2965 state.seal_as_format_snapshot();
2966 Self {
2967 source: PortableFormatSource::Owned(state),
2968 }
2969 }
2970
2971 fn from_sealed_state(state: Box<PortableTexState>) -> Self {
2974 Self {
2975 source: PortableFormatSource::Owned(state),
2976 }
2977 }
2978
2979 fn instantiate_state(&self) -> Box<PortableTexState> {
2980 match &self.source {
2981 PortableFormatSource::Owned(state) => state.clone_boxed(),
2982 PortableFormatSource::Static(bytes) => PortableTexState::from_portable_bytes(bytes)
2983 .expect("validated static format image became unreadable"),
2984 }
2985 }
2986
2987 #[must_use]
2989 pub fn validation_tag() -> [u8; 17] {
2990 PortableTexState::portable_validation_tag()
2991 }
2992
2993 #[must_use]
2995 pub fn bytes_match_target(bytes: &[u8]) -> bool {
2996 PortableTexState::portable_bytes_header_len(bytes).is_some()
2997 }
2998
2999 #[must_use]
3001 pub fn from_static_bytes(bytes: &'static [u8]) -> Option<Self> {
3002 Self::bytes_match_target(bytes).then_some(())?;
3003 Some(Self {
3004 source: PortableFormatSource::Static(bytes),
3005 })
3006 }
3007
3008 #[must_use]
3012 pub fn to_bytes(&self) -> Vec<u8> {
3013 match &self.source {
3014 PortableFormatSource::Owned(state) => state.to_portable_bytes(),
3015 PortableFormatSource::Static(bytes) => bytes.to_vec(),
3016 }
3017 }
3018
3019 #[must_use]
3022 pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
3023 Some(Self {
3024 source: PortableFormatSource::Owned(PortableTexState::from_portable_bytes(bytes)?),
3025 })
3026 }
3027
3028 #[must_use]
3031 pub fn state_array_bytes(&self) -> usize {
3032 match &self.source {
3033 PortableFormatSource::Owned(state) => state.state_array_bytes(),
3034 PortableFormatSource::Static(bytes) => PortableTexState::from_portable_bytes(bytes)
3035 .expect("validated static format image became unreadable")
3036 .state_array_bytes(),
3037 }
3038 }
3039}
3040
3041#[must_use]
3045pub fn memory_word_bytes() -> usize {
3046 core::mem::size_of::<memoryword>()
3047}
3048
3049pub struct PortableTexEngine<'resources> {
3050 pub(crate) state: Box<PortableTexState>,
3051 pub(crate) profile: EngineProfile,
3052 pub(crate) resources: Box<dyn ResourceProvider + 'resources>,
3053 pub(crate) fonts: Box<dyn FontPlatform + 'resources>,
3054 pub(crate) platform: Box<dyn PortablePlatform + 'resources>,
3055 pub(crate) nameoffile_storage: Vec<UTF8code>,
3056 native_glyph_infos: std::collections::BTreeMap<i32, PortableNativeGlyphInfo>,
3057 hostbox_records: Vec<PortableHostBox>,
3059 character_protrusions: std::collections::BTreeMap<(integer, u32, integer), integer>,
3060 pub(crate) resource_requests: usize,
3061 pub(crate) resource_request_records: Vec<PortableResourceRequestRecord>,
3062 pub(crate) virtual_files: std::collections::BTreeMap<String, Vec<u8>>,
3063 pub(crate) transcript_bytes: Vec<u8>,
3064 pub(crate) current_input_package_owner: Option<String>,
3065 pub(crate) stripped_page_builds: usize,
3066 pub(crate) stripped_shipouts: usize,
3067 pub(crate) stripped_special_outputs: usize,
3068 pub(crate) stripped_picture_loads: usize,
3069 pub(crate) stripped_source_specials: usize,
3070 pub(crate) stripped_write_whatsit_diagnostics: usize,
3071 pub(crate) stripped_pdf_extensions: usize,
3072 pub(crate) stripped_page_top_prunes: usize,
3073 pub(crate) last_stripped_shipout_box: Option<PortableNodeHandle>,
3074 pub(crate) fragment_capture_enabled: bool,
3075 pub(crate) format_initialization: bool,
3076 pub(crate) captured_fragment_root: Option<PortableNodeHandle>,
3077 pub(crate) last_abort_status: Option<integer>,
3078 pub(crate) last_error_message: Option<String>,
3082 pub(crate) sandbox: bool,
3088 pub(crate) sandbox_math_depth: i32,
3095 pub(crate) sandbox_math_opened: bool,
3099 pub(crate) sandbox_ops: u64,
3102}
3103
3104pub(crate) fn zround(value: real) -> integer {
3105 value.round() as integer
3106}
3107
3108impl<'resources> PortableTexEngine<'resources> {
3109 pub fn from_format<R>(
3110 profile: EngineProfile,
3111 format: &PortableFormatImage,
3112 resources: R,
3113 ) -> Self
3114 where
3115 R: ResourceProvider + 'resources,
3116 {
3117 Self {
3118 state: format.instantiate_state(),
3119 profile,
3120 resources: Box::new(resources),
3121 fonts: Box::<EmptyFontPlatform>::default(),
3122 platform: Box::<EmptyPlatform>::default(),
3123 nameoffile_storage: Vec::new(),
3124 native_glyph_infos: std::collections::BTreeMap::new(),
3125 hostbox_records: Vec::new(),
3126 character_protrusions: std::collections::BTreeMap::new(),
3127 resource_requests: 0,
3128 resource_request_records: Vec::new(),
3129 virtual_files: std::collections::BTreeMap::new(),
3130 transcript_bytes: Vec::new(),
3131 current_input_package_owner: None,
3132 stripped_page_builds: 0,
3133 stripped_shipouts: 0,
3134 stripped_special_outputs: 0,
3135 stripped_picture_loads: 0,
3136 stripped_source_specials: 0,
3137 stripped_write_whatsit_diagnostics: 0,
3138 stripped_pdf_extensions: 0,
3139 stripped_page_top_prunes: 0,
3140 last_stripped_shipout_box: None,
3141 fragment_capture_enabled: false,
3142 format_initialization: false,
3143 captured_fragment_root: None,
3144 last_abort_status: None,
3145 last_error_message: None,
3146 sandbox: false,
3147 sandbox_math_depth: 0,
3148 sandbox_math_opened: false,
3149 sandbox_ops: 0,
3150 }
3151 }
3152
3153 pub fn with_font_platform<F>(mut self, fonts: F) -> Self
3154 where
3155 F: FontPlatform + 'resources,
3156 {
3157 self.fonts = Box::new(fonts);
3158 self
3159 }
3160
3161 pub fn with_platform<P>(mut self, platform: P) -> Self
3162 where
3163 P: PortablePlatform + 'resources,
3164 {
3165 self.platform = Box::new(platform);
3166 self
3167 }
3168
3169 pub fn profile(&self) -> EngineProfile {
3170 self.profile
3171 }
3172
3173 pub fn initialize_format_state(self: &mut Self) -> bool {
3174 self.catch_engine_abort(|engine| unsafe {
3175 let this = engine as *mut PortableTexEngine<'_>;
3176 engine.state.allocate_initial_arrays();
3177 engine.initialize();
3178 if engine.supports_etex() {
3179 engine.state.eTeXmode = 1 as eightbits;
3180 }
3181 if engine.getstringsstarted()? == 0 {
3186 Self::abort_engine(this, 1 as integer)?;
3187 }
3188 engine.initprim()?;
3189 engine.init_etex_startup_primitives()?;
3190 engine.init_xetex_startup_primitives()?;
3191 engine.register_host_box_primitive()?;
3192 engine.state.initstrptr = engine.state.strptr;
3193 engine.state.initpoolptr = engine.state.poolptr;
3194 engine.state.magicoffset =
3203 (*engine.state.strstart.offset(784) as integer - 9 * 16) as integer;
3204 engine.state.alignstate = 1000000 as integer;
3205 Ok(())
3206 })
3207 }
3208
3209 pub(crate) fn ensure_nativetext_capacity(
3210 engine: &mut PortableTexEngine<'_>,
3211 required: integer,
3212 ) {
3213 let required = required.max(0) as usize;
3214 if engine.state.nativetext_storage.len() < required {
3215 engine.state.nativetext_storage.resize(required, UTF16code::default());
3216 }
3217 engine.state.nativetext = pointer_or_null(&mut engine.state.nativetext_storage);
3218 }
3219
3220 unsafe fn init_etex_startup_primitives(&mut self) -> EngineFlow<()> {
3221 if !self.supports_etex() || self.is_xetex() {
3222 return Ok(());
3223 }
3224 self.state.nonewcontrolsequence = false_0 as boolean;
3225 (&mut *(self as *mut PortableTexEngine<'_>))
3226 .zprimitive(1360 as i32, 70 as i32 as quarterword, 3 as i32)?;
3227 (&mut *(self as *mut PortableTexEngine<'_>))
3228 .zprimitive(1361 as i32, 70 as i32 as quarterword, 6 as i32)?;
3229 (&mut *(self as *mut PortableTexEngine<'_>))
3230 .zprimitive(765 as i32, 108 as i32 as quarterword, 5 as i32)?;
3231 (&mut *(self as *mut PortableTexEngine<'_>))
3232 .zprimitive(1363 as i32, 72 as i32 as quarterword, 25067 as i32)?;
3233 (&mut *(self as *mut PortableTexEngine<'_>))
3234 .zprimitive(1364 as i32, 73 as i32 as quarterword, 27234 as i32)?;
3235 (&mut *(self as *mut PortableTexEngine<'_>))
3236 .zprimitive(1365 as i32, 73 as i32 as quarterword, 27235 as i32)?;
3237 (&mut *(self as *mut PortableTexEngine<'_>))
3238 .zprimitive(1366 as i32, 73 as i32 as quarterword, 27236 as i32)?;
3239 (&mut *(self as *mut PortableTexEngine<'_>))
3240 .zprimitive(1367 as i32, 73 as i32 as quarterword, 27237 as i32)?;
3241 (&mut *(self as *mut PortableTexEngine<'_>))
3242 .zprimitive(1368 as i32, 73 as i32 as quarterword, 27238 as i32)?;
3243 (&mut *(self as *mut PortableTexEngine<'_>))
3244 .zprimitive(1369 as i32, 73 as i32 as quarterword, 27239 as i32)?;
3245 (&mut *(self as *mut PortableTexEngine<'_>))
3246 .zprimitive(1370 as i32, 73 as i32 as quarterword, 27240 as i32)?;
3247 (&mut *(self as *mut PortableTexEngine<'_>))
3248 .zprimitive(1371 as i32, 73 as i32 as quarterword, 27241 as i32)?;
3249 (&mut *(self as *mut PortableTexEngine<'_>))
3250 .zprimitive(1372 as i32, 73 as i32 as quarterword, 27242 as i32)?;
3251 (&mut *(self as *mut PortableTexEngine<'_>))
3252 .zprimitive(1387 as i32, 70 as i32 as quarterword, 7 as i32)?;
3253 (&mut *(self as *mut PortableTexEngine<'_>))
3254 .zprimitive(1388 as i32, 70 as i32 as quarterword, 8 as i32)?;
3255 (&mut *(self as *mut PortableTexEngine<'_>))
3256 .zprimitive(1389 as i32, 70 as i32 as quarterword, 9 as i32)?;
3257 (&mut *(self as *mut PortableTexEngine<'_>))
3258 .zprimitive(1390 as i32, 70 as i32 as quarterword, 10 as i32)?;
3259 (&mut *(self as *mut PortableTexEngine<'_>))
3260 .zprimitive(1391 as i32, 70 as i32 as quarterword, 11 as i32)?;
3261 (&mut *(self as *mut PortableTexEngine<'_>))
3262 .zprimitive(1392 as i32, 70 as i32 as quarterword, 14 as i32)?;
3263 (&mut *(self as *mut PortableTexEngine<'_>))
3264 .zprimitive(1393 as i32, 70 as i32 as quarterword, 15 as i32)?;
3265 (&mut *(self as *mut PortableTexEngine<'_>))
3266 .zprimitive(1394 as i32, 70 as i32 as quarterword, 16 as i32)?;
3267 (&mut *(self as *mut PortableTexEngine<'_>))
3268 .zprimitive(1395 as i32, 70 as i32 as quarterword, 17 as i32)?;
3269 (&mut *(self as *mut PortableTexEngine<'_>))
3270 .zprimitive(1396 as i32, 70 as i32 as quarterword, 18 as i32)?;
3271 (&mut *(self as *mut PortableTexEngine<'_>))
3272 .zprimitive(1397 as i32, 70 as i32 as quarterword, 19 as i32)?;
3273 (&mut *(self as *mut PortableTexEngine<'_>))
3274 .zprimitive(1398 as i32, 70 as i32 as quarterword, 20 as i32)?;
3275 (&mut *(self as *mut PortableTexEngine<'_>))
3276 .zprimitive(1399 as i32, 19 as i32 as quarterword, 4 as i32)?;
3277 (&mut *(self as *mut PortableTexEngine<'_>))
3278 .zprimitive(1401 as i32, 19 as i32 as quarterword, 5 as i32)?;
3279 (&mut *(self as *mut PortableTexEngine<'_>))
3280 .zprimitive(1402 as i32, 109 as i32 as quarterword, 1 as i32)?;
3281 (&mut *(self as *mut PortableTexEngine<'_>))
3282 .zprimitive(1403 as i32, 109 as i32 as quarterword, 5 as i32)?;
3283 (&mut *(self as *mut PortableTexEngine<'_>))
3284 .zprimitive(1404 as i32, 19 as i32 as quarterword, 6 as i32)?;
3285 (&mut *(self as *mut PortableTexEngine<'_>))
3286 .zprimitive(1408 as i32, 82 as i32 as quarterword, 2 as i32)?;
3287 (&mut *(self as *mut PortableTexEngine<'_>))
3288 .zprimitive(908 as i32, 49 as i32 as quarterword, 1 as i32)?;
3289 (&mut *(self as *mut PortableTexEngine<'_>))
3290 .zprimitive(1412 as i32, 73 as i32 as quarterword, 27243 as i32)?;
3291 (&mut *(self as *mut PortableTexEngine<'_>))
3292 .zprimitive(1413 as i32, 33 as i32 as quarterword, 6 as i32)?;
3293 (&mut *(self as *mut PortableTexEngine<'_>))
3294 .zprimitive(1414 as i32, 33 as i32 as quarterword, 7 as i32)?;
3295 (&mut *(self as *mut PortableTexEngine<'_>))
3296 .zprimitive(1415 as i32, 33 as i32 as quarterword, 10 as i32)?;
3297 (&mut *(self as *mut PortableTexEngine<'_>))
3298 .zprimitive(1416 as i32, 33 as i32 as quarterword, 11 as i32)?;
3299 (&mut *(self as *mut PortableTexEngine<'_>))
3300 .zprimitive(1425 as i32, 104 as i32 as quarterword, 2 as i32)?;
3301 (&mut *(self as *mut PortableTexEngine<'_>))
3302 .zprimitive(1427 as i32, 96 as i32 as quarterword, 1 as i32)?;
3303 (&mut *(self as *mut PortableTexEngine<'_>))
3304 .zprimitive(799 as i32, 102 as i32 as quarterword, 1 as i32)?;
3305 (&mut *(self as *mut PortableTexEngine<'_>))
3306 .zprimitive(1428 as i32, 105 as i32 as quarterword, 17 as i32)?;
3307 (&mut *(self as *mut PortableTexEngine<'_>))
3308 .zprimitive(1429 as i32, 105 as i32 as quarterword, 18 as i32)?;
3309 (&mut *(self as *mut PortableTexEngine<'_>))
3310 .zprimitive(1430 as i32, 105 as i32 as quarterword, 19 as i32)?;
3311 (&mut *(self as *mut PortableTexEngine<'_>))
3312 .zprimitive(1217 as i32, 93 as i32 as quarterword, 8 as i32)?;
3313 (&mut *(self as *mut PortableTexEngine<'_>))
3314 .zprimitive(1436 as i32, 70 as i32 as quarterword, 25 as i32)?;
3315 (&mut *(self as *mut PortableTexEngine<'_>))
3316 .zprimitive(1437 as i32, 70 as i32 as quarterword, 26 as i32)?;
3317 (&mut *(self as *mut PortableTexEngine<'_>))
3318 .zprimitive(1438 as i32, 70 as i32 as quarterword, 27 as i32)?;
3319 (&mut *(self as *mut PortableTexEngine<'_>))
3320 .zprimitive(1439 as i32, 70 as i32 as quarterword, 28 as i32)?;
3321 (&mut *(self as *mut PortableTexEngine<'_>))
3322 .zprimitive(1443 as i32, 70 as i32 as quarterword, 12 as i32)?;
3323 (&mut *(self as *mut PortableTexEngine<'_>))
3324 .zprimitive(1444 as i32, 70 as i32 as quarterword, 13 as i32)?;
3325 (&mut *(self as *mut PortableTexEngine<'_>))
3326 .zprimitive(1445 as i32, 70 as i32 as quarterword, 21 as i32)?;
3327 (&mut *(self as *mut PortableTexEngine<'_>))
3328 .zprimitive(1446 as i32, 70 as i32 as quarterword, 22 as i32)?;
3329 (&mut *(self as *mut PortableTexEngine<'_>))
3330 .zprimitive(1447 as i32, 70 as i32 as quarterword, 23 as i32)?;
3331 (&mut *(self as *mut PortableTexEngine<'_>))
3332 .zprimitive(1448 as i32, 70 as i32 as quarterword, 24 as i32)?;
3333 (&mut *(self as *mut PortableTexEngine<'_>))
3334 .zprimitive(1449 as i32, 18 as i32 as quarterword, 5 as i32)?;
3335 (&mut *(self as *mut PortableTexEngine<'_>))
3336 .zprimitive(1450 as i32, 110 as i32 as quarterword, 5 as i32)?;
3337 (&mut *(self as *mut PortableTexEngine<'_>))
3338 .zprimitive(1451 as i32, 110 as i32 as quarterword, 6 as i32)?;
3339 (&mut *(self as *mut PortableTexEngine<'_>))
3340 .zprimitive(1452 as i32, 110 as i32 as quarterword, 7 as i32)?;
3341 (&mut *(self as *mut PortableTexEngine<'_>))
3342 .zprimitive(1453 as i32, 110 as i32 as quarterword, 8 as i32)?;
3343 (&mut *(self as *mut PortableTexEngine<'_>))
3344 .zprimitive(1454 as i32, 110 as i32 as quarterword, 9 as i32)?;
3345 (&mut *(self as *mut PortableTexEngine<'_>))
3346 .zprimitive(1458 as i32, 24 as i32 as quarterword, 2 as i32)?;
3347 (&mut *(self as *mut PortableTexEngine<'_>))
3348 .zprimitive(1459 as i32, 24 as i32 as quarterword, 3 as i32)?;
3349 (&mut *(self as *mut PortableTexEngine<'_>))
3350 .zprimitive(1460 as i32, 84 as i32 as quarterword, 25324 as i32)?;
3351 (&mut *(self as *mut PortableTexEngine<'_>))
3352 .zprimitive(1461 as i32, 84 as i32 as quarterword, 25325 as i32)?;
3353 (&mut *(self as *mut PortableTexEngine<'_>))
3354 .zprimitive(1462 as i32, 84 as i32 as quarterword, 25326 as i32)?;
3355 (&mut *(self as *mut PortableTexEngine<'_>))
3356 .zprimitive(1463 as i32, 84 as i32 as quarterword, 25327 as i32)?;
3357 self.state.eTeXmode = 1 as eightbits;
3358 Ok(())
3359 }
3360 unsafe fn init_xetex_startup_primitives(&mut self) -> EngineFlow<()> {
3361 if !self.is_xetex() {
3362 return Ok(());
3363 }
3364 self.state.nonewcontrolsequence = false_0 as boolean;
3365 (&mut *(self as *mut PortableTexEngine<'_>))
3366 .zprimitive(66755 as i64 as strnumber, 59 as i32 as quarterword, 41 as i32)?;
3367 (&mut *(self as *mut PortableTexEngine<'_>))
3368 .zprimitive(66756 as i64 as strnumber, 59 as i32 as quarterword, 42 as i32)?;
3369 (&mut *(self as *mut PortableTexEngine<'_>))
3370 .zprimitive(66757 as i64 as strnumber, 59 as i32 as quarterword, 43 as i32)?;
3371 (&mut *(self as *mut PortableTexEngine<'_>))
3372 .zprimitive(66758 as i64 as strnumber, 59 as i32 as quarterword, 46 as i32)?;
3373 (&mut *(self as *mut PortableTexEngine<'_>))
3374 .zprimitive(
3375 66759 as i64 as strnumber,
3376 73 as i32 as quarterword,
3377 1206306 as i64 as halfword,
3378 )?;
3379 (&mut *(self as *mut PortableTexEngine<'_>))
3380 .zprimitive(66760 as i64 as strnumber, 59 as i32 as quarterword, 23 as i32)?;
3381 (&mut *(self as *mut PortableTexEngine<'_>))
3382 .zprimitive(66816 as i64 as strnumber, 71 as i32 as quarterword, 3 as i32)?;
3383 (&mut *(self as *mut PortableTexEngine<'_>))
3384 .zprimitive(66817 as i64 as strnumber, 71 as i32 as quarterword, 19 as i32)?;
3385 (&mut *(self as *mut PortableTexEngine<'_>))
3386 .zprimitive(66115 as i64 as strnumber, 111 as i32 as quarterword, 5 as i32)?;
3387 (&mut *(self as *mut PortableTexEngine<'_>))
3388 .zprimitive(66818 as i64 as strnumber, 71 as i32 as quarterword, 27 as i32)?;
3389 (&mut *(self as *mut PortableTexEngine<'_>))
3390 .zprimitive(
3391 66819 as i64 as strnumber,
3392 111 as i32 as quarterword,
3393 33 as i32,
3394 )?;
3395 (&mut *(self as *mut PortableTexEngine<'_>))
3396 .zprimitive(66820 as i64 as strnumber, 71 as i32 as quarterword, 28 as i32)?;
3397 (&mut *(self as *mut PortableTexEngine<'_>))
3398 .zprimitive(66821 as i64 as strnumber, 71 as i32 as quarterword, 29 as i32)?;
3399 (&mut *(self as *mut PortableTexEngine<'_>))
3400 .zprimitive(66822 as i64 as strnumber, 71 as i32 as quarterword, 30 as i32)?;
3401 (&mut *(self as *mut PortableTexEngine<'_>))
3402 .zprimitive(66823 as i64 as strnumber, 71 as i32 as quarterword, 31 as i32)?;
3403 (&mut *(self as *mut PortableTexEngine<'_>))
3404 .zprimitive(66824 as i64 as strnumber, 71 as i32 as quarterword, 32 as i32)?;
3405 (&mut *(self as *mut PortableTexEngine<'_>))
3406 .zprimitive(66825 as i64 as strnumber, 71 as i32 as quarterword, 33 as i32)?;
3407 (&mut *(self as *mut PortableTexEngine<'_>))
3408 .zprimitive(66826 as i64 as strnumber, 71 as i32 as quarterword, 34 as i32)?;
3409 (&mut *(self as *mut PortableTexEngine<'_>))
3410 .zprimitive(66827 as i64 as strnumber, 71 as i32 as quarterword, 35 as i32)?;
3411 (&mut *(self as *mut PortableTexEngine<'_>))
3412 .zprimitive(66828 as i64 as strnumber, 71 as i32 as quarterword, 36 as i32)?;
3413 (&mut *(self as *mut PortableTexEngine<'_>))
3414 .zprimitive(66829 as i64 as strnumber, 71 as i32 as quarterword, 37 as i32)?;
3415 (&mut *(self as *mut PortableTexEngine<'_>))
3416 .zprimitive(66830 as i64 as strnumber, 71 as i32 as quarterword, 38 as i32)?;
3417 (&mut *(self as *mut PortableTexEngine<'_>))
3418 .zprimitive(66831 as i64 as strnumber, 71 as i32 as quarterword, 39 as i32)?;
3419 (&mut *(self as *mut PortableTexEngine<'_>))
3420 .zprimitive(66832 as i64 as strnumber, 71 as i32 as quarterword, 40 as i32)?;
3421 (&mut *(self as *mut PortableTexEngine<'_>))
3422 .zprimitive(66833 as i64 as strnumber, 71 as i32 as quarterword, 41 as i32)?;
3423 (&mut *(self as *mut PortableTexEngine<'_>))
3424 .zprimitive(66834 as i64 as strnumber, 71 as i32 as quarterword, 42 as i32)?;
3425 (&mut *(self as *mut PortableTexEngine<'_>))
3426 .zprimitive(
3427 66835 as i64 as strnumber,
3428 111 as i32 as quarterword,
3429 34 as i32,
3430 )?;
3431 (&mut *(self as *mut PortableTexEngine<'_>))
3432 .zprimitive(
3433 66836 as i64 as strnumber,
3434 111 as i32 as quarterword,
3435 35 as i32,
3436 )?;
3437 (&mut *(self as *mut PortableTexEngine<'_>))
3438 .zprimitive(
3439 66837 as i64 as strnumber,
3440 111 as i32 as quarterword,
3441 36 as i32,
3442 )?;
3443 (&mut *(self as *mut PortableTexEngine<'_>))
3444 .zprimitive(66838 as i64 as strnumber, 71 as i32 as quarterword, 43 as i32)?;
3445 (&mut *(self as *mut PortableTexEngine<'_>))
3446 .zprimitive(66839 as i64 as strnumber, 71 as i32 as quarterword, 44 as i32)?;
3447 (&mut *(self as *mut PortableTexEngine<'_>))
3448 .zprimitive(66840 as i64 as strnumber, 71 as i32 as quarterword, 45 as i32)?;
3449 (&mut *(self as *mut PortableTexEngine<'_>))
3450 .zprimitive(66841 as i64 as strnumber, 71 as i32 as quarterword, 46 as i32)?;
3451 (&mut *(self as *mut PortableTexEngine<'_>))
3452 .zprimitive(66842 as i64 as strnumber, 71 as i32 as quarterword, 47 as i32)?;
3453 (&mut *(self as *mut PortableTexEngine<'_>))
3454 .zprimitive(66843 as i64 as strnumber, 71 as i32 as quarterword, 48 as i32)?;
3455 (&mut *(self as *mut PortableTexEngine<'_>))
3456 .zprimitive(66844 as i64 as strnumber, 71 as i32 as quarterword, 49 as i32)?;
3457 (&mut *(self as *mut PortableTexEngine<'_>))
3458 .zprimitive(66845 as i64 as strnumber, 71 as i32 as quarterword, 50 as i32)?;
3459 (&mut *(self as *mut PortableTexEngine<'_>))
3460 .zprimitive(66846 as i64 as strnumber, 71 as i32 as quarterword, 55 as i32)?;
3461 (&mut *(self as *mut PortableTexEngine<'_>))
3462 .zprimitive(
3463 66847 as i64 as strnumber,
3464 111 as i32 as quarterword,
3465 37 as i32,
3466 )?;
3467 (&mut *(self as *mut PortableTexEngine<'_>))
3468 .zprimitive(66848 as i64 as strnumber, 71 as i32 as quarterword, 51 as i32)?;
3469 (&mut *(self as *mut PortableTexEngine<'_>))
3470 .zprimitive(66849 as i64 as strnumber, 71 as i32 as quarterword, 52 as i32)?;
3471 (&mut *(self as *mut PortableTexEngine<'_>))
3472 .zprimitive(66850 as i64 as strnumber, 71 as i32 as quarterword, 53 as i32)?;
3473 (&mut *(self as *mut PortableTexEngine<'_>))
3474 .zprimitive(66851 as i64 as strnumber, 71 as i32 as quarterword, 54 as i32)?;
3475 (&mut *(self as *mut PortableTexEngine<'_>))
3476 .zprimitive(
3477 66861 as i64 as strnumber,
3478 73 as i32 as quarterword,
3479 1206305 as i64 as halfword,
3480 )?;
3481 (&mut *(self as *mut PortableTexEngine<'_>))
3482 .zprimitive(
3483 66862 as i64 as strnumber,
3484 74 as i32 as quarterword,
3485 7892325 as i64 as halfword,
3486 )?;
3487 (&mut *(self as *mut PortableTexEngine<'_>))
3488 .zprimitive(
3489 66863 as i64 as strnumber,
3490 74 as i32 as quarterword,
3491 7892326 as i64 as halfword,
3492 )?;
3493 (&mut *(self as *mut PortableTexEngine<'_>))
3494 .zprimitive(
3495 66864 as i64 as strnumber,
3496 74 as i32 as quarterword,
3497 7892327 as i64 as halfword,
3498 )?;
3499 (&mut *(self as *mut PortableTexEngine<'_>))
3500 .zprimitive(
3501 66865 as i64 as strnumber,
3502 74 as i32 as quarterword,
3503 7892328 as i64 as halfword,
3504 )?;
3505 (&mut *(self as *mut PortableTexEngine<'_>))
3506 .zprimitive(
3507 66866 as i64 as strnumber,
3508 74 as i32 as quarterword,
3509 7892329 as i64 as halfword,
3510 )?;
3511 (&mut *(self as *mut PortableTexEngine<'_>))
3512 .zprimitive(
3513 66867 as i64 as strnumber,
3514 74 as i32 as quarterword,
3515 7892330 as i64 as halfword,
3516 )?;
3517 (&mut *(self as *mut PortableTexEngine<'_>))
3518 .zprimitive(
3519 66868 as i64 as strnumber,
3520 74 as i32 as quarterword,
3521 7892331 as i64 as halfword,
3522 )?;
3523 (&mut *(self as *mut PortableTexEngine<'_>))
3524 .zprimitive(
3525 66869 as i64 as strnumber,
3526 74 as i32 as quarterword,
3527 7892332 as i64 as halfword,
3528 )?;
3529 (&mut *(self as *mut PortableTexEngine<'_>))
3530 .zprimitive(
3531 66870 as i64 as strnumber,
3532 74 as i32 as quarterword,
3533 7892333 as i64 as halfword,
3534 )?;
3535 (&mut *(self as *mut PortableTexEngine<'_>))
3536 .zprimitive(
3537 66871 as i64 as strnumber,
3538 74 as i32 as quarterword,
3539 7892335 as i64 as halfword,
3540 )?;
3541 (&mut *(self as *mut PortableTexEngine<'_>))
3542 .zprimitive(66885 as i64 as strnumber, 71 as i32 as quarterword, 20 as i32)?;
3543 (&mut *(self as *mut PortableTexEngine<'_>))
3544 .zprimitive(66886 as i64 as strnumber, 71 as i32 as quarterword, 21 as i32)?;
3545 (&mut *(self as *mut PortableTexEngine<'_>))
3546 .zprimitive(66887 as i64 as strnumber, 71 as i32 as quarterword, 22 as i32)?;
3547 (&mut *(self as *mut PortableTexEngine<'_>))
3548 .zprimitive(66888 as i64 as strnumber, 71 as i32 as quarterword, 23 as i32)?;
3549 (&mut *(self as *mut PortableTexEngine<'_>))
3550 .zprimitive(66889 as i64 as strnumber, 71 as i32 as quarterword, 24 as i32)?;
3551 (&mut *(self as *mut PortableTexEngine<'_>))
3552 .zprimitive(66890 as i64 as strnumber, 71 as i32 as quarterword, 56 as i32)?;
3553 (&mut *(self as *mut PortableTexEngine<'_>))
3554 .zprimitive(66891 as i64 as strnumber, 71 as i32 as quarterword, 57 as i32)?;
3555 (&mut *(self as *mut PortableTexEngine<'_>))
3556 .zprimitive(66892 as i64 as strnumber, 71 as i32 as quarterword, 58 as i32)?;
3557 (&mut *(self as *mut PortableTexEngine<'_>))
3558 .zprimitive(66893 as i64 as strnumber, 71 as i32 as quarterword, 59 as i32)?;
3559 (&mut *(self as *mut PortableTexEngine<'_>))
3560 .zprimitive(66894 as i64 as strnumber, 71 as i32 as quarterword, 60 as i32)?;
3561 (&mut *(self as *mut PortableTexEngine<'_>))
3562 .zprimitive(66895 as i64 as strnumber, 71 as i32 as quarterword, 61 as i32)?;
3563 (&mut *(self as *mut PortableTexEngine<'_>))
3564 .zprimitive(66896 as i64 as strnumber, 71 as i32 as quarterword, 62 as i32)?;
3565 (&mut *(self as *mut PortableTexEngine<'_>))
3566 .zprimitive(66897 as i64 as strnumber, 19 as i32 as quarterword, 4 as i32)?;
3567 (&mut *(self as *mut PortableTexEngine<'_>))
3568 .zprimitive(66899 as i64 as strnumber, 19 as i32 as quarterword, 5 as i32)?;
3569 (&mut *(self as *mut PortableTexEngine<'_>))
3570 .zprimitive(66900 as i64 as strnumber, 112 as i32 as quarterword, 1 as i32)?;
3571 (&mut *(self as *mut PortableTexEngine<'_>))
3572 .zprimitive(66901 as i64 as strnumber, 112 as i32 as quarterword, 5 as i32)?;
3573 (&mut *(self as *mut PortableTexEngine<'_>))
3574 .zprimitive(66902 as i64 as strnumber, 19 as i32 as quarterword, 6 as i32)?;
3575 (&mut *(self as *mut PortableTexEngine<'_>))
3576 .zprimitive(66906 as i64 as strnumber, 83 as i32 as quarterword, 2 as i32)?;
3577 (&mut *(self as *mut PortableTexEngine<'_>))
3578 .zprimitive(66288 as i64 as strnumber, 49 as i32 as quarterword, 1 as i32)?;
3579 (&mut *(self as *mut PortableTexEngine<'_>))
3580 .zprimitive(
3581 66910 as i64 as strnumber,
3582 74 as i32 as quarterword,
3583 7892334 as i64 as halfword,
3584 )?;
3585 (&mut *(self as *mut PortableTexEngine<'_>))
3586 .zprimitive(
3587 66911 as i64 as strnumber,
3588 74 as i32 as quarterword,
3589 7892339 as i64 as halfword,
3590 )?;
3591 (&mut *(self as *mut PortableTexEngine<'_>))
3592 .zprimitive(
3593 66912 as i64 as strnumber,
3594 74 as i32 as quarterword,
3595 7892341 as i64 as halfword,
3596 )?;
3597 (&mut *(self as *mut PortableTexEngine<'_>))
3598 .zprimitive(
3599 66913 as i64 as strnumber,
3600 74 as i32 as quarterword,
3601 7892342 as i64 as halfword,
3602 )?;
3603 (&mut *(self as *mut PortableTexEngine<'_>))
3604 .zprimitive(
3605 66914 as i64 as strnumber,
3606 74 as i32 as quarterword,
3607 7892343 as i64 as halfword,
3608 )?;
3609 (&mut *(self as *mut PortableTexEngine<'_>))
3610 .zprimitive(
3611 66915 as i64 as strnumber,
3612 74 as i32 as quarterword,
3613 7892340 as i64 as halfword,
3614 )?;
3615 (&mut *(self as *mut PortableTexEngine<'_>))
3616 .zprimitive(
3617 66916 as i64 as strnumber,
3618 74 as i32 as quarterword,
3619 7892344 as i64 as halfword,
3620 )?;
3621 (&mut *(self as *mut PortableTexEngine<'_>))
3622 .zprimitive(
3623 66917 as i64 as strnumber,
3624 74 as i32 as quarterword,
3625 7892347 as i64 as halfword,
3626 )?;
3627 (&mut *(self as *mut PortableTexEngine<'_>))
3628 .zprimitive(
3629 66918 as i64 as strnumber,
3630 74 as i32 as quarterword,
3631 7892348 as i64 as halfword,
3632 )?;
3633 (&mut *(self as *mut PortableTexEngine<'_>))
3634 .zprimitive(
3635 66919 as i64 as strnumber,
3636 74 as i32 as quarterword,
3637 7892349 as i64 as halfword,
3638 )?;
3639 (&mut *(self as *mut PortableTexEngine<'_>))
3640 .zprimitive(
3641 66920 as i64 as strnumber,
3642 74 as i32 as quarterword,
3643 7892350 as i64 as halfword,
3644 )?;
3645 (&mut *(self as *mut PortableTexEngine<'_>))
3646 .zprimitive(66761 as i64 as strnumber, 59 as i32 as quarterword, 44 as i32)?;
3647 (&mut *(self as *mut PortableTexEngine<'_>))
3648 .zprimitive(66762 as i64 as strnumber, 59 as i32 as quarterword, 45 as i32)?;
3649 (&mut *(self as *mut PortableTexEngine<'_>))
3650 .zprimitive(66921 as i64 as strnumber, 33 as i32 as quarterword, 6 as i32)?;
3651 (&mut *(self as *mut PortableTexEngine<'_>))
3652 .zprimitive(66922 as i64 as strnumber, 33 as i32 as quarterword, 7 as i32)?;
3653 (&mut *(self as *mut PortableTexEngine<'_>))
3654 .zprimitive(66923 as i64 as strnumber, 33 as i32 as quarterword, 10 as i32)?;
3655 (&mut *(self as *mut PortableTexEngine<'_>))
3656 .zprimitive(66924 as i64 as strnumber, 33 as i32 as quarterword, 11 as i32)?;
3657 (&mut *(self as *mut PortableTexEngine<'_>))
3658 .zprimitive(66933 as i64 as strnumber, 107 as i32 as quarterword, 2 as i32)?;
3659 (&mut *(self as *mut PortableTexEngine<'_>))
3660 .zprimitive(66935 as i64 as strnumber, 98 as i32 as quarterword, 1 as i32)?;
3661 (&mut *(self as *mut PortableTexEngine<'_>))
3662 .zprimitive(66164 as i64 as strnumber, 105 as i32 as quarterword, 1 as i32)?;
3663 (&mut *(self as *mut PortableTexEngine<'_>))
3664 .zprimitive(
3665 66936 as i64 as strnumber,
3666 108 as i32 as quarterword,
3667 17 as i32,
3668 )?;
3669 (&mut *(self as *mut PortableTexEngine<'_>))
3670 .zprimitive(
3671 66937 as i64 as strnumber,
3672 108 as i32 as quarterword,
3673 18 as i32,
3674 )?;
3675 (&mut *(self as *mut PortableTexEngine<'_>))
3676 .zprimitive(
3677 66938 as i64 as strnumber,
3678 108 as i32 as quarterword,
3679 19 as i32,
3680 )?;
3681 (&mut *(self as *mut PortableTexEngine<'_>))
3682 .zprimitive(
3683 66939 as i64 as strnumber,
3684 108 as i32 as quarterword,
3685 20 as i32,
3686 )?;
3687 (&mut *(self as *mut PortableTexEngine<'_>))
3688 .zprimitive(66623 as i64 as strnumber, 95 as i32 as quarterword, 8 as i32)?;
3689 (&mut *(self as *mut PortableTexEngine<'_>))
3690 .zprimitive(66945 as i64 as strnumber, 71 as i32 as quarterword, 67 as i32)?;
3691 (&mut *(self as *mut PortableTexEngine<'_>))
3692 .zprimitive(66946 as i64 as strnumber, 71 as i32 as quarterword, 68 as i32)?;
3693 (&mut *(self as *mut PortableTexEngine<'_>))
3694 .zprimitive(66947 as i64 as strnumber, 71 as i32 as quarterword, 69 as i32)?;
3695 (&mut *(self as *mut PortableTexEngine<'_>))
3696 .zprimitive(66948 as i64 as strnumber, 71 as i32 as quarterword, 70 as i32)?;
3697 (&mut *(self as *mut PortableTexEngine<'_>))
3698 .zprimitive(66952 as i64 as strnumber, 71 as i32 as quarterword, 25 as i32)?;
3699 (&mut *(self as *mut PortableTexEngine<'_>))
3700 .zprimitive(66953 as i64 as strnumber, 71 as i32 as quarterword, 26 as i32)?;
3701 (&mut *(self as *mut PortableTexEngine<'_>))
3702 .zprimitive(66954 as i64 as strnumber, 71 as i32 as quarterword, 63 as i32)?;
3703 (&mut *(self as *mut PortableTexEngine<'_>))
3704 .zprimitive(66955 as i64 as strnumber, 71 as i32 as quarterword, 64 as i32)?;
3705 (&mut *(self as *mut PortableTexEngine<'_>))
3706 .zprimitive(66956 as i64 as strnumber, 71 as i32 as quarterword, 65 as i32)?;
3707 (&mut *(self as *mut PortableTexEngine<'_>))
3708 .zprimitive(66957 as i64 as strnumber, 71 as i32 as quarterword, 66 as i32)?;
3709 (&mut *(self as *mut PortableTexEngine<'_>))
3710 .zprimitive(66958 as i64 as strnumber, 18 as i32 as quarterword, 5 as i32)?;
3711 (&mut *(self as *mut PortableTexEngine<'_>))
3712 .zprimitive(66959 as i64 as strnumber, 113 as i32 as quarterword, 5 as i32)?;
3713 (&mut *(self as *mut PortableTexEngine<'_>))
3714 .zprimitive(66960 as i64 as strnumber, 113 as i32 as quarterword, 6 as i32)?;
3715 (&mut *(self as *mut PortableTexEngine<'_>))
3716 .zprimitive(66961 as i64 as strnumber, 113 as i32 as quarterword, 7 as i32)?;
3717 (&mut *(self as *mut PortableTexEngine<'_>))
3718 .zprimitive(66962 as i64 as strnumber, 113 as i32 as quarterword, 8 as i32)?;
3719 (&mut *(self as *mut PortableTexEngine<'_>))
3720 .zprimitive(66963 as i64 as strnumber, 113 as i32 as quarterword, 9 as i32)?;
3721 (&mut *(self as *mut PortableTexEngine<'_>))
3722 .zprimitive(66968 as i64 as strnumber, 24 as i32 as quarterword, 2 as i32)?;
3723 (&mut *(self as *mut PortableTexEngine<'_>))
3724 .zprimitive(66969 as i64 as strnumber, 24 as i32 as quarterword, 3 as i32)?;
3725 (&mut *(self as *mut PortableTexEngine<'_>))
3726 .zprimitive(
3727 66970 as i64 as strnumber,
3728 85 as i32 as quarterword,
3729 1206563 as i64 as halfword,
3730 )?;
3731 (&mut *(self as *mut PortableTexEngine<'_>))
3732 .zprimitive(
3733 66971 as i64 as strnumber,
3734 85 as i32 as quarterword,
3735 1206564 as i64 as halfword,
3736 )?;
3737 (&mut *(self as *mut PortableTexEngine<'_>))
3738 .zprimitive(
3739 66972 as i64 as strnumber,
3740 85 as i32 as quarterword,
3741 1206565 as i64 as halfword,
3742 )?;
3743 (&mut *(self as *mut PortableTexEngine<'_>))
3744 .zprimitive(
3745 66973 as i64 as strnumber,
3746 85 as i32 as quarterword,
3747 1206566 as i64 as halfword,
3748 )?;
3749 if *self.state.buffer.offset(self.state.curinput.locfield as isize) == 42 as i32
3750 {
3751 self.state.curinput.locfield += 1;
3752 }
3753 self.state.eTeXmode = 1 as eightbits;
3754 self.state.maxregnum = 32767 as i32 as halfword;
3755 self.state.maxreghelpline = 66965 as i64 as strnumber;
3756 Ok(())
3757 }
3758
3759 pub fn begin_primary_input(self: &mut Self, name: &str, bytes: Vec<u8>) -> bool {
3760 self.last_abort_status = None;
3765 self.last_error_message = None;
3766 match unsafe { self.begin_primary_input_raw(name, bytes) } {
3767 Ok(started) => started != 0,
3768 Err(EngineBreak::Abort(EngineAbort { status })) => {
3769 self.last_abort_status = Some(status);
3770 false
3771 }
3772 Err(EngineBreak::Error(error)) => {
3773 self.last_error_message = Some(error.message);
3774 false
3775 }
3776 }
3777 }
3778
3779 pub fn run_main_control(self: &mut Self) -> bool {
3780 self.catch_engine_abort(|engine| unsafe { engine.maincontrol() })
3781 }
3782
3783 pub fn run_format_initialization(self: &mut Self) -> bool {
3784 self.format_initialization = true;
3785 let completed = self.catch_engine_abort(|engine| unsafe { engine.maincontrol() });
3786 self.format_initialization = false;
3787 completed
3788 }
3789
3790 pub fn begin_fragment_capture(self: &mut Self) {
3791 self.fragment_capture_enabled = true;
3792 self.captured_fragment_root = None;
3793 self.hostbox_records.clear();
3795 }
3796
3797 pub fn end_fragment_capture(self: &mut Self) {
3798 self.fragment_capture_enabled = false;
3799 }
3800
3801 fn catch_engine_abort<F>(self: &mut Self, run: F) -> bool
3802 where
3803 F: FnOnce(&mut Self) -> EngineFlow<()>,
3804 {
3805 self.last_abort_status = None;
3811 self.last_error_message = None;
3812 match run(self) {
3813 Ok(()) => self.last_abort_status.is_none(),
3814 Err(EngineBreak::Abort(EngineAbort { status: 0 })) => {
3815 self.last_abort_status = None;
3816 true
3817 }
3818 Err(EngineBreak::Abort(EngineAbort { status })) => {
3819 self.last_abort_status = Some(status);
3820 false
3821 }
3822 Err(EngineBreak::Error(error)) => {
3825 self.last_error_message = Some(error.message);
3826 false
3827 }
3828 }
3829 }
3830
3831 pub fn snapshot_format(&self) -> PortableFormatImage {
3832 PortableFormatImage::from_engine_state(self.state.as_ref())
3833 }
3834
3835 #[must_use]
3844 pub fn into_format(self) -> PortableFormatImage {
3845 let mut state = self.state;
3851 state.seal_as_format_snapshot();
3852 PortableFormatImage::from_sealed_state(state)
3853 }
3854
3855 pub fn finalize_trie(self: &mut Self) {
3863 if self.state.trienotready != 0 && !self.state.triehash.is_null() {
3865 let saved = self.format_initialization;
3866 self.format_initialization = false;
3867 let _ = unsafe { self.inittrie() };
3868 self.format_initialization = saved;
3869 }
3870 }
3871
3872 pub fn resource_request_count(&self) -> usize {
3873 self.resource_requests
3874 }
3875
3876 pub fn resource_request_records(&self) -> &[PortableResourceRequestRecord] {
3877 self.resource_request_records.as_slice()
3878 }
3879
3880 pub fn transcript_bytes(&self) -> &[u8] {
3881 self.transcript_bytes.as_slice()
3882 }
3883
3884 pub fn primary_input_source_span(&self) -> Option<PortableSourceSpan> {
3887 if !self.state.source_tracking {
3888 return None;
3889 }
3890 let primary = self.state.src_primary_name;
3891 let raw = self
3892 .state
3893 .src_spans
3894 .iter()
3895 .find(|raw| raw.name == primary)?;
3896 let name = unsafe { self.pool_string(raw.name) }?;
3897 Some(PortableSourceSpan {
3898 name,
3899 start: raw.start,
3900 end: raw.end,
3901 role: raw.role,
3902 })
3903 }
3904
3905 pub fn node_source_spans(&self) -> &[PortableNodeSourceSpan] {
3910 &[]
3911 }
3912
3913 pub fn stripped_page_build_count(&self) -> usize {
3914 self.stripped_page_builds
3915 }
3916
3917 pub fn stripped_shipout_count(&self) -> usize {
3918 self.stripped_shipouts
3919 }
3920
3921 pub fn stripped_special_output_count(&self) -> usize {
3922 self.stripped_special_outputs
3923 }
3924
3925 pub fn stripped_picture_load_count(&self) -> usize {
3926 self.stripped_picture_loads
3927 }
3928
3929 pub fn stripped_source_special_count(&self) -> usize {
3930 self.stripped_source_specials
3931 }
3932
3933 pub fn stripped_write_whatsit_diagnostic_count(&self) -> usize {
3934 self.stripped_write_whatsit_diagnostics
3935 }
3936
3937 pub fn stripped_pdf_extension_count(&self) -> usize {
3938 self.stripped_pdf_extensions
3939 }
3940
3941 pub fn stripped_page_top_prune_count(&self) -> usize {
3942 self.stripped_page_top_prunes
3943 }
3944
3945 pub fn last_stripped_shipout_box(&self) -> Option<PortableNodeHandle> {
3946 self.last_stripped_shipout_box
3947 }
3948
3949 pub fn captured_fragment_root(&self) -> Option<PortableNodeHandle> {
3950 self.captured_fragment_root
3951 }
3952
3953 pub fn host_box_record(&self, index: usize) -> Option<&PortableHostBox> {
3955 self.hostbox_records.get(index)
3956 }
3957
3958 pub fn font_at_size(&self, font: integer) -> integer {
3961 if font < 0 {
3962 return 0;
3963 }
3964 self.state
3965 .fontsize_storage
3966 .get(font as usize)
3967 .copied()
3968 .unwrap_or(0)
3969 }
3970
3971 pub fn font_name(&self, font: integer) -> Option<String> {
3977 if font < 0 {
3978 return None;
3979 }
3980 let name = self.state.fontname_storage.get(font as usize).copied()?;
3981 unsafe { self.pool_string(name) }
3984 }
3985
3986 pub fn native_font_spec(&self, font: integer) -> Option<String> {
3990 let handle = Self::font_handle_for_number(self, font)?;
3991 self.fonts.font_spec(handle)
3992 }
3993
3994 pub fn native_font_table(&self) -> Vec<(PortableFontHandle, String, i32)> {
3997 self.fonts.font_table()
3998 }
3999
4000 pub fn restore_native_font_table(
4005 self: &mut Self,
4006 table: &[(PortableFontHandle, String, i32)],
4007 ) -> bool {
4008 self.fonts.restore_font_table(table)
4009 }
4010
4011 pub fn last_abort_status(&self) -> Option<integer> {
4012 self.last_abort_status
4013 }
4014
4015 pub fn last_error_message(&self) -> Option<&str> {
4019 self.last_error_message.as_deref()
4020 }
4021
4022 pub fn set_sandbox(self: &mut Self, on: bool) {
4027 self.sandbox = on;
4028 self.sandbox_math_depth = 0;
4029 self.sandbox_math_opened = false;
4030 self.sandbox_ops = 0;
4031 }
4032
4033 pub(crate) fn capture_last_error_message(&self) -> String {
4040 let transcript = core::str::from_utf8(&self.transcript_bytes).unwrap_or("");
4041 for raw in transcript.lines().rev() {
4042 let collapsed = collapse_doubled_line(raw.trim());
4043 let line = collapsed.as_deref().unwrap_or(raw).trim();
4044 if let Some(rest) = line.strip_prefix("! ") {
4045 return rest.trim_end_matches('.').trim().into();
4046 }
4047 }
4048 "TeX error".into()
4049 }
4050
4051 pub fn snapshot_node(&self, handle: PortableNodeHandle) -> Option<PortableNodeSnapshot> {
4052 let node = handle.0 as halfword;
4053 let word = self.node_word(node, 0)?;
4054 let raw_kind = unsafe { word.hh.u.B0 as i32 };
4055 let subtype = unsafe { word.hh.u.B1 as i32 };
4056 let kind = self.node_kind(raw_kind, node, subtype);
4057 let link = self.node_link(node);
4058 let is_character = node >= self.state.himemmin;
4059 let native_word4 = if matches!(kind, PortableNodeKind::NativeWord | PortableNodeKind::NativeGlyph) {
4060 self.node_word(node, 4)
4061 } else {
4062 None
4063 };
4064 let font = if is_character {
4065 raw_kind
4066 } else {
4067 native_word4.map_or(0, |word| unsafe { word.v.QQQQ.u.B1 as i32 })
4068 };
4069 let character = if is_character {
4070 subtype
4071 } else if matches!(kind, PortableNodeKind::HostBoxRef) {
4072 self.node_word(node, 4).map_or(0, |word| unsafe { word.u.CINT })
4074 } else {
4075 native_word4.map_or(0, |word| unsafe { word.v.QQQQ.u.B2 as i32 })
4076 };
4077 let (width, height, depth, shift, list) = match raw_kind {
4078 _ if is_character => (
4079 self.character_width(font, character).unwrap_or_default(),
4080 0,
4081 0,
4082 0,
4083 None,
4084 ),
4085 0 | 1 | 13 => (
4086 self.node_scaled(node, 1).unwrap_or_default(),
4087 self.node_scaled(node, 3).unwrap_or_default(),
4088 self.node_scaled(node, 2).unwrap_or_default(),
4089 self.node_scaled(node, 4).unwrap_or_default(),
4090 self.node_field_link(node, 5),
4091 ),
4092 2 => (
4093 self.node_scaled(node, 1).unwrap_or_default(),
4094 self.node_scaled(node, 3).unwrap_or_default(),
4095 self.node_scaled(node, 2).unwrap_or_default(),
4096 0,
4097 None,
4098 ),
4099 10 => (
4100 self.glue_amount(node).unwrap_or_default(),
4101 0,
4102 0,
4103 0,
4104 None,
4105 ),
4106 11 => (
4107 self.node_scaled(node, 1).unwrap_or_default(),
4108 0,
4109 0,
4110 0,
4111 None,
4112 ),
4113 8 if matches!(
4114 kind,
4115 PortableNodeKind::NativeWord
4116 | PortableNodeKind::NativeGlyph
4117 | PortableNodeKind::HostBoxRef
4118 ) => (
4119 self.node_scaled(node, 1).unwrap_or_default(),
4120 self.node_scaled(node, 3).unwrap_or_default(),
4121 self.node_scaled(node, 2).unwrap_or_default(),
4122 0,
4123 None,
4124 ),
4125 _ => (0, 0, 0, 0, None),
4126 };
4127 let native_glyphs = if matches!(kind, PortableNodeKind::NativeWord | PortableNodeKind::NativeGlyph) {
4128 self.native_glyph_infos
4129 .get(&node)
4130 .map(|info| info.glyphs.clone())
4131 .unwrap_or_default()
4132 } else {
4133 Vec::new()
4134 };
4135
4136 let (glue_set, glue_sign, glue_order) = match raw_kind {
4141 0 | 1 | 13 => (
4142 self.node_word(node, 6).map_or(0.0, |word| unsafe { word.gr }),
4143 self.node_word(node, 5)
4144 .map_or(0, |word| unsafe { word.hh.u.B0 as i32 }),
4145 self.node_word(node, 5)
4146 .map_or(0, |word| unsafe { word.hh.u.B1 as i32 }),
4147 ),
4148 _ => (0.0, 0, 0),
4149 };
4150 let (glue_stretch, glue_shrink, glue_stretch_order, glue_shrink_order) = if raw_kind == 10 {
4152 match self.node_word(node, 1).map(|word| unsafe { word.hh.v.LH }) {
4153 Some(spec) => (
4154 self.node_scaled(spec, 2).unwrap_or_default(),
4155 self.node_scaled(spec, 3).unwrap_or_default(),
4156 self.node_word(spec, 0)
4157 .map_or(0, |word| unsafe { word.hh.u.B0 as i32 }),
4158 self.node_word(spec, 0)
4159 .map_or(0, |word| unsafe { word.hh.u.B1 as i32 }),
4160 ),
4161 None => (0, 0, 0, 0),
4162 }
4163 } else {
4164 (0, 0, 0, 0)
4165 };
4166
4167 Some(PortableNodeSnapshot {
4168 handle,
4169 kind,
4170 subtype,
4171 source: self.resolve_node_src(node),
4172 link,
4173 font,
4174 character,
4175 width,
4176 height,
4177 depth,
4178 shift,
4179 list,
4180 native_glyphs,
4181 glue_set,
4182 glue_sign,
4183 glue_order,
4184 glue_stretch,
4185 glue_shrink,
4186 glue_stretch_order,
4187 glue_shrink_order,
4188 })
4189 }
4190
4191 fn node_kind(&self, raw_kind: i32, node: halfword, subtype: i32) -> PortableNodeKind {
4192 if node >= self.state.himemmin {
4193 return PortableNodeKind::Character;
4194 }
4195
4196 match raw_kind {
4197 0 => PortableNodeKind::HorizontalBox,
4198 1 => PortableNodeKind::VerticalBox,
4199 2 => PortableNodeKind::Rule,
4200 3 => PortableNodeKind::Insertion,
4201 4 => PortableNodeKind::Mark,
4202 5 => PortableNodeKind::Adjustment,
4203 6 => PortableNodeKind::Ligature,
4204 7 => PortableNodeKind::Discretionary,
4205 8 if matches!(subtype, 40 | 41) => PortableNodeKind::NativeWord,
4206 8 if subtype == 42 => PortableNodeKind::NativeGlyph,
4207 8 if subtype == HOST_BOX_RESOLVED_SUBTYPE as i32 => PortableNodeKind::HostBoxRef,
4208 8 if matches!(subtype, 0 | 1 | 2 | 3) => PortableNodeKind::OutputWhatsit,
4209 8 => PortableNodeKind::Whatsit,
4210 9 => PortableNodeKind::Math,
4211 10 => PortableNodeKind::Glue,
4212 11 => PortableNodeKind::Kern,
4213 12 => PortableNodeKind::Penalty,
4214 13 => PortableNodeKind::UnsetBox,
4215 16 => PortableNodeKind::Noad,
4216 14 => PortableNodeKind::Style,
4217 15 => PortableNodeKind::Choice,
4218 other => PortableNodeKind::Unknown(other),
4219 }
4220 }
4221
4222 pub(crate) fn copy_native_glyph_info(
4223 this: &mut Self,
4224 src: halfword,
4225 dest: halfword,
4226 ) -> quarterword {
4227 if let Some(info) = this.native_glyph_infos.get(&src).cloned() {
4228 let glyph_count = info.glyphs.len().min(i32::MAX as usize) as quarterword;
4229 this.native_glyph_infos.insert(dest, info);
4230 glyph_count
4231 } else {
4232 this.native_glyph_infos.remove(&dest);
4233 0
4234 }
4235 }
4236
4237 fn font_handle_for_number(this: &Self, font: integer) -> Option<FontHandle> {
4238 if font < 0 || this.state.fontlayoutengine.is_null() {
4239 return None;
4240 }
4241 let handle = unsafe { *this.state.fontlayoutengine.offset(font as isize) as FontHandle };
4242 (handle != 0).then_some(handle)
4243 }
4244
4245 unsafe fn node_index_for_pointer(
4246 engine: &PortableTexEngine<'_>,
4247 node: voidpointer,
4248 ) -> Option<halfword> {
4249 if node.is_null() || engine.state.zmem.is_null() {
4250 return None;
4251 }
4252 let base = engine.state.zmem as isize;
4253 let address = node as isize;
4254 let word_size = core::mem::size_of::<memoryword>() as isize;
4255 if word_size == 0 || address < base {
4256 return None;
4257 }
4258 let bytes = address - base;
4259 if bytes % word_size != 0 {
4260 return None;
4261 }
4262 let index = (bytes / word_size) as halfword;
4263 if index < engine.state.memmin || index > engine.state.memmax {
4264 None
4265 } else {
4266 Some(index)
4267 }
4268 }
4269
4270 unsafe fn native_node_font(mem: *mut memoryword, node: halfword) -> integer {
4271 (*mem.offset((node + 4) as isize)).v.QQQQ.u.B1 as integer
4272 }
4273
4274 unsafe fn native_node_text<'a>(mem: *mut memoryword, node: halfword) -> &'a [u16] {
4275 let len = (*mem.offset((node + 4) as isize)).v.QQQQ.u.B2.max(0) as usize;
4276 if len == 0 {
4277 return &[];
4278 }
4279 core::slice::from_raw_parts(
4280 mem.offset((node + native_node_size) as isize) as *const memoryword as *const u16,
4281 len,
4282 )
4283 }
4284
4285 unsafe fn write_native_node_metrics(
4286 mem: *mut memoryword,
4287 node: halfword,
4288 width: i32,
4289 height: i32,
4290 depth: i32,
4291 ) {
4292 (*mem.offset((node + 1) as isize)).u.CINT = width;
4293 (*mem.offset((node + 2) as isize)).u.CINT = depth;
4294 (*mem.offset((node + 3) as isize)).u.CINT = height;
4295 }
4296
4297 fn node_word(&self, node: halfword, offset: halfword) -> Option<memoryword> {
4298 let index = node.checked_add(offset)?;
4299 if node as i64 == -(268435455 as i64) {
4300 return None;
4301 }
4302 if self.state.zmem.is_null() || index < self.state.memmin || index > self.state.memmax {
4303 return None;
4304 }
4305 unsafe { Some(*self.state.zmem.offset(index as isize)) }
4306 }
4307
4308 fn node_link(&self, node: halfword) -> Option<PortableNodeHandle> {
4309 let word = self.node_word(node, 0)?;
4310 let link = unsafe { word.hh.v.RH };
4311 Self::node_handle_from_raw(link)
4312 }
4313
4314 fn node_field_link(&self, node: halfword, offset: halfword) -> Option<PortableNodeHandle> {
4315 let word = self.node_word(node, offset)?;
4316 let link = unsafe { word.hh.v.RH };
4317 Self::node_handle_from_raw(link)
4318 }
4319
4320 fn node_scaled(&self, node: halfword, offset: halfword) -> Option<i32> {
4321 let word = self.node_word(node, offset)?;
4322 Some(unsafe { word.u.CINT })
4323 }
4324
4325 fn glue_amount(&self, node: halfword) -> Option<i32> {
4326 let word = self.node_word(node, 1)?;
4327 let glue_spec = unsafe { word.hh.v.LH };
4328 self.node_scaled(glue_spec, 1)
4329 }
4330
4331 fn character_width(&self, font: i32, character: i32) -> Option<i32> {
4332 if font < 0
4333 || character < 0
4334 || self.state.fontinfo.is_null()
4335 || self.state.charbase.is_null()
4336 || self.state.widthbase.is_null()
4337 {
4338 return None;
4339 }
4340 let char_info_index = unsafe {
4341 *self.state.charbase.offset(font as isize) + character
4342 };
4343 let char_info = unsafe {
4344 (*self.state.fontinfo.offset(char_info_index as isize)).v.QQQQ
4345 };
4346 let width_index = unsafe {
4347 *self.state.widthbase.offset(font as isize) as i32 + char_info.u.B0 as i32
4348 };
4349 Some(unsafe { (*self.state.fontinfo.offset(width_index as isize)).u.CINT })
4350 }
4351
4352 fn node_handle_from_raw(raw: halfword) -> Option<PortableNodeHandle> {
4353 if raw as i64 == -(268435455 as i64) {
4354 None
4355 } else {
4356 Some(PortableNodeHandle(raw))
4357 }
4358 }
4359
4360
4361 pub(crate) fn is_xetex(&self) -> bool {
4362 self.profile.xetex
4363 }
4364
4365 pub(crate) fn supports_etex(&self) -> bool {
4366 self.profile.etex
4367 }
4368
4369 pub(crate) fn supports_unicode_scalars(&self) -> bool {
4370 self.profile.unicode_scalars
4371 }
4372
4373 pub(crate) fn supports_unicode_math(&self) -> bool {
4374 self.profile.unicode_math
4375 }
4376
4377 pub(crate) fn supports_native_fonts(&self) -> bool {
4378 self.profile.native_fonts
4379 }
4380
4381 pub(crate) unsafe fn getinputnormalizationstate(&self) -> integer {
4382 if !self.is_xetex() {
4383 return 0;
4384 }
4385 let eqtb = self.state.zeqtb.as_mut_ptr();
4386 if eqtb.is_null() {
4387 return 0;
4388 }
4389 (*eqtb.offset(7892344 as i64 as isize)).u.CINT
4390 }
4391
4392 pub(crate) unsafe fn gettracingfontsstate(&self) -> integer {
4393 if !self.is_xetex() {
4394 return 0;
4395 }
4396 let eqtb = self.state.zeqtb.as_mut_ptr();
4397 if eqtb.is_null() {
4398 return 0;
4399 }
4400 (*eqtb.offset(7892347 as i64 as isize)).u.CINT
4401 }
4402
4403 unsafe fn current_resource_name(engine: *mut PortableTexEngine<'_>) -> Option<String> {
4404 let engine = engine.as_ref()?;
4405 if engine.state.nameoffile.is_null() || engine.state.namelength <= 0 {
4406 return None;
4407 }
4408
4409 let mut bytes = Vec::with_capacity(engine.state.namelength as usize);
4410 for index in 1..=engine.state.namelength {
4411 let value = *engine.state.nameoffile.offset(index as isize);
4412 if value <= 0 {
4413 continue;
4414 }
4415 bytes.push(value as u8);
4416 }
4417 Some(String::from_utf8_lossy(bytes.as_slice()).into_owned())
4418 }
4419
4420 pub(crate) unsafe fn get_encoding_mode_and_info(
4426 engine: *mut PortableTexEngine<'_>,
4427 info: *mut integer,
4428 ) -> integer {
4429 if !info.is_null() {
4430 *info = 0;
4431 }
4432 let name = Self::current_resource_name(engine).unwrap_or_default();
4433 let lowered = name.trim().to_ascii_lowercase();
4434 match lowered.as_str() {
4435 "auto" => 0, "utf8" | "utf-8" => 1, "utf16" | "utf-16" | "utf16be" | "utf-16be" => 2, "utf16le" | "utf-16le" => 3, "bytes" => 4, _ => 4,
4443 }
4444 }
4445
4446 unsafe fn mode_string(mode: const_string) -> String {
4447 if mode.is_null() {
4448 return String::new();
4449 }
4450
4451 let mut bytes = Vec::new();
4452 let mut cursor = mode;
4453 while *cursor != 0 {
4454 bytes.push(*cursor as u8);
4455 cursor = cursor.add(1);
4456 }
4457 String::from_utf8_lossy(bytes.as_slice()).into_owned()
4458 }
4459
4460 unsafe fn pool_string(&self, string: strnumber) -> Option<String> {
4461 if string < 0 || self.state.strstart.is_null() || self.state.strpool.is_null() {
4462 return None;
4463 }
4464 let index = Self::pool_string_index(string)?;
4465 let start = *self.state.strstart.offset(index);
4466 let end = *self.state.strstart.offset(index + 1);
4467 if start < 0 || end < start {
4468 return None;
4469 }
4470
4471 let len = usize::try_from(end - start).ok()?;
4472 let mut units = Vec::with_capacity(len);
4473 for offset in 0..len {
4474 units.push(*self.state.strpool.offset((start as usize + offset) as isize));
4475 }
4476 Some(
4477 char::decode_utf16(units)
4478 .map(|codepoint| codepoint.unwrap_or(char::REPLACEMENT_CHARACTER))
4479 .collect(),
4480 )
4481 }
4482
4483 pub(crate) fn pool_string_index(string: strnumber) -> Option<isize> {
4484 if string < 0 {
4485 return None;
4486 }
4487 let index = if string >= 65536 { string - 65536 } else { string };
4488 isize::try_from(index).ok()
4489 }
4490
4491 fn resource_kind(name: &str, format: integer) -> ResourceKind {
4492 match format {
4493 resource_format_tex_input | 0 => Self::tex_resource_kind(name),
4494 resource_format_tfm | resource_format_font => ResourceKind::Font,
4495 resource_format_encoding => ResourceKind::Encoding,
4496 resource_format_font_map => ResourceKind::Map,
4497 resource_format_config => ResourceKind::Config,
4498 resource_format_format_image => ResourceKind::FormatImage,
4499 other => ResourceKind::Other(other),
4500 }
4501 }
4502
4503 fn tex_resource_kind(name: &str) -> ResourceKind {
4504 let name = name.rsplit(['/', '\\']).next().unwrap_or(name);
4505 let name = name.to_ascii_lowercase();
4506 if name.ends_with(".sty") {
4507 return ResourceKind::Package;
4508 }
4509 if name.ends_with(".cls") {
4510 return ResourceKind::Class;
4511 }
4512 if name.ends_with(".fd") {
4513 return ResourceKind::FontDefinition;
4514 }
4515 if name.ends_with(".clo")
4516 || name.ends_with(".def")
4517 || name.ends_with(".ldf")
4518 || name.ends_with(".cfg")
4519 {
4520 return ResourceKind::PackageSupport;
4521 }
4522 ResourceKind::TexInput
4523 }
4524
4525 fn resource_kind_for_open(
4526 engine: &PortableTexEngine<'_>,
4527 name: &str,
4528 format: integer,
4529 ) -> ResourceKind {
4530 let kind = Self::resource_kind(name, format);
4531 if kind == ResourceKind::TexInput
4532 && Self::active_package_owner(engine).is_some()
4533 && Self::looks_like_package_asset(name)
4534 {
4535 ResourceKind::Asset
4536 } else {
4537 kind
4538 }
4539 }
4540
4541 fn resource_package_owner(
4542 engine: &PortableTexEngine<'_>,
4543 name: &str,
4544 kind: ResourceKind,
4545 ) -> Option<String> {
4546 match kind {
4547 ResourceKind::Package | ResourceKind::Class => Self::resource_stem(name),
4548 ResourceKind::PackageSupport | ResourceKind::FontDefinition | ResourceKind::Asset => {
4549 Self::active_package_owner(engine)
4550 }
4551 _ => None,
4552 }
4553 }
4554
4555 fn active_package_owner(engine: &PortableTexEngine<'_>) -> Option<String> {
4556 engine.current_input_package_owner.clone()
4557 }
4558
4559 fn looks_like_package_asset(name: &str) -> bool {
4560 let name = name.rsplit(['/', '\\']).next().unwrap_or(name);
4561 let name = name.to_ascii_lowercase();
4562 !(name.ends_with(".tex")
4563 || name.ends_with(".ltx")
4564 || name.ends_with(".sty")
4565 || name.ends_with(".cls")
4566 || name.ends_with(".fd")
4567 || name.ends_with(".clo")
4568 || name.ends_with(".def")
4569 || name.ends_with(".ldf")
4570 || name.ends_with(".cfg"))
4571 }
4572
4573 fn resource_stem(name: &str) -> Option<String> {
4574 let name = name.rsplit(['/', '\\']).next().unwrap_or(name);
4575 let stem = name.rsplit_once('.').map_or(name, |(stem, _)| stem);
4576 if stem.is_empty() {
4577 None
4578 } else {
4579 Some(stem.to_string())
4580 }
4581 }
4582
4583 fn source_index(value: usize) -> u32 {
4584 value.min(u32::MAX as usize) as u32
4585 }
4586
4587 fn virtual_file_key(name: &str) -> String {
4588 let mut name = name;
4589 while let Some(stripped) = name.strip_prefix("./") {
4590 name = stripped;
4591 }
4592 name.to_string()
4593 }
4594
4595 fn normalized_runtime_resource_name(mut name: &str) -> &str {
4596 while let Some(stripped) = name.strip_prefix("./") {
4597 name = stripped;
4598 }
4599 name
4600 }
4601
4602 unsafe fn intern_static_pool_string(
4609 engine: &mut PortableTexEngine<'_>,
4610 text: &str,
4611 ) -> EngineFlow<Option<strnumber>> {
4612 if engine.state.strpool.is_null() || engine.state.strstart.is_null() {
4613 return Ok(None);
4614 }
4615
4616 let Ok(needed) = integer::try_from(text.encode_utf16().count()) else {
4617 return Ok(None);
4618 };
4619 let Some(next_pool) = engine.state.poolptr.checked_add(needed) else {
4620 return Ok(None);
4621 };
4622 if next_pool > engine.state.poolsize {
4623 return Ok(None);
4624 }
4625
4626 for unit in text.encode_utf16() {
4627 *engine.state.strpool.offset(engine.state.poolptr as isize) = unit as packedUTF16code;
4628 engine.state.poolptr += 1;
4629 }
4630
4631 Ok(Some(engine.makestring()?))
4632 }
4633
4634 unsafe fn append_text_to_pool(engine: &mut PortableTexEngine<'_>, text: &str) -> boolean {
4635 if engine.state.strpool.is_null() {
4636 return false_0;
4637 }
4638 let needed = match integer::try_from(text.encode_utf16().count()) {
4639 Ok(needed) => needed,
4640 Err(_) => return false_0,
4641 };
4642 let Some(next_pool) = engine.state.poolptr.checked_add(needed) else {
4643 return false_0;
4644 };
4645 if next_pool > engine.state.poolsize {
4646 return false_0;
4647 }
4648 for unit in text.encode_utf16() {
4649 *engine.state.strpool.offset(engine.state.poolptr as isize) = unit as packedUTF16code;
4650 engine.state.poolptr += 1;
4651 }
4652 true_0
4653 }
4654
4655 unsafe fn resource_bytes_for_name(
4656 engine: &mut PortableTexEngine<'_>,
4657 name: &str,
4658 ) -> Option<Vec<u8>> {
4659 let name = Self::normalized_runtime_resource_name(name);
4660 let kind = Self::resource_kind_for_open(engine, name, resource_format_tex_input);
4661 let package = Self::resource_package_owner(engine, name, kind);
4662 let request = ResourceRequest {
4663 name,
4664 kind,
4665 package: package.as_deref(),
4666 format: resource_format_tex_input,
4667 mode: "rb",
4668 source: None,
4669 };
4670 let virtual_key = Self::virtual_file_key(name);
4671 if let Some(bytes) = engine.virtual_files.get(&virtual_key) {
4672 Some(bytes.clone())
4673 } else {
4674 engine.resources.read(request)
4675 }
4676 }
4677
4678 pub(crate) unsafe fn boundary_get_file_size(
4679 engine: *mut PortableTexEngine<'_>,
4680 string: integer,
4681 ) {
4682 let Some(engine) = engine.as_mut() else {
4683 return;
4684 };
4685 let Some(name) = engine.pool_string(string as strnumber) else {
4686 return;
4687 };
4688 const PLACEHOLDER_FILE_SIZE: usize = 4096;
4698 let size = Self::resource_bytes_for_name(engine, name.as_str())
4699 .map_or(PLACEHOLDER_FILE_SIZE, |bytes| bytes.len());
4700 Self::append_text_to_pool(engine, size.to_string().as_str());
4701 }
4702
4703 pub(crate) unsafe fn load_pool_strings(
4704 engine: &mut PortableTexEngine<'_>,
4705 spare_size: integer,
4706 ) -> EngineFlow<integer> {
4707 if engine.state.strpool.is_null() || engine.state.strstart.is_null()
4708 || spare_size <= 0
4709 {
4710 return Ok(0);
4711 }
4712 let mut used = 0_i32;
4713 let mut last = 0_i32;
4714 for line in include_str!("../pool/xetex.pool").lines() {
4715 if line.starts_with('*') {
4716 break;
4717 }
4718 let bytes = line.as_bytes();
4719 let text = if bytes.len() >= 2 && bytes[0].is_ascii_digit()
4720 && bytes[1].is_ascii_digit()
4721 {
4722 &line[2..]
4723 } else {
4724 line
4725 };
4726 let units = text.encode_utf16().count().min(i32::MAX as usize) as integer;
4727 used = used.saturating_add(units);
4728 if used >= spare_size
4729 || engine.state.poolptr.saturating_add(units) > engine.state.poolsize
4730 {
4731 return Ok(0);
4732 }
4733 for unit in text.encode_utf16() {
4734 *engine.state.strpool.offset(engine.state.poolptr as isize) = unit
4735 as packedUTF16code;
4736 engine.state.poolptr += 1;
4737 }
4738 last = engine.makestring()?;
4739 }
4740 Ok(last)
4741 }
4742
4743 pub(crate) unsafe fn boundary_open_log_file(
4744 engine: *mut PortableTexEngine<'_>,
4745 ) -> EngineFlow<()> {
4746 let Some(engine) = engine.as_mut() else {
4747 return Ok(());
4748 };
4749 let old_setting = engine.state.selector;
4750 if engine.state.jobname == 0 {
4751 if let Some(jobname) = Self::intern_static_pool_string(engine, "texput")? {
4752 engine.state.jobname = jobname;
4753 }
4754 }
4755 engine.state.logopened = true_0 as boolean;
4756 engine.state.selector = (old_setting as i32 + 2).clamp(0, 21) as eightbits;
4757 Ok(())
4758 }
4759
4760 pub(crate) unsafe fn boundary_jump_out(
4761 engine: *mut PortableTexEngine<'_>,
4762 ) -> EngineFlow<core::convert::Infallible> {
4763 let status = if let Some(engine) = engine.as_ref() {
4768 if engine.state.history as i32 <= 1 {
4769 0 as integer
4770 } else {
4771 1 as integer
4772 }
4773 } else {
4774 1 as integer
4775 };
4776 Self::abort_engine(engine, status)
4777 }
4778
4779 pub(crate) unsafe fn boundary_shipout(
4780 engine: *mut PortableTexEngine<'_>,
4781 box_node: halfword,
4782 ) {
4783 if let Some(engine) = engine.as_mut() {
4784 engine.stripped_shipouts = engine.stripped_shipouts.saturating_add(1);
4785 engine.last_stripped_shipout_box = Some(PortableNodeHandle(box_node));
4786 }
4787 }
4788
4789 pub(crate) unsafe fn boundary_capture_fragment_box(
4790 engine: *mut PortableTexEngine<'_>,
4791 box_node: halfword,
4792 mode: integer,
4793 boxcontext: integer,
4794 ) -> boolean {
4795 if let Some(engine) = engine.as_mut() {
4796 if engine.fragment_capture_enabled {
4797 engine.captured_fragment_root = Some(PortableNodeHandle(box_node));
4798 let absolute_mode = if mode >= 0 { mode } else { -mode };
4799 if absolute_mode == 1 && boxcontext < 1_073_741_824 {
4800 return true_0;
4801 }
4802 }
4803 }
4804 false_0
4805 }
4806
4807 pub(crate) unsafe fn boundary_build_page(
4808 engine: *mut PortableTexEngine<'_>,
4809 ) -> EngineFlow<()> {
4810 if let Some(engine) = engine.as_mut() {
4811 if engine.format_initialization
4812 && engine.state.curcmd as i32 == 15
4813 && engine.state.curchr == 1
4814 {
4815 Self::abort_engine(engine as *mut PortableTexEngine<'_>, 0 as integer)?;
4819 }
4820 engine.stripped_page_builds = engine.stripped_page_builds.saturating_add(1);
4821 }
4822 Ok(())
4823 }
4824
4825 pub(crate) unsafe fn boundary_prune_page_top(
4826 engine: *mut PortableTexEngine<'_>,
4827 node: halfword,
4828 _saving: boolean,
4829 ) -> halfword {
4830 if let Some(engine) = engine.as_mut() {
4831 engine.stripped_page_top_prunes =
4832 engine.stripped_page_top_prunes.saturating_add(1);
4833 }
4834 node
4835 }
4836
4837 pub(crate) unsafe fn boundary_special_out(
4838 engine: *mut PortableTexEngine<'_>,
4839 node: halfword,
4840 ) -> EngineFlow<()> {
4841 let Some(engine) = engine.as_mut() else {
4842 return Ok(());
4843 };
4844 if node < engine.state.memmin || node > engine.state.memend {
4845 engine.stripped_special_outputs = engine
4846 .stripped_special_outputs
4847 .saturating_add(1);
4848 return Ok(());
4849 }
4850 let mem = engine.state.zmem.as_mut_ptr();
4851 if (*mem.offset(node as isize)).hh.u.B0 as i32 == 8 {
4852 match (*mem.offset(node as isize)).hh.u.B1 as i32 {
4853 0 => {
4854 Self::boundary_open_write_whatsit(engine, node);
4855 return Ok(());
4856 }
4857 1 => {
4858 Self::boundary_write_whatsit(engine, node)?;
4859 return Ok(());
4860 }
4861 2 => {
4862 Self::boundary_close_write_whatsit(engine, node);
4863 return Ok(());
4864 }
4865 _ => {}
4866 }
4867 }
4868 engine.stripped_special_outputs = engine
4869 .stripped_special_outputs
4870 .saturating_add(1);
4871 Ok(())
4872 }
4873
4874 unsafe fn boundary_open_write_whatsit(engine: &mut PortableTexEngine<'_>, node: halfword) {
4875 let mem = engine.state.zmem.as_mut_ptr();
4876 let stream = (*mem.offset((node + 1) as isize)).hh.v.LH as usize;
4877 if stream >= 16 {
4878 return;
4879 }
4880
4881 if engine.state.writeopen[stream] != 0 {
4882 Self::boundary_close_write_stream(engine, stream);
4883 }
4884
4885 engine.state.curname = (*mem.offset((node + 1) as isize)).hh.v.RH as strnumber;
4886 engine.state.curarea = (*mem.offset((node + 2) as isize)).hh.v.LH as strnumber;
4887 engine.state.curext = (*mem.offset((node + 2) as isize)).hh.v.RH as strnumber;
4888 if engine.state.curext == 335 {
4889 engine.state.curext = 799;
4890 }
4891 engine.zpackfilename(engine.state.curname, engine.state.curarea, engine.state.curext);
4892 let Some(name) = Self::current_resource_name(engine as *mut PortableTexEngine<'_>) else {
4893 return;
4894 };
4895 let handle = Box::new(PortableFileHandle::new(
4896 name,
4897 ResourceKind::TexInput,
4898 None,
4899 resource_format_tex_input,
4900 Vec::new(),
4901 ));
4902 engine.state.writefile[stream] = Box::into_raw(handle);
4903 engine.state.writeopen[stream] = true_0;
4904 }
4905
4906 unsafe fn boundary_write_whatsit(
4907 engine: &mut PortableTexEngine<'_>,
4908 node: halfword,
4909 ) -> EngineFlow<()> {
4910 let mem = engine.state.zmem.as_mut_ptr();
4911 let stream = (*mem.offset((node + 1) as isize)).hh.v.LH as usize;
4912 if stream >= 16 || engine.state.writeopen[stream] == 0 {
4913 return Ok(());
4914 }
4915 let write_tokens = engine.profile.write_token_constants();
4916 let q = engine.getavail()?;
4917 (*mem.offset(q as isize)).hh.v.LH = write_tokens.open_group_token;
4918 let r = engine.getavail()?;
4919 (*mem.offset(q as isize)).hh.v.RH = r;
4920 (*mem.offset(r as isize)).hh.v.LH = write_tokens.end_write_token;
4921 engine.zbegintokenlist(q, 4)?;
4922 engine.zbegintokenlist((*mem.offset((node + 1) as isize)).hh.v.RH, 15)?;
4923 let q = engine.getavail()?;
4924 (*mem.offset(q as isize)).hh.v.LH = write_tokens.close_group_token;
4925 engine.zbegintokenlist(q, 4)?;
4926 let old_mode = engine.state.curlist.modefield;
4927 engine.state.curlist.modefield = 0;
4928 engine.state.curcs = engine.state.writeloc;
4929 engine.zscantoks(false_0, true_0)?;
4930 engine.state.curlist.modefield = old_mode;
4931 engine.gettoken()?;
4932 if engine.state.curtok != write_tokens.end_write_token {
4933 while engine.state.curtok != write_tokens.end_write_token {
4934 engine.gettoken()?;
4935 }
4936 }
4937 engine.endtokenlist()?;
4938 let old_setting = engine.state.selector;
4939 engine.state.selector = stream as eightbits;
4940 engine.ztokenshow(engine.state.defref);
4941 engine.println();
4942 engine.state.selector = old_setting;
4943 engine.zflushlist(engine.state.defref);
4944 Ok(())
4945 }
4946
4947 unsafe fn boundary_close_write_whatsit(engine: &mut PortableTexEngine<'_>, node: halfword) {
4948 let mem = engine.state.zmem.as_mut_ptr();
4949 let stream = (*mem.offset((node + 1) as isize)).hh.v.LH as usize;
4950 if stream < 16 {
4951 Self::boundary_close_write_stream(engine, stream);
4952 }
4953 }
4954
4955 unsafe fn boundary_close_write_stream(engine: &mut PortableTexEngine<'_>, stream: usize) {
4956 if stream >= 16 || engine.state.writeopen[stream] == 0 {
4957 return;
4958 }
4959 let file = engine.state.writefile[stream];
4960 engine.state.writefile[stream] = core::ptr::null_mut();
4961 engine.state.writeopen[stream] = false_0;
4962 if file.is_null() {
4963 return;
4964 }
4965 let handle = Box::from_raw(file);
4966 let key = Self::virtual_file_key(handle.name.as_str());
4967 engine.virtual_files.insert(key, handle.bytes);
4968 }
4969
4970 pub(crate) unsafe fn boundary_load_picture(
4971 engine: *mut PortableTexEngine<'_>,
4972 _is_pdf: boolean,
4973 ) {
4974 if let Some(engine) = engine.as_mut() {
4975 engine.stripped_picture_loads = engine.stripped_picture_loads.saturating_add(1);
4976 }
4977 }
4978
4979 pub(crate) fn record_stripped_source_special(engine: *mut PortableTexEngine<'_>) {
4980 if let Some(engine) = unsafe { engine.as_mut() } {
4981 engine.stripped_source_specials = engine.stripped_source_specials.saturating_add(1);
4982 }
4983 }
4984
4985 pub(crate) fn record_stripped_write_whatsit_diagnostic(engine: *mut PortableTexEngine<'_>) {
4986 if let Some(engine) = unsafe { engine.as_mut() } {
4987 engine.stripped_write_whatsit_diagnostics =
4988 engine.stripped_write_whatsit_diagnostics.saturating_add(1);
4989 }
4990 }
4991
4992 pub(crate) fn record_stripped_pdf_extension(engine: *mut PortableTexEngine<'_>) {
4993 if let Some(engine) = unsafe { engine.as_mut() } {
4994 engine.stripped_pdf_extensions = engine.stripped_pdf_extensions.saturating_add(1);
4995 }
4996 }
4997
4998 fn resolve_input_encoding(engine: &PortableTexEngine<'_>, handle: &mut PortableFileHandle) {
5008 let is_text = handle.format == resource_format_tex_input || handle.format == 0;
5009 if engine.is_xetex() && is_text {
5010 handle.resolve_text_encoding_auto();
5011 } else {
5012 handle.encoding = InputEncoding::Bytes;
5013 }
5014 }
5015
5016 pub(crate) unsafe fn boundary_open_input(
5017 engine: *mut PortableTexEngine<'_>,
5018 file: *mut NativeFileHandle,
5019 format: integer,
5020 mode: const_string,
5021 ) -> boolean {
5022 let Some(engine) = engine.as_mut() else {
5023 if !file.is_null() {
5024 *file = core::ptr::null_mut();
5025 }
5026 return false_0;
5027 };
5028 let Some(name) = Self::current_resource_name(engine as *mut PortableTexEngine<'_>) else {
5029 if !file.is_null() {
5030 *file = core::ptr::null_mut();
5031 }
5032 return false_0;
5033 };
5034 let mode = Self::mode_string(mode);
5035 let request_kind = Self::resource_kind_for_open(engine, name.as_str(), format);
5036 let request_package = Self::resource_package_owner(engine, name.as_str(), request_kind);
5037 let source: Option<PortableSourceSpan> = None;
5038 let request = ResourceRequest {
5039 name: name.as_str(),
5040 kind: request_kind,
5041 package: request_package.as_deref(),
5042 format,
5043 mode: mode.as_str(),
5044 source: source.clone(),
5045 };
5046 engine.resource_requests = engine.resource_requests.saturating_add(1);
5047 let virtual_key = Self::virtual_file_key(name.as_str());
5048 let bytes = if let Some(bytes) = engine.virtual_files.get(&virtual_key) {
5049 bytes.clone()
5050 } else if let Some(bytes) = engine.resources.read(request) {
5051 bytes
5052 } else {
5053 engine.resource_request_records.push(PortableResourceRequestRecord {
5054 name,
5055 kind: request_kind,
5056 package: request_package,
5057 format,
5058 mode,
5059 source,
5060 byte_len: None,
5061 });
5062 if !file.is_null() {
5063 *file = core::ptr::null_mut();
5064 }
5065 return false_0;
5066 };
5067 let byte_len = Self::source_index(bytes.len());
5068 engine.resource_request_records.push(PortableResourceRequestRecord {
5069 name: name.clone(),
5070 kind: request_kind,
5071 package: request_package.clone(),
5072 format,
5073 mode: mode.clone(),
5074 source,
5075 byte_len: Some(byte_len),
5076 });
5077 let mut handle = Box::new(PortableFileHandle::new(
5078 name,
5079 request_kind,
5080 request_package,
5081 format,
5082 bytes,
5083 ));
5084 Self::resolve_input_encoding(engine, &mut handle);
5088 if format == resource_format_tfm {
5089 engine.state.tfmtemp = handle.read_byte().map_or(-1, |byte| byte as integer);
5090 }
5091 if !file.is_null() {
5092 *file = Box::into_raw(handle);
5093 return true_0;
5094 }
5095 drop(handle);
5096 false_0
5097 }
5098
5099 unsafe fn begin_primary_input_raw(
5100 self: &mut Self,
5101 name: &str,
5102 bytes: Vec<u8>,
5103 ) -> EngineFlow<boolean> {
5104 if self.state.inputfile.is_null() || self.state.sourcefilenamestack.is_null()
5105 || self.state.fullsourcefilenamestack.is_null()
5106 || self.state.buffer.is_null()
5107 {
5108 return Ok(false_0);
5109 }
5110 let Some(source_name) = Self::intern_static_pool_string(self, name)? else {
5111 return Ok(false_0);
5112 };
5113 self.beginfilereading()?;
5114 let slot = self.state.curinput.indexfield as isize;
5115 let mut handle = Box::new(
5116 PortableFileHandle::new(
5117 name.to_string(),
5118 ResourceKind::TexInput,
5119 None,
5120 resource_format_tex_input,
5121 bytes,
5122 ),
5123 );
5124 Self::resolve_input_encoding(self, &mut handle);
5125 *self.state.inputfile.offset(slot) = Box::into_raw(handle);
5126 self.state.curinput.namefield = source_name as halfword;
5127 *self.state.sourcefilenamestack.offset(slot) = source_name;
5128 *self.state.fullsourcefilenamestack.offset(slot) = source_name;
5129 self.state.curinput.statefield = 33 as quarterword;
5130 self.state.line = 1 as integer;
5131 self.state.src_primary_name = source_name;
5132 self.state.cmd_span = 0;
5133 self.state.pending_call_span = 0;
5134 self.state.src_user_cmd_span = 0;
5135 self.state.src_tok_span = 0;
5136 self.state.src_anchor_cmd = 0;
5137 self.state.src_grp_stack.clear();
5138 self.state.src_grp_closing = 0;
5139 self.state.src_call_user_span = 0;
5140 self.state.src_line_base = 0;
5141 self.state.src_line_buf_start = 0;
5142 self.state.src_prev_line_len = 0;
5143 self.state.src_line_initialized = false;
5144 self.state.curinput.spanfield = 0;
5145 self.state.src_native_offsets.clear();
5146 self.state.src_stack_cells.clear();
5147 self.state.cur_stack_head = 0;
5148 if Self::boundary_input_line(
5149 self as *mut PortableTexEngine<'_>,
5150 *self.state.inputfile.offset(slot) as NativeFileHandle,
5151 ) == 0
5152 {
5153 self.endfilereading();
5154 return Ok(false_0);
5155 }
5156 self.firmuptheline()?;
5157 let eqtb = self.state.zeqtb.as_mut_ptr();
5158 let endline_char_index = if self.is_xetex() && self.state.eqtbtop >= 7_892_312 {
5159 7_892_312_i64
5160 } else {
5161 27_212_i64
5162 };
5163 let endline_char = if eqtb.is_null() {
5164 -1
5165 } else {
5166 (*eqtb.offset(endline_char_index as isize)).u.CINT
5167 };
5168 if !(0..=255).contains(&endline_char) {
5169 self.state.curinput.limitfield -= 1;
5170 } else {
5171 *self.state.buffer.offset(self.state.curinput.limitfield as isize) = endline_char
5172 as UnicodeScalar;
5173 }
5174 self.state.first = (self.state.curinput.limitfield as i32 + 1) as integer;
5175 self.state.curinput.locfield = self.state.curinput.startfield;
5176 Ok(true_0)
5177 }
5178
5179 pub(crate) unsafe fn boundary_input_line(
5180 engine: *mut PortableTexEngine<'_>,
5181 file: NativeFileHandle,
5182 ) -> boolean {
5183 let Some(engine) = engine.as_mut() else {
5184 return false_0;
5185 };
5186 if file.is_null() || engine.state.buffer.is_null() {
5187 return false_0;
5188 }
5189
5190 let handle = &mut *file;
5191 if !handle.has_remaining() {
5192 return false_0;
5193 }
5194
5195 let first = engine.state.first.max(0) as usize;
5196 let limit = engine.state.bufsize.max(0) as usize;
5197 let mut last = first;
5198 while last < limit {
5202 let Some(scalar) = handle.next_input_scalar() else {
5203 break;
5204 };
5205 match scalar {
5206 0x0A => break,
5207 0x0D => {
5208 let saved_cursor = handle.cursor;
5212 let saved_lookahead = handle.saved_char;
5213 let was_eof = handle.eof_after_failed_read;
5214 match handle.next_input_scalar() {
5215 Some(0x0A) => {} _ => {
5217 handle.cursor = saved_cursor;
5219 handle.saved_char = saved_lookahead;
5220 handle.eof_after_failed_read = was_eof;
5221 }
5222 }
5223 break;
5224 }
5225 scalar => {
5226 *engine.state.buffer.offset(last as isize) = scalar as UnicodeScalar;
5227 last += 1;
5228 }
5229 }
5230 }
5231
5232 while last > first && *engine.state.buffer.offset((last - 1) as isize) == b' ' as UnicodeScalar {
5233 last -= 1;
5234 }
5235 if handle.format == resource_format_tex_input || handle.format == 0 {
5236 engine.current_input_package_owner = handle.package.clone();
5237 }
5238 if engine.state.source_tracking
5245 && engine.state.curinput.namefield as strnumber == engine.state.src_primary_name
5246 {
5247 if engine.state.src_line_initialized {
5248 engine.state.src_line_base += engine.state.src_prev_line_len + 1;
5249 } else {
5250 engine.state.src_line_base = 0;
5251 engine.state.src_line_initialized = true;
5252 }
5253 engine.state.src_line_buf_start = first as integer;
5254 engine.state.src_prev_line_len = last.saturating_sub(first) as u32;
5255 engine.state.src_token_start = first as integer;
5261 }
5262 engine.state.last = last as integer;
5263 true_0
5264 }
5265
5266 pub(crate) unsafe fn boundary_read_byte(_file: NativeFileHandle) -> integer {
5267 if _file.is_null() {
5268 return -1;
5269 }
5270 (&mut *_file).read_byte().map_or(-1, |byte| byte as integer)
5271 }
5272
5273 pub(crate) unsafe fn boundary_end_of_file(_file: NativeFileHandle) -> integer {
5274 if _file.is_null() || (&*_file).is_eof() {
5275 1
5276 } else {
5277 0
5278 }
5279 }
5280
5281 pub(crate) unsafe fn boundary_flush_file(_file: NativeFileHandle) -> integer {
5282 0
5283 }
5284
5285 pub(crate) unsafe fn boundary_write_byte(
5286 engine: *mut PortableTexEngine<'_>,
5287 character: integer,
5288 file: NativeFileHandle,
5289 ) -> integer {
5290 if !file.is_null() {
5291 if let Ok(byte) = u8::try_from(character) {
5292 (*file).bytes.push(byte);
5293 }
5294 return character;
5295 }
5296 if let Some(engine) = engine.as_mut() {
5297 if let Ok(byte) = u8::try_from(character) {
5298 engine.transcript_bytes.push(byte);
5299 }
5300 }
5301 character
5302 }
5303
5304 pub(crate) unsafe fn boundary_close_file(_file: NativeFileHandle) {
5305 if !_file.is_null() {
5306 drop(Box::from_raw(_file));
5307 }
5308 }
5309
5310 pub(crate) unsafe fn get_seconds_and_micros(
5311 engine: *mut PortableTexEngine<'_>,
5312 seconds: *mut integer,
5313 micros: *mut integer,
5314 ) {
5315 let clock = engine
5316 .as_mut()
5317 .map(|engine| engine.platform.clock())
5318 .unwrap_or_default();
5319 if !seconds.is_null() {
5320 *seconds = clock.seconds;
5321 }
5322 if !micros.is_null() {
5323 *micros = clock.micros;
5324 }
5325 }
5326
5327 pub(crate) unsafe fn linebreak_start(
5328 engine: *mut PortableTexEngine<'_>,
5329 font: integer,
5330 locale: integer,
5331 text: *mut uint16_t,
5332 text_length: integer,
5333 ) {
5334 let Some(engine) = engine.as_mut() else {
5335 return;
5336 };
5337 let text = if text.is_null() || text_length <= 0 {
5338 &[]
5339 } else {
5340 core::slice::from_raw_parts(text as *const uint16_t, text_length as usize)
5341 };
5342 engine
5343 .platform
5344 .linebreak_start(PortableLinebreakRequest { font, locale, text });
5345 }
5346
5347 pub(crate) unsafe fn linebreak_next(engine: *mut PortableTexEngine<'_>) -> integer {
5348 engine
5349 .as_mut()
5350 .and_then(|engine| engine.platform.linebreak_next())
5351 .unwrap_or(-1)
5352 }
5353
5354 pub(crate) unsafe fn register_host_box_primitive(self: &mut Self) -> EngineFlow<()> {
5356 let eqtb = self.state.zeqtb.as_mut_ptr();
5357 let name = b"Uhostbox";
5358 for (index, byte) in name.iter().enumerate() {
5359 *self.state.buffer.offset(index as isize) = *byte as UnicodeScalar;
5360 }
5361 let saved = self.state.nonewcontrolsequence;
5362 self.state.nonewcontrolsequence = 0 as boolean;
5363 let cs = (&mut *(self as *mut PortableTexEngine<'_>))
5364 .zidlookup(0 as integer, name.len() as integer)?;
5365 self.state.nonewcontrolsequence = saved;
5366 (*eqtb.offset(cs as isize)).hh.u.B1 = 1 as i16;
5368 (*eqtb.offset(cs as isize)).hh.u.B0 = 59 as i16;
5369 (*eqtb.offset(cs as isize)).hh.v.RH = HOST_BOX_EXTENSION_CODE as halfword;
5370 Ok(())
5371 }
5372
5373 unsafe fn host_box_marker(
5377 engine: *mut PortableTexEngine<'_>,
5378 subtype: i16,
5379 payload: integer,
5380 width: scaled,
5381 height: scaled,
5382 depth: scaled,
5383 ) -> EngineFlow<halfword> {
5384 let this = &mut *engine;
5385 let marker = this.zgetnode(5 as i32)?;
5386 let mem: *mut memoryword = this.state.zmem.as_mut_ptr();
5387 (*mem.offset(marker as isize)).hh.u.B0 = 8 as i16;
5388 (*mem.offset(marker as isize)).hh.u.B1 = subtype;
5389 (*mem.offset(marker as isize)).hh.v.RH = -(268435455 as i64) as halfword;
5390 (*mem.offset((marker as i32 + 1 as i32) as isize)).u.CINT = width;
5391 (*mem.offset((marker as i32 + 2 as i32) as isize)).u.CINT = depth;
5392 (*mem.offset((marker as i32 + 3 as i32) as isize)).u.CINT = height;
5393 (*mem.offset((marker as i32 + 4 as i32) as isize)).u.CINT = payload;
5394 Ok(marker)
5395 }
5396
5397 unsafe fn host_box_build(
5399 engine: *mut PortableTexEngine<'_>,
5400 token: integer,
5401 style: PortableHostBoxStyle,
5402 font_size: scaled,
5403 ) -> EngineFlow<halfword> {
5404 let this = &mut *engine;
5405 let response = this.platform.host_box(PortableHostBoxRequest {
5406 token,
5407 style,
5408 font_size,
5409 });
5410 let hbox = this.newnullbox()?;
5411 let Some(host_box) = response else {
5412 return Ok(hbox);
5413 };
5414 let mem: *mut memoryword = this.state.zmem.as_mut_ptr();
5415 (*mem.offset((hbox as i32 + 1 as i32) as isize)).u.CINT = host_box.width;
5416 (*mem.offset((hbox as i32 + 2 as i32) as isize)).u.CINT = host_box.depth;
5417 (*mem.offset((hbox as i32 + 3 as i32) as isize)).u.CINT = host_box.height;
5418 let index = this.hostbox_records.len();
5419 let (width, height, depth) = (host_box.width, host_box.height, host_box.depth);
5420 this.hostbox_records.push(host_box);
5421 let marker = Self::host_box_marker(
5422 engine,
5423 HOST_BOX_RESOLVED_SUBTYPE,
5424 index as integer,
5425 width,
5426 height,
5427 depth,
5428 )?;
5429 (*mem.offset((hbox as i32 + 5 as i32) as isize)).hh.v.RH = marker;
5430 Ok(hbox)
5431 }
5432
5433 pub(crate) unsafe fn host_box_insert(
5435 engine: *mut PortableTexEngine<'_>,
5436 token: integer,
5437 ) -> EngineFlow<()> {
5438 let Some(this) = engine.as_mut() else {
5439 return Ok(());
5440 };
5441 let mode = (this.state.curlist.modefield as i32).abs();
5442 if mode == 209 as i32 {
5443 let marker =
5444 Self::host_box_marker(engine, HOST_BOX_PENDING_SUBTYPE, token, 0, 0, 0)?;
5445 let this = &mut *engine;
5446 let placeholder = this.newnullbox()?;
5447 let noad = this.newnoad()?;
5448 let mem: *mut memoryword = this.state.zmem.as_mut_ptr();
5449 (*mem.offset((placeholder as i32 + 5 as i32) as isize)).hh.v.RH = marker;
5450 (*mem.offset((noad as i32 + 1 as i32) as isize)).hh.v.RH = 2 as i32 as halfword;
5451 (*mem.offset((noad as i32 + 1 as i32) as isize)).hh.v.LH = placeholder;
5452 (*mem.offset(this.state.curlist.tailfield as isize)).hh.v.RH = noad;
5453 this.state.curlist.tailfield = noad;
5454 } else {
5455 let eqtb = this.state.zeqtb.as_mut_ptr();
5456 let font = (*eqtb.offset(EQTB_CUR_FONT_LOC as isize)).hh.v.RH as integer;
5457 let font_size = this.font_at_size(font);
5458 let hbox =
5459 Self::host_box_build(engine, token, PortableHostBoxStyle::Text, font_size)?;
5460 let this = &mut *engine;
5461 let mem: *mut memoryword = this.state.zmem.as_mut_ptr();
5462 (*mem.offset(this.state.curlist.tailfield as isize)).hh.v.RH = hbox;
5463 this.state.curlist.tailfield = hbox;
5464 }
5465 Ok(())
5466 }
5467
5468 pub(crate) unsafe fn host_box_resolve_noad(
5470 engine: *mut PortableTexEngine<'_>,
5471 q: halfword,
5472 ) -> EngineFlow<()> {
5473 let Some(this) = engine.as_mut() else {
5474 return Ok(());
5475 };
5476 if q < 0 || q >= this.state.himemmin {
5477 return Ok(());
5478 }
5479 let mem: *mut memoryword = this.state.zmem.as_mut_ptr();
5480 if (*mem.offset(q as isize)).hh.u.B0 as i32 != 16 as i32 {
5482 return Ok(());
5483 }
5484 let style_code = this.state.curstyle as i32;
5485 Self::host_box_resolve_field(engine, (q as i32 + 1 as i32) as halfword, style_code)
5486 }
5487
5488 pub(crate) unsafe fn host_box_resolve_field(
5490 engine: *mut PortableTexEngine<'_>,
5491 field: halfword,
5492 style_code: i32,
5493 ) -> EngineFlow<()> {
5494 let Some(this) = engine.as_mut() else {
5495 return Ok(());
5496 };
5497 if field < 0 {
5498 return Ok(());
5499 }
5500 let mem: *mut memoryword = this.state.zmem.as_mut_ptr();
5501 if (*mem.offset(field as isize)).hh.v.RH as i32 != 2 as i32 {
5503 return Ok(());
5504 }
5505 let placeholder = (*mem.offset(field as isize)).hh.v.LH;
5506 if placeholder < 0 || placeholder as i64 == -(268435455 as i64) {
5507 return Ok(());
5508 }
5509 let marker = (*mem.offset((placeholder as i32 + 5 as i32) as isize)).hh.v.RH;
5510 if marker < 0 || marker as i64 == -(268435455 as i64) || marker >= this.state.himemmin {
5511 return Ok(());
5512 }
5513 if (*mem.offset(marker as isize)).hh.u.B0 as i32 != 8 as i32
5514 || (*mem.offset(marker as isize)).hh.u.B1 as i32 != HOST_BOX_PENDING_SUBTYPE as i32
5515 {
5516 return Ok(());
5517 }
5518 let token = (*mem.offset((marker as i32 + 4 as i32) as isize)).u.CINT;
5519 let size = if style_code < 4 {
5521 0
5522 } else {
5523 256 * ((style_code - 2) / 2)
5524 };
5525 let style = match size {
5526 0 => PortableHostBoxStyle::Text,
5527 256 => PortableHostBoxStyle::Script,
5528 _ => PortableHostBoxStyle::ScriptScript,
5529 };
5530 let eqtb = this.state.zeqtb.as_mut_ptr();
5532 let font = (*eqtb.offset((EQTB_MATH_FONT_FAM2_BASE + size as i64) as isize))
5533 .hh
5534 .v
5535 .RH as integer;
5536 let font_size = this.font_at_size(font);
5537 let hbox = Self::host_box_build(engine, token, style, font_size)?;
5538 Self::src_carry_copy(engine as *mut Self, placeholder, hbox);
5541 let mem: *mut memoryword = (*engine).state.zmem.as_mut_ptr();
5542 let resolved_marker = (*mem.offset((hbox as i32 + 5 as i32) as isize)).hh.v.RH;
5543 if resolved_marker >= 0 && resolved_marker as i64 != -(268435455 as i64) {
5544 Self::src_carry_copy(engine as *mut Self, placeholder, resolved_marker);
5545 }
5546 (&mut *engine).zflushnodelist(placeholder)?;
5547 let this = &mut *engine;
5548 let mem: *mut memoryword = this.state.zmem.as_mut_ptr();
5549 (*mem.offset(field as isize)).hh.v.LH = hbox;
5550 Ok(())
5551 }
5552
5553 pub(crate) unsafe fn abort_engine(
5554 engine: *mut PortableTexEngine<'_>,
5555 status: integer,
5556 ) -> EngineFlow<core::convert::Infallible> {
5557 if let Some(engine) = engine.as_mut() {
5558 engine.last_abort_status = Some(status);
5559 }
5560 Err(EngineBreak::Abort(EngineAbort { status }))
5561 }
5562
5563 pub(crate) unsafe fn sandbox_reject(
5567 engine: *mut PortableTexEngine<'_>,
5568 message: &str,
5569 ) -> EngineFlow<()> {
5570 if let Some(engine) = engine.as_ref() {
5571 if engine.sandbox {
5572 return Err(EngineBreak::Error(EngineError {
5573 message: message.into(),
5574 }));
5575 }
5576 }
5577 Ok(())
5578 }
5579
5580 pub(crate) unsafe fn sandbox_open_math(
5587 engine: *mut PortableTexEngine<'_>,
5588 ) -> EngineFlow<()> {
5589 if let Some(engine) = engine.as_mut() {
5590 if engine.sandbox {
5591 if engine.sandbox_math_depth == 0 && engine.sandbox_math_opened {
5592 return Err(EngineBreak::Error(EngineError {
5593 message: "math shift ($) is not allowed inside a math expression"
5594 .into(),
5595 }));
5596 }
5597 engine.sandbox_math_opened = true;
5598 engine.sandbox_math_depth += 1;
5599 }
5600 }
5601 Ok(())
5602 }
5603
5604 pub(crate) unsafe fn sandbox_close_math(
5609 engine: *mut PortableTexEngine<'_>,
5610 ) -> EngineFlow<()> {
5611 if let Some(engine) = engine.as_mut() {
5612 if engine.sandbox && engine.sandbox_math_depth > 0 {
5613 engine.sandbox_math_depth -= 1;
5614 }
5615 }
5616 Ok(())
5617 }
5618
5619 pub(crate) unsafe fn sandbox_tick(
5623 engine: *mut PortableTexEngine<'_>,
5624 ) -> EngineFlow<()> {
5625 if let Some(engine) = engine.as_mut() {
5626 if engine.sandbox {
5627 engine.sandbox_ops = engine.sandbox_ops.saturating_add(1);
5628 if engine.sandbox_ops > SANDBOX_OP_BUDGET {
5629 return Err(EngineBreak::Error(EngineError {
5630 message: "expression is too complex or did not terminate".into(),
5631 }));
5632 }
5633 }
5634 }
5635 Ok(())
5636 }
5637
5638 pub(crate) unsafe fn surface_error(
5646 engine: *mut PortableTexEngine<'_>,
5647 ) -> EngineFlow<()> {
5648 let message = engine
5649 .as_ref()
5650 .map(|engine| engine.capture_last_error_message())
5651 .unwrap_or_else(|| "TeX error".into());
5652 Err(EngineBreak::Error(EngineError { message }))
5653 }
5654
5655 pub fn set_source_tracking(self: &mut Self, on: bool) {
5670 self.state.source_tracking = on;
5671 self.state.cmd_span = 0;
5672 self.state.pending_call_span = 0;
5673 self.state.src_token_start = 0;
5674 self.state.src_line_base = 0;
5675 self.state.src_line_buf_start = 0;
5676 self.state.src_prev_line_len = 0;
5677 self.state.src_line_initialized = false;
5678 self.state.src_call_start = 0;
5679 self.state.src_call_name = 0;
5680 self.state.src_call_state = 0;
5681 self.state.src_call_index = 0;
5682 self.state.src_call_span = 0;
5683 self.state.src_call_argspan = 0;
5684 self.state.src_user_cmd_span = 0;
5685 self.state.src_tok_span = 0;
5686 self.state.src_anchor_cmd = 0;
5687 self.state.src_grp_stack.clear();
5688 self.state.src_grp_closing = 0;
5689 self.state.src_call_user_span = 0;
5690 self.state.curinput.spanfield = 0;
5691 self.state.src_spans.clear();
5692 self.state.src_dedup.clear();
5693 self.state.src_native_offsets.clear();
5694 self.state.src_stack_cells.clear();
5695 self.state.cur_stack_head = 0;
5696 let end = if on { self.state.mem.len() } else { 0 };
5697 self.state.node_src = PagedArray::new(0, end, node_src_default, node_src_sig);
5698 self.state.node_stack = PagedArray::new(0, end, node_stack_default, node_stack_sig);
5699 }
5700
5701 pub fn source_tracking_enabled(&self) -> bool {
5703 self.state.source_tracking
5704 }
5705
5706 fn intern_span_raw(self: &mut Self, name: strnumber, start: u32, end: u32, role: u8) -> SrcId {
5711 let span = RawSpan { name, start, end, role };
5712 if let Some(&id) = self.state.src_dedup.get(&span) {
5713 return id;
5714 }
5715 self.state.src_spans.push(span);
5716 let id = self.state.src_spans.len() as SrcId;
5717 self.state.src_dedup.insert(span, id);
5718 id
5719 }
5720
5721 fn src_buf_offset(&self, loc: integer) -> u32 {
5724 let col = loc as i64 - self.state.src_line_buf_start as i64;
5725 (self.state.src_line_base as i64 + col).max(0) as u32
5726 }
5727
5728 pub(crate) fn resolve_node_src(&self, node: halfword) -> Option<PortableSourceSpan> {
5732 if !self.state.source_tracking || node < 0 {
5733 return None;
5734 }
5735 let id = self.state.node_src.get_copy(node as usize);
5736 if id == 0 {
5737 return None;
5738 }
5739 let raw = *self.state.src_spans.get((id - 1) as usize)?;
5740 let name = unsafe { self.pool_string(raw.name) }?;
5741 Some(PortableSourceSpan {
5742 name,
5743 start: raw.start,
5744 end: raw.end,
5745 role: raw.role,
5746 })
5747 }
5748
5749 pub(crate) unsafe fn src_mark_token_start(engine: *mut Self) {
5753 let Some(engine) = engine.as_mut() else {
5754 return;
5755 };
5756 if engine.state.source_tracking && engine.state.curinput.statefield as i32 != 0 {
5757 engine.state.src_token_start = engine.state.curinput.locfield as integer;
5758 }
5759 }
5760
5761 pub(crate) unsafe fn src_record_buffer_span(engine: *mut Self) {
5766 let Some(engine) = engine.as_mut() else {
5767 return;
5768 };
5769 if !engine.state.source_tracking || engine.state.curinput.statefield as i32 == 0 {
5770 return;
5771 }
5772 let a = engine.src_buf_offset(engine.state.src_token_start);
5773 let b = engine.src_buf_offset(engine.state.curinput.locfield as integer);
5774 let (lo, hi) = if a <= b { (a, b) } else { (b, a) };
5775 let name = engine.state.curinput.namefield as strnumber;
5776 let id = engine.intern_span_raw(name, lo, hi, 0);
5777 engine.state.curinput.spanfield = id;
5778 engine.state.src_tok_span = id;
5779 if engine.state.curcs != 0
5796 && name == engine.state.src_primary_name
5797 && engine.state.scannerstatus as i32 == 0
5798 {
5799 engine.state.src_user_cmd_span = id;
5800 engine.state.src_anchor_cmd = 0;
5805 }
5806 }
5807
5808 pub(crate) unsafe fn src_tokenlist_span(engine: *mut Self) {
5815 let Some(engine) = engine.as_mut() else {
5816 return;
5817 };
5818 if !engine.state.source_tracking {
5819 return;
5820 }
5821 if engine.state.curinput.indexfield as i32 >= 5 {
5822 return;
5823 }
5824 {
5831 let lf = engine.state.curinput.locfield as i32;
5832 if lf >= 0 {
5833 let cid = engine.state.node_src.get_copy(lf as usize);
5834 if cid != 0 {
5835 engine.state.src_tok_span = cid;
5836 }
5837 }
5838 }
5839 let cell = engine.state.curinput.locfield as i32;
5840 if cell < 0 {
5841 return;
5842 }
5843 let id = engine.state.node_src.get_copy(cell as usize);
5844 if id != 0 {
5845 engine.state.curinput.spanfield = id;
5846 }
5847 }
5848
5849 pub(crate) unsafe fn src_back_input_stamp(engine: *mut Self, p: halfword) {
5861 let Some(engine) = engine.as_mut() else {
5862 return;
5863 };
5864 if !engine.state.source_tracking || p < 0 {
5865 return;
5866 }
5867 let id = engine.state.src_tok_span;
5868 if id != 0 {
5869 engine.state.node_src.set(p as usize, id);
5870 }
5871 }
5872
5873 pub(crate) unsafe fn src_latch_cmd_span(engine: *mut Self) {
5877 let Some(engine) = engine.as_mut() else {
5878 return;
5879 };
5880 if engine.state.source_tracking {
5881 engine.state.cmd_span = engine.state.curinput.spanfield;
5882 }
5883 }
5884
5885 pub(crate) unsafe fn src_stamp_avail(engine: *mut Self, node: halfword) {
5890 let Some(engine) = engine.as_mut() else {
5891 return;
5892 };
5893 if engine.state.source_tracking && node >= 0 {
5894 let id = engine.state.curinput.spanfield;
5895 engine.state.node_src.set(node as usize, id);
5896 engine.state.node_stack.set(node as usize, engine.state.cur_stack_head);
5897 }
5898 }
5899
5900 pub(crate) unsafe fn src_stamp_node_range(engine: *mut Self, node: halfword, size: integer) {
5907 let Some(engine) = engine.as_mut() else {
5908 return;
5909 };
5910 if !engine.state.source_tracking || node < 0 || size <= 0 {
5911 return;
5912 }
5913 let id = engine.state.cmd_span;
5914 let head = engine.state.cur_stack_head;
5915 let base = node as usize;
5916 for i in 0..size as usize {
5917 if id != 0 {
5918 engine.state.node_src.set(base + i, id);
5919 }
5920 if head != 0 {
5921 engine.state.node_stack.set(base + i, head);
5922 }
5923 }
5924 }
5925
5926 pub(crate) unsafe fn src_carry_copy(engine: *mut Self, src: halfword, dst: halfword) {
5935 let Some(engine) = engine.as_mut() else {
5936 return;
5937 };
5938 if !engine.state.source_tracking || src < 0 || dst < 0 {
5939 return;
5940 }
5941 let id = engine.state.node_src.get_copy(src as usize);
5942 if id != 0 {
5943 engine.state.node_src.set(dst as usize, id);
5944 let head = engine.state.node_stack.get_copy(src as usize);
5945 engine.state.node_stack.set(dst as usize, head);
5946 }
5947 }
5948
5949 pub(crate) unsafe fn src_carry_token_span(engine: *mut Self, dest: halfword, src: halfword) {
5962 let Some(engine) = engine.as_mut() else {
5963 return;
5964 };
5965 if !engine.state.source_tracking || dest < 0 || src < 0 {
5966 return;
5967 }
5968 let id = engine.state.node_src.get_copy(src as usize);
5969 if id != 0 {
5970 engine.state.node_src.set(dest as usize, id);
5971 let head = engine.state.node_stack.get_copy(src as usize);
5972 engine.state.node_stack.set(dest as usize, head);
5973 }
5974 }
5975
5976 pub(crate) unsafe fn src_stamp_char(engine: *mut Self, node: halfword) {
5981 let Some(engine) = engine.as_mut() else {
5982 return;
5983 };
5984 if !engine.state.source_tracking || node < 0 {
5985 return;
5986 }
5987 let id = engine.state.cmd_span;
5988 if id != 0 {
5989 engine.state.node_src.set(node as usize, id);
5990 }
5991 engine.state.node_stack.set(node as usize, engine.state.cur_stack_head);
5992 }
5993
5994 pub(crate) unsafe fn src_mlist_repoint(engine: *mut Self, q: halfword) {
5998 let Some(engine) = engine.as_mut() else {
5999 return;
6000 };
6001 if !engine.state.source_tracking || q < 0 {
6002 return;
6003 }
6004 let id = engine.state.node_src.get_copy(q as usize);
6005 if id != 0 {
6006 engine.state.cmd_span = id;
6007 }
6008 }
6009
6010 pub(crate) unsafe fn src_stamp_field(engine: *mut Self, field: halfword) {
6019 let Some(engine) = engine.as_mut() else {
6020 return;
6021 };
6022 if !engine.state.source_tracking || field < 0 {
6023 return;
6024 }
6025 let id = engine.state.curinput.spanfield;
6026 if id != 0 {
6027 engine.state.node_src.set(field as usize, id);
6028 }
6029 }
6030
6031 pub(crate) unsafe fn src_carry_field(engine: *mut Self, field: halfword, noad: halfword) {
6039 let Some(engine) = engine.as_mut() else {
6040 return;
6041 };
6042 if !engine.state.source_tracking || field < 0 || noad < 0 {
6043 return;
6044 }
6045 let id = engine.state.node_src.get_copy(field as usize);
6046 let head = engine.state.node_stack.get_copy(field as usize);
6047 if id != 0 {
6048 for i in 0..4usize {
6051 engine.state.node_src.set(noad as usize + i, id);
6052 }
6053 }
6054 if head != 0 {
6057 for i in 0..4usize {
6058 engine.state.node_stack.set(noad as usize + i, head);
6059 }
6060 }
6061 }
6062
6063 pub(crate) unsafe fn src_carry_nucleus(engine: *mut Self, noad: halfword, glyph: halfword) {
6076 let Some(engine) = engine.as_mut() else {
6077 return;
6078 };
6079 if !engine.state.source_tracking || noad < 0 || glyph < 0 {
6080 return;
6081 }
6082 let id = engine.state.node_src.get_copy(noad as usize + 1);
6083 if id != 0 {
6084 engine.state.node_src.set(glyph as usize, id);
6085 }
6086 let head = engine.state.node_stack.get_copy(noad as usize + 1);
6090 engine.state.node_stack.set(glyph as usize, head);
6091 }
6092
6093 pub(crate) unsafe fn src_carry_collapse(engine: *mut Self, noad: halfword, field: halfword) {
6100 let Some(engine) = engine.as_mut() else {
6101 return;
6102 };
6103 if !engine.state.source_tracking || noad < 0 || field < 0 {
6104 return;
6105 }
6106 let id = engine.state.node_src.get_copy(noad as usize);
6107 if id != 0 {
6108 engine.state.node_src.set(field as usize, id);
6109 }
6110 let head = engine.state.node_stack.get_copy(noad as usize);
6114 if head != 0 {
6115 engine.state.node_stack.set(field as usize, head);
6116 }
6117 }
6118
6119 pub(crate) unsafe fn src_save_cmd_span(engine: *mut Self) -> u32 {
6122 engine.as_ref().map_or(0, |engine| engine.state.cmd_span)
6123 }
6124
6125 pub(crate) unsafe fn src_restore_cmd_span(engine: *mut Self, saved: u32) {
6128 if let Some(engine) = engine.as_mut() {
6129 if engine.state.source_tracking {
6130 engine.state.cmd_span = saved;
6131 }
6132 }
6133 }
6134
6135 fn src_stack_push_span(self: &mut Self, span: SrcId) -> u32 {
6145 self.state.src_stack_cells.push(SrcStackCell {
6146 span,
6147 parent: self.state.cur_stack_head,
6148 start: 0,
6149 name: 0,
6150 pending: false,
6151 });
6152 let head = self.state.src_stack_cells.len() as u32;
6153 self.state.cur_stack_head = head;
6154 head
6155 }
6156
6157 fn src_stack_push_pending(self: &mut Self, start: u32, name: strnumber) -> u32 {
6160 self.state.src_stack_cells.push(SrcStackCell {
6161 span: 0,
6162 parent: self.state.cur_stack_head,
6163 start,
6164 name,
6165 pending: true,
6166 });
6167 let head = self.state.src_stack_cells.len() as u32;
6168 self.state.cur_stack_head = head;
6169 head
6170 }
6171
6172 fn src_stack_pop(self: &mut Self) {
6174 let head = self.state.cur_stack_head;
6175 if head != 0 {
6176 if let Some(cell) = self.state.src_stack_cells.get((head - 1) as usize) {
6177 self.state.cur_stack_head = cell.parent;
6178 }
6179 }
6180 }
6181
6182 pub(crate) unsafe fn src_end_token_list(engine: *mut Self, token_type: i32) {
6191 let Some(engine) = engine.as_mut() else {
6192 return;
6193 };
6194 if !engine.state.source_tracking {
6195 return;
6196 }
6197 let cand = engine.state.curinput.spanfield;
6198 if cand != 0 {
6199 let cand_end = engine
6200 .state
6201 .src_spans
6202 .get((cand - 1) as usize)
6203 .map(|r| r.end)
6204 .unwrap_or(0);
6205 let cur_end = if engine.state.src_call_argspan != 0 {
6206 engine
6207 .state
6208 .src_spans
6209 .get((engine.state.src_call_argspan - 1) as usize)
6210 .map(|r| r.end)
6211 .unwrap_or(0)
6212 } else {
6213 0
6214 };
6215 if engine.state.src_call_argspan == 0 || cand_end > cur_end {
6216 engine.state.src_call_argspan = cand;
6217 }
6218 }
6219 if token_type == 6 {
6220 engine.src_stack_pop();
6221 }
6222 }
6223
6224 pub(crate) unsafe fn src_scan_math_group_open(engine: *mut Self) {
6231 let Some(engine) = engine.as_mut() else {
6232 return;
6233 };
6234 if !engine.state.source_tracking {
6235 return;
6236 }
6237 let cmd = engine.state.cmd_span;
6238 let (start, name) = if cmd != 0 {
6239 match engine.state.src_spans.get((cmd - 1) as usize) {
6240 Some(raw) => (raw.start, raw.name),
6241 None => (0, 0),
6242 }
6243 } else {
6244 (0, 0)
6245 };
6246 engine.src_stack_push_pending(start, name);
6247 engine.state.src_grp_stack.push(engine.state.curinput.spanfield);
6252 }
6253
6254 pub(crate) unsafe fn src_scan_math_group_close(engine: *mut Self) {
6258 let eptr = engine;
6259 let Some(e) = engine.as_mut() else {
6260 return;
6261 };
6262 if !e.state.source_tracking {
6263 return;
6264 }
6265 e.state.src_grp_closing = e.state.src_grp_stack.pop().unwrap_or(0);
6269 let grp = e.state.src_grp_closing;
6270 let aux = e.state.curlist.auxfield.u.CINT;
6275 let frac = if aux > 0 && aux != -(268435455 as i32) { aux } else { -1 };
6276 if e.state.cur_stack_head != 0 {
6277 let idx = (e.state.cur_stack_head - 1) as usize;
6278 if let Some(cell) = e.state.src_stack_cells.get(idx).copied() {
6279 if cell.pending
6282 && cell.name != 0
6283 && cell.name == e.state.curinput.namefield as strnumber
6284 {
6285 let end = e.src_buf_offset(e.state.curinput.locfield as integer);
6286 let (lo, hi) = if cell.start <= end {
6287 (cell.start, end)
6288 } else {
6289 (end, cell.start)
6290 };
6291 let id = e.intern_span_raw(cell.name, lo, hi, 1);
6292 if let Some(c) = e.state.src_stack_cells.get_mut(idx) {
6293 c.span = id;
6294 c.pending = false;
6295 }
6296 }
6297 e.state.cur_stack_head = cell.parent;
6298 }
6299 }
6300 if frac >= 0 {
6301 Self::src_construct_extent(eptr, frac, grp);
6302 }
6303 }
6304
6305 pub(crate) unsafe fn src_construct_anchor(engine: *mut Self) {
6318 let Some(engine) = engine.as_mut() else {
6319 return;
6320 };
6321 if !engine.state.source_tracking {
6322 return;
6323 }
6324 let noad = engine.state.curlist.tailfield as i32;
6325 if noad < 0 {
6326 return;
6327 }
6328 let id = engine.state.node_src.get_copy(noad as usize);
6329 if id == 0 {
6330 return;
6331 }
6332 let Some(raw) = engine.state.src_spans.get((id - 1) as usize).copied() else {
6333 return;
6334 };
6335 let anchor = (engine.state.src_anchor_cmd != 0)
6349 .then(|| engine.state.src_spans.get((engine.state.src_anchor_cmd - 1) as usize).copied())
6350 .flatten()
6351 .filter(|u| u.name == raw.name);
6352 let chosen = match anchor {
6353 Some(u) => {
6354 if u.start < raw.start {
6355 Some(u)
6356 } else {
6357 None
6358 }
6359 }
6360 None => (engine.state.src_user_cmd_span != 0)
6361 .then(|| engine.state.src_spans.get((engine.state.src_user_cmd_span - 1) as usize).copied())
6362 .flatten()
6363 .filter(|u| u.name == raw.name && u.start < raw.start),
6364 };
6365 let Some(u) = chosen else {
6366 return;
6367 };
6368 let newid = engine.intern_span_raw(raw.name, u.start, raw.end, raw.role);
6369 engine.state.node_src.set(noad as usize, newid);
6370 }
6371
6372 pub(crate) unsafe fn src_construct_extend_to_loc(engine: *mut Self) {
6387 let e = match engine.as_ref() {
6388 Some(e) => e,
6389 None => return,
6390 };
6391 if !e.state.source_tracking {
6392 return;
6393 }
6394 let field = (*e
6397 .state
6398 .savestack
6399 .offset((e.state.saveptr as i32 + 0 as i32) as isize))
6400 .u
6401 .CINT;
6402 let noad = e.state.curlist.tailfield as i32;
6403 let grp = e.state.src_grp_closing;
6404 if noad < 0 || field != noad + 1 {
6405 return;
6406 }
6407 Self::src_construct_extent(engine, noad, grp);
6408 }
6409
6410 pub(crate) unsafe fn src_construct_extent(engine: *mut Self, noad: halfword, group_open: SrcId) {
6425 let Some(engine) = engine.as_mut() else {
6426 return;
6427 };
6428 if !engine.state.source_tracking || noad < 0 {
6429 return;
6430 }
6431 let id = engine.state.node_src.get_copy(noad as usize);
6432 if id == 0 {
6433 return;
6434 }
6435 let Some(raw) = engine.state.src_spans.get((id - 1) as usize).copied() else {
6436 return;
6437 };
6438 let (end, name) = if engine.state.curinput.statefield as i32 != 0 {
6439 (
6440 engine.src_buf_offset(engine.state.curinput.locfield as integer),
6441 engine.state.curinput.namefield as strnumber,
6442 )
6443 } else {
6444 let sid = engine.state.curinput.spanfield;
6445 if sid == 0 {
6446 return;
6447 }
6448 let Some(braw) = engine.state.src_spans.get((sid - 1) as usize).copied() else {
6449 return;
6450 };
6451 (braw.end, braw.name)
6452 };
6453 if raw.name != name {
6454 return;
6455 }
6456 let end = end.max(raw.end);
6457 let mut start = raw.start;
6458 if group_open != 0 {
6459 if let Some(g) = engine.state.src_spans.get((group_open - 1) as usize).copied() {
6460 if g.name == name && g.start < start {
6461 start = g.start;
6462 }
6463 }
6464 }
6465 if start == raw.start && end == raw.end {
6466 return;
6467 }
6468 let newid = engine.intern_span_raw(name, start, end, raw.role);
6469 engine.state.node_src.set(noad as usize, newid);
6470 }
6471
6472 pub(crate) unsafe fn src_leftright(engine: *mut Self, p: halfword, t: integer) {
6479 let Some(eng) = engine.as_mut() else {
6480 return;
6481 };
6482 if !eng.state.source_tracking {
6483 return;
6484 }
6485 if t == 30 as i32 {
6486 let cmd = eng.state.cmd_span;
6487 eng.state.src_grp_stack.push(cmd);
6488 } else if t == 31 as i32 {
6489 let open = eng.state.src_grp_stack.pop().unwrap_or(0);
6490 Self::src_construct_extent(engine, p, open);
6491 }
6492 }
6493
6494 pub fn node_enclosing_spans(&self, handle: PortableNodeHandle) -> Vec<PortableSourceSpan> {
6501 let node = handle.0 as halfword;
6502 let mut out: Vec<PortableSourceSpan> = Vec::new();
6503 if !self.state.source_tracking || node < 0 {
6504 return out;
6505 }
6506 let primary = self.resolve_node_src(node);
6507 let mut head = self.state.node_stack.get_copy(node as usize);
6508 let mut guard = 0u32;
6509 while head != 0 {
6510 guard += 1;
6511 if guard > 4096 {
6512 break;
6513 }
6514 let Some(cell) = self.state.src_stack_cells.get((head - 1) as usize) else {
6515 break;
6516 };
6517 let parent = cell.parent;
6518 let span_id = cell.span;
6519 head = parent;
6520 if span_id == 0 {
6521 continue;
6522 }
6523 let Some(raw) = self.state.src_spans.get((span_id - 1) as usize) else {
6524 continue;
6525 };
6526 let Some(name) = (unsafe { self.pool_string(raw.name) }) else {
6527 continue;
6528 };
6529 if let Some(p) = primary.as_ref() {
6530 if name != p.name || raw.start > p.start || raw.end < p.end {
6533 continue;
6534 }
6535 if raw.start == p.start && raw.end == p.end {
6536 continue;
6537 }
6538 }
6539 if let Some(last) = out.last() {
6540 if last.name == name && last.start == raw.start && last.end == raw.end {
6541 continue;
6542 }
6543 }
6544 out.push(PortableSourceSpan {
6545 name,
6546 start: raw.start,
6547 end: raw.end,
6548 role: 1,
6549 });
6550 }
6551 out
6552 }
6553
6554 pub(crate) unsafe fn src_begin_token_list(engine: *mut Self, t: quarterword) {
6559 let Some(engine) = engine.as_mut() else {
6560 return;
6561 };
6562 if !engine.state.source_tracking {
6563 return;
6564 }
6565 if t as i32 == 6 {
6567 let call = engine.state.pending_call_span;
6568 if call != 0 {
6569 engine.state.curinput.spanfield = call;
6570 }
6571 engine.state.pending_call_span = 0;
6572 engine.src_stack_push_span(call);
6576 }
6577 }
6578
6579 pub(crate) unsafe fn src_capture_tok_span(engine: *mut Self) -> u32 {
6597 engine.as_ref().map_or(0, |engine| engine.state.src_tok_span)
6598 }
6599
6600 pub(crate) unsafe fn src_restore_tok_span(engine: *mut Self, saved: u32) {
6602 if let Some(engine) = engine.as_mut() {
6603 if engine.state.source_tracking {
6604 engine.state.src_tok_span = saved;
6605 }
6606 }
6607 }
6608
6609 pub(crate) unsafe fn src_macro_begin(engine: *mut Self) {
6613 let Some(engine) = engine.as_mut() else {
6614 return;
6615 };
6616 if !engine.state.source_tracking {
6617 return;
6618 }
6619 let span = engine.state.curinput.spanfield;
6620 engine.state.src_call_span = span;
6621 engine.state.src_call_state = engine.state.curinput.statefield as integer;
6622 engine.state.src_call_index = engine.state.curinput.indexfield as integer;
6623 engine.state.src_call_name = engine.state.curinput.namefield as strnumber;
6624 engine.state.src_call_argspan = 0;
6625 engine.state.src_call_user_span = engine.state.src_user_cmd_span;
6629 engine.state.src_call_start = if span != 0 {
6630 engine
6631 .state
6632 .src_spans
6633 .get((span - 1) as usize)
6634 .map(|s| s.start)
6635 .unwrap_or(0)
6636 } else {
6637 0
6638 };
6639 if engine.state.src_call_state == 0 && engine.state.src_call_index < 3 && span != 0 {
6650 if let Some(raw) = engine.state.src_spans.get((span - 1) as usize).copied() {
6651 if raw.name == engine.state.src_primary_name {
6652 engine.state.src_anchor_cmd = span;
6653 }
6654 }
6655 }
6656 }
6657
6658 unsafe fn src_arg_hull(self: &mut Self, n: integer) -> SrcId {
6665 let mut lo = u32::MAX;
6666 let mut hi = 0u32;
6667 let mut found = false;
6668 let mut name: strnumber = self.state.src_primary_name;
6669 if self.state.src_call_span != 0 {
6670 if let Some(raw) = self
6671 .state
6672 .src_spans
6673 .get((self.state.src_call_span - 1) as usize)
6674 {
6675 name = raw.name;
6676 lo = raw.start;
6677 hi = raw.end;
6678 found = true;
6679 }
6680 }
6681 let cmd_start = if found { lo } else { 0 };
6689 let zmem = self.state.zmem;
6690 let lo_b = self.state.memmin;
6691 let hi_b = self.state.memmax;
6692 for i in 0..n.max(0) {
6693 let mut p = self.state.pstack[i as usize];
6694 let mut guard = 0i32;
6695 while p >= lo_b && p <= hi_b && p as i64 != -(268435455 as i64) {
6696 guard += 1;
6697 if guard > 100000 {
6698 break;
6699 }
6700 let id = self.state.node_src.get_copy(p as usize);
6701 if id != 0 {
6702 if let Some(raw) = self.state.src_spans.get((id - 1) as usize) {
6703 if raw.name == name && raw.start >= cmd_start {
6704 if found {
6705 lo = lo.min(raw.start);
6706 hi = hi.max(raw.end);
6707 } else {
6708 lo = raw.start;
6709 hi = raw.end;
6710 found = true;
6711 }
6712 }
6713 }
6714 }
6715 p = (*zmem.offset(p as isize)).hh.v.RH;
6716 }
6717 }
6718 for cand in [self.state.src_call_argspan, self.state.curinput.spanfield] {
6725 if cand == 0 {
6726 continue;
6727 }
6728 if let Some(raw) = self.state.src_spans.get((cand - 1) as usize) {
6729 if raw.name == name && raw.start >= cmd_start {
6730 if found {
6731 lo = lo.min(raw.start);
6732 hi = hi.max(raw.end);
6733 } else {
6734 lo = raw.start;
6735 hi = raw.end;
6736 found = true;
6737 }
6738 }
6739 }
6740 }
6741 if found && hi > lo {
6742 self.intern_span_raw(name, lo, hi, 1)
6743 } else {
6744 0
6745 }
6746 }
6747
6748 pub(crate) unsafe fn src_macro_set_pending(engine: *mut Self, n: integer) {
6766 let Some(engine) = engine.as_mut() else {
6767 return;
6768 };
6769 if !engine.state.source_tracking {
6770 return;
6771 }
6772 if engine.state.src_call_index == 0 && engine.state.src_call_span == 0 {
6773 engine.state.pending_call_span = 0;
6783 } else if engine.state.src_call_index == 0 {
6784 let hull = engine.src_arg_hull(n);
6787 engine.state.pending_call_span = if hull != 0 {
6788 hull
6789 } else {
6790 engine.state.src_call_span
6791 };
6792 } else if engine.state.curinput.statefield as i32 != 0 {
6793 let end = engine.src_buf_offset(engine.state.curinput.locfield as integer);
6803 let name = engine.state.curinput.namefield as strnumber;
6804 let mut start = engine.state.src_call_start.min(end);
6805 let user = engine.state.src_call_user_span;
6806 if user != 0 {
6807 if let Some(raw) = engine.state.src_spans.get((user - 1) as usize) {
6808 if raw.name == name && raw.start <= start {
6809 start = raw.start;
6810 }
6811 }
6812 }
6813 let id = engine.intern_span_raw(name, start, end, 1);
6814 engine.state.pending_call_span = id;
6815 } else if n > 0 {
6816 let hull = engine.src_arg_hull(n);
6827 engine.state.pending_call_span = if hull != 0 {
6828 hull
6829 } else {
6830 engine.state.src_call_span
6831 };
6832 } else {
6833 engine.state.pending_call_span = engine.state.src_call_span;
6834 }
6835 }
6836
6837 pub(crate) unsafe fn src_native_run_push(engine: *mut Self) {
6846 let Some(engine) = engine.as_mut() else {
6847 return;
6848 };
6849 if !engine.state.source_tracking {
6850 return;
6851 }
6852 let nativelen = engine.state.nativelen.max(0) as usize;
6853 let units = if engine.state.curchr as i64 > 65535 { 2 } else { 1 };
6856 let prev = nativelen.saturating_sub(units);
6857 if prev == 0 {
6858 engine.state.src_native_offsets.clear();
6859 }
6860 if engine.state.src_native_offsets.len() > prev {
6863 engine.state.src_native_offsets.truncate(prev);
6864 }
6865 let id = engine.state.curinput.spanfield;
6866 while engine.state.src_native_offsets.len() < nativelen {
6867 engine.state.src_native_offsets.push(id);
6868 }
6869 }
6870
6871 pub(crate) unsafe fn src_resolve_native_glyphs(
6887 engine: *mut Self,
6888 node: halfword,
6889 text: &[u16],
6890 glyphs: &mut [PortableNativeGlyph],
6891 ) {
6892 let Some(engine) = engine.as_mut() else {
6893 return;
6894 };
6895 if !engine.state.source_tracking {
6896 return;
6897 }
6898 let offsets = core::mem::take(&mut engine.state.src_native_offsets);
6899 if text.is_empty() || offsets.len() != text.len() {
6902 return;
6903 }
6904 if node < 0 {
6905 return;
6906 }
6907 let node_id = engine.state.node_src.get_copy(node as usize);
6910 if node_id == 0 {
6911 return;
6912 }
6913 let node_name = match engine.state.src_spans.get((node_id - 1) as usize) {
6914 Some(raw) => raw.name,
6915 None => return,
6916 };
6917 let s = String::from_utf16_lossy(text);
6923 let n = s.len();
6924 let mut byte_src = vec![0u32; n];
6925 let mut u16i = 0usize;
6926 for (b, ch) in s.char_indices() {
6927 let id = offsets.get(u16i).copied().unwrap_or(0);
6928 let upper = (b + ch.len_utf8()).min(n);
6929 for slot in byte_src.iter_mut().take(upper).skip(b) {
6930 *slot = id;
6931 }
6932 u16i += ch.len_utf16();
6933 }
6934 for gi in 0..glyphs.len() {
6935 let cs = (glyphs[gi].cluster_start as usize).min(n);
6936 let mut ce = n;
6940 for g2 in glyphs.iter() {
6941 let c2 = (g2.cluster_start as usize).min(n);
6942 if c2 > cs && c2 < ce {
6943 ce = c2;
6944 }
6945 }
6946 let mut lo = u32::MAX;
6947 let mut hi = 0u32;
6948 let mut found = false;
6949 for &id in byte_src.iter().take(ce).skip(cs) {
6950 if id == 0 {
6951 continue;
6952 }
6953 let Some(raw) = engine.state.src_spans.get((id - 1) as usize) else {
6954 continue;
6955 };
6956 if raw.name != node_name {
6957 continue;
6958 }
6959 lo = lo.min(raw.start);
6960 hi = hi.max(raw.end);
6961 found = true;
6962 }
6963 if found && hi > lo {
6964 glyphs[gi].src_start = lo;
6965 glyphs[gi].src_end = hi;
6966 }
6967 }
6968 }
6969
6970 pub fn input_source_spans(&self) -> Vec<PortableSourceSpan> {
6973 self.state
6974 .src_spans
6975 .iter()
6976 .filter_map(|raw| {
6977 let name = unsafe { self.pool_string(raw.name) }?;
6978 Some(PortableSourceSpan {
6979 name,
6980 start: raw.start,
6981 end: raw.end,
6982 role: raw.role,
6983 })
6984 })
6985 .collect()
6986 }
6987
6988 pub(crate) unsafe fn resolve_font_handle(
6989 engine: *mut PortableTexEngine<'_>,
6990 name: *mut ASCIIcode,
6991 size: integer,
6992 ) -> FontHandle {
6993 let Some(engine) = engine.as_mut() else {
6994 return 0;
6995 };
6996 let name_len = engine.state.namelength.max(0) as usize;
6997 let name = if name.is_null() || name_len == 0 {
6998 &[]
6999 } else {
7000 core::slice::from_raw_parts(name as *const i32, name_len)
7001 };
7002 engine.fonts.resolve_font_handle(name, size).unwrap_or(0)
7003 }
7004
7005 pub(crate) unsafe fn measure_font_metrics(
7006 engine: *mut PortableTexEngine<'_>,
7007 font: FontHandle,
7008 ascent: *mut integer,
7009 descent: *mut integer,
7010 xheight: *mut integer,
7011 capheight: *mut integer,
7012 slant: *mut integer,
7013 ) {
7014 let metrics = engine
7015 .as_mut()
7016 .map(|engine| engine.fonts.font_metrics(font))
7017 .unwrap_or_default();
7018 if !ascent.is_null() {
7019 *ascent = metrics.ascent;
7020 }
7021 if !descent.is_null() {
7022 *descent = metrics.descent;
7023 }
7024 if !xheight.is_null() {
7025 *xheight = metrics.xheight;
7026 }
7027 if !capheight.is_null() {
7028 *capheight = metrics.capheight;
7029 }
7030 if !slant.is_null() {
7031 *slant = metrics.slant;
7032 }
7033 }
7034
7035 pub(crate) unsafe fn get_native_mathsy_parameter(
7036 engine: *mut PortableTexEngine<'resources>,
7037 font: integer,
7038 param: integer,
7039 ) -> integer {
7040 let Some(engine) = engine.as_mut() else {
7041 return 0;
7042 };
7043 let Some(font_handle) = Self::font_handle_for_number(engine, font) else {
7044 return 0;
7045 };
7046 engine.fonts.math_symbol_parameter(font_handle, param)
7047 }
7048
7049 pub(crate) unsafe fn get_native_mathex_parameter(
7050 engine: *mut PortableTexEngine<'resources>,
7051 font: integer,
7052 param: integer,
7053 ) -> integer {
7054 let Some(engine) = engine.as_mut() else {
7055 return 0;
7056 };
7057 let Some(font_handle) = Self::font_handle_for_number(engine, font) else {
7058 return 0;
7059 };
7060 engine.fonts.math_extension_parameter(font_handle, param)
7061 }
7062
7063 pub(crate) unsafe fn get_ot_math_ital_corr(
7072 engine: *mut PortableTexEngine<'resources>,
7073 font: integer,
7074 glyph: integer,
7075 ) -> integer {
7076 let Some(engine) = engine.as_mut() else {
7077 return 0;
7078 };
7079 let Some(font_handle) = Self::font_handle_for_number(engine, font) else {
7080 return 0;
7081 };
7082 engine.fonts.math_glyph_italic_correction(font_handle, glyph)
7083 }
7084
7085 pub(crate) unsafe fn get_ot_math_variant(
7090 engine: *mut PortableTexEngine<'resources>,
7091 f_0: integer,
7092 g_0: integer,
7093 v: integer,
7094 adv: *mut integer,
7095 horiz: integer,
7096 ) -> integer {
7097 if !adv.is_null() {
7098 *adv = -1;
7099 }
7100 let Some(engine) = engine.as_mut() else {
7101 return g_0;
7102 };
7103 let Some(font_handle) = Self::font_handle_for_number(engine, f_0) else {
7104 return g_0;
7105 };
7106 let index = u16::try_from(v).unwrap_or(u16::MAX);
7107 match engine
7108 .fonts
7109 .math_glyph_variant(font_handle, g_0, index, horiz != 0)
7110 {
7111 Some(variant) => {
7112 if !adv.is_null() {
7113 *adv = variant.advance;
7114 }
7115 variant.glyph
7116 }
7117 None => g_0,
7118 }
7119 }
7120
7121 pub(crate) unsafe fn get_ot_assembly_ptr(
7127 engine: *mut PortableTexEngine<'resources>,
7128 f_0: integer,
7129 g_0: integer,
7130 horiz: integer,
7131 ) -> voidpointer {
7132 let Some(engine) = engine.as_mut() else {
7133 return nullptr;
7134 };
7135 let Some(font_handle) = Self::font_handle_for_number(engine, f_0) else {
7136 return nullptr;
7137 };
7138 let parts = engine
7139 .fonts
7140 .math_glyph_assembly(font_handle, g_0, horiz != 0);
7141 if parts.is_empty() {
7142 return nullptr;
7143 }
7144 let assembly = Box::new(GlyphAssembly { parts });
7145 Box::into_raw(assembly) as voidpointer
7146 }
7147
7148 pub(crate) unsafe fn ot_min_connector_overlap(
7151 engine: *mut PortableTexEngine<'resources>,
7152 f_0: integer,
7153 ) -> integer {
7154 let Some(engine) = engine.as_mut() else {
7155 return 0;
7156 };
7157 let Some(font_handle) = Self::font_handle_for_number(engine, f_0) else {
7158 return 0;
7159 };
7160 engine.fonts.math_min_connector_overlap(font_handle)
7161 }
7162
7163 unsafe fn math_glyph_height(
7165 engine: &mut PortableTexEngine<'resources>,
7166 f_0: integer,
7167 g_0: integer,
7168 ) -> scaled {
7169 let Some(font_handle) = Self::font_handle_for_number(engine, f_0) else {
7170 return 0;
7171 };
7172 let Ok(glyph) = u16::try_from(g_0) else {
7173 return 0;
7174 };
7175 engine.fonts.measure_native_glyph(font_handle, glyph, true).height
7176 }
7177
7178 unsafe fn math_glyph_depth(
7180 engine: &mut PortableTexEngine<'resources>,
7181 f_0: integer,
7182 g_0: integer,
7183 ) -> scaled {
7184 let Some(font_handle) = Self::font_handle_for_number(engine, f_0) else {
7185 return 0;
7186 };
7187 let Ok(glyph) = u16::try_from(g_0) else {
7188 return 0;
7189 };
7190 engine.fonts.measure_native_glyph(font_handle, glyph, true).depth
7191 }
7192
7193 unsafe fn math_kern_at(
7196 engine: &mut PortableTexEngine<'resources>,
7197 f_0: integer,
7198 g_0: integer,
7199 height: integer,
7200 corner: PortableMathKernCorner,
7201 ) -> integer {
7202 let Some(font_handle) = Self::font_handle_for_number(engine, f_0) else {
7203 return 0;
7204 };
7205 engine.fonts.math_kern_at(font_handle, g_0, corner, height)
7206 }
7207
7208 pub(crate) unsafe fn get_ot_math_kern(
7215 engine: *mut PortableTexEngine<'resources>,
7216 f_0: integer,
7217 g_0: integer,
7218 sf: integer,
7219 sg: integer,
7220 cmd: integer,
7221 shift_scaled: integer,
7222 ) -> integer {
7223 const SUP_CMD: integer = 0;
7224 const SUB_CMD: integer = 1;
7225 let Some(engine) = engine.as_mut() else {
7226 return 0;
7227 };
7228 let Some(font_handle) = Self::font_handle_for_number(engine, f_0) else {
7229 return 0;
7230 };
7231 let Some(sfont_handle) = Self::font_handle_for_number(engine, sf) else {
7232 return 0;
7233 };
7234
7235 let g_height_pt = Self::math_glyph_height(engine, f_0, g_0) as f32 / 65536.0;
7237 let g_depth_pt = Self::math_glyph_depth(engine, f_0, g_0) as f32 / 65536.0;
7238 let sg_height_pt = Self::math_glyph_height(engine, sf, sg) as f32 / 65536.0;
7239 let sg_depth_pt = Self::math_glyph_depth(engine, sf, sg) as f32 / 65536.0;
7240
7241 let g_height = engine.fonts.math_points_to_units(font_handle, g_height_pt) as integer;
7243 let g_depth = engine.fonts.math_points_to_units(font_handle, g_depth_pt) as integer;
7244 let sg_height = engine
7245 .fonts
7246 .math_points_to_units(sfont_handle, sg_height_pt) as integer;
7247 let sg_depth = engine
7248 .fonts
7249 .math_points_to_units(sfont_handle, sg_depth_pt) as integer;
7250 let shift_pt = shift_scaled as f32 / 65536.0;
7251 let shift = engine.fonts.math_points_to_units(font_handle, shift_pt) as integer;
7252
7253 let f_size = engine.fonts.math_point_size(font_handle);
7254 let sf_size = engine.fonts.math_point_size(sfont_handle);
7255 if f_size == 0.0 {
7256 return 0;
7257 }
7258 let scale_factor = sf_size / f_size;
7259
7260 let mut rval: integer;
7261 if cmd == SUP_CMD {
7262 let kern = Self::math_kern_at(
7263 engine,
7264 f_0,
7265 g_0,
7266 shift - (scale_factor * sg_depth as f32) as integer,
7267 PortableMathKernCorner::TopRight,
7268 );
7269 let skern =
7270 Self::math_kern_at(engine, sf, sg, -sg_depth, PortableMathKernCorner::BottomLeft);
7271 let top_kern = kern + (scale_factor * skern as f32) as integer;
7272
7273 let kern =
7274 Self::math_kern_at(engine, f_0, g_0, g_height, PortableMathKernCorner::TopRight);
7275 let skern = Self::math_kern_at(
7276 engine,
7277 sf,
7278 sg,
7279 ((g_height - shift) as f32 / scale_factor) as integer,
7280 PortableMathKernCorner::BottomLeft,
7281 );
7282 let bot_kern = kern + (scale_factor * skern as f32) as integer;
7283
7284 rval = if top_kern > bot_kern { top_kern } else { bot_kern };
7285 } else if cmd == SUB_CMD {
7286 let kern = Self::math_kern_at(
7287 engine,
7288 f_0,
7289 g_0,
7290 (scale_factor * sg_height as f32) as integer - shift,
7291 PortableMathKernCorner::BottomRight,
7292 );
7293 let skern =
7294 Self::math_kern_at(engine, sf, sg, sg_height, PortableMathKernCorner::TopLeft);
7295 let top_kern = kern + (scale_factor * skern as f32) as integer;
7296
7297 let kern =
7298 Self::math_kern_at(engine, f_0, g_0, -g_depth, PortableMathKernCorner::BottomRight);
7299 let skern = Self::math_kern_at(
7300 engine,
7301 sf,
7302 sg,
7303 ((shift - g_depth) as f32 / scale_factor) as integer,
7304 PortableMathKernCorner::TopLeft,
7305 );
7306 let bot_kern = kern + (scale_factor * skern as f32) as integer;
7307
7308 rval = if top_kern > bot_kern { top_kern } else { bot_kern };
7309 } else {
7310 return 0;
7311 }
7312
7313 rval = engine.fonts.math_units_to_scaled(font_handle, rval);
7314 rval
7315 }
7316
7317 pub(crate) unsafe fn get_native_word_cp(
7318 engine: *mut PortableTexEngine<'resources>,
7319 node: voidpointer,
7320 side: integer,
7321 ) -> integer {
7322 let Some(engine) = engine.as_mut() else {
7323 return 0;
7324 };
7325 let Some(node_index) = Self::node_index_for_pointer(engine, node) else {
7326 return 0;
7327 };
7328 let Some(info) = engine.native_glyph_infos.get(&node_index) else {
7329 return 0;
7330 };
7331 let glyph = if side == 0 {
7332 info.glyphs.first()
7333 } else {
7334 info.glyphs.last()
7335 };
7336 let Some(glyph) = glyph else {
7337 return 0;
7338 };
7339 let font = Self::native_node_font(engine.state.zmem, node_index);
7340 Self::character_protrusion(engine, font, u32::from(glyph.glyph_id), side)
7341 }
7342
7343 pub(crate) unsafe fn get_native_glyph(
7344 engine: *mut PortableTexEngine<'resources>,
7345 node: voidpointer,
7346 index: u32,
7347 ) -> uint16_t {
7348 let Some(engine) = engine.as_mut() else {
7349 return 0;
7350 };
7351 let Some(node_index) = Self::node_index_for_pointer(engine, node) else {
7352 return 0;
7353 };
7354 engine
7355 .native_glyph_infos
7356 .get(&node_index)
7357 .and_then(|info| info.glyphs.get(index as usize))
7358 .map_or(0, |glyph| glyph.glyph_id)
7359 }
7360
7361 pub(crate) unsafe fn get_character_protrusion(
7362 engine: *mut PortableTexEngine<'_>,
7363 font: integer,
7364 code: u32,
7365 side: integer,
7366 ) -> integer {
7367 engine
7368 .as_mut()
7369 .map_or(0, |engine| Self::character_protrusion(engine, font, code, side))
7370 }
7371
7372 pub(crate) fn character_protrusion(
7373 engine: &PortableTexEngine<'_>,
7374 font: integer,
7375 code: u32,
7376 side: integer,
7377 ) -> integer {
7378 engine
7379 .character_protrusions
7380 .get(&(font, code, side))
7381 .copied()
7382 .unwrap_or(0)
7383 }
7384
7385 pub(crate) fn set_character_protrusion(
7386 engine: &mut PortableTexEngine<'_>,
7387 font: integer,
7388 code: u32,
7389 side: integer,
7390 value: integer,
7391 ) {
7392 let key = (font, code, side);
7393 if value == 0 {
7394 engine.character_protrusions.remove(&key);
7395 } else {
7396 engine.character_protrusions.insert(key, value);
7397 }
7398 }
7399
7400 pub(crate) unsafe fn get_opentype_math_constant(
7401 engine: *mut PortableTexEngine<'resources>,
7402 font: integer,
7403 constant: integer,
7404 ) -> integer {
7405 let Some(engine) = engine.as_mut() else {
7406 return 0;
7407 };
7408 let Some(font_handle) = Self::font_handle_for_number(engine, font) else {
7409 return 0;
7410 };
7411 engine.fonts.opentype_math_constant(font_handle, constant)
7412 }
7413
7414 pub(crate) unsafe fn get_opentype_math_accent_position(
7415 engine: *mut PortableTexEngine<'resources>,
7416 font: integer,
7417 glyph: integer,
7418 ) -> integer {
7419 let Some(engine) = engine.as_mut() else {
7420 return 0;
7421 };
7422 let Some(font_handle) = Self::font_handle_for_number(engine, font) else {
7423 return 0;
7424 };
7425 engine.fonts.opentype_math_accent_position(font_handle, glyph)
7426 }
7427
7428 pub(crate) unsafe fn map_char_to_glyph(
7429 engine: *mut PortableTexEngine<'resources>,
7430 font: integer,
7431 ch: integer,
7432 ) -> integer {
7433 let Some(engine) = engine.as_mut() else {
7434 return 0;
7435 };
7436 let Some(font_handle) = Self::font_handle_for_number(engine, font) else {
7437 return 0;
7438 };
7439 engine.fonts.map_char_to_glyph(font_handle, ch)
7440 }
7441
7442 pub(crate) unsafe fn map_glyph_to_index(
7443 engine: *mut PortableTexEngine<'resources>,
7444 font: integer,
7445 ) -> integer {
7446 let Some(engine) = engine.as_mut() else {
7447 return 0;
7448 };
7449 let Some(font_handle) = Self::font_handle_for_number(engine, font) else {
7450 return 0;
7451 };
7452 let Some(name) = engine.pool_string(engine.state.curname) else {
7453 return 0;
7454 };
7455 engine.fonts.map_glyph_to_index(font_handle, name.as_str())
7456 }
7457
7458 pub(crate) unsafe fn ot_font_get(
7463 engine: *mut PortableTexEngine<'resources>,
7464 what: integer,
7465 font: integer,
7466 param1: integer,
7467 param2: integer,
7468 param3: integer,
7469 ) -> integer {
7470 let Some(engine) = engine.as_mut() else {
7471 return 0;
7472 };
7473 let Some(font_handle) = Self::font_handle_for_number(engine, font) else {
7474 return 0;
7475 };
7476 engine
7477 .fonts
7478 .ot_font_get(font_handle, what, param1, param2, param3)
7479 }
7480
7481 pub(crate) unsafe fn is_opentype_math_font(
7482 engine: *mut PortableTexEngine<'_>,
7483 font: FontHandle,
7484 ) -> boolean {
7485 engine
7486 .as_mut()
7487 .map(|engine| engine.fonts.is_opentype_math_font(font) as boolean)
7488 .unwrap_or(false_0)
7489 }
7490
7491 pub(crate) unsafe fn using_opentype(
7492 engine: *mut PortableTexEngine<'_>,
7493 font: FontHandle,
7494 ) -> boolean {
7495 engine
7496 .as_mut()
7497 .map(|engine| engine.fonts.using_opentype(font) as boolean)
7498 .unwrap_or(false_0)
7499 }
7500
7501 pub(crate) unsafe fn release_font_engine(
7502 engine: *mut PortableTexEngine<'_>,
7503 font: FontHandle,
7504 type_flag: integer,
7505 ) {
7506 if let Some(engine) = engine.as_mut() {
7507 engine.fonts.release_font_handle(font, type_flag);
7508 }
7509 }
7510
7511 pub(crate) unsafe fn measure_opentype_font_metrics(
7512 engine: *mut PortableTexEngine<'_>,
7513 font: FontHandle,
7514 ascent: *mut integer,
7515 descent: *mut integer,
7516 xheight: *mut integer,
7517 capheight: *mut integer,
7518 slant: *mut integer,
7519 ) {
7520 let metrics = engine
7521 .as_mut()
7522 .map(|engine| engine.fonts.opentype_font_metrics(font))
7523 .unwrap_or_default();
7524 if !ascent.is_null() {
7525 *ascent = metrics.ascent;
7526 }
7527 if !descent.is_null() {
7528 *descent = metrics.descent;
7529 }
7530 if !xheight.is_null() {
7531 *xheight = metrics.xheight;
7532 }
7533 if !capheight.is_null() {
7534 *capheight = metrics.capheight;
7535 }
7536 if !slant.is_null() {
7537 *slant = metrics.slant;
7538 }
7539 }
7540
7541 pub(crate) unsafe fn measure_native_node(
7542 engine: *mut PortableTexEngine<'resources>,
7543 node: voidpointer,
7544 use_glyph_metrics: integer,
7545 ) {
7546 let Some(engine) = engine.as_mut() else {
7547 return;
7548 };
7549 let Some(node_index) = Self::node_index_for_pointer(engine, node) else {
7550 return;
7551 };
7552 let mem = engine.state.zmem;
7553 let font_number = Self::native_node_font(mem, node_index);
7554 let Some(font_handle) = Self::font_handle_for_number(engine, font_number) else {
7555 return;
7556 };
7557 let text = Self::native_node_text(mem, node_index);
7558 let mut metrics =
7559 engine
7560 .fonts
7561 .shape_native_text(font_handle, text, use_glyph_metrics != 0);
7562 Self::src_resolve_native_glyphs(
7566 engine as *mut PortableTexEngine<'resources>,
7567 node_index,
7568 text,
7569 metrics.glyphs.as_mut_slice(),
7570 );
7571 Self::write_native_node_metrics(
7572 mem,
7573 node_index,
7574 metrics.width,
7575 metrics.height,
7576 metrics.depth,
7577 );
7578 (*mem.offset((node_index + 4) as isize)).v.QQQQ.u.B3 =
7579 (metrics.glyphs.len().min(i32::MAX as usize) as quarterword) as u16;
7580 (*mem.offset((node_index + 5) as isize)).ptr = nullptr;
7581 engine.native_glyph_infos.insert(
7582 node_index,
7583 PortableNativeGlyphInfo {
7584 glyphs: metrics.glyphs,
7585 },
7586 );
7587 }
7588
7589 pub(crate) unsafe fn measure_native_glyph(
7590 engine: *mut PortableTexEngine<'resources>,
7591 node: voidpointer,
7592 use_glyph_metrics: integer,
7593 ) {
7594 let Some(engine) = engine.as_mut() else {
7595 return;
7596 };
7597 let Some(node_index) = Self::node_index_for_pointer(engine, node) else {
7598 return;
7599 };
7600 let mem = engine.state.zmem;
7601 let font_number = Self::native_node_font(mem, node_index);
7602 let Some(font_handle) = Self::font_handle_for_number(engine, font_number) else {
7603 return;
7604 };
7605 let glyph = (*mem.offset((node_index + 4) as isize)).v.QQQQ.u.B2 as u16;
7606 let metrics = engine
7607 .fonts
7608 .measure_native_glyph(font_handle, glyph, use_glyph_metrics != 0);
7609 Self::write_native_node_metrics(
7610 mem,
7611 node_index,
7612 metrics.width,
7613 metrics.height,
7614 metrics.depth,
7615 );
7616 (*mem.offset((node_index + 4) as isize)).v.QQQQ.u.B3 = (1 as quarterword) as u16;
7617 engine.native_glyph_infos.insert(
7627 node_index,
7628 PortableNativeGlyphInfo {
7629 glyphs: Vec::from([PortableNativeGlyph {
7630 glyph_id: glyph,
7631 x: 0,
7632 y: 0,
7633 advance: metrics.width,
7634 cluster_start: 0,
7635 cluster_end: 0,
7636 src_start: 0,
7637 src_end: 0,
7638 }]),
7639 },
7640 );
7641 }
7642
7643 pub(crate) unsafe fn znotaatfonterror(
7644 self: &mut Self,
7645 cmd: integer,
7646 c_0: integer,
7647 f_0: integer,
7648 ) -> EngineFlow<()> {
7649 self.znototfonterror(cmd, c_0, f_0)?;
7650 Ok(())
7651 }
7652
7653 pub(crate) unsafe fn znotaatgrfonterror(
7654 self: &mut Self,
7655 cmd: integer,
7656 c_0: integer,
7657 f_0: integer,
7658 ) -> EngineFlow<()> {
7659 self.znototfonterror(cmd, c_0, f_0)?;
7660 Ok(())
7661 }
7662
7663 unsafe fn stack_glyph_into_box(
7668 self: &mut Self,
7669 b: halfword,
7670 f_0: internalfontnumber,
7671 g_0: integer,
7672 ) -> EngineFlow<()> {
7673 let mem: *mut memoryword = self.state.zmem.as_mut_ptr();
7674 const NULL: halfword = -(268435455 as i64) as halfword;
7675 let p = (&mut *(self as *mut PortableTexEngine<'_>)).zgetnode(5)?;
7676 (*mem.offset(p as isize)).hh.u.B0 = 8;
7677 (*mem.offset(p as isize)).hh.u.B1 = 42;
7678 (*mem.offset((p + 4) as isize)).v.QQQQ.u.B1 = (f_0 as quarterword) as u16;
7679 (*mem.offset((p + 4) as isize)).v.QQQQ.u.B2 = (g_0 as quarterword) as u16;
7680 Self::measure_native_glyph(
7681 self as *mut PortableTexEngine<'resources>,
7682 mem.offset(p as isize) as *mut memoryword as *mut (),
7683 1,
7684 );
7685 Ok(
7686 if (*mem.offset(b as isize)).hh.u.B0 as i32 == 0 {
7687 let mut q = (*mem.offset((b + 5) as isize)).hh.v.RH;
7688 if q == NULL {
7689 (*mem.offset((b + 5) as isize)).hh.v.RH = p;
7690 } else {
7691 while (*mem.offset(q as isize)).hh.v.RH != NULL {
7692 q = (*mem.offset(q as isize)).hh.v.RH;
7693 }
7694 (*mem.offset(q as isize)).hh.v.RH = p;
7695 if (*mem.offset((b + 3) as isize)).u.CINT
7696 < (*mem.offset((p + 3) as isize)).u.CINT
7697 {
7698 (*mem.offset((b + 3) as isize)).u.CINT = (*mem
7699 .offset((p + 3) as isize))
7700 .u
7701 .CINT;
7702 }
7703 if (*mem.offset((b + 2) as isize)).u.CINT
7704 < (*mem.offset((p + 2) as isize)).u.CINT
7705 {
7706 (*mem.offset((b + 2) as isize)).u.CINT = (*mem
7707 .offset((p + 2) as isize))
7708 .u
7709 .CINT;
7710 }
7711 }
7712 } else {
7713 (*mem.offset(p as isize)).hh.v.RH = (*mem.offset((b + 5) as isize))
7714 .hh
7715 .v
7716 .RH;
7717 (*mem.offset((b + 5) as isize)).hh.v.RH = p;
7718 (*mem.offset((b + 3) as isize)).u.CINT = (*mem.offset((p + 3) as isize))
7719 .u
7720 .CINT;
7721 if (*mem.offset((b + 1) as isize)).u.CINT
7722 < (*mem.offset((p + 1) as isize)).u.CINT
7723 {
7724 (*mem.offset((b + 1) as isize)).u.CINT = (*mem
7725 .offset((p + 1) as isize))
7726 .u
7727 .CINT;
7728 }
7729 },
7730 )
7731 }
7732
7733 unsafe fn stack_glue_into_box(
7736 self: &mut Self,
7737 b: halfword,
7738 min: scaled,
7739 max: scaled,
7740 ) -> EngineFlow<()> {
7741 let mem: *mut memoryword = self.state.zmem.as_mut_ptr();
7742 const NULL: halfword = -(268435455 as i64) as halfword;
7743 const ZERO_GLUE: halfword = 0;
7744 let q = (&mut *(self as *mut PortableTexEngine<'_>)).znewspec(ZERO_GLUE)?;
7745 (*mem.offset((q + 1) as isize)).u.CINT = min;
7746 (*mem.offset((q + 2) as isize)).u.CINT = max - min;
7747 let p = (&mut *(self as *mut PortableTexEngine<'_>)).znewglue(q)?;
7748 Ok(
7749 if (*mem.offset(b as isize)).hh.u.B0 as i32 == 0 {
7750 let mut r = (*mem.offset((b + 5) as isize)).hh.v.RH;
7751 if r == NULL {
7752 (*mem.offset((b + 5) as isize)).hh.v.RH = p;
7753 } else {
7754 while (*mem.offset(r as isize)).hh.v.RH != NULL {
7755 r = (*mem.offset(r as isize)).hh.v.RH;
7756 }
7757 (*mem.offset(r as isize)).hh.v.RH = p;
7758 }
7759 } else {
7760 (*mem.offset(p as isize)).hh.v.RH = (*mem.offset((b + 5) as isize))
7761 .hh
7762 .v
7763 .RH;
7764 (*mem.offset((b + 5) as isize)).hh.v.RH = p;
7765 (*mem.offset((b + 3) as isize)).u.CINT = (*mem.offset((p + 3) as isize))
7766 .u
7767 .CINT;
7768 (*mem.offset((b + 1) as isize)).u.CINT = (*mem.offset((p + 1) as isize))
7769 .u
7770 .CINT;
7771 },
7772 )
7773 }
7774
7775 pub(crate) unsafe fn zbuildopentypeassembly(
7780 self: &mut Self,
7781 f_0: internalfontnumber,
7782 assembly: voidpointer,
7783 s: scaled,
7784 horiz_flag: integer,
7785 ) -> EngineFlow<halfword> {
7786 let mem: *mut memoryword = self.state.zmem.as_mut_ptr();
7787 let horiz = horiz_flag != 0;
7788 let b = (&mut *(self as *mut PortableTexEngine<'_>)).newnullbox()?;
7789 (*mem.offset(b as isize)).hh.u.B0 = if horiz { 0 } else { 1 };
7790 let parts: &[PortableMathAssemblyPart] = if assembly.is_null() {
7791 &[]
7792 } else {
7793 &(*(assembly as *const GlyphAssembly)).parts
7794 };
7795 let part_count = parts.len();
7796 let min_o = Self::ot_min_connector_overlap(
7797 self as *mut PortableTexEngine<'resources>,
7798 f_0 as i32,
7799 );
7800 let mut n: integer = -1;
7801 let mut no_extenders = true;
7802 loop {
7803 n += 1;
7804 let mut s_max: scaled = 0;
7805 let mut prev_o: scaled = 0;
7806 for part in parts.iter() {
7807 if part.extender {
7808 no_extenders = false;
7809 for _ in 0..n {
7810 let mut o = part.start_connector;
7811 if min_o < o {
7812 o = min_o;
7813 }
7814 if prev_o < o {
7815 o = prev_o;
7816 }
7817 s_max = s_max - o + part.full_advance;
7818 prev_o = part.end_connector;
7819 }
7820 } else {
7821 let mut o = part.start_connector;
7822 if min_o < o {
7823 o = min_o;
7824 }
7825 if prev_o < o {
7826 o = prev_o;
7827 }
7828 s_max = s_max - o + part.full_advance;
7829 prev_o = part.end_connector;
7830 }
7831 }
7832 if s_max >= s || no_extenders {
7833 break;
7834 }
7835 }
7836 let mut prev_o: scaled = 0;
7837 for i in 0..part_count {
7838 let part = parts[i];
7839 let reps = if part.extender { n } else { 1 };
7840 for _ in 0..reps {
7841 let mut o = part.start_connector;
7842 if prev_o < o {
7843 o = prev_o;
7844 }
7845 let oo = o;
7846 if min_o < o {
7847 o = min_o;
7848 }
7849 if oo > 0 {
7850 (&mut *(self as *mut PortableTexEngine<'_>))
7851 .stack_glue_into_box(b, -oo, -o)?;
7852 }
7853 let g = part.glyph;
7854 (&mut *(self as *mut PortableTexEngine<'_>))
7855 .stack_glyph_into_box(b, f_0, g)?;
7856 prev_o = part.end_connector;
7857 }
7858 }
7859 const NULL: halfword = -(268435455 as i64) as halfword;
7860 let mut p = (*mem.offset((b + 5) as isize)).hh.v.RH;
7861 let mut nat: scaled = 0;
7862 let mut str_: scaled = 0;
7863 while p != NULL {
7864 let ty = (*mem.offset(p as isize)).hh.u.B0 as i32;
7865 if ty == 8 {
7866 if horiz {
7867 nat += (*mem.offset((p + 1) as isize)).u.CINT;
7868 } else {
7869 nat
7870 += (*mem.offset((p + 3) as isize)).u.CINT
7871 + (*mem.offset((p + 2) as isize)).u.CINT;
7872 }
7873 } else if ty == 10 {
7874 let spec = (*mem.offset((p + 1) as isize)).hh.v.LH;
7875 nat += (*mem.offset((spec + 1) as isize)).u.CINT;
7876 str_ += (*mem.offset((spec + 2) as isize)).u.CINT;
7877 }
7878 p = (*mem.offset(p as isize)).hh.v.RH;
7879 }
7880 if s > nat && str_ > 0 {
7881 let mut o = s - nat;
7882 if o > str_ {
7883 o = str_;
7884 }
7885 (*mem.offset((b + 5) as isize)).hh.u.B1 = 0;
7886 (*mem.offset((b + 5) as isize)).hh.u.B0 = 1;
7887 (*mem.offset((b + 6) as isize)).gr = o as f64 / str_ as f64;
7888 let stretched = nat
7889 + (str_ as f64 * (*mem.offset((b + 6) as isize)).gr).round() as scaled;
7890 if horiz {
7891 (*mem.offset((b + 1) as isize)).u.CINT = stretched;
7892 } else {
7893 (*mem.offset((b + 3) as isize)).u.CINT = stretched;
7894 }
7895 } else if horiz {
7896 (*mem.offset((b + 1) as isize)).u.CINT = nat;
7897 } else {
7898 (*mem.offset((b + 3) as isize)).u.CINT = nat;
7899 }
7900 Ok(b)
7901 }
7902
7903}
7904
7905pub(crate) unsafe fn fputs(_text: const_string, _file: NativeFileHandle) -> i32 {
7906 0
7907}
7908
7909pub(crate) unsafe fn free(_ptr: voidpointer) {}
7910
7911pub(crate) unsafe fn xrealloc(old_address: address, _new_size: size_t) -> address {
7912 old_address
7913}
7914
7915pub(crate) unsafe fn getcreationdate() {}
7916
7917pub(crate) unsafe fn getfilemoddate(_s: integer) {}
7918
7919pub(crate) unsafe fn getfilesize(_s: integer) {}
7920
7921pub(crate) unsafe fn getfiledump(_s: integer, _offset: i32, _length: i32) {}
7922
7923pub(crate) unsafe fn getmd5sum(_s: integer, _file: i32) {}
7924
7925pub(crate) unsafe fn u_close_file_or_pipe(file: *mut unicodefile) {
7926 if !file.is_null() {
7927 PortableTexEngine::boundary_close_file(*file);
7928 *file = core::ptr::null_mut();
7929 }
7930}
7931
7932pub(crate) unsafe fn setinputfileencoding(
7933 file: unicodefile,
7934 mode: integer,
7935 _encoding_data: integer,
7936) {
7937 if file.is_null() {
7941 return;
7942 }
7943 let handle = &mut *file;
7944 handle.encoding = match mode {
7945 1 => InputEncoding::Utf8,
7946 2 => InputEncoding::Utf16Be,
7947 3 => InputEncoding::Utf16Le,
7948 4 => InputEncoding::Bytes,
7949 0 => InputEncoding::Utf8, _ => InputEncoding::Bytes,
7951 };
7952}
7953
7954pub(crate) unsafe fn usingGraphite(_engine: FontHandle) -> boolean {
7955 false_0
7956}
7957
7958pub(crate) unsafe fn aatprintfontname(
7959 _what: i32,
7960 _attrs: CFDictionaryRef,
7961 _param1: i32,
7962 _param2: i32,
7963) {
7964}
7965
7966pub(crate) unsafe fn grprintfontname(
7967 _what: integer,
7968 _engine: voidpointer,
7969 _param1: integer,
7970 _param2: integer,
7971) {
7972}
7973
7974pub(crate) unsafe fn printglyphname(_font: integer, _gid: integer) {}
7975
7976pub(crate) unsafe fn getnativecharheightdepth(
7977 _font: integer,
7978 _ch: integer,
7979 height: *mut integer,
7980 depth: *mut integer,
7981) {
7982 if !height.is_null() {
7983 *height = 0;
7984 }
7985 if !depth.is_null() {
7986 *depth = 0;
7987 }
7988}
7989
7990pub(crate) unsafe fn getnativecharsidebearings(
7991 _font: integer,
7992 _ch: integer,
7993 lsb: *mut integer,
7994 rsb: *mut integer,
7995) {
7996 if !lsb.is_null() {
7997 *lsb = 0;
7998 }
7999 if !rsb.is_null() {
8000 *rsb = 0;
8001 }
8002}
8003
8004pub(crate) unsafe fn getnativecharwd(_font: integer, _ch: integer) -> integer {
8005 0
8006}
8007
8008pub(crate) unsafe fn getnativecharht(_font: integer, _ch: integer) -> integer {
8009 0
8010}
8011
8012pub(crate) unsafe fn getnativechardp(_font: integer, _ch: integer) -> integer {
8013 0
8014}
8015
8016pub(crate) unsafe fn getnativecharic(_font: integer, _ch: integer) -> integer {
8017 0
8018}
8019
8020pub(crate) unsafe fn getglyphbounds(_font: integer, _edge: integer, _gid: integer) -> integer {
8021 0
8022}
8023
8024pub(crate) unsafe fn getfontcharrange(_font: integer, _first: i32) -> integer {
8025 0
8026}
8027
8028pub(crate) unsafe fn get_native_italic_correction(_node: voidpointer) -> Fixed {
8029 0
8030}
8031
8032pub(crate) unsafe fn get_native_glyph_italic_correction(_node: voidpointer) -> Fixed {
8033 0
8034}
8035
8036pub(crate) unsafe fn applymapping(
8037 _mapping: voidpointer,
8038 _text: *mut uint16_t,
8039 text_len: i32,
8040) -> i32 {
8041 text_len
8042}
8043
8044pub(crate) unsafe fn checkfortfmfontmapping() {}
8045
8046pub(crate) unsafe fn loadtfmfontmapping() -> voidpointer {
8047 nullptr
8048}
8049
8050pub(crate) unsafe fn applytfmfontmapping(_mapping: voidpointer, c_0: i32) -> i32 {
8051 c_0
8052}
8053
8054pub(crate) unsafe fn set_cp_code(
8055 _font_num: i32,
8056 _code: u32,
8057 _side: i32,
8058 _value: i32,
8059) -> i32 {
8060 0
8061}
8062
8063pub(crate) unsafe fn countpdffilepages() -> i32 {
8064 0
8065}
8066
8067pub(crate) unsafe fn aatfontget(_what: i32, _attrs: CFDictionaryRef) -> i32 {
8068 0
8069}
8070
8071pub(crate) unsafe fn aatfontget1(_what: i32, _attrs: CFDictionaryRef, _param: i32) -> i32 {
8072 0
8073}
8074
8075pub(crate) unsafe fn aatfontget2(
8076 _what: i32,
8077 _attrs: CFDictionaryRef,
8078 _param1: i32,
8079 _param2: i32,
8080) -> i32 {
8081 0
8082}
8083
8084pub(crate) unsafe fn aatfontgetnamed(_what: i32, _attrs: CFDictionaryRef) -> i32 {
8085 0
8086}
8087
8088pub(crate) unsafe fn aatfontgetnamed1(
8089 _what: i32,
8090 _attrs: CFDictionaryRef,
8091 _param: i32,
8092) -> i32 {
8093 0
8094}
8095
8096pub(crate) unsafe fn grfontgetnamed(_what: integer, _engine: voidpointer) -> integer {
8097 0
8098}
8099
8100pub(crate) unsafe fn grfontgetnamed1(
8101 _what: integer,
8102 _engine: voidpointer,
8103 _param: integer,
8104) -> integer {
8105 0
8106}
8107
8108pub(crate) unsafe fn otfontget(_what: integer, _engine: voidpointer) -> integer {
8109 0
8110}
8111
8112pub(crate) unsafe fn otfontget1(
8113 _what: integer,
8114 _engine: voidpointer,
8115 _param: integer,
8116) -> integer {
8117 0
8118}
8119
8120pub(crate) unsafe fn otfontget2(
8121 _what: integer,
8122 _engine: voidpointer,
8123 _param1: integer,
8124 _param2: integer,
8125) -> integer {
8126 0
8127}
8128
8129pub(crate) unsafe fn otfontget3(
8130 _what: integer,
8131 _engine: voidpointer,
8132 _param1: integer,
8133 _param2: integer,
8134 _param3: integer,
8135) -> integer {
8136 0
8137}
8138
8139pub(crate) unsafe fn free_ot_assembly(assembly: *mut GlyphAssembly) {
8147 if !assembly.is_null() {
8148 drop(Box::from_raw(assembly));
8149 }
8150}
8151
8152#[cfg(test)]
8153mod tests {
8154 use super::*;
8155
8156 fn text_handle(bytes: Vec<u8>, encoding: InputEncoding) -> PortableFileHandle {
8158 let mut handle = PortableFileHandle::new(
8159 "test.tex".to_string(),
8160 ResourceKind::TexInput,
8161 None,
8162 resource_format_tex_input,
8163 bytes,
8164 );
8165 handle.encoding = encoding;
8166 handle
8167 }
8168
8169 fn decode_all(handle: &mut PortableFileHandle) -> Vec<u32> {
8171 let mut out = Vec::new();
8172 while let Some(scalar) = handle.next_input_scalar() {
8173 out.push(scalar);
8174 }
8175 out
8176 }
8177
8178 #[test]
8179 fn utf8_decoder_reads_multibyte_scalars() {
8180 let mut h = text_handle(vec![0xCE, 0xB1, 0xCE, 0xB2, 0xCE, 0xB3], InputEncoding::Utf8);
8182 assert_eq!(decode_all(&mut h), vec![0x3B1, 0x3B2, 0x3B3]);
8183 let mut h = text_handle(
8186 vec![b'A', 0xE2, 0x82, 0xAC, 0xF0, 0x9F, 0x98, 0x80],
8187 InputEncoding::Utf8,
8188 );
8189 assert_eq!(decode_all(&mut h), vec![0x41, 0x20AC, 0x1F600]);
8190 }
8191
8192 #[test]
8193 fn utf8_decoder_replaces_bad_sequences() {
8194 let mut h = text_handle(vec![0xCE, b'A'], InputEncoding::Utf8);
8197 assert_eq!(decode_all(&mut h), vec![0xFFFD, 0x41]);
8198 let mut h = text_handle(vec![0x80], InputEncoding::Utf8);
8202 assert_eq!(decode_all(&mut h), vec![0x80]);
8203 }
8204
8205 #[test]
8206 fn utf16_decoders_read_units_and_surrogates() {
8207 let mut h = text_handle(
8209 vec![0xB1, 0x03, 0xB2, 0x03, 0xB3, 0x03],
8210 InputEncoding::Utf16Le,
8211 );
8212 assert_eq!(decode_all(&mut h), vec![0x3B1, 0x3B2, 0x3B3]);
8213 let mut h = text_handle(
8215 vec![0x03, 0xB1, 0x03, 0xB2, 0x03, 0xB3],
8216 InputEncoding::Utf16Be,
8217 );
8218 assert_eq!(decode_all(&mut h), vec![0x3B1, 0x3B2, 0x3B3]);
8219 let mut h = text_handle(vec![0x3D, 0xD8, 0x00, 0xDE], InputEncoding::Utf16Le);
8221 assert_eq!(decode_all(&mut h), vec![0x1F600]);
8222 let mut h = text_handle(vec![0x3D, 0xD8, 0x41, 0x00], InputEncoding::Utf16Le);
8225 assert_eq!(decode_all(&mut h), vec![0xFFFD, 0x41]);
8226 let mut h = text_handle(vec![0x00, 0xDC], InputEncoding::Utf16Le);
8228 assert_eq!(decode_all(&mut h), vec![0xFFFD]);
8229 }
8230
8231 #[test]
8232 fn bytes_mode_reads_each_byte_raw() {
8233 let mut h = text_handle(vec![0xCE, 0xB1, 0x41], InputEncoding::Bytes);
8235 assert_eq!(decode_all(&mut h), vec![0xCE, 0xB1, 0x41]);
8236 }
8237
8238 #[test]
8239 fn bom_sniff_selects_encoding_and_consumes_bom() {
8240 let mut h = text_handle(vec![0xEF, 0xBB, 0xBF, b'A'], InputEncoding::Bytes);
8242 h.resolve_text_encoding_auto();
8243 assert_eq!(h.encoding, InputEncoding::Utf8);
8244 assert_eq!(h.cursor, 3);
8245 assert_eq!(decode_all(&mut h), vec![0x41]);
8246 let mut h = text_handle(vec![0xFE, 0xFF, 0x03, 0xB1], InputEncoding::Bytes);
8248 h.resolve_text_encoding_auto();
8249 assert_eq!(h.encoding, InputEncoding::Utf16Be);
8250 assert_eq!(h.cursor, 2);
8251 assert_eq!(decode_all(&mut h), vec![0x3B1]);
8252 let mut h = text_handle(vec![0xFF, 0xFE, 0xB1, 0x03], InputEncoding::Bytes);
8254 h.resolve_text_encoding_auto();
8255 assert_eq!(h.encoding, InputEncoding::Utf16Le);
8256 assert_eq!(h.cursor, 2);
8257 assert_eq!(decode_all(&mut h), vec![0x3B1]);
8258 let mut h = text_handle(vec![b'h', b'i'], InputEncoding::Bytes);
8260 h.resolve_text_encoding_auto();
8261 assert_eq!(h.encoding, InputEncoding::Utf8);
8262 assert_eq!(h.cursor, 0);
8263 let mut h = text_handle(vec![0x00, 0x41], InputEncoding::Bytes);
8265 h.resolve_text_encoding_auto();
8266 assert_eq!(h.encoding, InputEncoding::Utf16Be);
8267 assert_eq!(h.cursor, 0);
8268 assert_eq!(decode_all(&mut h), vec![0x41]);
8269 }
8270
8271 #[test]
8272 fn input_line_decodes_into_buffer_per_profile() {
8273 fn buffer_after_input_line(profile: EngineProfile, bytes: Vec<u8>) -> Vec<u32> {
8279 let image = PortableFormatImage::empty();
8280 let mut engine = PortableTexEngine::from_format(profile, &image, EmptyResourceProvider);
8281 engine.initialize_format_state();
8282 let mut handle = PortableFileHandle::new(
8285 "input.tex".to_string(),
8286 ResourceKind::TexInput,
8287 None,
8288 resource_format_tex_input,
8289 bytes,
8290 );
8291 PortableTexEngine::resolve_input_encoding(&engine, &mut handle);
8292 let raw = Box::into_raw(Box::new(handle));
8293 engine.state.first = 0;
8295 let ok = unsafe {
8296 PortableTexEngine::boundary_input_line(
8297 &mut engine as *mut PortableTexEngine<'_>,
8298 raw as NativeFileHandle,
8299 )
8300 };
8301 assert_ne!(ok, 0, "boundary_input_line should succeed");
8302 let first = engine.state.first.max(0) as usize;
8303 let last = engine.state.last.max(0) as usize;
8304 let out = (first..last)
8305 .map(|i| unsafe { *engine.state.buffer.offset(i as isize) as u32 })
8306 .collect();
8307 unsafe { drop(Box::from_raw(raw)) };
8308 out
8309 }
8310 let utf8 = vec![0xCE, 0xB1, 0xCE, 0xB2, 0xCE, 0xB3];
8312 assert_eq!(
8313 buffer_after_input_line(EngineProfile::xetex(), utf8.clone()),
8314 vec![0x3B1, 0x3B2, 0x3B3],
8315 "xetex must UTF-8 decode the input line"
8316 );
8317 assert_eq!(
8318 buffer_after_input_line(EngineProfile::tex(), utf8),
8319 vec![0xCE, 0xB1, 0xCE, 0xB2, 0xCE, 0xB3],
8320 "non-xetex must read raw bytes"
8321 );
8322 let utf16le_bom = vec![0xFF, 0xFE, 0xB1, 0x03, 0xB2, 0x03, 0xB3, 0x03];
8324 assert_eq!(
8325 buffer_after_input_line(EngineProfile::xetex(), utf16le_bom),
8326 vec![0x3B1, 0x3B2, 0x3B3],
8327 "xetex must UTF-16LE decode a BOM'd input line"
8328 );
8329 let utf16be_bom = vec![0xFE, 0xFF, 0x03, 0xB1, 0x03, 0xB2, 0x03, 0xB3];
8331 assert_eq!(
8332 buffer_after_input_line(EngineProfile::xetex(), utf16be_bom),
8333 vec![0x3B1, 0x3B2, 0x3B3],
8334 "xetex must UTF-16BE decode a BOM'd input line"
8335 );
8336 }
8337
8338 #[test]
8339 fn engine_abort_is_captured_at_runtime_boundary() {
8340 let image = PortableFormatImage::empty();
8341 let mut engine =
8342 PortableTexEngine::from_format(EngineProfile::tex(), &image, EmptyResourceProvider);
8343
8344 let completed = engine.catch_engine_abort(|engine| unsafe {
8345 PortableTexEngine::abort_engine(engine as *mut PortableTexEngine<'_>, 7)?;
8346 Ok(())
8347 });
8348
8349 assert!(!completed);
8350 assert_eq!(engine.last_abort_status(), Some(7));
8351 }
8352
8353 #[test]
8354 fn successful_engine_abort_completes_runtime_boundary() {
8355 let image = PortableFormatImage::empty();
8356 let mut engine =
8357 PortableTexEngine::from_format(EngineProfile::tex(), &image, EmptyResourceProvider);
8358
8359 let completed = engine.catch_engine_abort(|engine| unsafe {
8360 PortableTexEngine::abort_engine(engine as *mut PortableTexEngine<'_>, 0)?;
8361 Ok(())
8362 });
8363
8364 assert!(completed);
8365 assert_eq!(engine.last_abort_status(), None);
8366 }
8367}