typst_embedded_package/
archive.rs

1use std::io;
2use std::io::Read as _;
3
4use typst::foundations::Bytes;
5use typst::syntax::package::PackageSpec;
6use typst::syntax::{FileId, Source, VirtualPath};
7
8/// A file from a package's archive.
9pub enum File {
10    /// A [`Source`] file, i.e. a file with the `.typ` extension.
11    Source(Source),
12    /// A non-source file.
13    File(FileId, Bytes),
14}
15
16/// Reads a tgz archive and calls the `inspect` callback for each file.
17pub 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
52/// Reads all the files of a tgz archive.
53pub 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    /// Reads the package's archive and calls `inspect` for each files.
61    pub fn inspect_archive(&self, inspect: impl FnMut(File)) -> io::Result<()> {
62        inspect_archive(self.spec(), self.archive, inspect)
63    }
64
65    /// Reads all the files from the package's archive.
66    pub fn read_archive(&self) -> io::Result<Vec<File>> {
67        read_archive(self.spec(), self.archive)
68    }
69}