typst_embedded_package/
archive.rs1use std::io;
2use std::io::Read as _;
3
4use typst::foundations::Bytes;
5use typst::syntax::package::PackageSpec;
6use typst::syntax::{FileId, Source, VirtualPath};
7
8pub enum File {
10 Source(Source),
12 File(FileId, Bytes),
14}
15
16pub fn inspect_archive(
18 spec: PackageSpec,
19 tar_gz: impl io::Read,
20 mut inspect: impl FnMut(File),
21) -> io::Result<()> {
22 let tar = flate2::read::GzDecoder::new(tar_gz);
23 let mut archive = tar::Archive::new(tar);
24 let entries = archive.entries()?;
25
26 for entry in entries {
27 let mut entry = entry?;
28 let path = entry.path()?;
29
30 let is_source_file = path.extension().is_some_and(|ext| ext == "typ");
31
32 let file_id = FileId::new(Some(spec.clone()), VirtualPath::new(path));
33
34 let file = if is_source_file {
35 let mut content = String::new();
36 entry.read_to_string(&mut content)?;
37
38 File::Source(Source::new(file_id, content))
39 } else {
40 let mut content = Vec::new();
41 entry.read_to_end(&mut content)?;
42
43 File::File(file_id, Bytes::new(content))
44 };
45
46 inspect(file)
47 }
48
49 Ok(())
50}
51
52pub fn read_archive(spec: PackageSpec, tar_gz: impl io::Read) -> io::Result<Vec<File>> {
54 let mut files = Vec::new();
55 inspect_archive(spec, tar_gz, |file| files.push(file))?;
56 Ok(files)
57}
58
59impl super::Package {
60 pub fn inspect_archive(&self, inspect: impl FnMut(File)) -> io::Result<()> {
62 inspect_archive(self.spec(), self.archive, inspect)
63 }
64
65 pub fn read_archive(&self) -> io::Result<Vec<File>> {
67 read_archive(self.spec(), self.archive)
68 }
69}