1use std::collections::HashMap;
11use std::rc::Rc;
12
13use crate::Engine;
14use crate::cmd::Cmd;
15use crate::eqtb::{CodeTable, Meaning, Slot};
16use crate::fonts::{CharMetrics, FontInfo, FontKind};
17use crate::glue::Glue;
18use crate::hash::{CsId, CsKind, CsTable};
19use crate::nodes::{NodeData, NodeRef, id};
20use crate::token::{Macro, Token, TokenList};
21
22pub const MAGIC: &[u8; 8] = b"RETEXFMT";
24pub const FORMAT_VERSION: u32 = 7;
26
27#[derive(Debug, thiserror::Error)]
29pub enum FormatError {
30 #[error("not a format file for this version of retex")]
32 BadHeader,
33 #[error("the format file is corrupt ({0})")]
35 Corrupt(&'static str),
36}
37
38#[derive(Default)]
40pub struct Writer {
41 pub buf: Vec<u8>,
43}
44
45impl Writer {
46 pub fn u(&mut self, mut v: u64) {
48 loop {
49 let b = (v & 0x7F) as u8;
50 v >>= 7;
51 if v == 0 {
52 self.buf.push(b);
53 return;
54 }
55 self.buf.push(b | 0x80);
56 }
57 }
58
59 pub fn i(&mut self, v: i64) {
61 self.u(((v << 1) ^ (v >> 63)) as u64);
62 }
63
64 pub fn bytes(&mut self, b: &[u8]) {
66 self.u(b.len() as u64);
67 self.buf.extend_from_slice(b);
68 }
69
70 pub fn glue(&mut self, g: &Glue) {
72 self.i(g.width.into());
73 self.i(g.stretch.into());
74 self.i(g.shrink.into());
75 self.buf.push(g.stretch_order);
76 self.buf.push(g.shrink_order);
77 }
78}
79
80pub struct Reader<'a> {
82 data: &'a [u8],
83 pos: usize,
84}
85
86impl<'a> Reader<'a> {
87 pub fn new(data: &'a [u8]) -> Self {
89 Reader { data, pos: 0 }
90 }
91
92 pub fn at_end(&self) -> bool {
94 self.pos >= self.data.len()
95 }
96
97 pub fn u(&mut self) -> Result<u64, FormatError> {
99 let mut v: u64 = 0;
100 let mut shift = 0;
101 loop {
102 let b = *self
103 .data
104 .get(self.pos)
105 .ok_or(FormatError::Corrupt("unexpected end"))?;
106 self.pos += 1;
107 if shift >= 64 {
108 return Err(FormatError::Corrupt("varint too long"));
109 }
110 v |= u64::from(b & 0x7F) << shift;
111 if b & 0x80 == 0 {
112 return Ok(v);
113 }
114 shift += 7;
115 }
116 }
117
118 pub fn u32(&mut self) -> Result<u32, FormatError> {
120 u32::try_from(self.u()?).map_err(|_| FormatError::Corrupt("value out of range"))
121 }
122
123 pub fn i(&mut self) -> Result<i64, FormatError> {
125 let v = self.u()?;
126 Ok(((v >> 1) as i64) ^ -((v & 1) as i64))
127 }
128
129 pub fn i32(&mut self) -> Result<i32, FormatError> {
131 i32::try_from(self.i()?).map_err(|_| FormatError::Corrupt("value out of range"))
132 }
133
134 pub fn byte(&mut self) -> Result<u8, FormatError> {
136 let b = *self
137 .data
138 .get(self.pos)
139 .ok_or(FormatError::Corrupt("unexpected end"))?;
140 self.pos += 1;
141 Ok(b)
142 }
143
144 pub fn bytes(&mut self) -> Result<&'a [u8], FormatError> {
146 let n = self.u()? as usize;
147 let end = self
148 .pos
149 .checked_add(n)
150 .filter(|&e| e <= self.data.len())
151 .ok_or(FormatError::Corrupt("string too long"))?;
152 let s = &self.data[self.pos..end];
153 self.pos = end;
154 Ok(s)
155 }
156
157 pub fn glue(&mut self) -> Result<Glue, FormatError> {
159 Ok(Glue {
160 width: self.i32()?,
161 stretch: self.i32()?,
162 shrink: self.i32()?,
163 stretch_order: self.byte()?,
164 shrink_order: self.byte()?,
165 })
166 }
167}
168
169fn cmd_of(b: u8) -> Result<Cmd, FormatError> {
170 Cmd::ALL
171 .get(b as usize)
172 .copied()
173 .ok_or(FormatError::Corrupt("bad command code"))
174}
175
176fn kind_code(k: &CsKind) -> (u8, u32) {
177 match k {
178 CsKind::Active(c) => (0, *c),
179 CsKind::Null => (1, 0),
180 CsKind::Single(c) => (2, *c),
181 CsKind::Multi => (3, 0),
182 CsKind::Frozen => (4, 0),
183 CsKind::Undefined => (5, 0),
184 CsKind::Internal => (6, 0),
185 }
186}
187
188fn kind_from(code: u8, c: u32) -> Result<CsKind, FormatError> {
189 Ok(match code {
190 0 => CsKind::Active(c),
191 1 => CsKind::Null,
192 2 => CsKind::Single(c),
193 3 => CsKind::Multi,
194 4 => CsKind::Frozen,
195 5 => CsKind::Undefined,
196 6 => CsKind::Internal,
197 _ => return Err(FormatError::Corrupt("bad control sequence kind")),
198 })
199}
200
201#[derive(Default)]
203struct ListPool {
204 index: HashMap<*const Token, u32>,
205 lists: Vec<TokenList>,
206}
207
208impl ListPool {
209 fn id(&mut self, l: &TokenList) -> u32 {
210 let key = l.as_ptr();
211 if l.is_empty() {
212 return 0;
213 }
214 *self.index.entry(key).or_insert_with(|| {
215 self.lists.push(l.clone());
216 self.lists.len() as u32
217 })
218 }
219}
220
221impl Engine {
222 pub fn dump_engine(&self) -> Vec<u8> {
224 let mut w = Writer::default();
225 let mut pool = ListPool::default();
226 w.u(self.hash.len() as u64);
228 for (name, kind) in self.hash.entries() {
229 let (k, c) = kind_code(kind);
230 w.buf.push(k);
231 w.u(c.into());
232 w.bytes(name);
233 }
234 let mut defined: Vec<(u32, &Slot<Meaning>)> = Vec::new();
236 for (i, slot) in self.eqtb.cs.iter().enumerate() {
237 if slot.val.cmd != Cmd::UndefinedCs || slot.level != 0 {
238 defined.push((i as u32, slot));
239 }
240 }
241 let mut meanings = Writer::default();
242 meanings.u(defined.len() as u64);
243 for (i, slot) in defined {
244 meanings.u(i.into());
245 meanings.buf.push(slot.val.cmd as u8);
246 meanings.u(slot.val.chr.into());
247 meanings.u(slot.level.into());
248 match &slot.val.mac {
249 Some(m) => {
250 meanings.buf.push(if m.protected { 2 } else { 1 });
251 let id = pool.id(&m.tokens);
252 meanings.u(id.into());
253 }
254 None => meanings.buf.push(0),
255 }
256 }
257 let mut params = Writer::default();
259 for v in [&self.eqtb.int_par, &self.eqtb.dimen_par] {
260 params.u(v.len() as u64);
261 for s in v {
262 params.i(s.val.into());
263 }
264 }
265 params.u(self.eqtb.glue_par.len() as u64);
266 for s in &self.eqtb.glue_par {
267 params.glue(&s.val);
268 }
269 params.u(self.eqtb.toks_par.len() as u64);
270 for s in &self.eqtb.toks_par {
271 params.u(pool.id(&s.val).into());
272 }
273 let sparse_int = |w: &mut Writer, v: &[Slot<i32>], default: i32| {
275 let n = v.iter().filter(|s| s.val != default).count();
276 w.u(n as u64);
277 for (i, s) in v.iter().enumerate() {
278 if s.val != default {
279 w.u(i as u64);
280 w.i(s.val.into());
281 }
282 }
283 };
284 sparse_int(&mut params, &self.eqtb.count, 0);
285 sparse_int(&mut params, &self.eqtb.attr, crate::eqtb::UNUSED_ATTRIBUTE);
286 sparse_int(&mut params, &self.eqtb.dimen, 0);
287 for v in [&self.eqtb.skip, &self.eqtb.muskip] {
288 let n = v.iter().filter(|s| s.val != Glue::ZERO).count();
289 params.u(n as u64);
290 for (i, s) in v.iter().enumerate() {
291 if s.val != Glue::ZERO {
292 params.u(i as u64);
293 params.glue(&s.val);
294 }
295 }
296 }
297 let n = self.eqtb.toks.iter().filter(|s| !s.val.is_empty()).count();
298 params.u(n as u64);
299 for (i, s) in self.eqtb.toks.iter().enumerate() {
300 if !s.val.is_empty() {
301 params.u(i as u64);
302 params.u(pool.id(&s.val).into());
303 }
304 }
305 let n = self.eqtb.boxes.iter().filter(|s| !s.val.is_null()).count();
307 params.u(n as u64);
308 for (i, s) in self.eqtb.boxes.iter().enumerate() {
309 if !s.val.is_null() {
310 params.u(i as u64);
311 self.dump_node_list(&mut params, s.val, &mut pool);
312 }
313 }
314 params.u(self.eqtb.cur_font.val.into());
315 let n = self.eqtb.math_font.iter().filter(|s| s.val != 0).count();
316 params.u(n as u64);
317 for (i, s) in self.eqtb.math_font.iter().enumerate() {
318 if s.val != 0 {
319 params.u(i as u64);
320 params.u(s.val.into());
321 }
322 }
323 let shape = |w: &mut Writer, s: &Option<Rc<[i32]>>| match s {
324 None => w.u(0),
325 Some(v) => {
326 w.u(v.len() as u64 + 1);
327 for x in v.iter() {
328 w.i((*x).into());
329 }
330 }
331 };
332 shape(&mut params, &self.eqtb.par_shape.val);
333 params.u(self.eqtb.etex_shape.len() as u64);
334 for s in &self.eqtb.etex_shape {
335 shape(&mut params, &s.val);
336 }
337 let mut tables: Vec<(&u32, &CodeTable)> = self.eqtb.catcode_tables.iter().collect();
343 tables.sort_by_key(|(k, _)| **k);
344 let all: Vec<&CodeTable> = tables
345 .iter()
346 .map(|(_, t)| *t)
347 .chain([
348 &self.eqtb.lc,
349 &self.eqtb.uc,
350 &self.eqtb.sf,
351 &self.eqtb.math,
352 &self.eqtb.del,
353 ])
354 .collect();
355 let mut page_pool: Vec<Vec<u8>> = Vec::new();
356 let mut page_index: std::collections::HashMap<Vec<u8>, usize> =
357 std::collections::HashMap::new();
358 let mut refs: Vec<Vec<(usize, usize)>> = Vec::new();
359 for t in &all {
360 let mut r = Vec::new();
361 for (k, vals) in t.dump_pages() {
362 let mut raw = Vec::with_capacity(vals.len() * 8);
363 for v in vals {
364 raw.extend_from_slice(&v.to_le_bytes());
365 }
366 let next = page_pool.len();
367 let i = *page_index.entry(raw.clone()).or_insert(next);
368 if i == next {
369 page_pool.push(raw);
370 }
371 r.push((k, i));
372 }
373 refs.push(r);
374 }
375 params.u(page_pool.len() as u64);
376 for raw in &page_pool {
377 params.bytes(raw);
378 }
379 let code_table = |w: &mut Writer, r: &[(usize, usize)]| {
380 w.u(r.len() as u64);
381 for &(k, i) in r {
382 w.u(k as u64);
383 w.u(i as u64);
384 }
385 };
386 params.u(tables.len() as u64);
387 for ((k, _), r) in tables.iter().zip(&refs) {
388 params.u((**k).into());
389 code_table(&mut params, r);
390 }
391 for r in &refs[tables.len()..] {
392 code_table(&mut params, r);
393 }
394 let mut mp: Vec<(&u32, &Slot<i32>)> = self.eqtb.math_param.iter().collect();
395 mp.sort_by_key(|(k, _)| **k);
396 params.u(mp.len() as u64);
397 for (k, s) in mp {
398 params.u((*k).into());
399 params.i(s.val.into());
400 }
401 let mut fonts = Writer::default();
403 fonts.u(self.fonts.fonts.len() as u64);
404 for (f, fi) in self.fonts.fonts.iter().enumerate() {
405 fonts.bytes(&fi.name);
406 fonts.i(fi.size.into());
407 fonts.i(fi.design_size.into());
408 fonts.u(fi.checksum.into());
409 fonts.u(fi.params.len() as u64);
410 for p in &fi.params {
411 fonts.i((*p).into());
412 }
413 let mut chars: Vec<(&u32, &CharMetrics)> = fi.chars.iter().collect();
414 chars.sort_by_key(|(c, _)| **c);
415 fonts.u(chars.len() as u64);
416 for (c, m) in chars {
417 fonts.u((*c).into());
418 fonts.i(m.width.into());
419 fonts.i(m.height.into());
420 fonts.i(m.depth.into());
421 fonts.i(m.italic.into());
422 fonts.u(m.index.into());
423 }
424 fonts.i(fi.hyphen_char.into());
425 fonts.i(fi.skew_char.into());
426 fonts.buf.push(match fi.kind {
427 FontKind::Null => 0,
428 FontKind::Tfm => 1,
429 FontKind::OpenType => 2,
430 });
431 fonts.u(fi.handle);
432 fonts.u(self.fonts.id_cs.get(f).map_or(0, |c| c.0).into());
433 let raw = fi
434 .data
435 .as_ref()
436 .and_then(|d| d.0.downcast_ref::<crate::fonts::TfmData>())
437 .map(|t| t.raw.clone())
438 .unwrap_or_default();
439 fonts.bytes(&raw);
440 match &fi.math_constants {
441 None => fonts.u(0),
442 Some(m) => {
443 let mut kv: Vec<(&String, &i32)> = m.iter().collect();
444 kv.sort();
445 fonts.u(kv.len() as u64 + 1);
446 for (k, v) in kv {
447 fonts.bytes(k.as_bytes());
448 fonts.i((*v).into());
449 }
450 }
451 }
452 }
453 let mut misc = Writer::default();
455 let cs = &self.cs;
456 for id in [
457 cs.par,
458 cs.frozen_protection,
459 cs.frozen_cr,
460 cs.frozen_end_group,
461 cs.frozen_right,
462 cs.frozen_fi,
463 cs.frozen_end_template,
464 cs.frozen_endv,
465 cs.frozen_relax,
466 cs.end_write,
467 cs.frozen_dont_expand,
468 cs.frozen_special,
469 cs.frozen_null_font,
470 cs.end_local,
471 self.par_token_cs,
472 ] {
473 misc.u(id.0.into());
474 }
475 misc.bytes(self.format_ident.as_bytes());
476 misc.buf.push(self.err.interaction as u8);
477 let mut fp: Vec<(&Vec<u8>, &CsId)> = self.frozen_prims.iter().collect();
478 fp.sort();
479 misc.u(fp.len() as u64);
480 for (n, c) in fp {
481 misc.bytes(n);
482 misc.u(c.0.into());
483 }
484 let mut bc: Vec<(&&str, &CsId)> = self.backend_cs.iter().collect();
485 bc.sort();
486 misc.u(bc.len() as u64);
487 for (n, c) in bc {
488 misc.bytes(n.as_bytes());
489 misc.u(c.0.into());
490 }
491 for i in 0..8 {
493 misc.i(self.eqtb.dir_par.get(i).map_or(0, |d| d.val).into());
494 }
495 misc.u(self.math_glues.len() as u64);
496 for g in &self.math_glues {
497 misc.glue(g);
498 }
499 let mut lists = Writer::default();
501 lists.u(pool.lists.len() as u64);
502 for l in &pool.lists {
503 lists.u(l.len() as u64);
504 for t in l.iter() {
505 lists.u(t.0.into());
506 }
507 }
508 let mut langs = Writer::default();
510 let present: Vec<(usize, &retex_hyph::Language)> = self
511 .languages
512 .iter()
513 .enumerate()
514 .filter_map(|(i, l)| l.as_ref().map(|l| (i, l)))
515 .collect();
516 langs.u(present.len() as u64);
517 for (i, l) in present {
518 langs.u(i as u64);
519 langs.bytes(&l.to_bytes());
520 }
521 let mut out = Writer::default();
523 let parts = [
524 ("names", w),
525 ("token lists", lists),
526 ("meanings", meanings),
527 ("parameters and registers", params),
528 ("fonts", fonts),
529 ("misc", misc),
530 ("hyphenation", langs),
531 ];
532 for (name, part) in parts {
533 if crate::timing::enabled() {
534 eprintln!("[format] {:>10} bytes {name}", part.buf.len());
535 }
536 out.bytes(&part.buf);
537 }
538 out.buf
539 }
540
541 fn dump_node_list(&self, w: &mut Writer, mut p: NodeRef, pool: &mut ListPool) {
542 let mut items: Vec<NodeRef> = Vec::new();
543 while !p.is_null() {
544 items.push(p);
545 p = self.nodes.next(p);
546 }
547 w.u(items.len() as u64);
548 for p in items {
549 let n = self.nodes.get(p);
550 w.buf.push(n.id);
551 w.u(n.subtype.into());
552 match &n.data {
553 NodeData::Box(b) => {
554 for v in [b.width, b.depth, b.height, b.shift] {
555 w.i(v.into());
556 }
557 w.buf.push(b.dir as u8);
558 w.buf.push(b.glue_order);
559 w.buf.push(b.glue_sign);
560 w.u(b.glue_set.to_bits());
561 self.dump_node_list(w, b.head, pool);
562 }
563 NodeData::Glue { spec, .. } => w.glue(spec),
564 NodeData::Kern { kern, .. } => w.i((*kern).into()),
565 NodeData::Penalty { penalty } => w.i((*penalty).into()),
566 NodeData::Rule {
567 width,
568 depth,
569 height,
570 ..
571 } => {
572 for v in [*width, *depth, *height] {
573 w.i(v.into());
574 }
575 }
576 NodeData::Glyph(g) => {
577 w.u(g.chr.into());
578 w.u(g.font.into());
579 }
580 NodeData::Mark { class, mark } => {
581 w.u((*class).into());
582 w.u(pool.id(mark).into());
583 }
584 _ => {}
585 }
586 }
587 }
588
589 pub fn undump_engine(&mut self, data: &[u8]) -> Result<(), FormatError> {
593 let mut top = Reader::new(data);
594 let mut hash_r = Reader::new(top.bytes()?);
595 let mut lists_r = Reader::new(top.bytes()?);
596 let mut meanings_r = Reader::new(top.bytes()?);
597 let mut params_r = Reader::new(top.bytes()?);
598 let mut fonts_r = Reader::new(top.bytes()?);
599 let mut misc_r = Reader::new(top.bytes()?);
600 let mut langs_r = Reader::new(top.bytes()?);
601
602 let n = hash_r.u()? as usize;
604 let mut entries = Vec::with_capacity(n);
605 for _ in 0..n {
606 let k = hash_r.byte()?;
607 let c = hash_r.u32()?;
608 let name: Box<[u8]> = Box::from(hash_r.bytes()?);
609 entries.push((name, kind_from(k, c)?));
610 }
611 self.hash = CsTable::from_entries(entries);
612
613 crate::timing::mark("undump: hash");
614 let n = lists_r.u()? as usize;
616 let mut lists: Vec<TokenList> = Vec::with_capacity(n + 1);
617 lists.push(crate::token::empty_list());
618 for _ in 0..n {
619 let len = lists_r.u()? as usize;
620 let mut v = Vec::with_capacity(len);
621 for _ in 0..len {
622 v.push(Token(lists_r.u32()?));
623 }
624 lists.push(Rc::from(v));
625 }
626 let list = |i: u32| -> Result<TokenList, FormatError> {
627 lists
628 .get(i as usize)
629 .cloned()
630 .ok_or(FormatError::Corrupt("bad token list index"))
631 };
632
633 crate::timing::mark("undump: token lists");
634 self.eqtb.cs.clear();
636 self.eqtb.ensure_cs(CsId(self.hash.len() as u32 - 1));
637 let n = meanings_r.u()? as usize;
638 for _ in 0..n {
639 let i = meanings_r.u32()? as usize;
640 let cmd = cmd_of(meanings_r.byte()?)?;
641 let chr = meanings_r.u32()?;
642 let level = meanings_r.u()? as u16;
643 let flag = meanings_r.byte()?;
644 let mac = if flag == 0 {
645 None
646 } else {
647 Some(Rc::new(Macro::new(flag == 2, list(meanings_r.u32()?)?)))
648 };
649 let slot = self
650 .eqtb
651 .cs
652 .get_mut(i)
653 .ok_or(FormatError::Corrupt("meaning index"))?;
654 *slot = Slot {
655 val: Meaning { cmd, chr, mac },
656 level,
657 };
658 }
659
660 crate::timing::mark("undump: meanings");
661 let r = &mut params_r;
663 for which in 0..2 {
664 let n = r.u()? as usize;
665 let v = if which == 0 {
666 &mut self.eqtb.int_par
667 } else {
668 &mut self.eqtb.dimen_par
669 };
670 if v.len() < n {
671 return Err(FormatError::Corrupt("parameter count"));
672 }
673 for s in v.iter_mut().take(n) {
674 s.val = r.i32()?;
675 }
676 }
677 let n = r.u()? as usize;
678 for s in self.eqtb.glue_par.iter_mut().take(n) {
679 s.val = r.glue()?;
680 }
681 let n = r.u()? as usize;
682 for s in self.eqtb.toks_par.iter_mut().take(n) {
683 s.val = list(r.u32()?)?;
684 }
685 for which in 0..3 {
686 let n = r.u()? as usize;
687 for _ in 0..n {
688 let i = r.u()? as usize;
689 let v = r.i32()?;
690 let target = match which {
691 0 => &mut self.eqtb.count,
692 1 => &mut self.eqtb.attr,
693 _ => &mut self.eqtb.dimen,
694 };
695 target
696 .get_mut(i)
697 .ok_or(FormatError::Corrupt("register index"))?
698 .val = v;
699 }
700 }
701 for which in 0..2 {
702 let n = r.u()? as usize;
703 for _ in 0..n {
704 let i = r.u()? as usize;
705 let g = r.glue()?;
706 let target = if which == 0 {
707 &mut self.eqtb.skip
708 } else {
709 &mut self.eqtb.muskip
710 };
711 target
712 .get_mut(i)
713 .ok_or(FormatError::Corrupt("register index"))?
714 .val = g;
715 }
716 }
717 let n = r.u()? as usize;
718 for _ in 0..n {
719 let i = r.u()? as usize;
720 let l = list(r.u32()?)?;
721 self.eqtb
722 .toks
723 .get_mut(i)
724 .ok_or(FormatError::Corrupt("register index"))?
725 .val = l;
726 }
727 let n = r.u()? as usize;
728 for _ in 0..n {
729 let i = r.u()? as usize;
730 let b = self.undump_node_list(r, &lists)?;
731 self.eqtb
732 .boxes
733 .get_mut(i)
734 .ok_or(FormatError::Corrupt("box index"))?
735 .val = b;
736 }
737 self.eqtb.cur_font.val = r.u32()?;
738 let n = r.u()? as usize;
739 for _ in 0..n {
740 let i = r.u()? as usize;
741 let f = r.u32()?;
742 self.eqtb
743 .math_font
744 .get_mut(i)
745 .ok_or(FormatError::Corrupt("math font index"))?
746 .val = f;
747 }
748 let read_shape = |r: &mut Reader| -> Result<Option<Rc<[i32]>>, FormatError> {
749 let n = r.u()? as usize;
750 if n == 0 {
751 return Ok(None);
752 }
753 let mut v = Vec::with_capacity(n - 1);
754 for _ in 0..n - 1 {
755 v.push(r.i32()?);
756 }
757 Ok(Some(Rc::from(v)))
758 };
759 self.eqtb.par_shape.val = read_shape(r)?;
760 let n = r.u()? as usize;
761 for i in 0..n {
762 let s = read_shape(r)?;
763 if let Some(slot) = self.eqtb.etex_shape.get_mut(i) {
764 slot.val = s;
765 }
766 }
767 let n = r.u()? as usize;
768 let mut page_pool: Vec<Rc<crate::eqtb::Page>> = Vec::with_capacity(n);
769 for _ in 0..n {
770 let raw = r.bytes()?;
771 if raw.len() != 256 * 8 {
772 return Err(FormatError::Corrupt("code table page"));
773 }
774 page_pool.push(Rc::new(std::array::from_fn(|i| {
775 let b: [u8; 8] = raw[i * 8..i * 8 + 8].try_into().unwrap_or_default();
776 Slot {
777 val: i64::from_le_bytes(b),
778 level: crate::eqtb::LEVEL_ONE,
779 }
780 })));
781 }
782 let read_table = |r: &mut Reader, t: &mut CodeTable| -> Result<(), FormatError> {
783 let n = r.u()? as usize;
784 for _ in 0..n {
785 let k = r.u()? as usize;
786 let i = r.u()? as usize;
787 let page = page_pool
788 .get(i)
789 .ok_or(FormatError::Corrupt("code table page"))?;
790 if k > 0x11_0000 / 256 {
791 return Err(FormatError::Corrupt("code table page"));
792 }
793 t.load_page(k, page.clone());
794 }
795 Ok(())
796 };
797 crate::timing::mark("undump: registers (before code tables)");
798 let n = r.u()? as usize;
799 self.eqtb.catcode_tables.clear();
800 for _ in 0..n {
801 let k = r.u32()?;
802 let mut t = CodeTable::new(crate::eqtb::initex_catcode);
803 read_table(r, &mut t)?;
804 self.eqtb.catcode_tables.insert(k, t);
805 }
806 crate::timing::mark(&format!("undump: {n} catcode tables"));
807 read_table(r, &mut self.eqtb.lc)?;
808 read_table(r, &mut self.eqtb.uc)?;
809 read_table(r, &mut self.eqtb.sf)?;
810 read_table(r, &mut self.eqtb.math)?;
811 read_table(r, &mut self.eqtb.del)?;
812 let n = r.u()? as usize;
813 for _ in 0..n {
814 let k = r.u32()?;
815 let v = r.i32()?;
816 self.eqtb.math_param.insert(
817 k,
818 Slot {
819 val: v,
820 level: crate::eqtb::LEVEL_ONE,
821 },
822 );
823 }
824
825 crate::timing::mark("undump: parameters and registers");
826 let r = &mut fonts_r;
828 let n = r.u()? as usize;
829 self.fonts.fonts.clear();
830 self.fonts.id_cs.clear();
831 for _ in 0..n {
832 let mut fi = FontInfo::null();
833 fi.name = r.bytes()?.to_vec();
834 fi.size = r.i32()?;
835 fi.design_size = r.i32()?;
836 fi.checksum = r.u32()?;
837 let np = r.u()? as usize;
838 fi.params = (0..np).map(|_| r.i32()).collect::<Result<_, _>>()?;
839 let nc = r.u()? as usize;
840 fi.chars = HashMap::with_capacity_and_hasher(nc, crate::hash::FastHash::default());
841 for _ in 0..nc {
842 let c = r.u32()?;
843 let m = CharMetrics {
844 width: r.i32()?,
845 height: r.i32()?,
846 depth: r.i32()?,
847 italic: r.i32()?,
848 index: r.u32()?,
849 };
850 fi.chars.insert(c, m);
851 }
852 fi.hyphen_char = r.i32()?;
854 fi.skew_char = r.i32()?;
855 fi.kind = match r.byte()? {
856 0 => FontKind::Null,
857 1 => FontKind::Tfm,
858 _ => FontKind::OpenType,
859 };
860 fi.handle = r.u()?;
861 let cs = CsId(r.u32()?);
862 let raw = r.bytes()?;
863 if !raw.is_empty() {
864 let tfm = retex_font::tfm::Tfm::parse(raw)
865 .map_err(|_| FormatError::Corrupt("tfm font data"))?;
866 let scaled = tfm.scaled(fi.size);
868 fi.lig_kern = crate::fonts::lig_kern_table(&tfm, &scaled.kerns);
869 fi.right_boundary = tfm.bchar.map(u32::from);
870 fi.data = Some(crate::fonts::tfm_font_data(tfm, raw.to_vec()));
871 }
872 let nm = r.u()? as usize;
873 if nm > 0 {
874 let mut m = crate::fonts::MathConstants::new();
875 for _ in 1..nm {
876 let k = String::from_utf8_lossy(r.bytes()?).into_owned();
877 m.insert(k, r.i32()?);
878 }
879 fi.math_constants = Some(std::rc::Rc::new(m));
880 }
881 self.fonts.fonts.push(fi);
882 self.fonts.id_cs.push(cs);
883 }
884
885 crate::timing::mark("undump: fonts");
886 let r = &mut misc_r;
888 let mut ids = [CsId(0); 15];
889 for id in ids.iter_mut() {
890 *id = CsId(r.u32()?);
891 }
892 self.cs = crate::init::KnownCs {
893 par: ids[0],
894 frozen_protection: ids[1],
895 frozen_cr: ids[2],
896 frozen_end_group: ids[3],
897 frozen_right: ids[4],
898 frozen_fi: ids[5],
899 frozen_end_template: ids[6],
900 frozen_endv: ids[7],
901 frozen_relax: ids[8],
902 end_write: ids[9],
903 frozen_dont_expand: ids[10],
904 frozen_special: ids[11],
905 frozen_null_font: ids[12],
906 end_local: ids[13],
907 };
908 self.par_token_cs = ids[14];
909 self.format_ident = String::from_utf8_lossy(r.bytes()?).into_owned();
910 self.err.interaction = crate::error::Interaction::from_i32(i32::from(r.byte()?));
911 let n = r.u()? as usize;
912 self.frozen_prims.clear();
913 for _ in 0..n {
914 let name = r.bytes()?.to_vec();
915 let c = CsId(r.u32()?);
916 self.frozen_prims.insert(name, c);
917 }
918 let n = r.u()? as usize;
919 self.backend_cs.clear();
920 for _ in 0..n {
921 let name = r.bytes()?.to_vec();
922 let c = CsId(r.u32()?);
923 if let Some((static_name, _, _)) = crate::backend::PDF_VARIABLES
924 .iter()
925 .find(|(s, _, _)| s.as_bytes() == name.as_slice())
926 {
927 self.backend_cs.insert(static_name, c);
928 }
929 }
930 for i in 0..8 {
931 let v = r.i32()?;
932 if let Some(d) = self.eqtb.dir_par.get_mut(i) {
933 d.val = v;
934 }
935 }
936 let n = r.u()? as usize;
937 self.math_glues = (0..n).map(|_| r.glue()).collect::<Result<_, _>>()?;
938 self.printer.new_line_char = self
939 .eqtb
940 .int(crate::primitives_gen::assign_int::NEWLINECHAR);
941 crate::timing::mark("undump: misc");
942 let n = langs_r.u()? as usize;
944 self.languages.clear();
945 for _ in 0..n {
946 let i = langs_r.u()? as usize;
947 let l = retex_hyph::Language::from_bytes(langs_r.bytes()?)
948 .map_err(|_| FormatError::Corrupt("hyphenation language"))?;
949 if self.languages.len() <= i {
950 self.languages.resize_with(i + 1, || None);
951 }
952 self.languages[i] = Some(l);
953 }
954 Ok(())
955 }
956
957 fn undump_node_list(
958 &mut self,
959 r: &mut Reader,
960 lists: &[TokenList],
961 ) -> Result<NodeRef, FormatError> {
962 let n = r.u()? as usize;
963 let mut head = NodeRef::NULL;
964 let mut tail = NodeRef::NULL;
965 for _ in 0..n {
966 let t = r.byte()?;
967 let sub = r.u()? as u16;
968 let data = match t {
969 id::HLIST | id::VLIST => {
970 let width = r.i32()?;
971 let depth = r.i32()?;
972 let height = r.i32()?;
973 let shift = r.i32()?;
974 let dir = r.byte()? as i8;
975 let glue_order = r.byte()?;
976 let glue_sign = r.byte()?;
977 let glue_set = f64::from_bits(r.u()?);
978 let head = self.undump_node_list(r, lists)?;
979 NodeData::Box(Box::new(crate::nodes::BoxData {
980 width,
981 depth,
982 height,
983 dir,
984 shift,
985 glue_order,
986 glue_sign,
987 glue_set,
988 head,
989 }))
990 }
991 id::GLUE => NodeData::Glue {
992 spec: r.glue()?,
993 leader: NodeRef::NULL,
994 },
995 id::KERN => NodeData::Kern {
996 kern: r.i32()?,
997 expansion_factor: 0,
998 },
999 id::PENALTY => NodeData::Penalty { penalty: r.i32()? },
1000 id::RULE => NodeData::Rule {
1001 width: r.i32()?,
1002 depth: r.i32()?,
1003 height: r.i32()?,
1004 dir: 0,
1005 index: 0,
1006 left: 0,
1007 right: 0,
1008 },
1009 id::GLYPH => {
1010 let chr = r.u32()?;
1011 let font = r.u32()?;
1012 NodeData::Glyph(crate::nodes::GlyphData {
1013 chr,
1014 font,
1015 ..Default::default()
1016 })
1017 }
1018 id::MARK => {
1019 let class = r.u32()?;
1020 let i = r.u32()? as usize;
1021 NodeData::Mark {
1022 class,
1023 mark: lists
1024 .get(i)
1025 .cloned()
1026 .ok_or(FormatError::Corrupt("bad mark list"))?,
1027 }
1028 }
1029 _ => NodeData::Temp,
1030 };
1031 let p = self.nodes.alloc(t, sub, data);
1032 if head.is_null() {
1033 head = p;
1034 } else {
1035 self.nodes.link(tail, p);
1036 }
1037 tail = p;
1038 }
1039 Ok(head)
1040 }
1041}
1042
1043pub fn assemble(sections: &[(&str, &[u8])]) -> Vec<u8> {
1045 let mut w = Writer::default();
1046 w.buf.extend_from_slice(MAGIC);
1047 w.u(FORMAT_VERSION.into());
1048 w.bytes(env!("CARGO_PKG_VERSION").as_bytes());
1049 w.u(sections.len() as u64);
1050 for (name, data) in sections {
1051 w.bytes(name.as_bytes());
1052 w.bytes(data);
1053 }
1054 w.buf
1055}
1056
1057pub fn disassemble(data: &[u8]) -> Result<Vec<(&str, &[u8])>, FormatError> {
1059 if !data.starts_with(MAGIC) {
1060 return Err(FormatError::BadHeader);
1061 }
1062 let mut r = Reader::new(&data[MAGIC.len()..]);
1063 if r.u32()? != FORMAT_VERSION {
1064 return Err(FormatError::BadHeader);
1065 }
1066 if r.bytes()? != env!("CARGO_PKG_VERSION").as_bytes() {
1067 return Err(FormatError::BadHeader);
1068 }
1069 let n = r.u()? as usize;
1070 let mut out = Vec::with_capacity(n);
1071 for _ in 0..n {
1072 let name =
1073 std::str::from_utf8(r.bytes()?).map_err(|_| FormatError::Corrupt("section name"))?;
1074 let d = r.bytes()?;
1075 out.push((name, d));
1076 }
1077 Ok(out)
1078}
1079
1080#[cfg(test)]
1081mod tests {
1082 use super::*;
1083
1084 #[test]
1085 fn varints_round_trip() {
1086 let mut w = Writer::default();
1087 for v in [
1088 0i64,
1089 1,
1090 -1,
1091 63,
1092 -64,
1093 1 << 40,
1094 i64::from(i32::MIN),
1095 i64::from(i32::MAX),
1096 ] {
1097 w.i(v);
1098 }
1099 let mut r = Reader::new(&w.buf);
1100 for v in [
1101 0i64,
1102 1,
1103 -1,
1104 63,
1105 -64,
1106 1 << 40,
1107 i64::from(i32::MIN),
1108 i64::from(i32::MAX),
1109 ] {
1110 assert_eq!(r.i().unwrap(), v);
1111 }
1112 assert!(r.at_end());
1113 }
1114
1115 #[test]
1116 fn corrupt_data_is_an_error() {
1117 assert!(disassemble(b"nonsense").is_err());
1118 let mut r = Reader::new(&[0xFF, 0xFF]);
1119 assert!(r.u().is_err());
1120 }
1121}