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 {
648 protected: flag == 2,
649 tokens: list(meanings_r.u32()?)?,
650 }))
651 };
652 let slot = self
653 .eqtb
654 .cs
655 .get_mut(i)
656 .ok_or(FormatError::Corrupt("meaning index"))?;
657 *slot = Slot {
658 val: Meaning { cmd, chr, mac },
659 level,
660 };
661 }
662
663 crate::timing::mark("undump: meanings");
664 let r = &mut params_r;
666 for which in 0..2 {
667 let n = r.u()? as usize;
668 let v = if which == 0 {
669 &mut self.eqtb.int_par
670 } else {
671 &mut self.eqtb.dimen_par
672 };
673 if v.len() < n {
674 return Err(FormatError::Corrupt("parameter count"));
675 }
676 for s in v.iter_mut().take(n) {
677 s.val = r.i32()?;
678 }
679 }
680 let n = r.u()? as usize;
681 for s in self.eqtb.glue_par.iter_mut().take(n) {
682 s.val = r.glue()?;
683 }
684 let n = r.u()? as usize;
685 for s in self.eqtb.toks_par.iter_mut().take(n) {
686 s.val = list(r.u32()?)?;
687 }
688 for which in 0..3 {
689 let n = r.u()? as usize;
690 for _ in 0..n {
691 let i = r.u()? as usize;
692 let v = r.i32()?;
693 let target = match which {
694 0 => &mut self.eqtb.count,
695 1 => &mut self.eqtb.attr,
696 _ => &mut self.eqtb.dimen,
697 };
698 target
699 .get_mut(i)
700 .ok_or(FormatError::Corrupt("register index"))?
701 .val = v;
702 }
703 }
704 for which in 0..2 {
705 let n = r.u()? as usize;
706 for _ in 0..n {
707 let i = r.u()? as usize;
708 let g = r.glue()?;
709 let target = if which == 0 {
710 &mut self.eqtb.skip
711 } else {
712 &mut self.eqtb.muskip
713 };
714 target
715 .get_mut(i)
716 .ok_or(FormatError::Corrupt("register index"))?
717 .val = g;
718 }
719 }
720 let n = r.u()? as usize;
721 for _ in 0..n {
722 let i = r.u()? as usize;
723 let l = list(r.u32()?)?;
724 self.eqtb
725 .toks
726 .get_mut(i)
727 .ok_or(FormatError::Corrupt("register index"))?
728 .val = l;
729 }
730 let n = r.u()? as usize;
731 for _ in 0..n {
732 let i = r.u()? as usize;
733 let b = self.undump_node_list(r, &lists)?;
734 self.eqtb
735 .boxes
736 .get_mut(i)
737 .ok_or(FormatError::Corrupt("box index"))?
738 .val = b;
739 }
740 self.eqtb.cur_font.val = r.u32()?;
741 let n = r.u()? as usize;
742 for _ in 0..n {
743 let i = r.u()? as usize;
744 let f = r.u32()?;
745 self.eqtb
746 .math_font
747 .get_mut(i)
748 .ok_or(FormatError::Corrupt("math font index"))?
749 .val = f;
750 }
751 let read_shape = |r: &mut Reader| -> Result<Option<Rc<[i32]>>, FormatError> {
752 let n = r.u()? as usize;
753 if n == 0 {
754 return Ok(None);
755 }
756 let mut v = Vec::with_capacity(n - 1);
757 for _ in 0..n - 1 {
758 v.push(r.i32()?);
759 }
760 Ok(Some(Rc::from(v)))
761 };
762 self.eqtb.par_shape.val = read_shape(r)?;
763 let n = r.u()? as usize;
764 for i in 0..n {
765 let s = read_shape(r)?;
766 if let Some(slot) = self.eqtb.etex_shape.get_mut(i) {
767 slot.val = s;
768 }
769 }
770 let n = r.u()? as usize;
771 let mut page_pool: Vec<Rc<crate::eqtb::Page>> = Vec::with_capacity(n);
772 for _ in 0..n {
773 let raw = r.bytes()?;
774 if raw.len() != 256 * 8 {
775 return Err(FormatError::Corrupt("code table page"));
776 }
777 page_pool.push(Rc::new(std::array::from_fn(|i| {
778 let b: [u8; 8] = raw[i * 8..i * 8 + 8].try_into().unwrap_or_default();
779 Slot {
780 val: i64::from_le_bytes(b),
781 level: crate::eqtb::LEVEL_ONE,
782 }
783 })));
784 }
785 let read_table = |r: &mut Reader, t: &mut CodeTable| -> Result<(), FormatError> {
786 let n = r.u()? as usize;
787 for _ in 0..n {
788 let k = r.u()? as usize;
789 let i = r.u()? as usize;
790 let page = page_pool
791 .get(i)
792 .ok_or(FormatError::Corrupt("code table page"))?;
793 if k > 0x11_0000 / 256 {
794 return Err(FormatError::Corrupt("code table page"));
795 }
796 t.load_page(k, page.clone());
797 }
798 Ok(())
799 };
800 crate::timing::mark("undump: registers (before code tables)");
801 let n = r.u()? as usize;
802 self.eqtb.catcode_tables.clear();
803 for _ in 0..n {
804 let k = r.u32()?;
805 let mut t = CodeTable::new(crate::eqtb::initex_catcode);
806 read_table(r, &mut t)?;
807 self.eqtb.catcode_tables.insert(k, t);
808 }
809 crate::timing::mark(&format!("undump: {n} catcode tables"));
810 read_table(r, &mut self.eqtb.lc)?;
811 read_table(r, &mut self.eqtb.uc)?;
812 read_table(r, &mut self.eqtb.sf)?;
813 read_table(r, &mut self.eqtb.math)?;
814 read_table(r, &mut self.eqtb.del)?;
815 let n = r.u()? as usize;
816 for _ in 0..n {
817 let k = r.u32()?;
818 let v = r.i32()?;
819 self.eqtb.math_param.insert(
820 k,
821 Slot {
822 val: v,
823 level: crate::eqtb::LEVEL_ONE,
824 },
825 );
826 }
827
828 crate::timing::mark("undump: parameters and registers");
829 let r = &mut fonts_r;
831 let n = r.u()? as usize;
832 self.fonts.fonts.clear();
833 self.fonts.id_cs.clear();
834 for _ in 0..n {
835 let mut fi = FontInfo::null();
836 fi.name = r.bytes()?.to_vec();
837 fi.size = r.i32()?;
838 fi.design_size = r.i32()?;
839 fi.checksum = r.u32()?;
840 let np = r.u()? as usize;
841 fi.params = (0..np).map(|_| r.i32()).collect::<Result<_, _>>()?;
842 let nc = r.u()? as usize;
843 fi.chars = HashMap::with_capacity_and_hasher(nc, crate::hash::FastHash::default());
844 for _ in 0..nc {
845 let c = r.u32()?;
846 let m = CharMetrics {
847 width: r.i32()?,
848 height: r.i32()?,
849 depth: r.i32()?,
850 italic: r.i32()?,
851 index: r.u32()?,
852 };
853 fi.chars.insert(c, m);
854 }
855 fi.hyphen_char = r.i32()?;
857 fi.skew_char = r.i32()?;
858 fi.kind = match r.byte()? {
859 0 => FontKind::Null,
860 1 => FontKind::Tfm,
861 _ => FontKind::OpenType,
862 };
863 fi.handle = r.u()?;
864 let cs = CsId(r.u32()?);
865 let raw = r.bytes()?;
866 if !raw.is_empty() {
867 let tfm = retex_font::tfm::Tfm::parse(raw)
868 .map_err(|_| FormatError::Corrupt("tfm font data"))?;
869 let scaled = tfm.scaled(fi.size);
871 fi.lig_kern = crate::fonts::lig_kern_table(&tfm, &scaled.kerns);
872 fi.right_boundary = tfm.bchar.map(u32::from);
873 fi.data = Some(crate::fonts::tfm_font_data(tfm, raw.to_vec()));
874 }
875 let nm = r.u()? as usize;
876 if nm > 0 {
877 let mut m = crate::fonts::MathConstants::new();
878 for _ in 1..nm {
879 let k = String::from_utf8_lossy(r.bytes()?).into_owned();
880 m.insert(k, r.i32()?);
881 }
882 fi.math_constants = Some(std::rc::Rc::new(m));
883 }
884 self.fonts.fonts.push(fi);
885 self.fonts.id_cs.push(cs);
886 }
887
888 crate::timing::mark("undump: fonts");
889 let r = &mut misc_r;
891 let mut ids = [CsId(0); 15];
892 for id in ids.iter_mut() {
893 *id = CsId(r.u32()?);
894 }
895 self.cs = crate::init::KnownCs {
896 par: ids[0],
897 frozen_protection: ids[1],
898 frozen_cr: ids[2],
899 frozen_end_group: ids[3],
900 frozen_right: ids[4],
901 frozen_fi: ids[5],
902 frozen_end_template: ids[6],
903 frozen_endv: ids[7],
904 frozen_relax: ids[8],
905 end_write: ids[9],
906 frozen_dont_expand: ids[10],
907 frozen_special: ids[11],
908 frozen_null_font: ids[12],
909 end_local: ids[13],
910 };
911 self.par_token_cs = ids[14];
912 self.format_ident = String::from_utf8_lossy(r.bytes()?).into_owned();
913 self.err.interaction = crate::error::Interaction::from_i32(i32::from(r.byte()?));
914 let n = r.u()? as usize;
915 self.frozen_prims.clear();
916 for _ in 0..n {
917 let name = r.bytes()?.to_vec();
918 let c = CsId(r.u32()?);
919 self.frozen_prims.insert(name, c);
920 }
921 let n = r.u()? as usize;
922 self.backend_cs.clear();
923 for _ in 0..n {
924 let name = r.bytes()?.to_vec();
925 let c = CsId(r.u32()?);
926 if let Some((static_name, _, _)) = crate::backend::PDF_VARIABLES
927 .iter()
928 .find(|(s, _, _)| s.as_bytes() == name.as_slice())
929 {
930 self.backend_cs.insert(static_name, c);
931 }
932 }
933 for i in 0..8 {
934 let v = r.i32()?;
935 if let Some(d) = self.eqtb.dir_par.get_mut(i) {
936 d.val = v;
937 }
938 }
939 let n = r.u()? as usize;
940 self.math_glues = (0..n).map(|_| r.glue()).collect::<Result<_, _>>()?;
941 self.printer.new_line_char = self
942 .eqtb
943 .int(crate::primitives_gen::assign_int::NEWLINECHAR);
944 crate::timing::mark("undump: misc");
945 let n = langs_r.u()? as usize;
947 self.languages.clear();
948 for _ in 0..n {
949 let i = langs_r.u()? as usize;
950 let l = retex_hyph::Language::from_bytes(langs_r.bytes()?)
951 .map_err(|_| FormatError::Corrupt("hyphenation language"))?;
952 if self.languages.len() <= i {
953 self.languages.resize_with(i + 1, || None);
954 }
955 self.languages[i] = Some(l);
956 }
957 Ok(())
958 }
959
960 fn undump_node_list(
961 &mut self,
962 r: &mut Reader,
963 lists: &[TokenList],
964 ) -> Result<NodeRef, FormatError> {
965 let n = r.u()? as usize;
966 let mut head = NodeRef::NULL;
967 let mut tail = NodeRef::NULL;
968 for _ in 0..n {
969 let t = r.byte()?;
970 let sub = r.u()? as u16;
971 let data = match t {
972 id::HLIST | id::VLIST => {
973 let width = r.i32()?;
974 let depth = r.i32()?;
975 let height = r.i32()?;
976 let shift = r.i32()?;
977 let dir = r.byte()? as i8;
978 let glue_order = r.byte()?;
979 let glue_sign = r.byte()?;
980 let glue_set = f64::from_bits(r.u()?);
981 let head = self.undump_node_list(r, lists)?;
982 NodeData::Box(Box::new(crate::nodes::BoxData {
983 width,
984 depth,
985 height,
986 dir,
987 shift,
988 glue_order,
989 glue_sign,
990 glue_set,
991 head,
992 }))
993 }
994 id::GLUE => NodeData::Glue {
995 spec: r.glue()?,
996 leader: NodeRef::NULL,
997 },
998 id::KERN => NodeData::Kern {
999 kern: r.i32()?,
1000 expansion_factor: 0,
1001 },
1002 id::PENALTY => NodeData::Penalty { penalty: r.i32()? },
1003 id::RULE => NodeData::Rule {
1004 width: r.i32()?,
1005 depth: r.i32()?,
1006 height: r.i32()?,
1007 dir: 0,
1008 index: 0,
1009 left: 0,
1010 right: 0,
1011 },
1012 id::GLYPH => {
1013 let chr = r.u32()?;
1014 let font = r.u32()?;
1015 NodeData::Glyph(crate::nodes::GlyphData {
1016 chr,
1017 font,
1018 ..Default::default()
1019 })
1020 }
1021 id::MARK => {
1022 let class = r.u32()?;
1023 let i = r.u32()? as usize;
1024 NodeData::Mark {
1025 class,
1026 mark: lists
1027 .get(i)
1028 .cloned()
1029 .ok_or(FormatError::Corrupt("bad mark list"))?,
1030 }
1031 }
1032 _ => NodeData::Temp,
1033 };
1034 let p = self.nodes.alloc(t, sub, data);
1035 if head.is_null() {
1036 head = p;
1037 } else {
1038 self.nodes.link(tail, p);
1039 }
1040 tail = p;
1041 }
1042 Ok(head)
1043 }
1044}
1045
1046pub fn assemble(sections: &[(&str, &[u8])]) -> Vec<u8> {
1048 let mut w = Writer::default();
1049 w.buf.extend_from_slice(MAGIC);
1050 w.u(FORMAT_VERSION.into());
1051 w.bytes(env!("CARGO_PKG_VERSION").as_bytes());
1052 w.u(sections.len() as u64);
1053 for (name, data) in sections {
1054 w.bytes(name.as_bytes());
1055 w.bytes(data);
1056 }
1057 w.buf
1058}
1059
1060pub fn disassemble(data: &[u8]) -> Result<Vec<(&str, &[u8])>, FormatError> {
1062 if !data.starts_with(MAGIC) {
1063 return Err(FormatError::BadHeader);
1064 }
1065 let mut r = Reader::new(&data[MAGIC.len()..]);
1066 if r.u32()? != FORMAT_VERSION {
1067 return Err(FormatError::BadHeader);
1068 }
1069 if r.bytes()? != env!("CARGO_PKG_VERSION").as_bytes() {
1070 return Err(FormatError::BadHeader);
1071 }
1072 let n = r.u()? as usize;
1073 let mut out = Vec::with_capacity(n);
1074 for _ in 0..n {
1075 let name =
1076 std::str::from_utf8(r.bytes()?).map_err(|_| FormatError::Corrupt("section name"))?;
1077 let d = r.bytes()?;
1078 out.push((name, d));
1079 }
1080 Ok(out)
1081}
1082
1083#[cfg(test)]
1084mod tests {
1085 use super::*;
1086
1087 #[test]
1088 fn varints_round_trip() {
1089 let mut w = Writer::default();
1090 for v in [
1091 0i64,
1092 1,
1093 -1,
1094 63,
1095 -64,
1096 1 << 40,
1097 i64::from(i32::MIN),
1098 i64::from(i32::MAX),
1099 ] {
1100 w.i(v);
1101 }
1102 let mut r = Reader::new(&w.buf);
1103 for v in [
1104 0i64,
1105 1,
1106 -1,
1107 63,
1108 -64,
1109 1 << 40,
1110 i64::from(i32::MIN),
1111 i64::from(i32::MAX),
1112 ] {
1113 assert_eq!(r.i().unwrap(), v);
1114 }
1115 assert!(r.at_end());
1116 }
1117
1118 #[test]
1119 fn corrupt_data_is_an_error() {
1120 assert!(disassemble(b"nonsense").is_err());
1121 let mut r = Reader::new(&[0xFF, 0xFF]);
1122 assert!(r.u().is_err());
1123 }
1124}