Merge pull request #6001 from mockydevs/fix/eps-subfile-long-count

EPS import: SubFileDecode reads counts past 4 MiB (eps2write files with long streams open)
This commit is contained in:
BFlat
2026-11-07 09:35:19 +08:00
committed by GitHub
2 changed files with 14 additions and 1 deletions
+3 -1
View File
@@ -270,7 +270,9 @@ impl Interp<'_> {
let name = self.pop()?.text().ok_or(PsError::Ps("typecheck", "filter".into()))?;
let sub = if &*name == "SubFileDecode" {
let eod = self.pop_str()?.to_vec();
let count = self.pop_count()?;
// The count bounds what the filter reads, not what it allocates: a stream of several
// megabytes read through `currentfile N () /SubFileDecode filter` gives its length.
let count = usize::try_from(self.pop_int()?).map_err(|_| PsError::Ps("rangecheck", "a count".into()))?;
(count, eod)
} else {
(0, vec![])
+11
View File
@@ -1060,6 +1060,17 @@ fn an_executable_filter_runs_its_data_as_a_program() {
check("(1 2 add) 0 () /SubFileDecode filter exec type /filetype eq");
}
/// `SubFileDecode`'s count is how many bytes (or end strings) to pass, not an allocation: a count
/// past the 4 MiB cap on allocations (a long content stream's `/Length`) is read, and only the data
/// there passes through.
#[test]
fn subfile_counts_past_the_allocation_cap_are_read() {
check("(1 2 add) 6000000 () /SubFileDecode filter cvx exec 3 eq");
check("(1 2 add) 5000000 (x) /SubFileDecode filter cvx exec 3 eq");
check("(abcd) 7000000 () /SubFileDecode filter 8 string readstring pop (abcd) eq");
check("{ (1) -1 () /SubFileDecode filter } stopped");
}
#[test]
fn flushfile_skips_the_data_of_a_filter() {
// Metadata that isn't PostScript, skipped up to its end marker.